Browse Source

Export: allow exporting of additional properties

This change introduces an additional property that may be set on a
target to allow additional properties to be exported. Normally only a
limited number of properties are exported.

Additional properties may be exported by simply setting the
`EXPORT_PROPERTIES` property on a target that is exported.
Wouter Klouwen 7 years ago
parent
commit
6db61f0725

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -176,6 +176,7 @@ Properties on Targets
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD
    /prop_tgt/EXPORT_NAME
+   /prop_tgt/EXPORT_PROPERTIES
    /prop_tgt/FOLDER
    /prop_tgt/Fortran_FORMAT
    /prop_tgt/Fortran_MODULE_DIRECTORY

+ 14 - 0
Help/prop_tgt/EXPORT_PROPERTIES.rst

@@ -0,0 +1,14 @@
+EXPORT_PROPERTIES
+-----------------
+
+List additional properties to export for a target.
+
+This property contains a list of property names that should be exported by
+the :command:`install(EXPORT)` and :command:`export` commands.  By default
+only a limited number of properties are exported. This property can be used
+to additionally export other properties as well.
+
+Properties starting with ``INTERFACE_`` or ``IMPORTED_`` are not allowed as
+they are reserved for internal CMake use.
+
+Properties containing generator expressions are also not allowed.

+ 6 - 0
Help/release/dev/export-properties.rst

@@ -0,0 +1,6 @@
+EXPORT_PROPERTIES
+-----------------
+
+* An :prop_tgt:`EXPORT_PROPERTIES` target property was added to specify a
+  custom list of target properties to include in targets exported by the
+  :command:`install(EXPORT)` and :command:`export` commands.

+ 9 - 0
Source/cmExportBuildFileGenerator.cxx

@@ -97,6 +97,15 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
                                     properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
                                     properties);
+
+    std::string errorMessage;
+    if (!this->PopulateExportProperties(gte, properties, errorMessage)) {
+      this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+        cmake::FATAL_ERROR, errorMessage,
+        this->LG->GetMakefile()->GetBacktrace());
+      return false;
+    }
+
     const bool newCMP0022Behavior =
       gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
       gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;

+ 40 - 0
Source/cmExportFileGenerator.cxx

@@ -11,6 +11,8 @@
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -1097,3 +1099,41 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode(
 
   os << ")\n\n";
 }
+
+bool cmExportFileGenerator::PopulateExportProperties(
+  cmGeneratorTarget* gte, ImportPropertyMap& properties,
+  std::string& errorMessage)
+{
+  auto& targetProperties = gte->Target->GetProperties();
+  const auto& exportProperties = targetProperties.find("EXPORT_PROPERTIES");
+  if (exportProperties != targetProperties.end()) {
+    std::vector<std::string> propsToExport;
+    cmSystemTools::ExpandListArgument(exportProperties->second.GetValue(),
+                                      propsToExport);
+    for (auto& prop : propsToExport) {
+      /* Black list reserved properties */
+      if (cmSystemTools::StringStartsWith(prop, "IMPORTED_") ||
+          cmSystemTools::StringStartsWith(prop, "INTERFACE_")) {
+        std::ostringstream e;
+        e << "Target \"" << gte->Target->GetName() << "\" contains property \""
+          << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* "
+          << "properties are reserved.";
+        errorMessage = e.str();
+        return false;
+      }
+      auto propertyValue = targetProperties.GetPropertyValue(prop);
+      std::string evaluatedValue = cmGeneratorExpression::Preprocess(
+        propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions);
+      if (evaluatedValue != propertyValue) {
+        std::ostringstream e;
+        e << "Target \"" << gte->Target->GetName() << "\" contains property \""
+          << prop << "\" in EXPORT_PROPERTIES but this property contains a "
+          << "generator expression. This is not allowed.";
+        errorMessage = e.str();
+        return false;
+      }
+      properties[prop] = propertyValue;
+    }
+  }
+  return true;
+}

+ 4 - 0
Source/cmExportFileGenerator.h

@@ -168,6 +168,10 @@ protected:
   virtual void GenerateRequiredCMakeVersion(std::ostream& os,
                                             const char* versionString);
 
+  bool PopulateExportProperties(cmGeneratorTarget* gte,
+                                ImportPropertyMap& properties,
+                                std::string& errorMessage);
+
   // The namespace in which the exports are placed in the generated file.
   std::string Namespace;
 

+ 6 - 0
Source/cmExportInstallFileGenerator.cxx

@@ -104,6 +104,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
                                     cmGeneratorExpression::InstallInterface,
                                     properties, missingTargets);
 
+    std::string errorMessage;
+    if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
+      cmSystemTools::Error(errorMessage.c_str());
+      return false;
+    }
+
     const bool newCMP0022Behavior =
       gt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
       gt->GetPolicyStatusCMP0022() != cmPolicies::OLD;

+ 8 - 0
Tests/ExportImport/Export/CMakeLists.txt

@@ -356,6 +356,14 @@ install(FILES
 
 set_property(TARGET testLib2 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS USING_TESTLIB2)
 set_property(TARGET testLib3 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS USING_TESTLIB3)
+set_target_properties(testLib3 PROPERTIES
+  EXPORT_PROPERTIES "EXPORTED_PROPERTY1"
+  EXPORTED_PROPERTY1 "EXPORTING_TESTLIB3")
+set_target_properties(testLib4 PROPERTIES
+  EXPORTED_PROPERTY2 "EXPORTING_TESTLIB4_1"
+  EXPORTED_PROPERTY3 "EXPORTING_TESTLIB4_2")
+set_property(TARGET testLib4 PROPERTY
+  EXPORT_PROPERTIES EXPORTED_PROPERTY2 EXPORTED_PROPERTY3)
 
 set_property(TARGET cmp0022NEW APPEND PROPERTY INTERFACE_LINK_LIBRARIES testLib2)
 # set_property(TARGET cmp0022NEW APPEND PROPERTY LINK_INTERFACE_LIBRARIES testLibIncludeRequired2) # TODO: Test for error

+ 14 - 0
Tests/ExportImport/Import/A/CMakeLists.txt

@@ -32,6 +32,20 @@ add_executable(imp_testExe1
   ${Import_BINARY_DIR}/exp_generated4.c
   )
 
+function(checkForProperty _TARGET _PROP _EXPECTED)
+  get_target_property(EXPORTED_PROPERTY ${_TARGET} "${_PROP}")
+  if (NOT EXPORTED_PROPERTY STREQUAL "${_EXPECTED}")
+    message(SEND_ERROR "${_TARGET} was expected to export \"${_PROP}\" with value \"${_EXPECTED}\" but got \"${EXPORTED_PROPERTY}\"")
+  endif()
+endfunction()
+
+checkForProperty(bld_testLib3 "EXPORTED_PROPERTY1"  "EXPORTING_TESTLIB3")
+checkForProperty(exp_testLib3 "EXPORTED_PROPERTY1"  "EXPORTING_TESTLIB3")
+checkForProperty(bld_testLib4 "EXPORTED_PROPERTY2"  "EXPORTING_TESTLIB4_1")
+checkForProperty(exp_testLib4 "EXPORTED_PROPERTY2"  "EXPORTING_TESTLIB4_1")
+checkForProperty(bld_testLib4 "EXPORTED_PROPERTY3"  "EXPORTING_TESTLIB4_2")
+checkForProperty(exp_testLib4 "EXPORTED_PROPERTY3"  "EXPORTING_TESTLIB4_2")
+
 # Try linking to a library imported from the install tree.
 target_link_libraries(imp_testExe1
   exp_testLib2

+ 1 - 0
Tests/RunCMake/export/ForbiddenToExportImportedProperties-result.txt

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

+ 3 - 0
Tests/RunCMake/export/ForbiddenToExportImportedProperties-stderr.txt

@@ -0,0 +1,3 @@
+CMake Error in CMakeLists.txt:
+  Target \"foo\" contains property \"IMPORTED_FOOBAR\" in EXPORT_PROPERTIES but
+  IMPORTED_\* and INTERFACE_\* properties are reserved.

+ 12 - 0
Tests/RunCMake/export/ForbiddenToExportImportedProperties.cmake

@@ -0,0 +1,12 @@
+enable_language(CXX)
+add_library(foo empty.cpp)
+set_target_properties(foo PROPERTIES
+  IMPORTED_FOOBAR "Some other string"
+  EXPORT_PROPERTIES "IMPORTED_FOOBAR"
+)
+export(TARGETS foo FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake")
+install(TARGETS foo EXPORT fooExport
+  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+)

+ 1 - 0
Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-result.txt

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

+ 3 - 0
Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-stderr.txt

@@ -0,0 +1,3 @@
+CMake Error in CMakeLists.txt:
+  Target \"foo\" contains property \"INTERFACE_FOOBAR\" in EXPORT_PROPERTIES but
+  IMPORTED_\* and INTERFACE_\* properties are reserved.

+ 12 - 0
Tests/RunCMake/export/ForbiddenToExportInterfaceProperties.cmake

@@ -0,0 +1,12 @@
+enable_language(CXX)
+add_library(foo empty.cpp)
+set_target_properties(foo PROPERTIES
+  INTERFACE_FOOBAR "Some string"
+  EXPORT_PROPERTIES "INTERFACE_FOOBAR"
+)
+export(TARGETS foo FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake")
+install(TARGETS foo EXPORT fooExport
+  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+)

+ 1 - 0
Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-result.txt

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

+ 3 - 0
Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-stderr.txt

@@ -0,0 +1,3 @@
+CMake Error in CMakeLists.txt:
+  Target \"foo\" contains property \"JUST_A_PROPERTY\" in EXPORT_PROPERTIES but
+  this property contains a generator expression.  This is not allowed.

+ 12 - 0
Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp.cmake

@@ -0,0 +1,12 @@
+enable_language(CXX)
+add_library(foo empty.cpp)
+set_target_properties(foo PROPERTIES
+  JUST_A_PROPERTY "$<C_COMPILER_VERSION:0>"
+  EXPORT_PROPERTIES "JUST_A_PROPERTY"
+)
+export(TARGETS foo FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake")
+install(TARGETS foo EXPORT fooExport
+  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+)

+ 3 - 0
Tests/RunCMake/export/RunCMakeTest.cmake

@@ -5,3 +5,6 @@ run_cmake(TargetNotFound)
 run_cmake(AppendExport)
 run_cmake(OldIface)
 run_cmake(NoExportSet)
+run_cmake(ForbiddenToExportInterfaceProperties)
+run_cmake(ForbiddenToExportImportedProperties)
+run_cmake(ForbiddenToExportPropertyWithGenExp)

+ 7 - 0
Tests/RunCMake/export/empty.cpp

@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  int empty()
+{
+  return 0;
+}