Sfoglia il codice sorgente

Genex: Per-source $<COMPILE_LANGUAGE:...> support

Fixes: #17542
Marc Chevrier 7 anni fa
parent
commit
10f58b27ac

+ 13 - 7
Source/cmExtraSublimeTextGenerator.cxx

@@ -361,9 +361,11 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
   }
 
   // Add source file specific flags.
-  if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) {
-    cmGeneratorExpressionInterpreter genexInterpreter(lg, gtgt, config);
-    lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags));
+  const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+  if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
+    cmGeneratorExpressionInterpreter genexInterpreter(
+      lg, gtgt, config, gtgt->GetName(), language);
+    lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
   }
 
   return flags;
@@ -379,7 +381,8 @@ 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);
+  cmGeneratorExpressionInterpreter genexInterpreter(
+    lg, target, config, target->GetName(), language);
 
   // Add the export symbol definition for shared library objects.
   if (const char* exportMacro = target->GetExportMacro()) {
@@ -388,14 +391,17 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
 
   // Add preprocessor definitions for this target and configuration.
   lg->AddCompileDefinitions(defines, target, config, language);
-  if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) {
-    lg->AppendDefines(defines, genexInterpreter.Evaluate(compile_defs));
+  const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+  if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
+    lg->AppendDefines(
+      defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS));
   }
 
   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));
+    lg->AppendDefines(defines, genexInterpreter.Evaluate(config_compile_defs,
+                                                         COMPILE_DEFINITIONS));
   }
 
   std::string definesString;

+ 16 - 0
Source/cmGeneratorExpression.cxx

@@ -9,6 +9,7 @@
 #include "assert.h"
 #include "cmAlgorithms.h"
 #include "cmGeneratorExpressionContext.h"
+#include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpressionEvaluator.h"
 #include "cmGeneratorExpressionLexer.h"
 #include "cmGeneratorExpressionParser.h"
@@ -385,3 +386,18 @@ void cmCompiledGeneratorExpression::GetMaxLanguageStandard(
     mapping = it->second;
   }
 }
+
+const char* cmGeneratorExpressionInterpreter::Evaluate(
+  const char* expression, const std::string& property)
+{
+  if (this->Target.empty()) {
+    return this->EvaluateExpression(expression);
+  }
+
+  // Specify COMPILE_OPTIONS to DAGchecker, same semantic as COMPILE_FLAGS
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this->Target, property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property,
+    nullptr, nullptr);
+
+  return this->EvaluateExpression(expression, &dagChecker);
+}

+ 41 - 6
Source/cmGeneratorExpression.h

@@ -160,25 +160,38 @@ class cmGeneratorExpressionInterpreter
 public:
   cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator,
                                    cmGeneratorTarget* generatorTarget,
-                                   const std::string& config)
+                                   const std::string& config,
+                                   const std::string& target,
+                                   const std::string& lang)
     : LocalGenerator(localGenerator)
     , GeneratorTarget(generatorTarget)
     , Config(config)
+    , Target(target)
+    , Language(lang)
+  {
+  }
+  cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator,
+                                   cmGeneratorTarget* generatorTarget,
+                                   const std::string& config)
+    : cmGeneratorExpressionInterpreter(localGenerator, generatorTarget, config,
+                                       std::string(), std::string())
   {
   }
 
   const char* Evaluate(const char* expression)
   {
-    this->CompiledGeneratorExpression =
-      this->GeneratorExpression.Parse(expression);
-
-    return this->CompiledGeneratorExpression->Evaluate(
-      this->LocalGenerator, this->Config, false, this->GeneratorTarget);
+    return this->EvaluateExpression(expression);
   }
   const char* Evaluate(const std::string& expression)
   {
     return this->Evaluate(expression.c_str());
   }
+  const char* Evaluate(const char* expression, const std::string& property);
+  const char* Evaluate(const std::string& expression,
+                       const std::string& property)
+  {
+    return this->Evaluate(expression.c_str(), property);
+  }
 
 protected:
   cmGeneratorExpression& GetGeneratorExpression()
@@ -195,12 +208,34 @@ protected:
 
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
 
+  const std::string& GetTargetName() const { return this->Target; }
+  const std::string& GetLanguage() const { return this->Language; }
+
+  const char* EvaluateExpression(
+    const char* expression,
+    cmGeneratorExpressionDAGChecker* dagChecker = nullptr)
+  {
+    this->CompiledGeneratorExpression =
+      this->GeneratorExpression.Parse(expression);
+
+    if (dagChecker == nullptr) {
+      return this->CompiledGeneratorExpression->Evaluate(
+        this->LocalGenerator, this->Config, false, this->GeneratorTarget);
+    }
+
+    return this->CompiledGeneratorExpression->Evaluate(
+      this->LocalGenerator, this->Config, false, this->GeneratorTarget,
+      dagChecker, this->Language);
+  }
+
 private:
   cmGeneratorExpression GeneratorExpression;
   std::unique_ptr<cmCompiledGeneratorExpression> CompiledGeneratorExpression;
   cmLocalGenerator* LocalGenerator = nullptr;
   cmGeneratorTarget* GeneratorTarget = nullptr;
   std::string Config;
+  std::string Target;
+  std::string Language;
 };
 
 #endif

+ 17 - 12
Source/cmGlobalXCodeGenerator.cxx

@@ -684,18 +684,21 @@ class XCodeGeneratorExpressionInterpreter
 public:
   XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile,
                                       cmLocalGenerator* localGenerator,
-                                      cmGeneratorTarget* generatorTarget)
+                                      cmGeneratorTarget* generatorTarget,
+                                      const std::string& lang)
     : cmGeneratorExpressionInterpreter(localGenerator, generatorTarget,
-                                       "NO-PER-CONFIG-SUPPORT-IN-XCODE")
+                                       "NO-PER-CONFIG-SUPPORT-IN-XCODE",
+                                       generatorTarget->GetName(), lang)
     , SourceFile(sourceFile)
   {
   }
 
   using cmGeneratorExpressionInterpreter::Evaluate;
 
-  const char* Evaluate(const char* expression, const char* property)
+  const char* Evaluate(const char* expression, const std::string& property)
   {
-    const char* processed = this->Evaluate(expression);
+    const char* processed =
+      this->cmGeneratorExpressionInterpreter::Evaluate(expression, property);
     if (this->GetCompiledGeneratorExpression()
           .GetHadContextSensitiveCondition()) {
       std::ostringstream e;
@@ -719,7 +722,9 @@ private:
 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
   cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt)
 {
-  XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt);
+  std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+
+  XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt, lang);
 
   // Add flags from target and source file properties.
   std::string flags;
@@ -734,16 +739,18 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
     default:
       break;
   }
-  if (const char* cflags = sf->GetProperty("COMPILE_FLAGS")) {
-    lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, "COMPILE_FLAGS"));
+  const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+  if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) {
+    lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
   }
 
   // Add per-source definitions.
   BuildObjectListOrString flagsBuild(this, false);
-  if (const char* compile_defs = sf->GetProperty("COMPILE_DEFINITIONS")) {
+  const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+  if (const char* compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) {
     this->AppendDefines(
-      flagsBuild,
-      genexInterpreter.Evaluate(compile_defs, "COMPILE_DEFINITIONS"), true);
+      flagsBuild, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS),
+      true);
   }
   if (!flagsBuild.IsEmpty()) {
     if (!flags.empty()) {
@@ -752,8 +759,6 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
     flags += flagsBuild.GetString();
   }
 
-  std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
-
   cmXCodeObject* buildFile =
     this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), gtgt, lang, sf);
 

+ 22 - 15
Source/cmLocalVisualStudio7Generator.cxx

@@ -1458,14 +1458,28 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
        i != configs.end(); ++i, ++ci) {
     std::string configUpper = cmSystemTools::UpperCase(*i);
     cmLVS7GFileConfig fc;
-    cmGeneratorExpressionInterpreter genexInterpreter(lg, gt, *i);
+
+    std::string lang =
+      lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
+    const std::string& sourceLang = lg->GetSourceFileLanguage(sf);
+    bool needForceLang = false;
+    // source file does not match its extension language
+    if (lang != sourceLang) {
+      needForceLang = true;
+      lang = sourceLang;
+    }
+
+    cmGeneratorExpressionInterpreter genexInterpreter(lg, gt, *i,
+                                                      gt->GetName(), lang);
+
     bool needfc = false;
     if (!objectName.empty()) {
       fc.ObjectName = objectName;
       needfc = true;
     }
-    if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
-      fc.CompileFlags = genexInterpreter.Evaluate(cflags);
+    const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+    if (const char* cflags = sf.GetProperty(COMPILE_FLAGS)) {
+      fc.CompileFlags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS);
       needfc = true;
     }
     if (lg->FortranProject) {
@@ -1483,14 +1497,16 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
           break;
       }
     }
-    if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
-      fc.CompileDefs = genexInterpreter.Evaluate(cdefs);
+    const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+    if (const char* cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) {
+      fc.CompileDefs = genexInterpreter.Evaluate(cdefs, COMPILE_DEFINITIONS);
       needfc = true;
     }
     std::string defPropName = "COMPILE_DEFINITIONS_";
     defPropName += configUpper;
     if (const char* ccdefs = sf.GetProperty(defPropName)) {
-      fc.CompileDefsConfig = genexInterpreter.Evaluate(ccdefs);
+      fc.CompileDefsConfig =
+        genexInterpreter.Evaluate(ccdefs, COMPILE_DEFINITIONS);
       needfc = true;
     }
 
@@ -1508,16 +1524,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
       }
     }
 
-    std::string lang =
-      lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
-    const std::string& sourceLang = lg->GetSourceFileLanguage(sf);
     const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str());
-    bool needForceLang = false;
-    // source file does not match its extension language
-    if (lang != sourceLang) {
-      needForceLang = true;
-      lang = sourceLang;
-    }
     // If HEADER_FILE_ONLY is set, we must suppress this generation in
     // the project file
     fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||

+ 12 - 6
Source/cmMakefileTargetGenerator.cxx

@@ -426,7 +426,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   std::string config = this->LocalGenerator->GetConfigName();
   std::string configUpper = cmSystemTools::UpperCase(config);
   cmGeneratorExpressionInterpreter genexInterpreter(
-    this->LocalGenerator, this->GeneratorTarget, config);
+    this->LocalGenerator, this->GeneratorTarget, config,
+    this->GeneratorTarget->GetName(), lang);
 
   // Add Fortran format flags.
   if (lang == "Fortran") {
@@ -434,8 +435,10 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   }
 
   // Add flags from source file properties.
-  if (const char* cflags = source.GetProperty("COMPILE_FLAGS")) {
-    const char* evaluatedFlags = genexInterpreter.Evaluate(cflags);
+  const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+  if (const char* cflags = source.GetProperty(COMPILE_FLAGS)) {
+    const char* evaluatedFlags =
+      genexInterpreter.Evaluate(cflags, COMPILE_FLAGS);
     this->LocalGenerator->AppendFlags(flags, evaluatedFlags);
     *this->FlagFileStream << "# Custom flags: " << relativeObj
                           << "_FLAGS = " << evaluatedFlags << "\n"
@@ -446,8 +449,10 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   std::set<std::string> defines;
 
   // Add source-sepcific preprocessor definitions.
-  if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) {
-    const char* evaluatedDefs = genexInterpreter.Evaluate(compile_defs);
+  const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+  if (const char* compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) {
+    const char* evaluatedDefs =
+      genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS);
     this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
     *this->FlagFileStream << "# Custom defines: " << relativeObj
                           << "_DEFINES = " << evaluatedDefs << "\n"
@@ -456,7 +461,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
   std::string defPropName = "COMPILE_DEFINITIONS_";
   defPropName += configUpper;
   if (const char* config_compile_defs = source.GetProperty(defPropName)) {
-    const char* evaluatedDefs = genexInterpreter.Evaluate(config_compile_defs);
+    const char* evaluatedDefs =
+      genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS);
     this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
     *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_"
                           << configUpper << " = " << evaluatedDefs << "\n"

+ 13 - 8
Source/cmNinjaTargetGenerator.cxx

@@ -135,12 +135,14 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
   }
 
   // Add source file specific flags.
-  if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) {
+  const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+  if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
     cmGeneratorExpressionInterpreter genexInterpreter(
       this->LocalGenerator, this->GeneratorTarget,
-      this->LocalGenerator->GetConfigName());
-    this->LocalGenerator->AppendFlags(flags,
-                                      genexInterpreter.Evaluate(cflags));
+      this->LocalGenerator->GetConfigName(), this->GeneratorTarget->GetName(),
+      language);
+    this->LocalGenerator->AppendFlags(
+      flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
   }
 
   return flags;
@@ -179,18 +181,21 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
   std::set<std::string> defines;
   const std::string config = this->LocalGenerator->GetConfigName();
   cmGeneratorExpressionInterpreter genexInterpreter(
-    this->LocalGenerator, this->GeneratorTarget, config);
+    this->LocalGenerator, this->GeneratorTarget, config,
+    this->GeneratorTarget->GetName(), language);
 
-  if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) {
+  const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+  if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
     this->LocalGenerator->AppendDefines(
-      defines, genexInterpreter.Evaluate(compile_defs));
+      defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS));
   }
 
   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));
+      defines,
+      genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS));
   }
 
   std::string definesString = this->GetDefines(language);

+ 12 - 7
Source/cmServerProtocol.cxx

@@ -691,8 +691,6 @@ static Json::Value DumpSourceFilesList(
 
   std::vector<cmSourceFile*> files;
   target->GetSourceFiles(files, config);
-  cmGeneratorExpressionInterpreter genexInterpreter(
-    target->GetLocalGenerator(), target, config);
 
   std::unordered_map<LanguageData, std::vector<std::string>> fileGroups;
   for (cmSourceFile* file : files) {
@@ -701,24 +699,31 @@ static Json::Value DumpSourceFilesList(
     if (!fileData.Language.empty()) {
       const LanguageData& ld = languageDataMap.at(fileData.Language);
       cmLocalGenerator* lg = target->GetLocalGenerator();
+      cmGeneratorExpressionInterpreter genexInterpreter(
+        lg, target, config, target->GetName(), fileData.Language);
 
       std::string compileFlags = ld.Flags;
-      if (const char* cflags = file->GetProperty("COMPILE_FLAGS")) {
-        lg->AppendFlags(compileFlags, genexInterpreter.Evaluate(cflags));
+      const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+      if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) {
+        lg->AppendFlags(compileFlags,
+                        genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
       }
       fileData.Flags = compileFlags;
 
       fileData.IncludePathList = ld.IncludePathList;
 
+      const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
       std::set<std::string> defines;
-      if (const char* defs = file->GetProperty("COMPILE_DEFINITIONS")) {
-        lg->AppendDefines(defines, genexInterpreter.Evaluate(defs));
+      if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) {
+        lg->AppendDefines(
+          defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS));
       }
 
       const std::string defPropName =
         "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
       if (const char* config_defs = file->GetProperty(defPropName)) {
-        lg->AppendDefines(defines, genexInterpreter.Evaluate(config_defs));
+        lg->AppendDefines(defines, genexInterpreter.Evaluate(
+                                     config_defs, COMPILE_DEFINITIONS));
       }
 
       defines.insert(ld.Defines.begin(), ld.Defines.end());

+ 5 - 3
Source/cmVisualStudio10TargetGenerator.cxx

@@ -2152,7 +2152,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
         flagtable = gg->GetCSharpFlagTable();
       }
       cmGeneratorExpressionInterpreter genexInterpreter(
-        this->LocalGenerator, this->GeneratorTarget, *config);
+        this->LocalGenerator, this->GeneratorTarget, *config,
+        this->GeneratorTarget->GetName(), lang);
       cmVisualStudioGeneratorOptions clOptions(
         this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler,
         flagtable, 0, this);
@@ -2163,7 +2164,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
         clOptions.AddFlag("CompileAsWinRT", "false");
       }
       if (configDependentFlags) {
-        clOptions.Parse(genexInterpreter.Evaluate(flags));
+        clOptions.Parse(genexInterpreter.Evaluate(flags, "COMPILE_FLAGS"));
       } else {
         clOptions.Parse(flags.c_str());
       }
@@ -2176,7 +2177,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
                              "%(DisableSpecificWarnings)");
       }
       if (configDependentDefines) {
-        clOptions.AddDefines(genexInterpreter.Evaluate(configDefines));
+        clOptions.AddDefines(
+          genexInterpreter.Evaluate(configDefines, "COMPILE_DEFINITIONS"));
       } else {
         clOptions.AddDefines(configDefines.c_str());
       }

+ 8 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -263,9 +263,17 @@ add_custom_target(check-part4 ALL
 add_executable(srcgenex_flags srcgenex_flags.c)
 set_property(SOURCE srcgenex_flags.c PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>")
 
+add_executable(srcgenex_flags_COMPILE_LANGUAGE srcgenex_flags_COMPILE_LANGUAGE.c)
+set_property(SOURCE srcgenex_flags_COMPILE_LANGUAGE.c PROPERTY COMPILE_FLAGS "$<$<COMPILE_LANGUAGE:C>:-DNAME=$<TARGET_PROPERTY:NAME>>")
+
 add_executable(srcgenex_defs srcgenex_defs.c)
 set_property(SOURCE srcgenex_defs.c PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>)
 
+if (CMAKE_GENERATOR MATCHES "Makefiles|Ninja|Watcom WMake")
+  add_executable(srcgenex_defs_COMPILE_LANGUAGE srcgenex_defs_COMPILE_LANGUAGE.c)
+  set_property(SOURCE srcgenex_defs_COMPILE_LANGUAGE.c PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>)
+endif()
+
 #-----------------------------------------------------------------------------
 # Cover test properties with generator expressions.
 add_executable(echo echo.c)

+ 12 - 0
Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c

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

+ 12 - 0
Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c

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

+ 1 - 0
Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt

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

+ 7 - 0
Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<COMPILE_LANGUAGE:CXX>
+
+  \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
+  file\(GENERATE\) with the Visual Studio generator.

+ 7 - 0
Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<COMPILE_LANGUAGE:CXX>
+
+  \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
+  file\(GENERATE\) with the Xcode generator.

+ 5 - 0
Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake

@@ -0,0 +1,5 @@
+
+enable_language(CXX)
+
+add_executable(main main.cpp)
+set_property(SOURCE main.cpp PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:CXX>:ANYTHING>)

+ 7 - 0
Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake

@@ -14,3 +14,10 @@ elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
     set(RunCMake-stderr-file IncludeDirectories-stderr-VS.txt)
     run_cmake(IncludeDirectories)
 endif()
+if (RunCMake_GENERATOR STREQUAL "Xcode")
+    set(RunCMake-stderr-file PerSourceCompileDefinitions-stderr-Xcode.txt)
+    run_cmake(PerSourceCompileDefinitions)
+elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
+    set(RunCMake-stderr-file PerSourceCompileDefinitions-stderr-VS.txt)
+    run_cmake(PerSourceCompileDefinitions)
+endif()