Skip to content

Commit

Permalink
Genex: Allow COMPILE_LANGUAGE when processing compile definitions.
Browse files Browse the repository at this point in the history
Issue an error if this is encountered by an IDE generator.
  • Loading branch information
steveire committed Mar 9, 2015
1 parent 5c559f1 commit 0b945ea
Show file tree
Hide file tree
Showing 24 changed files with 154 additions and 42 deletions.
10 changes: 10 additions & 0 deletions Help/manual/cmake-generator-expressions.7.rst
Expand Up @@ -120,6 +120,16 @@ Available logical expressions are:
add_executable(myapp main.cpp)
target_link_libraries(myapp myapp_c myapp_cxx)
The ``Makefile`` and ``Ninja`` based generators can also use this
expression to specify compile-language specific compile definitions:

.. code-block:: cmake
add_executable(myapp main.cpp foo.c bar.cpp)
target_compile_definitions(myapp
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX>
)
Informational Expressions
=========================

Expand Down
2 changes: 1 addition & 1 deletion Source/cmExtraCodeBlocksGenerator.cxx
Expand Up @@ -599,7 +599,7 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout,

// the compilerdefines for this target
std::vector<std::string> cdefs;
target->GetCompileDefinitions(cdefs, buildType);
target->GetCompileDefinitions(cdefs, buildType, "C");

// Expand the list.
for(std::vector<std::string>::const_iterator di = cdefs.begin();
Expand Down
2 changes: 1 addition & 1 deletion Source/cmExtraSublimeTextGenerator.cxx
Expand Up @@ -436,7 +436,7 @@ ComputeDefines(cmSourceFile *source, cmLocalGenerator* lg, cmTarget *target,
}

// Add preprocessor definitions for this target and configuration.
lg->AddCompileDefinitions(defines, target, config);
lg->AddCompileDefinitions(defines, target, config, language);
lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS"));
{
std::string defPropName = "COMPILE_DEFINITIONS_";
Expand Down
15 changes: 12 additions & 3 deletions Source/cmGeneratorExpressionEvaluator.cxx
Expand Up @@ -817,7 +817,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if(context->Language.empty())
{
Expand Down Expand Up @@ -849,12 +849,21 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
"generators.");
return std::string();
}
else if (genName.find("Xcode") != std::string::npos)
{
if (dagChecker && dagChecker->EvaluatingCompileDefinitions())
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> may only be used with COMPILE_OPTIONS "
"with the Xcode generator.");
return std::string();
}
}
else
{
if(genName.find("Makefiles") == std::string::npos &&
genName.find("Ninja") == std::string::npos &&
genName.find("Watcom WMake") == std::string::npos &&
genName.find("Xcode") == std::string::npos)
genName.find("Watcom WMake") == std::string::npos)
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> not supported for this generator.");
Expand Down
2 changes: 1 addition & 1 deletion Source/cmGlobalXCodeGenerator.cxx
Expand Up @@ -1803,7 +1803,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
}
cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
std::vector<std::string> targetDefines;
target.GetCompileDefinitions(targetDefines, configName);
target.GetCompileDefinitions(targetDefines, configName, "C");
this->AppendDefines(ppDefs, targetDefines);
buildSettings->AddAttribute
("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());
Expand Down
6 changes: 3 additions & 3 deletions Source/cmLocalGenerator.cxx
Expand Up @@ -1428,11 +1428,11 @@ std::string cmLocalGenerator::GetIncludeFlags(
//----------------------------------------------------------------------------
void cmLocalGenerator::AddCompileDefinitions(std::set<std::string>& defines,
cmTarget const* target,
const std::string& config)
const std::string& config,
const std::string& lang)
{
std::vector<std::string> targetDefines;
target->GetCompileDefinitions(targetDefines,
config);
target->GetCompileDefinitions(targetDefines, config, lang);
this->AppendDefines(defines, targetDefines);
}

Expand Down
3 changes: 2 additions & 1 deletion Source/cmLocalGenerator.h
Expand Up @@ -239,7 +239,8 @@ class cmLocalGenerator
const std::string& lang, const std::string& config);
void AddCompileDefinitions(std::set<std::string>& defines,
cmTarget const* target,
const std::string& config);
const std::string& config,
const std::string& lang);

/** Compute the language used to compile the given source file. */
std::string GetSourceFileLanguage(const cmSourceFile& source);
Expand Down
32 changes: 16 additions & 16 deletions Source/cmLocalUnixMakefileGenerator3.cxx
Expand Up @@ -2094,26 +2094,26 @@ ::WriteDependLanguageInfo(std::ostream& cmakefileStream, cmTarget &target)
<< "set(CMAKE_" << l->first << "_COMPILER_ID \""
<< cid << "\")\n";
}
}

// Build a list of preprocessor definitions for the target.
std::set<std::string> defines;
this->AddCompileDefinitions(defines, &target,
this->ConfigurationName);
if(!defines.empty())
{
cmakefileStream
<< "\n"
<< "# Preprocessor definitions for this target.\n"
<< "set(CMAKE_TARGET_DEFINITIONS\n";
for(std::set<std::string>::const_iterator di = defines.begin();
di != defines.end(); ++di)
// Build a list of preprocessor definitions for the target.
std::set<std::string> defines;
this->AddCompileDefinitions(defines, &target,
this->ConfigurationName, l->first);
if(!defines.empty())
{
cmakefileStream
<< " " << this->EscapeForCMake(*di) << "\n";
<< "\n"
<< "# Preprocessor definitions for this target.\n"
<< "set(CMAKE_TARGET_DEFINITIONS_" << l->first << "\n";
for(std::set<std::string>::const_iterator di = defines.begin();
di != defines.end(); ++di)
{
cmakefileStream
<< " " << this->EscapeForCMake(*di) << "\n";
}
cmakefileStream
<< " )\n";
}
cmakefileStream
<< " )\n";
}

// Store include transform rule properties. Write the directory
Expand Down
10 changes: 5 additions & 5 deletions Source/cmLocalVisualStudio6Generator.cxx
Expand Up @@ -1778,15 +1778,15 @@ ::WriteDSPHeader(std::ostream& fout,
std::set<std::string> minsizeDefinesSet;
std::set<std::string> debugrelDefinesSet;

this->AddCompileDefinitions(definesSet, &target, "");
this->AddCompileDefinitions(definesSet, &target, "", linkLanguage);
this->AddCompileDefinitions(debugDefinesSet, &target,
"DEBUG");
"DEBUG", linkLanguage);
this->AddCompileDefinitions(releaseDefinesSet, &target,
"RELEASE");
"RELEASE", linkLanguage);
this->AddCompileDefinitions(minsizeDefinesSet, &target,
"MINSIZEREL");
"MINSIZEREL", linkLanguage);
this->AddCompileDefinitions(debugrelDefinesSet, &target,
"RELWITHDEBINFO");
"RELWITHDEBINFO", linkLanguage);

std::string defines = " ";
std::string debugDefines = " ";
Expand Down
2 changes: 1 addition & 1 deletion Source/cmLocalVisualStudio7Generator.cxx
Expand Up @@ -775,7 +775,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
std::vector<std::string> targetDefines;
target.GetCompileDefinitions(targetDefines, configName);
target.GetCompileDefinitions(targetDefines, configName, "CXX");
targetOptions.AddDefines(targetDefines);
targetOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
Expand Down
2 changes: 1 addition & 1 deletion Source/cmMakefileTargetGenerator.cxx
Expand Up @@ -329,7 +329,7 @@ std::string cmMakefileTargetGenerator::GetDefines(const std::string &l)

// Add preprocessor definitions for this target and configuration.
this->LocalGenerator->AddCompileDefinitions(defines, this->Target,
this->LocalGenerator->ConfigurationName);
this->LocalGenerator->ConfigurationName, l);

std::string definesString;
this->LocalGenerator->JoinDefines(defines, definesString, lang);
Expand Down
2 changes: 1 addition & 1 deletion Source/cmNinjaTargetGenerator.cxx
Expand Up @@ -231,7 +231,7 @@ ComputeDefines(cmSourceFile const* source, const std::string& language)

// Add preprocessor definitions for this target and configuration.
this->LocalGenerator->AddCompileDefinitions(defines, this->Target,
this->GetConfigName());
this->GetConfigName(), language);
this->LocalGenerator->AppendDefines
(defines,
source->GetProperty("COMPILE_DEFINITIONS"));
Expand Down
2 changes: 1 addition & 1 deletion Source/cmQtAutoGenerators.cxx
Expand Up @@ -507,7 +507,7 @@ static void GetCompileDefinitionsAndDirectories(cmTarget const* target,
incs = cmJoin(includeDirs, ";");

std::set<std::string> defines;
localGen->AddCompileDefinitions(defines, target, config);
localGen->AddCompileDefinitions(defines, target, config, "CXX");

defs += cmJoin(defines, ";");
}
Expand Down
14 changes: 9 additions & 5 deletions Source/cmTarget.cxx
Expand Up @@ -2336,16 +2336,18 @@ static void processCompileDefinitions(cmTarget const* tgt,
std::vector<std::string> &options,
UNORDERED_SET<std::string> &uniqueOptions,
cmGeneratorExpressionDAGChecker *dagChecker,
const std::string& config, bool debugOptions)
const std::string& config, bool debugOptions,
std::string const& language)
{
processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions,
"definitions", std::string());
"definitions", language);
}

//----------------------------------------------------------------------------
void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
const std::string& config) const
const std::string& config,
const std::string& language) const
{
UNORDERED_SET<std::string> uniqueOptions;

Expand Down Expand Up @@ -2377,7 +2379,8 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
uniqueOptions,
&dagChecker,
config,
debugDefines);
debugDefines,
language);

std::vector<cmTargetInternals::TargetPropertyEntry*>
linkInterfaceCompileDefinitionsEntries;
Expand Down Expand Up @@ -2424,7 +2427,8 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
uniqueOptions,
&dagChecker,
config,
debugDefines);
debugDefines,
language);

deleteAndClear(linkInterfaceCompileDefinitionsEntries);
}
Expand Down
3 changes: 2 additions & 1 deletion Source/cmTarget.h
Expand Up @@ -496,7 +496,8 @@ class cmTarget
const char* GetExportMacro() const;

void GetCompileDefinitions(std::vector<std::string> &result,
const std::string& config) const;
const std::string& config,
const std::string& language) const;

// Compute the set of languages compiled by the target. This is
// computed every time it is called because the languages can change
Expand Down
3 changes: 2 additions & 1 deletion Source/cmVisualStudio10TargetGenerator.cxx
Expand Up @@ -1876,7 +1876,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
clOptions.Parse(flags.c_str());
clOptions.Parse(defineFlags.c_str());
std::vector<std::string> targetDefines;
this->Target->GetCompileDefinitions(targetDefines, configName.c_str());
this->Target->GetCompileDefinitions(targetDefines,
configName.c_str(), "CXX");
clOptions.AddDefines(targetDefines);
if(this->MSTools)
{
Expand Down
15 changes: 15 additions & 0 deletions Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
Expand Up @@ -26,6 +26,21 @@ target_compile_definitions(consumer
PRIVATE
)

if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja")
target_sources(consumer PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
)
target_compile_definitions(consumer
PRIVATE
CONSUMER_LANG_$<COMPILE_LANGUAGE>
LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
LANG_IS_C=$<COMPILE_LANGUAGE:C>
)
target_compile_definitions(consumer
PRIVATE -DTEST_LANG_DEFINES
)
endif()

add_definitions(-DSOME_DEF)
add_library(imp UNKNOWN IMPORTED)
get_target_property(_res imp COMPILE_DEFINITIONS)
Expand Down
23 changes: 23 additions & 0 deletions Tests/CMakeCommands/target_compile_definitions/consumer.c
@@ -0,0 +1,23 @@

#ifdef TEST_LANG_DEFINES
#ifdef CONSUMER_LANG_CXX
#error Unexpected CONSUMER_LANG_CXX
#endif

#ifndef CONSUMER_LANG_C
#error Expected CONSUMER_LANG_C
#endif

#if !LANG_IS_C
#error Expected LANG_IS_C
#endif

#if LANG_IS_CXX
#error Unexpected LANG_IS_CXX
#endif
#endif

void consumer_c()
{

}
18 changes: 18 additions & 0 deletions Tests/CMakeCommands/target_compile_definitions/consumer.cpp
Expand Up @@ -15,4 +15,22 @@
#error Expected DASH_D_DEFINE
#endif

#ifdef TEST_LANG_DEFINES
#ifndef CONSUMER_LANG_CXX
#error Expected CONSUMER_LANG_CXX
#endif

#ifdef CONSUMER_LANG_C
#error Unexpected CONSUMER_LANG_C
#endif

#if !LANG_IS_CXX
#error Expected LANG_IS_CXX
#endif

#if LANG_IS_C
#error Unexpected LANG_IS_C
#endif
#endif

int main() { return 0; }
@@ -0,0 +1 @@
1
@@ -0,0 +1,8 @@
CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\):
Error evaluating generator expression:

\$<COMPILE_LANGUAGE:CXX>

\$<COMPILE_LANGUAGE:...> may not be used with Visual Studio generators.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
@@ -0,0 +1,9 @@
CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\):
Error evaluating generator expression:

\$<COMPILE_LANGUAGE:CXX>

\$<COMPILE_LANGUAGE:...> may only be used with COMPILE_OPTIONS with the
Xcode generator.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
@@ -0,0 +1,5 @@

enable_language(CXX)

add_executable(main main.cpp)
target_compile_definitions(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-DANYTHING>)
7 changes: 7 additions & 0 deletions Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake
Expand Up @@ -4,3 +4,10 @@ if (RunCMake_GENERATOR MATCHES "Visual Studio")
set(RunCMake-stderr-file CompileOptions-stderr-VS.txt)
run_cmake(CompileOptions)
endif()
if (RunCMake_GENERATOR STREQUAL "Xcode")
set(RunCMake-stderr-file CompileDefinitions-stderr-Xcode.txt)
run_cmake(CompileDefinitions)
elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
set(RunCMake-stderr-file CompileDefinitions-stderr-VS.txt)
run_cmake(CompileDefinitions)
endif()

0 comments on commit 0b945ea

Please sign in to comment.