Browse Source

install: Teach CODE,SCRIPT modes to evaluate generator expressions

Fixes: #15785
Jon Chronopoulos 7 years ago
parent
commit
6dad812143

+ 4 - 0
Help/command/install.rst

@@ -427,6 +427,10 @@ example, the code
 
 will print a message during installation.
 
+The contents of ``SCRIPT`` or ``CODE`` may use "generator expressions" with
+the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.
+
 Installing Exports
 ^^^^^^^^^^^^^^^^^^
 

+ 5 - 0
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.

+ 32 - 8
Source/cmInstallScriptGenerator.cxx

@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallScriptGenerator.h"
 
+#include "cmGeneratorExpression.h"
 #include "cmScriptGenerator.h"
 
 #include <ostream>
@@ -16,24 +17,47 @@ cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script,
   , Script(script)
   , Code(code)
 {
+  // 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;
+}
 
+void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os,
+                                                    Indent indent,
+                                                    std::string const& script)
+{
   if (this->Code) {
-    os << indent.Next() << this->Script << "\n";
+    os << indent.Next() << script << "\n";
+  } else {
+    os << indent.Next() << "include(\"" << script << "\")\n";
+  }
+}
+
+void cmInstallScriptGenerator::GenerateScriptActions(std::ostream& os,
+                                                     Indent indent)
+{
+  if (this->ActionsPerConfig) {
+    this->cmInstallGenerator::GenerateScriptActions(os, indent);
   } else {
-    os << indent.Next() << "include(\"" << this->Script << "\")\n";
+    this->AddScriptInstallRule(os, indent, this->Script);
   }
+}
 
-  os << indent << "endif()\n\n";
+void cmInstallScriptGenerator::GenerateScriptForConfig(
+  std::ostream& os, const std::string& config, Indent indent)
+{
+  cmGeneratorExpression ge;
+  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(this->Script);
+  this->AddScriptInstallRule(os, indent,
+                             cge->Evaluate(this->LocalGenerator, config));
 }

+ 12 - 1
Source/cmInstallScriptGenerator.h

@@ -6,10 +6,13 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmInstallGenerator.h"
+#include "cmScriptGenerator.h"
 
 #include <iosfwd>
 #include <string>
 
+class cmLocalGenerator;
+
 /** \class cmInstallScriptGenerator
  * \brief Generate target installation rules.
  */
@@ -20,10 +23,18 @@ 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;
 };
 
 #endif

+ 1 - 0
Tests/RunCMake/install/CODE-genex-bad-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
Tests/RunCMake/install/CODE-genex-bad-stderr.txt

@@ -0,0 +1,6 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<NOTAGENEX>
+
+  Expression did not evaluate to a known generator expression

+ 1 - 0
Tests/RunCMake/install/CODE-genex-bad.cmake

@@ -0,0 +1 @@
+install(CODE "message(\"$<NOTAGENEX>\")")

+ 7 - 0
Tests/RunCMake/install/CODE-genex-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()

+ 2 - 0
Tests/RunCMake/install/CODE-genex.cmake

@@ -0,0 +1,2 @@
+add_library( codegenexlib INTERFACE )
+install(CODE "message( STATUS \"$<TARGET_PROPERTY:codegenexlib,NAME>\")")

+ 2 - 0
Tests/RunCMake/install/RunCMakeTest.cmake

@@ -65,6 +65,8 @@ run_cmake(CMP0062-NEW)
 run_cmake(CMP0062-WARN)
 run_cmake(TARGETS-NAMELINK_COMPONENT-bad-all)
 run_cmake(TARGETS-NAMELINK_COMPONENT-bad-exc)
+run_cmake(CODE-genex)
+run_cmake(CODE-genex-bad)
 
 if(NOT RunCMake_GENERATOR STREQUAL "Xcode" OR NOT "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
   run_install_test(FILES-TARGET_OBJECTS)