浏览代码

Add generator expression support to per-source COMPILE_DEFINITIONS

This allows users to specify different genex-based compile definitions for each file in a target.

Fixes: #17508
Marc Chevrier 8 年之前
父节点
当前提交
9432f686e6

+ 10 - 0
Help/prop_sf/COMPILE_DEFINITIONS.rst

@@ -17,3 +17,13 @@ by the native build tool.  Xcode does not support per-configuration
 definitions on source files.
 
 .. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
+
+Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions"
+with the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.  However, :generator:`Xcode`
+does not support per-config per-source settings, so expressions
+that depend on the build configuration are not allowed with that
+generator.
+
+Generator expressions should be preferred instead of setting the alternative per-configuration
+property.

+ 5 - 0
Help/release/dev/src-COMPILE_DEFINITIONS-genex.rst

@@ -0,0 +1,5 @@
+src-COMPILE_DEFINITIONS-genex
+-----------------------------
+
+* The :prop_sf:`COMPILE_DEFINITIONS` source file property learned to support
+  :manual:`generator expressions <cmake-generator-expressions(7)>`.

+ 9 - 5
Source/cmExtraSublimeTextGenerator.cxx

@@ -379,6 +379,7 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
   cmMakefile* makefile = lg->GetMakefile();
   const std::string& language = source->GetLanguage();
   const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  cmGeneratorExpressionInterpreter genexInterpreter(lg, target, config);
 
   // Add the export symbol definition for shared library objects.
   if (const char* exportMacro = target->GetExportMacro()) {
@@ -387,11 +388,14 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
 
   // Add preprocessor definitions for this target and configuration.
   lg->AddCompileDefinitions(defines, target, config, language);
-  lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS"));
-  {
-    std::string defPropName = "COMPILE_DEFINITIONS_";
-    defPropName += cmSystemTools::UpperCase(config);
-    lg->AppendDefines(defines, source->GetProperty(defPropName));
+  if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) {
+    lg->AppendDefines(defines, genexInterpreter.Evaluate(compile_defs));
+  }
+
+  std::string defPropName = "COMPILE_DEFINITIONS_";
+  defPropName += cmSystemTools::UpperCase(config);
+  if (const char* config_compile_defs = source->GetProperty(defPropName)) {
+    lg->AppendDefines(defines, genexInterpreter.Evaluate(config_compile_defs));
   }
 
   std::string definesString;

+ 5 - 2
Source/cmGlobalXCodeGenerator.cxx

@@ -740,8 +740,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
 
   // Add per-source definitions.
   BuildObjectListOrString flagsBuild(this, false);
-  this->AppendDefines(flagsBuild, sf->GetProperty("COMPILE_DEFINITIONS"),
-                      true);
+  if (const char* compile_defs = sf->GetProperty("COMPILE_DEFINITIONS")) {
+    this->AppendDefines(
+      flagsBuild,
+      genexInterpreter.Evaluate(compile_defs, "COMPILE_DEFINITIONS"), true);
+  }
   if (!flagsBuild.IsEmpty()) {
     if (!flags.empty()) {
       flags += ' ';

+ 3 - 3
Source/cmLocalVisualStudio7Generator.cxx

@@ -1484,13 +1484,13 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
       }
     }
     if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
-      fc.CompileDefs = cdefs;
+      fc.CompileDefs = genexInterpreter.Evaluate(cdefs);
       needfc = true;
     }
     std::string defPropName = "COMPILE_DEFINITIONS_";
     defPropName += configUpper;
-    if (const char* ccdefs = sf.GetProperty(defPropName.c_str())) {
-      fc.CompileDefsConfig = ccdefs;
+    if (const char* ccdefs = sf.GetProperty(defPropName)) {
+      fc.CompileDefsConfig = genexInterpreter.Evaluate(ccdefs);
       needfc = true;
     }
 

+ 6 - 5
Source/cmMakefileTargetGenerator.cxx

@@ -447,18 +447,19 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
 
   // Add source-sepcific preprocessor definitions.
   if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) {
-    this->LocalGenerator->AppendDefines(defines, compile_defs);
+    const char* evaluatedDefs = genexInterpreter.Evaluate(compile_defs);
+    this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
     *this->FlagFileStream << "# Custom defines: " << relativeObj
-                          << "_DEFINES = " << compile_defs << "\n"
+                          << "_DEFINES = " << evaluatedDefs << "\n"
                           << "\n";
   }
   std::string defPropName = "COMPILE_DEFINITIONS_";
   defPropName += configUpper;
   if (const char* config_compile_defs = source.GetProperty(defPropName)) {
-    this->LocalGenerator->AppendDefines(defines, config_compile_defs);
+    const char* evaluatedDefs = genexInterpreter.Evaluate(config_compile_defs);
+    this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
     *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_"
-                          << configUpper << " = " << config_compile_defs
-                          << "\n"
+                          << configUpper << " = " << evaluatedDefs << "\n"
                           << "\n";
   }
 

+ 14 - 7
Source/cmNinjaTargetGenerator.cxx

@@ -177,13 +177,20 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
                                                    const std::string& language)
 {
   std::set<std::string> defines;
-  this->LocalGenerator->AppendDefines(
-    defines, source->GetProperty("COMPILE_DEFINITIONS"));
-  {
-    std::string defPropName = "COMPILE_DEFINITIONS_";
-    defPropName += cmSystemTools::UpperCase(this->GetConfigName());
-    this->LocalGenerator->AppendDefines(defines,
-                                        source->GetProperty(defPropName));
+  const std::string config = this->LocalGenerator->GetConfigName();
+  cmGeneratorExpressionInterpreter genexInterpreter(
+    this->LocalGenerator, this->GeneratorTarget, config);
+
+  if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) {
+    this->LocalGenerator->AppendDefines(
+      defines, genexInterpreter.Evaluate(compile_defs));
+  }
+
+  std::string defPropName = "COMPILE_DEFINITIONS_";
+  defPropName += cmSystemTools::UpperCase(config);
+  if (const char* config_compile_defs = source->GetProperty(defPropName)) {
+    this->LocalGenerator->AppendDefines(
+      defines, genexInterpreter.Evaluate(config_compile_defs));
   }
 
   std::string definesString = this->GetDefines(language);

+ 8 - 2
Source/cmServerProtocol.cxx

@@ -712,10 +712,16 @@ static Json::Value DumpSourceFilesList(
       fileData.IncludePathList = ld.IncludePathList;
 
       std::set<std::string> defines;
-      lg->AppendDefines(defines, file->GetProperty("COMPILE_DEFINITIONS"));
+      if (const char* defs = file->GetProperty("COMPILE_DEFINITIONS")) {
+        lg->AppendDefines(defines, genexInterpreter.Evaluate(defs));
+      }
+
       const std::string defPropName =
         "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
-      lg->AppendDefines(defines, file->GetProperty(defPropName));
+      if (const char* config_defs = file->GetProperty(defPropName)) {
+        lg->AppendDefines(defines, genexInterpreter.Evaluate(config_defs));
+      }
+
       defines.insert(ld.Defines.begin(), ld.Defines.end());
 
       fileData.SetDefines(defines);

+ 10 - 1
Source/cmVisualStudio10TargetGenerator.cxx

@@ -2066,12 +2066,15 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
   std::string flags;
   bool configDependentFlags = false;
   std::string defines;
+  bool configDependentDefines = false;
   if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
     configDependentFlags =
       cmGeneratorExpression::Find(cflags) != std::string::npos;
     flags += cflags;
   }
   if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
+    configDependentDefines =
+      cmGeneratorExpression::Find(cdefs) != std::string::npos;
     defines += cdefs;
   }
   std::string lang =
@@ -2121,6 +2124,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
       if (!configDefines.empty()) {
         configDefines += ";";
       }
+      configDependentDefines |=
+        cmGeneratorExpression::Find(ccdefs) != std::string::npos;
       configDefines += ccdefs;
     }
     // if we have flags or defines for this config then
@@ -2170,7 +2175,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
         clOptions.AppendFlag("DisableSpecificWarnings",
                              "%(DisableSpecificWarnings)");
       }
-      clOptions.AddDefines(configDefines.c_str());
+      if (configDependentDefines) {
+        clOptions.AddDefines(genexInterpreter.Evaluate(configDefines));
+      } else {
+        clOptions.AddDefines(configDefines.c_str());
+      }
       clOptions.SetConfiguration((*config).c_str());
       clOptions.PrependInheritedString("AdditionalOptions");
       clOptions.OutputFlagMap(*this->BuildFileStream, "      ");

+ 7 - 2
Tests/GeneratorExpression/CMakeLists.txt

@@ -258,8 +258,13 @@ add_custom_target(check-part4 ALL
   VERBATIM
   )
 
-add_executable(srcgenex srcgenex.c)
-set_property(SOURCE srcgenex.c PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>")
+#-----------------------------------------------------------------------------
+# Cover source file properties with generator expressions.
+add_executable(srcgenex_flags srcgenex_flags.c)
+set_property(SOURCE srcgenex_flags.c PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>")
+
+add_executable(srcgenex_defs srcgenex_defs.c)
+set_property(SOURCE srcgenex_defs.c PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>)
 
 #-----------------------------------------------------------------------------
 # Cover test properties with generator expressions.

+ 1 - 1
Tests/GeneratorExpression/srcgenex.c → Tests/GeneratorExpression/srcgenex_defs.c

@@ -1,4 +1,4 @@
-int srcgenex(void)
+int srcgenex_defs(void)
 {
   return 0;
 }

+ 12 - 0
Tests/GeneratorExpression/srcgenex_flags.c

@@ -0,0 +1,12 @@
+int srcgenex_flags(void)
+{
+  return 0;
+}
+
+int main(int argc, char* argv[])
+{
+#ifndef NAME
+#error NAME not defined
+#endif
+  return NAME();
+}

+ 1 - 0
Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-result.txt

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

+ 8 - 0
Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt

@@ -0,0 +1,8 @@
+^CMake Error in CMakeLists.txt:
+  Xcode does not support per-config per-source COMPILE_DEFINITIONS:
+
+    \$<\$<CONFIG:Debug>:MYDEBUG>
+
+  specified for source:
+
+    .*/Tests/RunCMake/XcodeProject/main.c$

+ 3 - 0
Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions.cmake

@@ -0,0 +1,3 @@
+enable_language(C)
+add_executable(main main.c)
+set_property(SOURCE main.c PROPERTY COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:MYDEBUG>")

+ 1 - 0
Tests/RunCMake/XcodeProject/RunCMakeTest.cmake

@@ -19,6 +19,7 @@ if (NOT XCODE_VERSION VERSION_LESS 6)
 endif()
 
 run_cmake(PerConfigPerSourceFlags)
+run_cmake(PerConfigPerSourceDefinitions)
 
 # Use a single build tree for a few tests without cleaning.