From 25cae1e85d501c463141388e4eb580bdfae6ed2f Mon Sep 17 00:00:00 2001 From: Jon Chronopoulos Date: Thu, 29 Nov 2018 21:11:07 +1100 Subject: install: Teach CODE,SCRIPT modes to evaluate generator expressions This also introduces CMP0087 which will keep the OLD behaviour of not evaluating generator expressions Fixes: #15785 --- Help/command/install.rst | 5 ++ Help/manual/cmake-policies.7.rst | 1 + Help/policy/CMP0087.rst | 29 ++++++++++ Help/release/dev/install-code-script-genex.rst | 5 ++ Source/cmInstallScriptGenerator.cxx | 70 +++++++++++++++++++---- Source/cmInstallScriptGenerator.h | 14 ++++- Source/cmPolicies.h | 6 +- Tests/RunCMake/install/CMP0087-NEW-check.cmake | 7 +++ Tests/RunCMake/install/CMP0087-NEW.cmake | 3 + Tests/RunCMake/install/CMP0087-NEW/CMakeLists.txt | 7 +++ Tests/RunCMake/install/CMP0087-OLD-check.cmake | 8 +++ Tests/RunCMake/install/CMP0087-OLD.cmake | 3 + Tests/RunCMake/install/CMP0087-OLD/CMakeLists.txt | 6 ++ Tests/RunCMake/install/CMP0087-WARN-stderr.txt | 5 ++ Tests/RunCMake/install/CMP0087-WARN.cmake | 2 + Tests/RunCMake/install/RunCMakeTest.cmake | 3 + 16 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 Help/policy/CMP0087.rst create mode 100644 Help/release/dev/install-code-script-genex.rst create mode 100644 Tests/RunCMake/install/CMP0087-NEW-check.cmake create mode 100644 Tests/RunCMake/install/CMP0087-NEW.cmake create mode 100644 Tests/RunCMake/install/CMP0087-NEW/CMakeLists.txt create mode 100644 Tests/RunCMake/install/CMP0087-OLD-check.cmake create mode 100644 Tests/RunCMake/install/CMP0087-OLD.cmake create mode 100644 Tests/RunCMake/install/CMP0087-OLD/CMakeLists.txt create mode 100644 Tests/RunCMake/install/CMP0087-WARN-stderr.txt create mode 100644 Tests/RunCMake/install/CMP0087-WARN.cmake diff --git a/Help/command/install.rst b/Help/command/install.rst index 55c8485..a0e8c37 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -547,6 +547,11 @@ example, the code will print a message during installation. +```` or ```` may use "generator expressions" with the syntax +``$<...>`` (in the case of ````, this refers to their use in the file +name, not the file's contents). See the +:manual:`cmake-generator-expressions(7)` manual for available expressions. + Installing Exports ^^^^^^^^^^^^^^^^^^ diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index ed61ae0..40ec1ef 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,7 @@ Policies Introduced by CMake 3.14 .. toctree:: :maxdepth: 1 + CMP0087: install(SCRIPT | CODE) supports generator expressions. CMP0086: UseSWIG honors SWIG_MODULE_NAME via -module flag. CMP0085: IN_LIST generator expression handles empty list items. CMP0084: The FindQt module does not exist for find_package(). diff --git a/Help/policy/CMP0087.rst b/Help/policy/CMP0087.rst new file mode 100644 index 0000000..4c45b99 --- /dev/null +++ b/Help/policy/CMP0087.rst @@ -0,0 +1,29 @@ +CMP0087 +------- + +:command:`install(CODE)` and :command:`install(SCRIPT)` support generator +expressions. + +In CMake 3.13 and earlier, :command:`install(CODE)` and +:command:`install(SCRIPT)` did not evaluate generator expressions. CMake 3.14 +and later will evaluate generator expressions for :command:`install(CODE)` and +:command:`install(SCRIPT)`. + +The ``OLD`` behavior of this policy is for :command:`install(CODE)` and +:command:`install(SCRIPT)` to not evaluate generator expressions. The ``NEW`` +behavior is to evaluate generator expressions for :command:`install(CODE)` and +:command:`install(SCRIPT)`. + +Note that it is the value of this policy setting at the end of the directory +scope that is important, not its setting at the time of the call to +:command:`install(CODE)` or :command:`install(SCRIPT)`. This has implications +for calling these commands from places that have their own policy scope but not +their own directory scope (e.g. from files brought in via :command:`include()` +rather than :command:`add_subdirectory()`). + +This policy was introduced in CMake version 3.14. CMake version +|release| warns when the policy is not set and uses ``OLD`` behavior. +Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` +explicitly. + +.. include:: DEPRECATED.txt diff --git a/Help/release/dev/install-code-script-genex.rst b/Help/release/dev/install-code-script-genex.rst new file mode 100644 index 0000000..a28a466 --- /dev/null +++ b/Help/release/dev/install-code-script-genex.rst @@ -0,0 +1,5 @@ +install-code-script-genex +------------------------- + +* The :command:`install(CODE)` and :command:`install(SCRIPT)` commands + learned to support generator expressions. See policy :policy:`CMP0087`. diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx index 7d77b7c..b93debb 100644 --- a/Source/cmInstallScriptGenerator.cxx +++ b/Source/cmInstallScriptGenerator.cxx @@ -2,11 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallScriptGenerator.h" -#include "cmScriptGenerator.h" - #include #include +#include "cmGeneratorExpression.h" +#include "cmLocalGenerator.h" +#include "cmPolicies.h" +#include "cmScriptGenerator.h" +#include "cmake.h" + cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script, bool code, const char* component, @@ -15,25 +19,71 @@ cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script, MessageDefault, exclude_from_all) , Script(script) , Code(code) + , AllowGenex(false) { + // We need per-config actions if the script has generator expressions. + if (cmGeneratorExpression::Find(Script) != std::string::npos) { + this->ActionsPerConfig = true; + } } cmInstallScriptGenerator::~cmInstallScriptGenerator() { } -void cmInstallScriptGenerator::GenerateScript(std::ostream& os) +void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg) { - Indent indent; - std::string component_test = - this->CreateComponentTest(this->Component.c_str(), this->ExcludeFromAll); - os << indent << "if(" << component_test << ")\n"; + this->LocalGenerator = lg; + if (this->ActionsPerConfig) { + switch (this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0087)) { + case cmPolicies::WARN: + this->LocalGenerator->IssueMessage( + cmake::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0087)); + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + this->AllowGenex = true; + break; + } + } +} + +void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os, + Indent indent, + std::string const& script) +{ if (this->Code) { - os << indent << this->Script << "\n"; + os << indent << script << "\n"; } else { - os << indent << "include(\"" << this->Script << "\")\n"; + os << indent << "include(\"" << script << "\")\n"; } +} - os << indent << "endif()\n\n"; +void cmInstallScriptGenerator::GenerateScriptActions(std::ostream& os, + Indent indent) +{ + if (this->AllowGenex && this->ActionsPerConfig) { + this->cmInstallGenerator::GenerateScriptActions(os, indent); + } else { + this->AddScriptInstallRule(os, indent, this->Script); + } +} + +void cmInstallScriptGenerator::GenerateScriptForConfig( + std::ostream& os, const std::string& config, Indent indent) +{ + if (this->AllowGenex) { + cmGeneratorExpression ge; + std::unique_ptr cge = + ge.Parse(this->Script); + this->AddScriptInstallRule(os, indent, + cge->Evaluate(this->LocalGenerator, config)); + } else { + this->AddScriptInstallRule(os, indent, this->Script); + } } diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h index fe0f7c6..05199d7 100644 --- a/Source/cmInstallScriptGenerator.h +++ b/Source/cmInstallScriptGenerator.h @@ -6,10 +6,13 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmInstallGenerator.h" +#include "cmScriptGenerator.h" #include #include +class cmLocalGenerator; + /** \class cmInstallScriptGenerator * \brief Generate target installation rules. */ @@ -20,10 +23,19 @@ public: const char* component, bool exclude_from_all); ~cmInstallScriptGenerator() override; + void Compute(cmLocalGenerator* lg) override; + protected: - void GenerateScript(std::ostream& os) override; + void GenerateScriptActions(std::ostream& os, Indent indent) override; + void GenerateScriptForConfig(std::ostream& os, const std::string& config, + Indent indent) override; + void AddScriptInstallRule(std::ostream& os, Indent indent, + std::string const& script); + std::string Script; bool Code; + cmLocalGenerator* LocalGenerator; + bool AllowGenex; }; #endif diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 7674877..206dd3d 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -254,7 +254,11 @@ class cmMakefile; 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0086, \ "UseSWIG honors SWIG_MODULE_NAME via -module flag.", 3, 14, 0, \ - cmPolicies::WARN) + cmPolicies::WARN) \ + SELECT(POLICY, CMP0087, \ + "Install CODE|SCRIPT allow the use of generator " \ + "expressions.", \ + 3, 14, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Tests/RunCMake/install/CMP0087-NEW-check.cmake b/Tests/RunCMake/install/CMP0087-NEW-check.cmake new file mode 100644 index 0000000..422c532 --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-NEW-check.cmake @@ -0,0 +1,7 @@ +execute_process(COMMAND ${CMAKE_COMMAND} -P ${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake + OUTPUT_VARIABLE out ERROR_VARIABLE err) +if(NOT out MATCHES "-- Install configuration: .*-- codegenexlib") + string(REGEX REPLACE "\n" "\n " out " ${out}") + string(APPEND RunCMake_TEST_FAILED + "\"-- codegenexlib\" was not found:\n${out}") +endif() diff --git a/Tests/RunCMake/install/CMP0087-NEW.cmake b/Tests/RunCMake/install/CMP0087-NEW.cmake new file mode 100644 index 0000000..0177960 --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-NEW.cmake @@ -0,0 +1,3 @@ +# Need a new directory scope, not just a new policy scope +# to test this correctly +add_subdirectory(CMP0087-NEW) diff --git a/Tests/RunCMake/install/CMP0087-NEW/CMakeLists.txt b/Tests/RunCMake/install/CMP0087-NEW/CMakeLists.txt new file mode 100644 index 0000000..07b4589 --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-NEW/CMakeLists.txt @@ -0,0 +1,7 @@ +# Note that it is the policy settings at the end of the directory +# scope that will be used when deciding whether or not generator +# expressions should be evaluated in the installed code. +cmake_policy(VERSION 3.13) +cmake_policy(SET CMP0087 NEW) +add_library( codegenexlib INTERFACE ) +install(CODE "message( STATUS \"$\")") diff --git a/Tests/RunCMake/install/CMP0087-OLD-check.cmake b/Tests/RunCMake/install/CMP0087-OLD-check.cmake new file mode 100644 index 0000000..c5984bc --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-OLD-check.cmake @@ -0,0 +1,8 @@ +execute_process(COMMAND ${CMAKE_COMMAND} -P ${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake + OUTPUT_VARIABLE out ERROR_VARIABLE err) + +if(NOT out MATCHES "-- Install configuration: .*-- \\$") + string(REGEX REPLACE "\n" "\n " out " ${out}") + string(APPEND RunCMake_TEST_FAILED + "\"-- $\" was not found:\n${out}") +endif() diff --git a/Tests/RunCMake/install/CMP0087-OLD.cmake b/Tests/RunCMake/install/CMP0087-OLD.cmake new file mode 100644 index 0000000..e7ed4ee --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-OLD.cmake @@ -0,0 +1,3 @@ +# Need a new directory scope, not just a new policy scope +# to test this correctly +add_subdirectory(CMP0087-OLD) diff --git a/Tests/RunCMake/install/CMP0087-OLD/CMakeLists.txt b/Tests/RunCMake/install/CMP0087-OLD/CMakeLists.txt new file mode 100644 index 0000000..b1d4e2e --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-OLD/CMakeLists.txt @@ -0,0 +1,6 @@ +# Note that it is the policy settings at the end of the directory +# scope that will be used when deciding whether or not generator +# expressions should be evaluated in the installed code. +cmake_policy(VERSION 3.13) +cmake_policy(SET CMP0087 OLD) +install(CODE "message( STATUS \"$\")") diff --git a/Tests/RunCMake/install/CMP0087-WARN-stderr.txt b/Tests/RunCMake/install/CMP0087-WARN-stderr.txt new file mode 100644 index 0000000..75fbf2c --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-WARN-stderr.txt @@ -0,0 +1,5 @@ +CMake Warning (dev) in CMakeLists.txt: + Policy CMP0087 is not set: Install CODE|SCRIPT allow the use of generator + expressions. Run "cmake --help-policy CMP0087" for policy details. Use + the cmake_policy command to set the policy and suppress this warning. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/install/CMP0087-WARN.cmake b/Tests/RunCMake/install/CMP0087-WARN.cmake new file mode 100644 index 0000000..3b8513d --- /dev/null +++ b/Tests/RunCMake/install/CMP0087-WARN.cmake @@ -0,0 +1,2 @@ +add_library( codegenexlib INTERFACE ) +install(CODE "message( STATUS \"$\")") diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index f7e1dee..28e8ec4 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -63,6 +63,9 @@ run_cmake(EXPORT-OldIFace) run_cmake(CMP0062-OLD) run_cmake(CMP0062-NEW) run_cmake(CMP0062-WARN) +run_cmake(CMP0087-OLD) +run_cmake(CMP0087-NEW) +run_cmake(CMP0087-WARN) run_cmake(TARGETS-NAMELINK_COMPONENT-bad-all) run_cmake(TARGETS-NAMELINK_COMPONENT-bad-exc) run_cmake(FILES-DESTINATION-TYPE) -- cgit v0.12