Genex: Enable use of COMPILE_LANGUAGE for compile options.

Follow-ups will allow the use of the generator expression
for compile definitions and include directories for non-IDE
generators.
This commit is contained in:
Stephen Kelly 2014-11-25 22:47:44 +01:00
parent e387ce7d68
commit 5c559f1113
19 changed files with 185 additions and 12 deletions

View File

@ -93,6 +93,32 @@ Available logical expressions are:
for the 'head' target, an error is reported. See the for the 'head' target, an error is reported. See the
:manual:`cmake-compile-features(7)` manual for information on :manual:`cmake-compile-features(7)` manual for information on
compile features. compile features.
``$<COMPILE_LANGUAGE:lang>``
``1`` when the language used for compilation unit matches ``lang``,
otherwise ``0``. This expression used to specify compile options for
source files of a particular language in a target. For example, to specify
the use of the ``-fno-exceptions`` compile option (compiler id checks
elided):
.. code-block:: cmake
add_executable(myapp main.cpp foo.c bar.cpp)
target_compile_options(myapp
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
)
This generator expression has limited use because it is not possible to
use it with the Visual Studio generators. Portable buildsystems would
not use this expression, and would create separate libraries for each
source file language instead:
.. code-block:: cmake
add_library(myapp_c foo.c)
add_library(myapp_cxx foo.c)
target_compile_options(myapp_cxx PUBLIC -fno-exceptions)
add_executable(myapp main.cpp)
target_link_libraries(myapp myapp_c myapp_cxx)
Informational Expressions Informational Expressions
========================= =========================
@ -174,6 +200,10 @@ Available informational expressions are:
``$<INSTALL_PREFIX>`` ``$<INSTALL_PREFIX>``
Content of the install prefix when the target is exported via Content of the install prefix when the target is exported via
:command:`install(EXPORT)` and empty otherwise. :command:`install(EXPORT)` and empty otherwise.
``$<COMPILE_LANGUAGE>``
The compile language of source files when evaluating compile options. See
the unary version for notes about portability of this generator
expression.
Output Expressions Output Expressions
================== ==================

View File

@ -827,6 +827,40 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
"components of the file(GENERATE) command."); "components of the file(GENERATE) command.");
return std::string(); return std::string();
} }
std::vector<std::string> enabledLanguages;
cmGlobalGenerator* gg
= context->Makefile->GetLocalGenerator()->GetGlobalGenerator();
gg->GetEnabledLanguages(enabledLanguages);
if (!parameters.empty() &&
std::find(enabledLanguages.begin(), enabledLanguages.end(),
parameters.front()) == enabledLanguages.end())
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> Unknown language.");
return std::string();
}
std::string genName = gg->GetName();
if (genName.find("Visual Studio") != std::string::npos)
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> may not be used with Visual Studio "
"generators.");
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)
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> not supported for this generator.");
return std::string();
}
}
if (parameters.empty()) if (parameters.empty())
{ {
return context->Language; return context->Language;

View File

@ -1453,7 +1453,7 @@ void cmLocalGenerator::AddCompileOptions(
{ {
cmSystemTools::ParseWindowsCommandLine(targetFlags, opts); cmSystemTools::ParseWindowsCommandLine(targetFlags, opts);
} }
target->GetCompileOptions(opts, config); target->GetCompileOptions(opts, config, lang);
for(std::vector<std::string>::const_iterator i = opts.begin(); for(std::vector<std::string>::const_iterator i = opts.begin();
i != opts.end(); ++i) i != opts.end(); ++i)
{ {
@ -1474,7 +1474,7 @@ void cmLocalGenerator::AddCompileOptions(
this->AppendFlags(flags, targetFlags); this->AppendFlags(flags, targetFlags);
} }
std::vector<std::string> opts; std::vector<std::string> opts;
target->GetCompileOptions(opts, config); target->GetCompileOptions(opts, config, lang);
for(std::vector<std::string>::const_iterator i = opts.begin(); for(std::vector<std::string>::const_iterator i = opts.begin();
i != opts.end(); ++i) i != opts.end(); ++i)
{ {

View File

@ -2192,7 +2192,8 @@ static void processCompileOptionsInternal(cmTarget const* tgt,
std::vector<std::string> &options, std::vector<std::string> &options,
UNORDERED_SET<std::string> &uniqueOptions, UNORDERED_SET<std::string> &uniqueOptions,
cmGeneratorExpressionDAGChecker *dagChecker, cmGeneratorExpressionDAGChecker *dagChecker,
const std::string& config, bool debugOptions, const char *logName) const std::string& config, bool debugOptions, const char *logName,
std::string const& language)
{ {
cmMakefile *mf = tgt->GetMakefile(); cmMakefile *mf = tgt->GetMakefile();
@ -2204,7 +2205,8 @@ static void processCompileOptionsInternal(cmTarget const* tgt,
config, config,
false, false,
tgt, tgt,
dagChecker), dagChecker,
language),
entryOptions); entryOptions);
std::string usedOptions; std::string usedOptions;
for(std::vector<std::string>::iterator for(std::vector<std::string>::iterator
@ -2238,10 +2240,12 @@ static void processCompileOptions(cmTarget const* tgt,
std::vector<std::string> &options, std::vector<std::string> &options,
UNORDERED_SET<std::string> &uniqueOptions, UNORDERED_SET<std::string> &uniqueOptions,
cmGeneratorExpressionDAGChecker *dagChecker, cmGeneratorExpressionDAGChecker *dagChecker,
const std::string& config, bool debugOptions) const std::string& config, bool debugOptions,
std::string const& language)
{ {
processCompileOptionsInternal(tgt, entries, options, uniqueOptions, processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions, "options"); dagChecker, config, debugOptions, "options",
language);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -2271,7 +2275,8 @@ void cmTarget::GetAutoUicOptions(std::vector<std::string> &result,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::GetCompileOptions(std::vector<std::string> &result, void cmTarget::GetCompileOptions(std::vector<std::string> &result,
const std::string& config) const const std::string& config,
const std::string& language) const
{ {
UNORDERED_SET<std::string> uniqueOptions; UNORDERED_SET<std::string> uniqueOptions;
@ -2303,7 +2308,8 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result,
uniqueOptions, uniqueOptions,
&dagChecker, &dagChecker,
config, config,
debugOptions); debugOptions,
language);
std::vector<cmTargetInternals::TargetPropertyEntry*> std::vector<cmTargetInternals::TargetPropertyEntry*>
linkInterfaceCompileOptionsEntries; linkInterfaceCompileOptionsEntries;
@ -2318,7 +2324,8 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result,
uniqueOptions, uniqueOptions,
&dagChecker, &dagChecker,
config, config,
debugOptions); debugOptions,
language);
deleteAndClear(linkInterfaceCompileOptionsEntries); deleteAndClear(linkInterfaceCompileOptionsEntries);
} }
@ -2333,7 +2340,7 @@ static void processCompileDefinitions(cmTarget const* tgt,
{ {
processCompileOptionsInternal(tgt, entries, options, uniqueOptions, processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions, dagChecker, config, debugOptions,
"definitions"); "definitions", std::string());
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -2431,7 +2438,8 @@ static void processCompileFeatures(cmTarget const* tgt,
const std::string& config, bool debugOptions) const std::string& config, bool debugOptions)
{ {
processCompileOptionsInternal(tgt, entries, options, uniqueOptions, processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions, "features"); dagChecker, config, debugOptions, "features",
std::string());
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -577,7 +577,8 @@ public:
void AppendBuildInterfaceIncludes(); void AppendBuildInterfaceIncludes();
void GetCompileOptions(std::vector<std::string> &result, void GetCompileOptions(std::vector<std::string> &result,
const std::string& config) const; const std::string& config,
const std::string& language) const;
void GetAutoUicOptions(std::vector<std::string> &result, void GetAutoUicOptions(std::vector<std::string> &result,
const std::string& config) const; const std::string& config) const;
void GetCompileFeatures(std::vector<std::string> &features, void GetCompileFeatures(std::vector<std::string> &features,

View File

@ -23,6 +23,21 @@ add_executable(consumer
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
) )
if (NOT CMAKE_GENERATOR MATCHES "Visual Studio")
target_sources(consumer PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
)
target_compile_options(consumer
PRIVATE
-DCONSUMER_LANG_$<COMPILE_LANGUAGE>
-DLANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
-DLANG_IS_C=$<COMPILE_LANGUAGE:C>
)
target_compile_definitions(consumer
PRIVATE -DTEST_LANG_DEFINES
)
endif()
target_compile_options(consumer target_compile_options(consumer
PRIVATE $<$<CXX_COMPILER_ID:GNU>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>> PRIVATE $<$<CXX_COMPILER_ID:GNU>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
) )

View File

@ -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()
{
}

View File

@ -15,4 +15,22 @@
#endif #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; } int main() { return 0; }

View File

@ -208,3 +208,5 @@ add_RunCMake_test(IfacePaths_SOURCES TEST_DIR IfacePaths)
if(RPMBUILD_EXECUTABLE) if(RPMBUILD_EXECUTABLE)
add_RunCMake_test(CPackRPM) add_RunCMake_test(CPackRPM)
endif() endif()
add_RunCMake_test(COMPILE_LANGUAGE-genex)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.1)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,8 @@
CMake Error at CompileOptions.cmake:5 \(target_compile_options\):
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\)

View File

@ -0,0 +1,5 @@
enable_language(CXX)
add_executable(main main.cpp)
target_compile_options(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-DANYTHING>)

View File

@ -0,0 +1,6 @@
include(RunCMake)
if (RunCMake_GENERATOR MATCHES "Visual Studio")
set(RunCMake-stderr-file CompileOptions-stderr-VS.txt)
run_cmake(CompileOptions)
endif()

View File

@ -0,0 +1,5 @@
int main()
{
return 0;
}

View File

@ -0,0 +1,8 @@
CMake Error at COMPILE_LANGUAGE-unknown-lang.cmake:4 \(target_compile_options\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE:CXX>
\$<COMPILE_LANGUAGE:...> Unknown language.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,4 @@
enable_language(C)
add_executable(empty empty.c)
target_compile_options(empty PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wall>)

View File

@ -23,6 +23,7 @@ run_cmake(COMPILE_LANGUAGE-target_sources)
run_cmake(COMPILE_LANGUAGE-add_executable) run_cmake(COMPILE_LANGUAGE-add_executable)
run_cmake(COMPILE_LANGUAGE-add_library) run_cmake(COMPILE_LANGUAGE-add_library)
run_cmake(COMPILE_LANGUAGE-add_test) run_cmake(COMPILE_LANGUAGE-add_test)
run_cmake(COMPILE_LANGUAGE-unknown-lang)
if(LINKER_SUPPORTS_PDB) if(LINKER_SUPPORTS_PDB)
run_cmake(NonValidTarget-TARGET_PDB_FILE) run_cmake(NonValidTarget-TARGET_PDB_FILE)