Browse Source

Merge topic 'src-COMPILE_FLAGS-genex'

9a58517d Tests: Add case for Xcode per-config per-source COMPILE_FLAGS diagnostic
1e4bb358 Add generator expression support to per-source COMPILE_FLAGS
Brad King 9 years ago
parent
commit
01567fd74f

+ 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
 These flags will be added to the list of compile flags when this
 source file builds.  Use :prop_sf:`COMPILE_DEFINITIONS` to pass
 source file builds.  Use :prop_sf:`COMPILE_DEFINITIONS` to pass
 additional preprocessor definitions.
 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

@@ -373,7 +373,11 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
   }
   }
 
 
   // Add source file specific flags.
   // 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;
   return flags;
 }
 }

+ 18 - 1
Source/cmGlobalXCodeGenerator.cxx

@@ -675,7 +675,24 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
     default:
     default:
       break;
       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.
   // Add per-source definitions.
   BuildObjectListOrString flagsBuild(this, false);
   BuildObjectListOrString flagsBuild(this, false);

+ 3 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -1464,7 +1464,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
       needfc = true;
       needfc = true;
     }
     }
     if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
     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;
       needfc = true;
     }
     }
     if (lg->FortranProject) {
     if (lg->FortranProject) {

+ 9 - 7
Source/cmMakefileTargetGenerator.cxx

@@ -437,8 +437,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   langFlags += "_FLAGS)";
   langFlags += "_FLAGS)";
   this->LocalGenerator->AppendFlags(flags, langFlags);
   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.
   // Add Fortran format flags.
   if (lang == "Fortran") {
   if (lang == "Fortran") {
@@ -446,12 +446,14 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   }
   }
 
 
   // Add flags from source file properties.
   // 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
     *this->FlagFileStream << "# Custom flags: " << relativeObj
-                          << "_FLAGS = " << source.GetProperty("COMPILE_FLAGS")
-                          << "\n"
+                          << "_FLAGS = " << evaluatedFlags << "\n"
                           << "\n";
                           << "\n";
   }
   }
 
 

+ 8 - 2
Source/cmNinjaTargetGenerator.cxx

@@ -132,8 +132,14 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
   }
   }
 
 
   // Add source file specific flags.
   // 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;
   return flags;
 }
 }

+ 6 - 1
Source/cmServerProtocol.cxx

@@ -686,7 +686,12 @@ static Json::Value DumpSourceFilesList(
       cmLocalGenerator* lg = target->GetLocalGenerator();
       cmLocalGenerator* lg = target->GetLocalGenerator();
 
 
       std::string compileFlags = ld.Flags;
       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.Flags = compileFlags;
 
 
       fileData.IncludePathList = ld.IncludePathList;
       fileData.IncludePathList = ld.IncludePathList;

+ 16 - 2
Source/cmVisualStudio10TargetGenerator.cxx

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

+ 1 - 0
Tests/GeneratorExpression/CMakeLists.txt

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

+ 3 - 0
Tests/GeneratorExpression/echo.c

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

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

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

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

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

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

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

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

@@ -13,6 +13,8 @@ if (NOT XCODE_VERSION VERSION_LESS 6)
   run_cmake(XcodePlatformFrameworks)
   run_cmake(XcodePlatformFrameworks)
 endif()
 endif()
 
 
+run_cmake(PerConfigPerSourceFlags)
+
 # Use a single build tree for a few tests without cleaning.
 # Use a single build tree for a few tests without cleaning.
 
 
 if(NOT XCODE_VERSION VERSION_LESS 5)
 if(NOT XCODE_VERSION VERSION_LESS 5)