diff --git a/Help/command/install.rst b/Help/command/install.rst index 7ed27e7546..0d6ccb6116 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -60,6 +60,11 @@ signatures that specify them. The common options are: ```` should be a relative path. An absolute path is allowed, but not recommended. + .. versionadded:: 4.4 + The :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION ` + diagnostic can be enabled to warn or error out when an absolute destination + is provided. + 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`` diff --git a/Help/manual/cmake-diagnostics.7.rst b/Help/manual/cmake-diagnostics.7.rst index 66a08d5409..5612299aae 100644 --- a/Help/manual/cmake-diagnostics.7.rst +++ b/Help/manual/cmake-diagnostics.7.rst @@ -88,3 +88,15 @@ Warn about variables that are declared on the command line, but not used. Although the action of this warning category can be queried as usual, changes made using the :command:`cmake_diagnostic` command have no effect. + +.. _CMD_INSTALL_ABSOLUTE_DESTINATION: + +``CMD_INSTALL_ABSOLUTE_DESTINATION`` (``-Winstall-absolute-destination``) +------------------------------------------------------------------------- + +:Default: Ignore + +Warn when an :command:`install` command specifies an absolute +``DESTINATION`` path. Absolute destinations are typically undesirable +because they prevent the installation prefix from being overridden at +install time. diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst index e135cdf86f..4c672135ce 100644 --- a/Help/manual/cmake-presets.7.rst +++ b/Help/manual/cmake-presets.7.rst @@ -474,6 +474,9 @@ they were added and a summary of the new features and changes is given below. * The ``uninitialized`` and ``unusedCli`` fields were added to :preset:`configurePresets.errors`. + * The ``installAbsoluteDestination`` field was added to + :preset:`configurePresets.warnings` and :preset:`configurePresets.errors`. + * Changes to `Macro Expansion`_ * The `${fileDir} `_ macro now always expands to diff --git a/Help/manual/presets/errors-properties.rst b/Help/manual/presets/errors-properties.rst index 3f1216f9b3..7bf5dacba7 100644 --- a/Help/manual/presets/errors-properties.rst +++ b/Help/manual/presets/errors-properties.rst @@ -32,6 +32,15 @@ This may not be set to ``true`` if ``warnings.dev`` is set to ``false``. +.. _`CMakePresets.configurePresets.errors.installAbsoluteDestination`: + +``installAbsoluteDestination`` + .. presets-versionadded:: 12 + + An optional boolean. Equivalent to passing :cmake-option:`-Werror=install-absolute-destination` or + :cmake-option:`-Wno-error=install-absolute-destination` on the command line. + This may not be set to ``true`` if ``warnings.installAbsoluteDestination`` is set to ``false``. + .. _`CMakePresets.configurePresets.errors.uninitialized`: ``uninitialized`` diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json index 70f5024e5a..cd52447067 100644 --- a/Help/manual/presets/schema.json +++ b/Help/manual/presets/schema.json @@ -1286,6 +1286,9 @@ "deprecated": { "$ref": "#/definitions/configurePresets.warnings.deprecated@v1.." }, + "installAbsoluteDestination": { + "$ref": "#/definitions/configurePresets.warnings.installAbsoluteDestination@v12" + }, "uninitialized": { "$ref": "#/definitions/configurePresets.warnings.uninitialized@v1.." }, @@ -1312,6 +1315,10 @@ "type": "boolean", "description": "An optional boolean. Equivalent to passing -Wdev or -Wno-dev on the command line. This may not be set to false if errors.dev is set to true." }, + "configurePresets.warnings.installAbsoluteDestination@v12": { + "type": "boolean", + "description": "An optional boolean. Equivalent to passing -Winstall-absolute-destination or -Wno-install-absolute-destination on the command line. This may not be set to false if errors.installAbsoluteDestination is set to true." + }, "configurePresets.warnings.uninitialized@v1..": { "type": "boolean", "description": "An optional boolean. Equivalent to passing -Wuninitialized or -Wno-uninitialized on the command line. This may not be set to false if errors.uninitialized is set to true." @@ -1364,6 +1371,9 @@ "deprecated": { "$ref": "#/definitions/configurePresets.errors.deprecated@v1.." }, + "installAbsoluteDestination": { + "$ref": "#/definitions/configurePresets.errors.installAbsoluteDestination@v12" + }, "uninitialized": { "$ref": "#/definitions/configurePresets.errors.uninitialized@v12" }, @@ -1387,6 +1397,10 @@ "type": "boolean", "description": "An optional boolean. Equivalent to passing -Werror=dev or -Wno-error=dev on the command line. This may not be set to true if warnings.dev is set to false." }, + "configurePresets.errors.installAbsoluteDestination@v12": { + "type": "boolean", + "description": "An optional boolean. Equivalent to passing -Werror=install-absolute-destination or -Wno-error=install-absolute-destination on the command line. This may not be set to true if warnings.installAbsoluteDestination is set to false." + }, "configurePresets.errors.uninitialized@v12": { "type": "boolean", "description": "An optional boolean. Equivalent to passing -Werror=uninitialized or -Wno-error=uninitialized on the command line. This may not be set to true if warnings.uninitialized is set to false." diff --git a/Help/manual/presets/warnings-properties.rst b/Help/manual/presets/warnings-properties.rst index acfce8ffe5..0a311908ab 100644 --- a/Help/manual/presets/warnings-properties.rst +++ b/Help/manual/presets/warnings-properties.rst @@ -32,6 +32,15 @@ This may not be set to ``false`` if ``errors.dev`` is set to ``true``. +.. _`CMakePresets.configurePresets.warnings.installAbsoluteDestination`: + +``installAbsoluteDestination`` + .. presets-versionadded:: 12 + + An optional boolean. Equivalent to passing :option:`-Winstall-absolute-destination ` or + :option:`-Wno-install-absolute-destination ` on the command line. + This may not be set to ``false`` if ``errors.installAbsoluteDestination`` is set to ``true``. + .. _`CMakePresets.configurePresets.warnings.uninitialized`: ``uninitialized`` diff --git a/Help/release/dev/install-absolute-dest-configure-time.rst b/Help/release/dev/install-absolute-dest-configure-time.rst new file mode 100644 index 0000000000..25a9c0add3 --- /dev/null +++ b/Help/release/dev/install-absolute-dest-configure-time.rst @@ -0,0 +1,10 @@ +install-absolute-dest-configure-time +------------------------------------- + +* CMake gained the ability to diagnose :command:`install` commands that + specify an absolute ``DESTINATION`` path via the + :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION ` + diagnostic category. This diagnostic may be controlled with the + :option:`-Winstall-absolute-destination ` command-line option, the + ``installAbsoluteDestination`` field in a :manual:`cmake-presets(7)` + ``warnings`` object, or the :command:`cmake_diagnostic` command. diff --git a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst index 38e9b7b365..84a27e5fe0 100644 --- a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst +++ b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst @@ -8,3 +8,11 @@ The fatal error is emitted before the installation of the offending file takes place. This variable is used by CMake-generated ``cmake_install.cmake`` scripts. If one sets this variable to ``ON`` while running the script, it may get fatal error messages from the script. + +.. versionadded:: 4.4 + + The :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION ` + diagnostic can be used to to generate errors for absolute install destinations + at generate time. + +See also :variable:`CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION`. diff --git a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst index 81c1158c26..fac680ea95 100644 --- a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst +++ b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst @@ -7,3 +7,11 @@ Ask ``cmake_install.cmake`` script to warn each time a file with absolute This variable is used by CMake-generated ``cmake_install.cmake`` scripts. If one sets this variable to ``ON`` while running the script, it may get warning messages from the script. + +.. versionadded:: 4.4 + + The :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION ` + diagnostic can be used to to generate warnings for absolute install destinations + at generate time. + +See also :variable:`CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION`. diff --git a/Source/cmDiagnostics.h b/Source/cmDiagnostics.h index 3ab2239e1f..bad732b216 100644 --- a/Source/cmDiagnostics.h +++ b/Source/cmDiagnostics.h @@ -28,6 +28,7 @@ #define CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, SELECT) \ SELECT(ACTION, Warn, CMD_NONE, CMD_AUTHOR, 12) \ SELECT(ACTION, Warn, CMD_AUTHOR, CMD_DEPRECATED, 1) \ + SELECT(ACTION, Ignore, CMD_AUTHOR, CMD_INSTALL_ABSOLUTE_DESTINATION, 12) \ SELECT(ACTION, Ignore, CMD_NONE, CMD_UNINITIALIZED, 1) \ SELECT(ACTION, Warn, CMD_NONE, CMD_UNUSED_CLI, 1) diff --git a/Source/cmExportInstallCMakeConfigGenerator.cxx b/Source/cmExportInstallCMakeConfigGenerator.cxx index eae42b6ee5..2f87099323 100644 --- a/Source/cmExportInstallCMakeConfigGenerator.cxx +++ b/Source/cmExportInstallCMakeConfigGenerator.cxx @@ -284,22 +284,21 @@ std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories( auto configs = gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance()); - auto cge = - ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination()); - for (auto const& config : configs) { - auto unescapedDest = cge->Evaluate(gte->LocalGenerator, config, gte); - auto dest = cmOutputConverter::EscapeForCMake( - unescapedDest, cmOutputConverter::WrapQuotes::NoWrap); - if (!cmSystemTools::FileIsFullPath(unescapedDest)) { + cmInstallFileSetGenerator::DestinationContext result = + te->FileSetGenerators.at(fileSet->GetName()) + ->GetDestination(gte, config); + + std::string dest = cmOutputConverter::EscapeForCMake( + result.UnescapedDestination, cmOutputConverter::WrapQuotes::NoWrap); + if (!cmSystemTools::FileIsFullPath(result.UnescapedDestination)) { dest = cmStrCat("${_IMPORT_PREFIX}/", dest); } auto const& type = fileSet->GetType(); // C++ modules do not support interface file sets which are dependent upon // the configuration. - if (cge->GetHadContextSensitiveCondition() && + if (result.HadContextSensitiveCondition && type == cm::FileSetMetadata::CXX_MODULES) { auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile(); std::ostringstream e; @@ -311,7 +310,7 @@ std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories( return std::string{}; } - if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) { + if (result.HadContextSensitiveCondition && configs.size() != 1) { resultVector.push_back( cmStrCat("\"$<$:", dest, ">\"")); } else { diff --git a/Source/cmExportInstallPackageInfoGenerator.cxx b/Source/cmExportInstallPackageInfoGenerator.cxx index 78eb146299..202594a754 100644 --- a/Source/cmExportInstallPackageInfoGenerator.cxx +++ b/Source/cmExportInstallPackageInfoGenerator.cxx @@ -224,18 +224,14 @@ cmExportInstallPackageInfoGenerator::GetFileSetDirectory( cmGeneratorTarget* gte, cmTargetExport const* te, cmGeneratorFileSet const* fileSet, cm::optional const& config) { - cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance()); - auto cge = - ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination()); + cmInstallFileSetGenerator::DestinationContext result = + te->FileSetGenerators.at(fileSet->GetName()) + ->GetDestination(gte, config.value_or("")); - std::string const unescapedDest = - cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte); - bool const isConfigDependent = cge->GetHadContextSensitiveCondition(); - - if (config && !isConfigDependent) { + if (config && !result.HadContextSensitiveCondition) { return {}; } - if (!config && isConfigDependent) { + if (!config && result.HadContextSensitiveCondition) { this->RequiresConfigFiles = true; return {}; } @@ -255,9 +251,9 @@ cmExportInstallPackageInfoGenerator::GetFileSetDirectory( } cm::optional dest = cmOutputConverter::EscapeForCMake( - unescapedDest, cmOutputConverter::WrapQuotes::NoWrap); + result.UnescapedDestination, cmOutputConverter::WrapQuotes::NoWrap); - if (!cmSystemTools::FileIsFullPath(unescapedDest)) { + if (!cmSystemTools::FileIsFullPath(result.UnescapedDestination)) { dest = cmStrCat("@prefix@/"_s, *dest); } diff --git a/Source/cmExportInstallSbomGenerator.cxx b/Source/cmExportInstallSbomGenerator.cxx index d944383902..f9641a1b48 100644 --- a/Source/cmExportInstallSbomGenerator.cxx +++ b/Source/cmExportInstallSbomGenerator.cxx @@ -216,15 +216,11 @@ cm::optional cmExportInstallSbomGenerator::GetFileSetDirectory( cmGeneratorTarget* gte, cmTargetExport const* te, cmGeneratorFileSet const* fileSet, cm::optional const& config) { - cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance()); - auto cge = - ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination()); + cmInstallFileSetGenerator::DestinationContext result = + te->FileSetGenerators.at(fileSet->GetName()) + ->GetDestination(gte, config.value_or("")); - std::string const unescapedDest = - cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte); - bool const isConfigDependent = cge->GetHadContextSensitiveCondition(); - - if (config && !isConfigDependent) { + if (config && !result.HadContextSensitiveCondition) { return {}; } @@ -241,9 +237,9 @@ cm::optional cmExportInstallSbomGenerator::GetFileSetDirectory( } cm::optional dest = cmOutputConverter::EscapeForCMake( - unescapedDest, cmOutputConverter::WrapQuotes::NoWrap); + result.UnescapedDestination, cmOutputConverter::WrapQuotes::NoWrap); - if (!cmSystemTools::FileIsFullPath(unescapedDest)) { + if (!cmSystemTools::FileIsFullPath(result.UnescapedDestination)) { dest = cmStrCat("@prefix@/"_s, *dest); } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 1fb9d4b5dd..8137d69b1b 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -1912,6 +1912,15 @@ bool HandleDirectoryMode(std::vector const& args, cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(helper.Makefile, message_never); + // Check for an absolute destination. + if (cmGeneratorExpression::Find(*destination) == std::string::npos && + cmSystemTools::FileIsFullPath(*destination)) { + helper.Makefile->IssueDiagnostic( + cmDiagnostics::CMD_INSTALL_ABSOLUTE_DESTINATION, + cmStrCat("INSTALL command given absolute DESTINATION path (", + *destination, ").\n")); + } + // Create the directory install generator. helper.Makefile->AddInstallGenerator( cm::make_unique( diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index 7bf861ea3e..c8b1ad94c7 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -22,7 +22,7 @@ public: this->GenericArguments = args; } - // Compute destination path.and check permissions + // Compute destination path and check permissions. bool Finalize(); std::string const& GetDestination() const; diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index cf1fac91fc..bd62dd372c 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -118,6 +118,9 @@ void cmInstallDirectoryGenerator::AddDirectoryInstallRule( std::string cmInstallDirectoryGenerator::GetDestination( std::string const& config) const { - return cmGeneratorExpression::Evaluate(this->Destination, - this->LocalGenerator, config); + std::string dest = cmGeneratorExpression::Evaluate( + this->Destination, this->LocalGenerator, config); + cmInstallGenerator::CheckAbsoluteDestination(dest, this->LocalGenerator, + this->Backtrace); + return dest; } diff --git a/Source/cmInstallFileSetGenerator.cxx b/Source/cmInstallFileSetGenerator.cxx index 85b8275ca3..e6e9f031e8 100644 --- a/Source/cmInstallFileSetGenerator.cxx +++ b/Source/cmInstallFileSetGenerator.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" +#include "cmMakefile.h" #include "cmMessageType.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" @@ -91,11 +93,32 @@ bool cmInstallFileSetGenerator::Compute(cmLocalGenerator* lg) return true; } +std::string cmInstallFileSetGenerator::GetDestination() const +{ + cmInstallGenerator::CheckAbsoluteDestination( + this->Destination, this->LocalGenerator, this->Backtrace); + return this->Destination; +} + std::string cmInstallFileSetGenerator::GetDestination( std::string const& config) const { - return cmGeneratorExpression::Evaluate(this->Destination, - this->LocalGenerator, config); + return this->GetDestination(this->Target, config).UnescapedDestination; +} + +cmInstallFileSetGenerator::DestinationContext +cmInstallFileSetGenerator::GetDestination(cmGeneratorTarget* gte, + std::string const& config) const +{ + cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance()); + std::unique_ptr cge = + ge.Parse(this->Destination); + + std::string const dest = cge->Evaluate(gte->LocalGenerator, config, gte); + cmInstallGenerator::CheckAbsoluteDestination(dest, gte->LocalGenerator, + this->Backtrace); + + return { dest, cge->GetHadContextSensitiveCondition() }; } void cmInstallFileSetGenerator::GenerateScriptForConfig( diff --git a/Source/cmInstallFileSetGenerator.h b/Source/cmInstallFileSetGenerator.h index ff562011f8..b0488fb3d5 100644 --- a/Source/cmInstallFileSetGenerator.h +++ b/Source/cmInstallFileSetGenerator.h @@ -9,8 +9,9 @@ #include "cmInstallGenerator.h" -class cmGeneratorTarget; +class cmExportInstallCMakeConfigGenerator; class cmGeneratorFileSet; +class cmGeneratorTarget; class cmListFileBacktrace; class cmLocalGenerator; @@ -28,14 +29,23 @@ public: bool Compute(cmLocalGenerator* lg) override; + struct DestinationContext + { + std::string UnescapedDestination; + bool HadContextSensitiveCondition; + }; std::string GetDestination(std::string const& config) const; - std::string GetDestination() const { return this->Destination; } + DestinationContext GetDestination(cmGeneratorTarget* gt, + std::string const& config) const; bool GetOptional() const { return this->Optional; } std::string GetFileSetName() const { return this->FileSetName; } cmGeneratorFileSet const* GetFileSet() const { return this->FileSet; }; cmGeneratorTarget* GetTarget() const { return this->Target; } protected: + friend cmExportInstallCMakeConfigGenerator; + std::string GetDestination() const; + void GenerateScriptForConfig(std::ostream& os, std::string const& config, Indent indent) override; diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index 6da1862ba4..f5613fad28 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -54,8 +54,11 @@ bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg) std::string cmInstallFilesGenerator::GetDestination( std::string const& config) const { - return cmGeneratorExpression::Evaluate(this->Destination, - this->LocalGenerator, config); + std::string dest = cmGeneratorExpression::Evaluate( + this->Destination, this->LocalGenerator, config); + cmInstallGenerator::CheckAbsoluteDestination(dest, this->LocalGenerator, + this->Backtrace); + return dest; } std::string cmInstallFilesGenerator::GetRename(std::string const& config) const diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index dd9ade73c6..9317f94f5f 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -7,6 +7,9 @@ #include +#include "cmDiagnostics.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -229,6 +232,19 @@ std::string cmInstallGenerator::ConvertToAbsoluteDestination( return result; } +void cmInstallGenerator::CheckAbsoluteDestination( + std::string const& dest, cmLocalGenerator* lg, cmListFileBacktrace const& bt) +{ + if (!cmSystemTools::FileIsFullPath(dest)) { + return; + } + lg->IssueDiagnostic( + cmDiagnostics::CMD_INSTALL_ABSOLUTE_DESTINATION, + cmStrCat("INSTALL command given absolute DESTINATION path (", dest, + ").\n"), + bt); +} + cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel( cmMakefile* mf, bool never) { diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index 572d192361..d35a4b6bf0 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -56,6 +56,9 @@ public: /** Get the install destination as it should appear in the installation script. */ static std::string ConvertToAbsoluteDestination(std::string const& dest); + static void CheckAbsoluteDestination(std::string const& dest, + cmLocalGenerator* lg, + cmListFileBacktrace const& bt); /** Test if this generator installs something for a given configuration. */ bool InstallsForConfig(std::string const& config); diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 6b89f86df2..e2e7924b35 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -479,8 +479,11 @@ void cmInstallTargetGenerator::GetInstallObjectNames( std::string cmInstallTargetGenerator::GetDestination( std::string const& config) const { - return cmGeneratorExpression::Evaluate( - this->Destination, this->Target->GetLocalGenerator(), config); + cmLocalGenerator* lg = this->Target->GetLocalGenerator(); + std::string dest = + cmGeneratorExpression::Evaluate(this->Destination, lg, config); + cmInstallGenerator::CheckAbsoluteDestination(dest, lg, this->Backtrace); + return dest; } std::string cmInstallTargetGenerator::GetInstallFilename( diff --git a/Tests/RunCMake/CMakePresets/ErrorAbsInstallPath-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorAbsInstallPath-stderr.txt new file mode 100644 index 0000000000..6d9315ee93 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/ErrorAbsInstallPath-stderr.txt @@ -0,0 +1,5 @@ +CMake Warning \(unused-cli\): + Manually-specified variables were not used by the project: + + RunCMake_GENERATOR + UNUSED_VARIABLE$ diff --git a/Tests/RunCMake/CMakePresets/ErrorAbsInstallPath.cmake b/Tests/RunCMake/CMakePresets/ErrorAbsInstallPath.cmake new file mode 100644 index 0000000000..d6fe2ff38c --- /dev/null +++ b/Tests/RunCMake/CMakePresets/ErrorAbsInstallPath.cmake @@ -0,0 +1,6 @@ +cmake_diagnostic(GET CMD_INSTALL_ABSOLUTE_DESTINATION action) +if(NOT "${action}" STREQUAL SEND_ERROR) + message(SEND_ERROR + "wrong action for diagnostic CMD_INSTALL_ABSOLUTE_DESTINATION" + " (expected 'SEND_ERROR', actual '${action}')") +endif() diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake index 303e0c9be9..c816830a9d 100644 --- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake @@ -363,7 +363,9 @@ run_cmake_presets(ErrorDeprecated) set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Warnings12.json.in") run_cmake_presets(NoWarningFlags) run_cmake_presets(WarningFlags) +run_cmake_presets(WarningAbsInstallPath) run_cmake_presets(DisableWarningFlags) +run_cmake_presets(ErrorAbsInstallPath) run_cmake_presets(ErrorDev) run_cmake_presets(ErrorUninitialized) run_cmake_presets(ErrorUnusedCli) diff --git a/Tests/RunCMake/CMakePresets/WarningAbsInstallPath-stderr.txt b/Tests/RunCMake/CMakePresets/WarningAbsInstallPath-stderr.txt new file mode 100644 index 0000000000..6d9315ee93 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/WarningAbsInstallPath-stderr.txt @@ -0,0 +1,5 @@ +CMake Warning \(unused-cli\): + Manually-specified variables were not used by the project: + + RunCMake_GENERATOR + UNUSED_VARIABLE$ diff --git a/Tests/RunCMake/CMakePresets/WarningAbsInstallPath.cmake b/Tests/RunCMake/CMakePresets/WarningAbsInstallPath.cmake new file mode 100644 index 0000000000..fc59b1ca4e --- /dev/null +++ b/Tests/RunCMake/CMakePresets/WarningAbsInstallPath.cmake @@ -0,0 +1,6 @@ +cmake_diagnostic(GET CMD_INSTALL_ABSOLUTE_DESTINATION action) +if(NOT "${action}" STREQUAL WARN) + message(SEND_ERROR + "wrong action for diagnostic CMD_INSTALL_ABSOLUTE_DESTINATION" + " (expected 'WARN', actual '${action}')") +endif() diff --git a/Tests/RunCMake/CMakePresets/Warnings12.json.in b/Tests/RunCMake/CMakePresets/Warnings12.json.in index 650f111de1..701e5f46bf 100644 --- a/Tests/RunCMake/CMakePresets/Warnings12.json.in +++ b/Tests/RunCMake/CMakePresets/Warnings12.json.in @@ -29,6 +29,20 @@ "unusedCli": false } }, + { + "name": "WarningAbsInstallPath", + "inherits": "NoWarningFlags", + "warnings": { + "installAbsoluteDestination": true + } + }, + { + "name": "ErrorAbsInstallPath", + "inherits": "NoWarningFlags", + "errors": { + "installAbsoluteDestination": true + } + }, { "name": "ErrorDev", "inherits": "NoWarningFlags", diff --git a/Tests/RunCMake/Diagnostics/CacheInit.cmake b/Tests/RunCMake/Diagnostics/CacheInit.cmake index 1af149535a..24baac2c6b 100644 --- a/Tests/RunCMake/Diagnostics/CacheInit.cmake +++ b/Tests/RunCMake/Diagnostics/CacheInit.cmake @@ -1,4 +1,5 @@ include(Assertions.cmake) expect(CMD_AUTHOR IGNORE) +expect(CMD_INSTALL_ABSOLUTE_DESTINATION IGNORE) expect(CMD_DEPRECATED SEND_ERROR) diff --git a/Tests/RunCMake/Diagnostics/CommandLine3.cmake b/Tests/RunCMake/Diagnostics/CommandLine3.cmake index e11e17d099..96f8e1ae80 100644 --- a/Tests/RunCMake/Diagnostics/CommandLine3.cmake +++ b/Tests/RunCMake/Diagnostics/CommandLine3.cmake @@ -1,3 +1,5 @@ include(Assertions.cmake) expect_cached(CMD_UNINITIALIZED IGNORE) + +expect_cached(CMD_INSTALL_ABSOLUTE_DESTINATION WARN) diff --git a/Tests/RunCMake/Diagnostics/RunCMakeTest.cmake b/Tests/RunCMake/Diagnostics/RunCMakeTest.cmake index 5ffb6fa844..5f77f8ea98 100644 --- a/Tests/RunCMake/Diagnostics/RunCMakeTest.cmake +++ b/Tests/RunCMake/Diagnostics/RunCMakeTest.cmake @@ -12,4 +12,4 @@ run_cmake_with_options(CommandLine1 -Werror=author) run_cmake_with_options(CommandLine1 -Werror=author -Wdeprecated) run_cmake_with_options(CommandLine1 -Wno-deprecated -Werror=author) run_cmake_with_options(CommandLine2 -Werror=author -Wno-deprecated) -run_cmake_with_options(CommandLine3 -Wno-error=uninitialized) +run_cmake_with_options(CommandLine3 -Wno-error=uninitialized -Winstall-absolute-destination) diff --git a/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error-result.txt b/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error-stderr.txt b/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error-stderr.txt new file mode 100644 index 0000000000..d742940529 --- /dev/null +++ b/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error-stderr.txt @@ -0,0 +1,2 @@ +CMake Error \(install-absolute-destination\) at DIRECTORY-AbsoluteDest-error\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/path\)\. diff --git a/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error.cmake b/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error.cmake new file mode 100644 index 0000000000..a76ddb48d6 --- /dev/null +++ b/Tests/RunCMake/install/DIRECTORY-AbsoluteDest-error.cmake @@ -0,0 +1 @@ +install(DIRECTORY DESTINATION /absolute/path) diff --git a/Tests/RunCMake/install/FILES-AbsoluteDest-error-result.txt b/Tests/RunCMake/install/FILES-AbsoluteDest-error-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/FILES-AbsoluteDest-error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/FILES-AbsoluteDest-error-stderr.txt b/Tests/RunCMake/install/FILES-AbsoluteDest-error-stderr.txt new file mode 100644 index 0000000000..689d48b42e --- /dev/null +++ b/Tests/RunCMake/install/FILES-AbsoluteDest-error-stderr.txt @@ -0,0 +1,2 @@ +CMake Error \(install-absolute-destination\) at FILES-AbsoluteDest-error\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/path\)\. diff --git a/Tests/RunCMake/install/FILES-AbsoluteDest-error.cmake b/Tests/RunCMake/install/FILES-AbsoluteDest-error.cmake new file mode 100644 index 0000000000..28cb56bcce --- /dev/null +++ b/Tests/RunCMake/install/FILES-AbsoluteDest-error.cmake @@ -0,0 +1 @@ +install(FILES empty.c DESTINATION /absolute/path) diff --git a/Tests/RunCMake/install/FILES-AbsoluteDest-warn-stderr.txt b/Tests/RunCMake/install/FILES-AbsoluteDest-warn-stderr.txt new file mode 100644 index 0000000000..f320131e0c --- /dev/null +++ b/Tests/RunCMake/install/FILES-AbsoluteDest-warn-stderr.txt @@ -0,0 +1,2 @@ +CMake Warning \(install-absolute-destination\) at FILES-AbsoluteDest-warn\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/path\)\. diff --git a/Tests/RunCMake/install/FILES-AbsoluteDest-warn.cmake b/Tests/RunCMake/install/FILES-AbsoluteDest-warn.cmake new file mode 100644 index 0000000000..28cb56bcce --- /dev/null +++ b/Tests/RunCMake/install/FILES-AbsoluteDest-warn.cmake @@ -0,0 +1 @@ +install(FILES empty.c DESTINATION /absolute/path) diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index ff8e812fba..5e40e88e27 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -82,6 +82,14 @@ run_cmake(DIRECTORY-DESTINATION-bad) run_cmake(FILES-DESTINATION-bad) run_cmake(FILES-RENAME-bad) run_cmake(TARGETS-DESTINATION-bad) +run_cmake_with_options(DIRECTORY-AbsoluteDest-error -Werror=install-absolute-destination) +run_cmake_with_options(FILES-AbsoluteDest-error -Werror=install-absolute-destination) +run_cmake_with_options(FILES-AbsoluteDest-warn -Winstall-absolute-destination) +run_cmake_with_options(TARGETS-AbsoluteDest-error -Werror=install-absolute-destination) +run_cmake_with_options(TARGETS-AbsoluteDest-warn -Winstall-absolute-destination) +run_cmake_with_options(TARGETS-AbsoluteDest-archive-error -Werror=install-absolute-destination) +run_cmake_with_options(TARGETS-AbsoluteDest-library-error -Werror=install-absolute-destination) +run_cmake_with_options(TARGETS-AbsoluteDest-runtime-error -Werror=install-absolute-destination) run_cmake(EXPORT-Component) run_cmake(EXPORT-FindDependencyExportGate) run_cmake(EXPORT-OldIFace) diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error-result.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error-stderr.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error-stderr.txt new file mode 100644 index 0000000000..e091ab01d8 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error-stderr.txt @@ -0,0 +1,2 @@ +CMake Error \(install-absolute-destination\) at TARGETS-AbsoluteDest-archive-error\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/archive\)\. diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error.cmake b/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error.cmake new file mode 100644 index 0000000000..3ecc7e387b --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-archive-error.cmake @@ -0,0 +1,3 @@ +enable_language(C) +add_library(mylib STATIC empty.c) +install(TARGETS mylib ARCHIVE DESTINATION /absolute/archive) diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-error-result.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-error-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-error-stderr.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-error-stderr.txt new file mode 100644 index 0000000000..22c0d98269 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-error-stderr.txt @@ -0,0 +1,2 @@ +CMake Error \(install-absolute-destination\) at TARGETS-AbsoluteDest-error\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/path\)\. diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-error.cmake b/Tests/RunCMake/install/TARGETS-AbsoluteDest-error.cmake new file mode 100644 index 0000000000..b16af5c2e6 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-error.cmake @@ -0,0 +1,12 @@ +enable_language(C) +add_library(mylib STATIC empty.c) + +# FIXME(#27770): This diagnostic is issued at generate time. Currently, the +# install generator doesn't capture the immediate diagnostic state, only the +# top-most state of the current subdirectory, which we cannot affect (because +# this test was include()d. When we fix that, we should test by changing the +# diagnostic action here rather than by -W... in the test CLI arguments. +# cmake_diagnostic(SET CMD_INSTALL_ABSOLUTE_DESTINATION SEND_ERROR) + +cmake_diagnostic(PROMOTE CMD_INSTALL_ABSOLUTE_DESTINATION WARN) +install(TARGETS mylib DESTINATION /absolute/path) diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error-result.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error-stderr.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error-stderr.txt new file mode 100644 index 0000000000..368434d81c --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error-stderr.txt @@ -0,0 +1,2 @@ +CMake Error \(install-absolute-destination\) at TARGETS-AbsoluteDest-library-error\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/lib\)\. diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error.cmake b/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error.cmake new file mode 100644 index 0000000000..b5be8fdd3e --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-library-error.cmake @@ -0,0 +1,3 @@ +enable_language(C) +add_library(mylib MODULE empty.c) +install(TARGETS mylib LIBRARY DESTINATION /absolute/lib) diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error-result.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error-stderr.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error-stderr.txt new file mode 100644 index 0000000000..279fb88e28 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error-stderr.txt @@ -0,0 +1,2 @@ +CMake Error \(install-absolute-destination\) at TARGETS-AbsoluteDest-runtime-error\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/bin\)\. diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error.cmake b/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error.cmake new file mode 100644 index 0000000000..638f7fba95 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-runtime-error.cmake @@ -0,0 +1,3 @@ +enable_language(C) +add_executable(myexe empty.c) +install(TARGETS myexe RUNTIME DESTINATION /absolute/bin) diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-warn-stderr.txt b/Tests/RunCMake/install/TARGETS-AbsoluteDest-warn-stderr.txt new file mode 100644 index 0000000000..730a8edf95 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-warn-stderr.txt @@ -0,0 +1,2 @@ +CMake Warning \(install-absolute-destination\) at TARGETS-AbsoluteDest-warn\.cmake:[0-9]+ \(install\): + INSTALL command given absolute DESTINATION path \(/absolute/path\)\. diff --git a/Tests/RunCMake/install/TARGETS-AbsoluteDest-warn.cmake b/Tests/RunCMake/install/TARGETS-AbsoluteDest-warn.cmake new file mode 100644 index 0000000000..e2ca4befcd --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-AbsoluteDest-warn.cmake @@ -0,0 +1,3 @@ +enable_language(C) +add_library(mylib STATIC empty.c) +install(TARGETS mylib DESTINATION /absolute/path)