Bläddra i källkod

Add generator expression support to per-source COMPILE_FLAGS

This allows users to specify different genex-based compile flags for
each file in a target, e.g. compiling just a single file with `Od/Ox` in
release builds on Visual Studio.
Zsolt Parragi 9 år sedan
förälder
incheckning
1e4bb35894

+ 7 - 0
Help/prop_sf/COMPILE_FLAGS.rst

@@ -6,3 +6,10 @@ Additional flags to be added when compiling this source file.
 These flags will be added to the list of compile flags when this
 source file builds.  Use :prop_sf:`COMPILE_DEFINITIONS` to pass
 additional preprocessor definitions.
+
+Contents of ``COMPILE_FLAGS`` 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.

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

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

+ 5 - 1
Source/cmExtraSublimeTextGenerator.cxx

@@ -341,7 +341,11 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
   }
 
   // Add source file specific flags.
-  lg->AppendFlags(flags, source->GetProperty("COMPILE_FLAGS"));
+  if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) {
+    cmGeneratorExpression ge;
+    const char* processed = ge.Parse(cflags)->Evaluate(lg, config);
+    lg->AppendFlags(flags, processed);
+  }
 
   return flags;
 }

+ 18 - 1
Source/cmGlobalXCodeGenerator.cxx

@@ -675,7 +675,24 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
     default:
       break;
   }
-  lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
+  if (const char* cflags = sf->GetProperty("COMPILE_FLAGS")) {
+    cmGeneratorExpression ge;
+    std::string configName = "NO-PER-CONFIG-SUPPORT-IN-XCODE";
+    CM_AUTO_PTR<cmCompiledGeneratorExpression> compiledExpr = ge.Parse(cflags);
+    const char* processed = compiledExpr->Evaluate(lg, configName);
+    if (compiledExpr->GetHadContextSensitiveCondition()) {
+      std::ostringstream e;
+      /* clang-format off */
+      e <<
+        "Xcode does not support per-config per-source COMPILE_FLAGS:\n"
+        "  " << cflags << "\n"
+        "specified for source:\n"
+        "  " << sf->GetFullPath() << "\n";
+      /* clang-format on */
+      lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+    }
+    lg->AppendFlags(flags, processed);
+  }
 
   // Add per-source definitions.
   BuildObjectListOrString flagsBuild(this, false);

+ 3 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -1464,7 +1464,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
       needfc = true;
     }
     if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
-      fc.CompileFlags = cflags;
+      cmGeneratorExpression ge;
+      CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(cflags);
+      fc.CompileFlags = cge->Evaluate(lg, *i);
       needfc = true;
     }
     if (lg->FortranProject) {

+ 9 - 7
Source/cmMakefileTargetGenerator.cxx

@@ -437,8 +437,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   langFlags += "_FLAGS)";
   this->LocalGenerator->AppendFlags(flags, langFlags);
 
-  std::string configUpper =
-    cmSystemTools::UpperCase(this->LocalGenerator->GetConfigName());
+  std::string config = this->LocalGenerator->GetConfigName();
+  std::string configUpper = cmSystemTools::UpperCase(config);
 
   // Add Fortran format flags.
   if (lang == "Fortran") {
@@ -446,12 +446,14 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   }
 
   // Add flags from source file properties.
-  if (source.GetProperty("COMPILE_FLAGS")) {
-    this->LocalGenerator->AppendFlags(flags,
-                                      source.GetProperty("COMPILE_FLAGS"));
+  if (const char* cflags = source.GetProperty("COMPILE_FLAGS")) {
+    cmGeneratorExpression ge;
+    CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(cflags);
+    const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config,
+                                               false, this->GeneratorTarget);
+    this->LocalGenerator->AppendFlags(flags, evaluatedFlags);
     *this->FlagFileStream << "# Custom flags: " << relativeObj
-                          << "_FLAGS = " << source.GetProperty("COMPILE_FLAGS")
-                          << "\n"
+                          << "_FLAGS = " << evaluatedFlags << "\n"
                           << "\n";
   }
 

+ 8 - 2
Source/cmNinjaTargetGenerator.cxx

@@ -132,8 +132,14 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
   }
 
   // Add source file specific flags.
-  this->LocalGenerator->AppendFlags(flags,
-                                    source->GetProperty("COMPILE_FLAGS"));
+  if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) {
+    std::string config = this->LocalGenerator->GetConfigName();
+    cmGeneratorExpression ge;
+    CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(cflags);
+    const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config,
+                                               false, this->GeneratorTarget);
+    this->LocalGenerator->AppendFlags(flags, evaluatedFlags);
+  }
 
   return flags;
 }

+ 6 - 1
Source/cmServerProtocol.cxx

@@ -686,7 +686,12 @@ static Json::Value DumpSourceFilesList(
       cmLocalGenerator* lg = target->GetLocalGenerator();
 
       std::string compileFlags = ld.Flags;
-      lg->AppendFlags(compileFlags, file->GetProperty("COMPILE_FLAGS"));
+      if (const char* cflags = file->GetProperty("COMPILE_FLAGS")) {
+        cmGeneratorExpression ge;
+        const char* processed =
+          ge.Parse(cflags)->Evaluate(target->GetLocalGenerator(), config);
+        lg->AppendFlags(compileFlags, processed);
+      }
       fileData.Flags = compileFlags;
 
       fileData.IncludePathList = ld.IncludePathList;

+ 16 - 2
Source/cmVisualStudio10TargetGenerator.cxx

@@ -1355,8 +1355,13 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
     objectName = this->GeneratorTarget->GetObjectName(&sf);
   }
   std::string flags;
+  bool configDependentFlags = false;
   std::string defines;
   if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
+
+    if (cmGeneratorExpression::Find(cflags) != std::string::npos) {
+      configDependentFlags = true;
+    }
     flags += cflags;
   }
   if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
@@ -1412,7 +1417,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
     }
     // if we have flags or defines for this config then
     // use them
-    if (!flags.empty() || !configDefines.empty() || compileAs || noWinRT) {
+    if (!flags.empty() || configDependentFlags || !configDefines.empty() ||
+        compileAs || noWinRT) {
       (*this->BuildFileStream) << firstString;
       firstString = ""; // only do firstString once
       hasFlags = true;
@@ -1427,7 +1433,15 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
       if (noWinRT) {
         clOptions.AddFlag("CompileAsWinRT", "false");
       }
-      clOptions.Parse(flags.c_str());
+      if (configDependentFlags) {
+        cmGeneratorExpression ge;
+        CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(flags);
+        std::string evaluatedFlags =
+          cge->Evaluate(this->LocalGenerator, *config);
+        clOptions.Parse(evaluatedFlags.c_str());
+      } else {
+        clOptions.Parse(flags.c_str());
+      }
       if (clOptions.HasFlag("AdditionalIncludeDirectories")) {
         clOptions.AppendFlag("AdditionalIncludeDirectories",
                              "%(AdditionalIncludeDirectories)");

+ 1 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -257,6 +257,7 @@ add_custom_target(check-part4 ALL
 # Cover test properties with generator expressions.
 add_executable(echo echo.c)
 add_executable(pwd pwd.c)
+set_property(SOURCE echo.c PROPERTY COMPILE_FLAGS $<1:-DSRC_GENEX_WORKS>)
 
 add_test(NAME echo-configuration COMMAND echo $<CONFIGURATION>)
 set_property(TEST echo-configuration PROPERTY

+ 3 - 0
Tests/GeneratorExpression/echo.c

@@ -3,6 +3,9 @@
 
 int main(int argc, char* argv[])
 {
+#ifndef SRC_GENEX_WORKS
+#error SRC_GENEX_WORKS not defined
+#endif
   printf("%s\n", argv[1]);
   return EXIT_SUCCESS;
 }