mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-16 12:11:04 -06:00
install: Normalize DESTINATION paths
The file generated by install(EXPORT) computes _IMPORT_PREFIX in a way that assumes a normalized path. If the DESTINATION contains any ../ components, the computed _IMPORT_PREFIX would be wrong. Force the DESTINATION path to be normalized, subject to the new CMP0176 policy. Also normalize all other DESTINATION paths for consistency, except for INCLUDES DESTINATION, which is not strictly a destination but rather a search path to add. Fixes: #26252
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -807,6 +818,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
|
||||
|
||||
@@ -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
38
Help/policy/CMP0177.rst
Normal 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
|
||||
6
Help/release/dev/normalize-install-destination-paths.rst
Normal file
6
Help/release/dev/normalize-install-destination-paths.rst
Normal 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.
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmArgumentParserTypes.h"
|
||||
#include "cmCMakePath.h"
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmExperimental.h"
|
||||
#include "cmExportSet.h"
|
||||
@@ -453,7 +454,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);
|
||||
@@ -467,19 +469,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.
|
||||
@@ -499,7 +513,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);
|
||||
}
|
||||
@@ -1310,16 +1325,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.
|
||||
@@ -1547,7 +1567,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;
|
||||
@@ -1681,7 +1701,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;
|
||||
@@ -1839,7 +1859,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) {
|
||||
@@ -1909,7 +1955,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();
|
||||
}
|
||||
|
||||
@@ -1917,15 +1963,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 "
|
||||
@@ -1957,7 +2001,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;
|
||||
@@ -2050,7 +2094,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;
|
||||
@@ -2176,7 +2220,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;
|
||||
@@ -2335,14 +2379,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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) \
|
||||
|
||||
36
Tests/RunCMake/install/CMP0177-NEW-all-check.cmake
Normal file
36
Tests/RunCMake/install/CMP0177-NEW-all-check.cmake
Normal 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()
|
||||
2
Tests/RunCMake/install/CMP0177-NEW-verify.cmake
Normal file
2
Tests/RunCMake/install/CMP0177-NEW-verify.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
enable_language(C)
|
||||
find_package(pkg REQUIRED)
|
||||
2
Tests/RunCMake/install/CMP0177-NEW.cmake
Normal file
2
Tests/RunCMake/install/CMP0177-NEW.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
cmake_policy(SET CMP0177 NEW)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMP0177.cmake)
|
||||
1
Tests/RunCMake/install/CMP0177-OLD-verify-result.txt
Normal file
1
Tests/RunCMake/install/CMP0177-OLD-verify-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
13
Tests/RunCMake/install/CMP0177-OLD-verify-stderr.txt
Normal file
13
Tests/RunCMake/install/CMP0177-OLD-verify-stderr.txt
Normal 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\)
|
||||
2
Tests/RunCMake/install/CMP0177-OLD-verify.cmake
Normal file
2
Tests/RunCMake/install/CMP0177-OLD-verify.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
enable_language(C)
|
||||
find_package(pkg REQUIRED)
|
||||
2
Tests/RunCMake/install/CMP0177-OLD.cmake
Normal file
2
Tests/RunCMake/install/CMP0177-OLD.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
cmake_policy(SET CMP0177 OLD)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMP0177.cmake)
|
||||
35
Tests/RunCMake/install/CMP0177-WARN-stderr.txt
Normal file
35
Tests/RunCMake/install/CMP0177-WARN-stderr.txt
Normal 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\.
|
||||
1
Tests/RunCMake/install/CMP0177-WARN-verify-result.txt
Normal file
1
Tests/RunCMake/install/CMP0177-WARN-verify-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
13
Tests/RunCMake/install/CMP0177-WARN-verify-stderr.txt
Normal file
13
Tests/RunCMake/install/CMP0177-WARN-verify-stderr.txt
Normal 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\)
|
||||
2
Tests/RunCMake/install/CMP0177-WARN-verify.cmake
Normal file
2
Tests/RunCMake/install/CMP0177-WARN-verify.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
enable_language(C)
|
||||
find_package(pkg REQUIRED)
|
||||
1
Tests/RunCMake/install/CMP0177-WARN.cmake
Normal file
1
Tests/RunCMake/install/CMP0177-WARN.cmake
Normal file
@@ -0,0 +1 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMP0177.cmake)
|
||||
29
Tests/RunCMake/install/CMP0177.cmake
Normal file
29
Tests/RunCMake/install/CMP0177.cmake
Normal 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/../
|
||||
)
|
||||
@@ -94,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)
|
||||
|
||||
Reference in New Issue
Block a user