Merge topic 'normalize-install-destination-paths'

6a1fac1450 install: Normalize DESTINATION paths
2184fcfb00 Tests: Configure RunCMake.install cases with correct build type
5a8a6dfe81 cmGeneratorExpression: Change Find() parameter type to cm::string_view
d810374b3d install(PACKAGE_INFO): Remove outdated TODO comment
d13ed01d54 Tests: Remove unused files from RunCMake.install

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !9800
This commit is contained in:
Brad King
2024-09-20 14:27:18 +00:00
committed by Kitware Robot
26 changed files with 357 additions and 58 deletions

View File

@@ -58,7 +58,7 @@ signatures that specify them. The common options are:
``<dir>`` should be a relative path. An absolute path is allowed,
but not recommended.
When a relative path is given it is interpreted relative to the value
When a relative path is given, it is interpreted relative to the value
of the :variable:`CMAKE_INSTALL_PREFIX` variable.
The prefix can be relocated at install time using the ``DESTDIR``
mechanism explained in the :variable:`CMAKE_INSTALL_PREFIX` variable
@@ -75,6 +75,11 @@ signatures that specify them. The common options are:
If an absolute path (with a leading slash or drive letter) is given
it is used verbatim.
.. versionchanged:: 3.31
``<dir>`` will be normalized according to the same
:ref:`normalization rules <Normalization>` as the
:command:`cmake_path` command.
``PERMISSIONS <permission>...``
Specify permissions for installed files. Valid permissions are
``OWNER_READ``, ``OWNER_WRITE``, ``OWNER_EXECUTE``, ``GROUP_READ``,
@@ -396,6 +401,12 @@ Signatures
If a relative path is specified, it is treated as relative to the
:genex:`$<INSTALL_PREFIX>`.
Unlike other ``DESTINATION`` arguments for the various ``install()``
subcommands, paths given after ``INCLUDES DESTINATION`` are used as
given. They are not normalized, nor assumed to be normalized, although
it is recommended that they are given in normalized form (see
:ref:`Normalization`).
``RUNTIME_DEPENDENCY_SET <set-name>``
.. versionadded:: 3.21
@@ -815,6 +826,7 @@ Signatures
the generated file will be called ``<export-name>.cmake`` but the ``FILE``
option may be used to specify a different name. The value given to
the ``FILE`` option must be a file name with the ``.cmake`` extension.
If a ``CONFIGURATIONS`` option is given then the file will only be installed
when one of the named configurations is installed. Additionally, the
generated import file will reference only the matching target

View File

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.31
.. toctree::
:maxdepth: 1
CMP0177: install() DESTINATION paths are normalized. </policy/CMP0177>
CMP0176: execute_process() ENCODING is UTF-8 by default. </policy/CMP0176>
CMP0175: add_custom_command() rejects invalid arguments. </policy/CMP0175>
CMP0174: cmake_parse_arguments(PARSE_ARGV) defines a variable for an empty string after a single-value keyword. </policy/CMP0174>

38
Help/policy/CMP0177.rst Normal file
View File

@@ -0,0 +1,38 @@
CMP0177
-------
.. versionadded:: 3.31
:command:`install` ``DESTINATION`` paths are normalized.
The :command:`install` command has a number of different forms, and most of
them take a ``DESTINATION`` keyword, some in more than one place.
CMake 3.30 and earlier used the value given after the ``DESTINATION`` keyword
as provided with no transformations. The :command:`install(EXPORT)` form
assumes the path contains no ``..`` or ``.`` path components when computing
a path relative to the ``DESTINATION``, and if the project provided a path
that violated that assumption, the computed path would be incorrect.
CMake 3.31 normalizes all ``DESTINATION`` values given in any form of the
:command:`install` command, except for the ``INCLUDES DESTINATION`` of the
:command:`install(TARGETS)` form. The normalization performed is the same
as for the :command:`cmake_path` command (see :ref:`Normalization`).
The ``OLD`` behavior of this policy performs no translation on the
``DESTINATION`` values of any :command:`install` command. They are used
exactly as provided. If a destination path contains ``..`` or ``.`` path
components, :command:`install(EXPORT)` will use the same wrong paths as
CMake 3.30 and earlier.
The ``NEW`` behavior will normalize all ``DESTINATION`` values except for
``INCLUDES DESTINATION``. If a destination path contains a generator
expression, it will be wrapped in a ``$<PATH:CMAKE_PATH,NORMALIZE,...>``
generator expression.
This policy was introduced in CMake version 3.31.
It may be set by :command:`cmake_policy` or :command:`cmake_minimum_required`.
If it is not set, CMake will warn if it detects a path that would be different
if normalized, and uses ``OLD`` behavior. If a destination path contains a
generator expression, no such warning will be issued regardless of the value.
.. include:: DEPRECATED.txt

View File

@@ -0,0 +1,6 @@
normalize-install-destination-paths
-----------------------------------
* All ``DESTINATION`` arguments in :command:`install` commands
are now :ref:`normalized <Normalization>`, with the exception
of ``INCLUDES DESTINATION`` arguments in the ``TARGETS`` form.

View File

@@ -375,14 +375,15 @@ std::string cmGeneratorExpression::Preprocess(const std::string& input,
return std::string();
}
std::string::size_type cmGeneratorExpression::Find(const std::string& input)
cm::string_view::size_type cmGeneratorExpression::Find(
const cm::string_view& input)
{
const std::string::size_type openpos = input.find("$<");
if (openpos != std::string::npos &&
input.find('>', openpos) != std::string::npos) {
const cm::string_view::size_type openpos = input.find("$<");
if (openpos != cm::string_view::npos &&
input.find('>', openpos) != cm::string_view::npos) {
return openpos;
}
return std::string::npos;
return cm::string_view::npos;
}
bool cmGeneratorExpression::IsValidTargetName(const std::string& input)

View File

@@ -66,7 +66,7 @@ public:
static void Split(const std::string& input,
std::vector<std::string>& output);
static std::string::size_type Find(const std::string& input);
static cm::string_view::size_type Find(const cm::string_view& input);
static bool IsValidTargetName(const std::string& input);

View File

@@ -20,6 +20,7 @@
#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
#include "cmCMakePath.h"
#include "cmExecutionStatus.h"
#include "cmExperimental.h"
#include "cmExportSet.h"
@@ -455,7 +456,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
runtimeDependenciesArgVector;
std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
cmInstallCommandArguments genericArgs(helper.DefaultComponentName,
*helper.Makefile);
genericArgs.Bind("TARGETS"_s, targetList);
genericArgs.Bind("EXPORT"_s, exports);
genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
@@ -469,19 +471,31 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
&unknownArgs)
: RuntimeDependenciesArgs();
cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
cmInstallCommandArguments objectArgs(helper.DefaultComponentName);
cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
cmInstallCommandArguments privateHeaderArgs(helper.DefaultComponentName);
cmInstallCommandArguments publicHeaderArgs(helper.DefaultComponentName);
cmInstallCommandArguments resourceArgs(helper.DefaultComponentName);
cmInstallCommandArguments archiveArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments objectArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments bundleArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments privateHeaderArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments publicHeaderArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments resourceArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandIncludesArgument includesArgs;
std::vector<cmInstallCommandFileSetArguments> fileSetArgs(
argVectors.FileSets.size(), { helper.DefaultComponentName });
cmInstallCommandArguments cxxModuleBmiArgs(helper.DefaultComponentName);
argVectors.FileSets.size(),
{ cmInstallCommandFileSetArguments(helper.DefaultComponentName,
*helper.Makefile) });
cmInstallCommandArguments cxxModuleBmiArgs(helper.DefaultComponentName,
*helper.Makefile);
// now parse the args for specific parts of the target (e.g. LIBRARY,
// RUNTIME, ARCHIVE etc.
@@ -501,7 +515,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
// cmArgumentParser<void>::Bind() binds to a specific address, but the
// objects in the vector can move around. So we parse in an object with a
// fixed address and then copy the data into the vector.
cmInstallCommandFileSetArguments fileSetArg(helper.DefaultComponentName);
cmInstallCommandFileSetArguments fileSetArg(helper.DefaultComponentName,
*helper.Makefile);
fileSetArg.Parse(argVectors.FileSets[i], &unknownArgs);
fileSetArgs[i] = std::move(fileSetArg);
}
@@ -1312,16 +1327,21 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
cmInstallCommandArguments genericArgs(helper.DefaultComponentName,
*helper.Makefile);
genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList)
.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments bundleArgs(helper.DefaultComponentName,
*helper.Makefile);
// now parse the args for specific parts of the target (e.g. LIBRARY,
// RUNTIME etc.
@@ -1549,7 +1569,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
// This is the FILES mode.
bool programs = (args[0] == "PROGRAMS");
cmInstallCommandArguments ica(helper.DefaultComponentName);
cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile);
ArgumentParser::MaybeEmpty<std::vector<std::string>> files;
ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
std::vector<std::string> unknownArgs;
@@ -1683,7 +1703,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
bool exclude_from_all = false;
bool message_never = false;
std::vector<std::string> dirs;
const std::string* destination = nullptr;
cm::optional<std::string> destination;
std::string permissions_file;
std::string permissions_dir;
std::vector<std::string> configurations;
@@ -1841,7 +1861,33 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
} else if (doing == DoingConfigurations) {
configurations.push_back(args[i]);
} else if (doing == DoingDestination) {
destination = &args[i];
// A trailing slash is meaningful for this form, but normalization
// preserves it if present
switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0177)) {
case cmPolicies::NEW:
destination = cmCMakePath(args[i]).Normal().String();
break;
case cmPolicies::WARN:
// We can't be certain if a warning is appropriate if there are any
// generator expressions
if (cmGeneratorExpression::Find(args[i]) == cm::string_view::npos &&
args[i] != cmCMakePath(args[i]).Normal().String()) {
status.GetMakefile().IssueMessage(
MessageType::AUTHOR_WARNING,
cmPolicies::GetPolicyWarning(cmPolicies::CMP0177));
}
CM_FALLTHROUGH;
case cmPolicies::OLD:
destination = args[i];
break;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
// We should never get here, only OLD, WARN, and NEW are used
status.GetMakefile().IssueMessage(
MessageType::FATAL_ERROR,
cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0177));
return false;
}
doing = DoingNone;
} else if (doing == DoingType) {
if (allowedTypes.count(args[i]) == 0) {
@@ -1911,7 +1957,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
}
// Support installing an empty directory.
if (dirs.empty() && destination) {
if (dirs.empty() && destination.has_value()) {
dirs.emplace_back();
}
@@ -1919,15 +1965,13 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
if (dirs.empty()) {
return true;
}
std::string destinationStr;
if (!destination) {
if (!destination.has_value()) {
if (type.empty()) {
// A destination is required.
status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
return false;
}
destinationStr = helper.GetDestinationForType(nullptr, type);
destination = &destinationStr;
destination = helper.GetDestinationForType(nullptr, type);
} else if (!type.empty()) {
status.SetError(cmStrCat(args[0],
" given both TYPE and DESTINATION "
@@ -1959,7 +2003,7 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
Helper helper(status);
// This is the EXPORT mode.
cmInstallCommandArguments ica(helper.DefaultComponentName);
cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile);
std::string exp;
std::string name_space;
@@ -2052,7 +2096,7 @@ bool HandleExportMode(std::vector<std::string> const& args,
Helper helper(status);
// This is the EXPORT mode.
cmInstallCommandArguments ica(helper.DefaultComponentName);
cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile);
std::string exp;
std::string name_space;
@@ -2178,7 +2222,7 @@ bool HandlePackageInfoMode(std::vector<std::string> const& args,
Helper helper(status);
// This is the PACKAGE_INFO mode.
cmInstallCommandArguments ica(helper.DefaultComponentName);
cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile);
ArgumentParser::NonEmpty<std::string> pkg;
ArgumentParser::NonEmpty<std::string> appendix;
@@ -2191,7 +2235,6 @@ bool HandlePackageInfoMode(std::vector<std::string> const& args,
ArgumentParser::NonEmpty<std::vector<std::string>> defaultConfigs;
ArgumentParser::NonEmpty<std::string> cxxModulesDirectory;
// TODO: Support DESTINATION.
ica.Bind("PACKAGE_INFO"_s, pkg);
ica.Bind("EXPORT"_s, exportName);
ica.Bind("APPENDIX"_s, appendix);
@@ -2338,14 +2381,18 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
// These generic args also contain the runtime dependency set
std::string runtimeDependencySetArg;
std::vector<std::string> runtimeDependencyArgVector;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
cmInstallCommandArguments genericArgs(helper.DefaultComponentName,
*helper.Makefile);
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector);
bool success = genericArgs.Finalize();
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName,
*helper.Makefile);
cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName,
*helper.Makefile);
// Now also parse the file(GET_RUNTIME_DEPENDENCY) args
std::vector<std::string> unknownArgs;

View File

@@ -3,11 +3,19 @@
#include "cmInstallCommandArguments.h"
#include <algorithm>
#include <functional>
#include <utility>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmCMakePath.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
// Table of valid permissions.
@@ -20,10 +28,53 @@ const char* cmInstallCommandArguments::PermissionsTable[] = {
const std::string cmInstallCommandArguments::EmptyString;
cmInstallCommandArguments::cmInstallCommandArguments(
std::string defaultComponent)
std::string defaultComponent, cmMakefile& makefile)
: DefaultComponentName(std::move(defaultComponent))
{
this->Bind("DESTINATION"_s, this->Destination);
std::function<ArgumentParser::Continue(cm::string_view)> normalizeDest;
switch (makefile.GetPolicyStatus(cmPolicies::CMP0177)) {
case cmPolicies::OLD:
normalizeDest = [this](cm::string_view arg) -> ArgumentParser::Continue {
this->Destination = std::string(arg.begin(), arg.end());
return ArgumentParser::Continue::Yes;
};
break;
case cmPolicies::WARN:
normalizeDest =
[this, &makefile](cm::string_view arg) -> ArgumentParser::Continue {
this->Destination = std::string(arg.begin(), arg.end());
// We can't be certain if a warning is appropriate if there are any
// generator expressions
if (cmGeneratorExpression::Find(arg) == cm::string_view::npos &&
arg != cmCMakePath(arg).Normal().String()) {
makefile.IssueMessage(
MessageType::AUTHOR_WARNING,
cmPolicies::GetPolicyWarning(cmPolicies::CMP0177));
}
return ArgumentParser::Continue::Yes;
};
break;
case cmPolicies::NEW:
normalizeDest = [this](cm::string_view arg) -> ArgumentParser::Continue {
if (cmGeneratorExpression::Find(arg) == cm::string_view::npos) {
this->Destination = cmCMakePath(arg).Normal().String();
} else {
this->Destination =
cmStrCat("$<PATH:CMAKE_PATH,NORMALIZE,", arg, '>');
}
return ArgumentParser::Continue::Yes;
};
break;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
// We should never get here, only OLD, WARN, and NEW are used
makefile.IssueMessage(
MessageType::FATAL_ERROR,
cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0177));
}
this->Bind("DESTINATION"_s, normalizeDest);
this->Bind("COMPONENT"_s, this->Component);
this->Bind("NAMELINK_COMPONENT"_s, this->NamelinkComponent);
this->Bind("EXCLUDE_FROM_ALL"_s, this->ExcludeFromAll);
@@ -227,8 +278,8 @@ void cmInstallCommandIncludesArgument::Parse(
}
cmInstallCommandFileSetArguments::cmInstallCommandFileSetArguments(
std::string defaultComponent)
: cmInstallCommandArguments(std::move(defaultComponent))
std::string defaultComponent, cmMakefile& makefile)
: cmInstallCommandArguments(std::move(defaultComponent), makefile)
{
this->Bind("FILE_SET"_s, this->FileSet);
}

View File

@@ -10,10 +10,13 @@
#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
class cmMakefile;
class cmInstallCommandArguments : public cmArgumentParser<void>
{
public:
cmInstallCommandArguments(std::string defaultComponent);
cmInstallCommandArguments(std::string defaultComponent,
cmMakefile& makefile);
void SetGenericArguments(cmInstallCommandArguments* args)
{
this->GenericArguments = args;
@@ -78,7 +81,8 @@ private:
class cmInstallCommandFileSetArguments : public cmInstallCommandArguments
{
public:
cmInstallCommandFileSetArguments(std::string defaultComponent);
cmInstallCommandFileSetArguments(std::string defaultComponent,
cmMakefile& makefile);
void Parse(std::vector<std::string> args,
std::vector<std::string>* unconsumedArgs);

View File

@@ -541,7 +541,9 @@ class cmMakefile;
SELECT(POLICY, CMP0175, "add_custom_command() rejects invalid arguments.", \
3, 31, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0176, "execute_process() ENCODING is UTF-8 by default.", \
3, 31, 0, cmPolicies::WARN)
3, 31, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0177, "install() DESTINATION paths are normalized.", 3, \
31, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \

View File

@@ -0,0 +1,36 @@
set(installBase ${RunCMake_TEST_BINARY_DIR}/root-all)
foreach(i RANGE 1 5)
set(subdir shouldNotRemain${i})
if(IS_DIRECTORY ${installBase}/${subdir})
set(RunCMake_TEST_FAILED "Check failed.")
string(APPEND RunCMake_TEST_FAILURE_MESSAGE
"\nUnexpectedly created install path that should have disappeared with "
"normalization:\n"
" ${installBase}/${subdir}"
)
endif()
endforeach()
file(GLOB perConfigFiles ${installBase}/lib/cmake/pkg/pkg-config-*.cmake)
foreach(file IN LISTS perConfigFiles ITEMS ${installBase}/lib/cmake/pkg/pkg-config.cmake)
file(STRINGS ${file} matches REGEX shouldNotRemain)
if(NOT matches STREQUAL "")
set(RunCMake_TEST_FAILED "Check failed.")
string(APPEND RunCMake_TEST_FAILURE_MESSAGE
"\nNon-normalized path found in ${file}:"
)
foreach(match IN LISTS matches)
string(APPEND RunCMake_TEST_FAILURE_MESSAGE "\n ${match}")
endforeach()
endif()
endforeach()
if(NOT EXISTS "${installBase}/dirs/dir/empty.txt")
set(RunCMake_TEST_FAILED "Check failed.")
string(APPEND RunCMake_TEST_FAILURE_MESSAGE
"\nNon-normalized DIRECTORY destination not handled correctly. "
"Expected to find the following file, but it was missing:\n"
" ${installBase}/dirs/dir/empty.txt"
)
endif()

View File

@@ -0,0 +1,2 @@
enable_language(C)
find_package(pkg REQUIRED)

View File

@@ -0,0 +1,2 @@
cmake_policy(SET CMP0177 NEW)
include(${CMAKE_CURRENT_LIST_DIR}/CMP0177.cmake)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,13 @@
CMake Error at [^
]*CMP0177-OLD-build/root-all/lib/cmake/pkg/pkg-config\.cmake:[0-9]+ \(message\):
The imported target "foo1" references the file
+ ".*/shouldNotRemain1/\.\./lib/(libfoo1\.a|foo1\.l(ib)?)"
+ but this file does not exist\. Possible reasons include:
+ \* The file was deleted, renamed, or moved to another location\.
+ \* An install or uninstall procedure did not complete successfully\.
+ \* The installation package was faulty and contained
+ ".*/Tests/RunCMake/install/CMP0177-OLD-build/root-all/lib/cmake/pkg/pkg-config\.cmake"
+ but not all the files it references\.
+Call Stack \(most recent call first\):
CMP0177-OLD-verify\.cmake:2 \(find_package\)
CMakeLists\.txt:3 \(include\)

View File

@@ -0,0 +1,2 @@
enable_language(C)
find_package(pkg REQUIRED)

View File

@@ -0,0 +1,2 @@
cmake_policy(SET CMP0177 OLD)
include(${CMAKE_CURRENT_LIST_DIR}/CMP0177.cmake)

View File

@@ -0,0 +1,35 @@
CMake Warning \(dev\) at CMP0177\.cmake:[0-9]+ \(install\):
Policy CMP0177 is not set: install\(\) DESTINATION paths are normalized\. Run
"cmake --help-policy CMP0177" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Call Stack \(most recent call first\):
CMP0177-WARN\.cmake:1 \(include\)
CMakeLists\.txt:3 \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
CMake Warning \(dev\) at CMP0177\.cmake:[0-9]+ \(install\):
Policy CMP0177 is not set: install\(\) DESTINATION paths are normalized\. Run
"cmake --help-policy CMP0177" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Call Stack \(most recent call first\):
CMP0177-WARN\.cmake:1 \(include\)
CMakeLists\.txt:3 \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
CMake Warning \(dev\) at CMP0177\.cmake:[0-9]+ \(install\):
Policy CMP0177 is not set: install\(\) DESTINATION paths are normalized\. Run
"cmake --help-policy CMP0177" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Call Stack \(most recent call first\):
CMP0177-WARN\.cmake:1 \(include\)
CMakeLists\.txt:3 \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
CMake Warning \(dev\) at CMP0177\.cmake:[0-9]+ \(install\):
Policy CMP0177 is not set: install\(\) DESTINATION paths are normalized\. Run
"cmake --help-policy CMP0177" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Call Stack \(most recent call first\):
CMP0177-WARN\.cmake:1 \(include\)
CMakeLists\.txt:3 \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,13 @@
CMake Error at [^
]*CMP0177-WARN-build/root-all/lib/cmake/pkg/pkg-config\.cmake:[0-9]+ \(message\):
The imported target "foo1" references the file
+ ".*/shouldNotRemain1/\.\./lib/(libfoo1\.a|foo1\.l(ib)?)"
+ but this file does not exist\. Possible reasons include:
+ \* The file was deleted, renamed, or moved to another location\.
+ \* An install or uninstall procedure did not complete successfully\.
+ \* The installation package was faulty and contained
+ ".*/Tests/RunCMake/install/CMP0177-WARN-build/root-all/lib/cmake/pkg/pkg-config\.cmake"
+ but not all the files it references\.
+Call Stack \(most recent call first\):
CMP0177-WARN-verify\.cmake:2 \(find_package\)
CMakeLists\.txt:3 \(include\)

View File

@@ -0,0 +1,2 @@
enable_language(C)
find_package(pkg REQUIRED)

View File

@@ -0,0 +1 @@
include(${CMAKE_CURRENT_LIST_DIR}/CMP0177.cmake)

View File

@@ -0,0 +1,29 @@
enable_language(C)
add_library(foo1 STATIC obj1.c)
add_library(foo2 STATIC obj2.c)
set_target_properties(foo2 PROPERTIES HIDDEN_DOUBLE_DOT "..")
# All the shouldNotRemainX path components below should be normalized out when
# CMP0177 is set to NEW, and retained for OLD and WARN.
install(TARGETS foo1
EXPORT pkg
ARCHIVE DESTINATION shouldNotRemain1/../lib
)
install(TARGETS foo2
EXPORT pkg
ARCHIVE DESTINATION shouldNotRemain2/$<TARGET_PROPERTY:foo2,HIDDEN_DOUBLE_DOT>/lib
)
install(EXPORT pkg
DESTINATION shouldNotRemain3/deeper/../.././lib/cmake/pkg
FILE pkg-config.cmake
)
install(FILES obj1.c
DESTINATION shouldNotRemain4/anotherSubdir/../../files
)
install(DIRECTORY dir
# Trailing slash here is significant
DESTINATION shouldNotRemain5/../dirs/more/../
)

View File

@@ -1,5 +0,0 @@
.+
set_target_properties\(pkg1::foo PROPERTIES
.+INTERFACE_INCLUDE_DIRECTORIES "\${_IMPORT_PREFIX}/pkg1/inc"
\)
.+

View File

@@ -1,5 +0,0 @@
.+
set_target_properties\(pkg2::foo PROPERTIES
.+INTERFACE_INCLUDE_DIRECTORIES "\${_IMPORT_PREFIX}/pkg2/inc"
\)
.+

View File

@@ -7,7 +7,9 @@ function(run_install_test case)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
set(RunCMake_TEST_RAW_ARGS -DCMAKE_BUILD_TYPE:STRING=Debug)
run_cmake(${case})
unset(RunCMake_TEST_RAW_ARGS)
set(RunCMake_TEST_OUTPUT_MERGE 1)
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
unset(RunCMake_TEST_OUTPUT_MERGE)
@@ -92,6 +94,12 @@ run_cmake(CMP0062-WARN)
run_cmake(CMP0087-OLD)
run_cmake(CMP0087-NEW)
run_cmake(CMP0087-WARN)
foreach(policy IN ITEMS NEW OLD WARN)
run_install_test(CMP0177-${policy})
run_cmake_with_options(CMP0177-${policy}-verify
-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/CMP0177-${policy}-build/root-all
)
endforeach()
run_cmake(TARGETS-ImportedGlobal)
run_cmake(TARGETS-NAMELINK_COMPONENT-bad-all)
run_cmake(TARGETS-NAMELINK_COMPONENT-bad-exc)