Merge topic 'target-language-genex'

232a6883 Help: Add release notes for target-language-genex.
9e168941 File(GENERATE): Process genex evaluation files for each language.
b734fa44 Genex: Allow COMPILE_LANGUAGE when processing include directories.
0b945ea9 Genex: Allow COMPILE_LANGUAGE when processing compile definitions.
5c559f11 Genex: Enable use of COMPILE_LANGUAGE for compile options.
e387ce7d Genex: Add a COMPILE_LANGUAGE generator expression.
4a0128f4 VS6: Compute CMAKE_*_FLAGS and COMPILE_DEFINITIONS* only when needed
This commit is contained in:
Brad King 2015-03-10 09:12:34 -04:00 committed by CMake Topic Stage
commit ad6fbb88bb
80 changed files with 759 additions and 180 deletions

View File

@ -93,6 +93,46 @@ Available logical expressions are:
for the 'head' target, an error is reported. See the
:manual:`cmake-compile-features(7)` manual for information on
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)
The ``Makefile`` and ``Ninja`` based generators can also use this
expression to specify compile-language specific compile definitions
and include directories:
.. code-block:: cmake
add_executable(myapp main.cpp foo.c bar.cpp)
target_compile_definitions(myapp
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX>
)
target_include_directories(myapp
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers>
)
Informational Expressions
=========================
@ -174,6 +214,10 @@ Available informational expressions are:
``$<INSTALL_PREFIX>``
Content of the install prefix when the target is exported via
: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
==================

View File

@ -0,0 +1,9 @@
target-language-genex
---------------------
* A new ``COMPILE_LANGUAGE`` generator expression was introduced to
allow specification of compile options for target files based on the
:prop_sf:`LANGUAGE` of each source file. Due to limitations of the
underlying native build tools, this feature has varying support across
generators. See the :manual:`cmake-generator-expressions(7)` manual
for details.

View File

@ -604,7 +604,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();

View File

@ -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_";

View File

@ -52,14 +52,16 @@ cmGeneratorExpression::~cmGeneratorExpression()
const char *cmCompiledGeneratorExpression::Evaluate(
cmMakefile* mf, const std::string& config, bool quiet,
cmTarget const* headTarget,
cmGeneratorExpressionDAGChecker *dagChecker) const
cmGeneratorExpressionDAGChecker *dagChecker,
std::string const& language) const
{
return this->Evaluate(mf,
config,
quiet,
headTarget,
headTarget,
dagChecker);
dagChecker,
language);
}
//----------------------------------------------------------------------------
@ -67,7 +69,8 @@ const char *cmCompiledGeneratorExpression::Evaluate(
cmMakefile* mf, const std::string& config, bool quiet,
cmTarget const* headTarget,
cmTarget const* currentTarget,
cmGeneratorExpressionDAGChecker *dagChecker) const
cmGeneratorExpressionDAGChecker *dagChecker,
std::string const& language) const
{
if (!this->NeedsEvaluation)
{
@ -93,6 +96,7 @@ const char *cmCompiledGeneratorExpression::Evaluate(
context.EvaluateForBuildsystem = this->EvaluateForBuildsystem;
context.CurrentTarget = currentTarget ? currentTarget : headTarget;
context.Backtrace = this->Backtrace;
context.Language = language;
for ( ; it != end; ++it)
{

View File

@ -80,11 +80,13 @@ public:
bool quiet = false,
cmTarget const* headTarget = 0,
cmTarget const* currentTarget = 0,
cmGeneratorExpressionDAGChecker *dagChecker = 0) const;
cmGeneratorExpressionDAGChecker *dagChecker = 0,
std::string const& language = std::string()) const;
const char* Evaluate(cmMakefile* mf, const std::string& config,
bool quiet,
cmTarget const* headTarget,
cmGeneratorExpressionDAGChecker *dagChecker) const;
cmGeneratorExpressionDAGChecker *dagChecker,
std::string const& language = std::string()) const;
/** Get set of targets found during evaluations. */
std::set<cmTarget*> const& GetTargets() const

View File

@ -38,13 +38,15 @@ cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
//----------------------------------------------------------------------------
void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
const std::string& lang,
cmCompiledGeneratorExpression* inputExpression,
std::map<std::string, std::string> &outputFiles, mode_t perm)
{
std::string rawCondition = this->Condition->GetInput();
if (!rawCondition.empty())
{
std::string condResult = this->Condition->Evaluate(this->Makefile, config);
std::string condResult = this->Condition->Evaluate(this->Makefile, config,
false, 0, 0, 0, lang);
if (condResult == "0")
{
return;
@ -60,9 +62,11 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
}
const std::string outputFileName
= this->OutputFileExpr->Evaluate(this->Makefile, config);
= this->OutputFileExpr->Evaluate(this->Makefile, config,
false, 0, 0, 0, lang);
const std::string outputContent
= inputExpression->Evaluate(this->Makefile, config);
= inputExpression->Evaluate(this->Makefile, config,
false, 0, 0, 0, lang);
std::map<std::string, std::string>::iterator it
= outputFiles.find(outputFileName);
@ -75,7 +79,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
}
std::ostringstream e;
e << "Evaluation file to be written multiple times for different "
"configurations with different content:\n " << outputFileName;
"configurations or languages with different content:\n "
<< outputFileName;
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
@ -97,14 +102,22 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
std::string const& config)
{
std::string name = this->OutputFileExpr->Evaluate(this->Makefile, config);
std::vector<std::string> enabledLanguages;
cmGlobalGenerator *gg
= this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
gg->GetEnabledLanguages(enabledLanguages);
for(std::vector<std::string>::const_iterator le = enabledLanguages.begin();
le != enabledLanguages.end(); ++le)
{
std::string name = this->OutputFileExpr->Evaluate(this->Makefile, config,
false, 0, 0, 0, *le);
cmSourceFile* sf = this->Makefile->GetOrCreateSource(name);
sf->SetProperty("GENERATED", "1");
cmGlobalGenerator *gg
= this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
gg->SetFilenameTargetDepends(sf,
this->OutputFileExpr->GetSourceSensitiveTargets());
}
}
//----------------------------------------------------------------------------
@ -153,13 +166,23 @@ void cmGeneratorExpressionEvaluationFile::Generate()
{
allConfigs.push_back("");
}
std::vector<std::string> enabledLanguages;
cmGlobalGenerator *gg
= this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
gg->GetEnabledLanguages(enabledLanguages);
for(std::vector<std::string>::const_iterator le = enabledLanguages.begin();
le != enabledLanguages.end(); ++le)
{
for(std::vector<std::string>::const_iterator li = allConfigs.begin();
li != allConfigs.end(); ++li)
{
this->Generate(*li, inputExpression.get(), outputFiles, perm);
this->Generate(*li, *le, inputExpression.get(), outputFiles, perm);
if(cmSystemTools::GetFatalErrorOccured())
{
return;
}
}
}
}

View File

@ -34,7 +34,7 @@ public:
void CreateOutputFile(std::string const& config);
private:
void Generate(const std::string& config,
void Generate(const std::string& config, const std::string& lang,
cmCompiledGeneratorExpression* inputExpression,
std::map<std::string, std::string> &outputFiles, mode_t perm);

View File

@ -16,6 +16,7 @@
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmGeneratorExpression.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
#include <cmsys/String.h>
@ -89,7 +90,8 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
context->Quiet,
headTarget,
currentTarget,
dagChecker);
dagChecker,
context->Language);
if (cge->GetHadContextSensitiveCondition())
{
context->HadContextSensitiveCondition = true;
@ -806,6 +808,77 @@ static const struct JoinNode : public cmGeneratorExpressionNode
}
} joinNode;
static const struct CompileLanguageNode : public cmGeneratorExpressionNode
{
CompileLanguageNode() {}
virtual int NumExpectedParameters() const { return OneOrZeroParameters; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if(context->Language.empty())
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> may only be used to specify include "
"directories compile definitions, compile options and to evaluate "
"components of the file(GENERATE) command.");
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("Xcode") != std::string::npos)
{
if (dagChecker && (dagChecker->EvaluatingCompileDefinitions()
|| dagChecker->EvaluatingIncludeDirectories()))
{
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)
{
reportError(context, content->GetOriginalExpression(),
"$<COMPILE_LANGUAGE:...> not supported for this generator.");
return std::string();
}
}
if (parameters.empty())
{
return context->Language;
}
return context->Language == parameters.front() ? "1" : "0";
}
} languageNode;
#define TRANSITIVE_PROPERTY_NAME(PROPERTY) \
, "INTERFACE_" #PROPERTY
@ -1829,6 +1902,7 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
nodeMap["INSTALL_PREFIX"] = &installPrefixNode;
nodeMap["JOIN"] = &joinNode;
nodeMap["LINK_ONLY"] = &linkOnlyNode;
nodeMap["COMPILE_LANGUAGE"] = &languageNode;
}
NodeMap::const_iterator i = nodeMap.find(identifier);
if (i == nodeMap.end())

View File

@ -36,6 +36,7 @@ struct cmGeneratorExpressionContext
MaxLanguageStandard;
cmMakefile *Makefile;
std::string Config;
std::string Language;
cmTarget const* HeadTarget; // The target whose property is being evaluated.
cmTarget const* CurrentTarget; // The dependent of HeadTarget which appears
// directly or indirectly in the property.

View File

@ -960,9 +960,10 @@ cmGeneratorTarget::GetCreateRuleVariable(std::string const& lang,
//----------------------------------------------------------------------------
std::vector<std::string>
cmGeneratorTarget::GetIncludeDirectories(const std::string& config) const
cmGeneratorTarget::GetIncludeDirectories(const std::string& config,
const std::string& lang) const
{
return this->Target->GetIncludeDirectories(config);
return this->Target->GetIncludeDirectories(config, lang);
}
//----------------------------------------------------------------------------

View File

@ -85,7 +85,7 @@ public:
/** Get the include directories for this target. */
std::vector<std::string> GetIncludeDirectories(
const std::string& config) const;
const std::string& config, const std::string& lang) const;
bool IsSystemIncludeDirectory(const std::string& dir,
const std::string& config) const;

View File

@ -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());

View File

@ -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);
}
@ -1453,7 +1453,7 @@ void cmLocalGenerator::AddCompileOptions(
{
cmSystemTools::ParseWindowsCommandLine(targetFlags, opts);
}
target->GetCompileOptions(opts, config);
target->GetCompileOptions(opts, config, lang);
for(std::vector<std::string>::const_iterator i = opts.begin();
i != opts.end(); ++i)
{
@ -1474,7 +1474,7 @@ void cmLocalGenerator::AddCompileOptions(
this->AppendFlags(flags, targetFlags);
}
std::vector<std::string> opts;
target->GetCompileOptions(opts, config);
target->GetCompileOptions(opts, config, lang);
for(std::vector<std::string>::const_iterator i = opts.begin();
i != opts.end(); ++i)
{
@ -1600,7 +1600,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
// Get the target-specific include directories.
std::vector<std::string> includes;
includes = target->GetIncludeDirectories(config);
includes = target->GetIncludeDirectories(config, lang);
// Support putting all the in-project include directories first if
// it is requested by the project.

View File

@ -239,7 +239,8 @@ public:
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);

View File

@ -2042,18 +2042,17 @@ void cmLocalUnixMakefileGenerator3
<< "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);
this->ConfigurationName, l->first);
if(!defines.empty())
{
cmakefileStream
<< "\n"
<< "# Preprocessor definitions for this target.\n"
<< "set(CMAKE_TARGET_DEFINITIONS\n";
<< "set(CMAKE_TARGET_DEFINITIONS_" << l->first << "\n";
for(std::set<std::string>::const_iterator di = defines.begin();
di != defines.end(); ++di)
{
@ -2064,6 +2063,33 @@ void cmLocalUnixMakefileGenerator3
<< " )\n";
}
// Target-specific include directories:
cmakefileStream
<< "\n"
<< "# The include file search paths:\n";
cmakefileStream
<< "set(CMAKE_" << l->first << "_TARGET_INCLUDE_PATH\n";
std::vector<std::string> includes;
cmGeneratorTarget* gt = this->GetGlobalGenerator()
->GetGeneratorTarget(&target);
const std::string& config =
this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
this->GetIncludeDirectories(includes, gt,
l->first, config);
for(std::vector<std::string>::iterator i = includes.begin();
i != includes.end(); ++i)
{
cmakefileStream
<< " \""
<< this->Convert(*i, cmLocalGenerator::HOME_OUTPUT)
<< "\"\n";
}
cmakefileStream
<< " )\n";
}
// Store include transform rule properties. Write the directory
// rules first because they may be overridden by later target rules.
std::vector<std::string> transformRules;

View File

@ -1701,15 +1701,15 @@ void cmLocalVisualStudio6Generator
= this->Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX");
cmSystemTools::ReplaceString(line, "DEBUG_POSTFIX",
debugPostfix?debugPostfix:"");
if(target.GetType() >= cmTarget::EXECUTABLE &&
target.GetType() <= cmTarget::OBJECT_LIBRARY)
{
// store flags for each configuration
std::string flags = " ";
std::string flagsRelease = " ";
std::string flagsMinSizeRel = " ";
std::string flagsDebug = " ";
std::string flagsRelWithDebInfo = " ";
if(target.GetType() >= cmTarget::EXECUTABLE &&
target.GetType() <= cmTarget::OBJECT_LIBRARY)
{
std::vector<std::string> configs;
target.GetMakefile()->GetConfigurations(configs);
std::vector<std::string>::const_iterator it = configs.begin();
@ -1760,7 +1760,6 @@ void cmLocalVisualStudio6Generator
"MinSizeRel");
this->AddCompileOptions(flagsRelWithDebInfo, &target, linkLanguage,
"RelWithDebInfo");
}
// if _UNICODE and _SBCS are not found, then add -D_MBCS
std::string defs = this->Makefile->GetDefineFlags();
@ -1779,11 +1778,15 @@ void cmLocalVisualStudio6Generator
std::set<std::string> minsizeDefinesSet;
std::set<std::string> debugrelDefinesSet;
this->AddCompileDefinitions(definesSet, &target, "");
this->AddCompileDefinitions(debugDefinesSet, &target, "DEBUG");
this->AddCompileDefinitions(releaseDefinesSet, &target, "RELEASE");
this->AddCompileDefinitions(minsizeDefinesSet, &target, "MINSIZEREL");
this->AddCompileDefinitions(debugrelDefinesSet, &target, "RELWITHDEBINFO");
this->AddCompileDefinitions(definesSet, &target, "", linkLanguage);
this->AddCompileDefinitions(debugDefinesSet, &target,
"DEBUG", linkLanguage);
this->AddCompileDefinitions(releaseDefinesSet, &target,
"RELEASE", linkLanguage);
this->AddCompileDefinitions(minsizeDefinesSet, &target,
"MINSIZEREL", linkLanguage);
this->AddCompileDefinitions(debugrelDefinesSet, &target,
"RELWITHDEBINFO", linkLanguage);
std::string defines = " ";
std::string debugDefines = " ";
@ -1805,8 +1808,8 @@ void cmLocalVisualStudio6Generator
// The template files have CXX FLAGS in them, that need to be replaced.
// There are not separate CXX and C template files, so we use the same
// variable names. The previous code sets up flags* variables to contain
// the correct C or CXX flags
// variable names. The previous code sets up flags* variables to
// contain the correct C or CXX flags
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL",
flagsMinSizeRel.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG",
@ -1825,7 +1828,9 @@ void cmLocalVisualStudio6Generator
debugrelDefines.c_str());
cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_RELEASE",
releaseDefines.c_str());
cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS", defines.c_str());
cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS",
defines.c_str());
}
fout << line.c_str() << std::endl;
}

View File

@ -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"));

View File

@ -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);
@ -1126,40 +1126,6 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
<< "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n";
}
// Target-specific include directories:
*this->InfoFileStream
<< "\n"
<< "# The include file search paths:\n";
*this->InfoFileStream
<< "set(CMAKE_C_TARGET_INCLUDE_PATH\n";
std::vector<std::string> includes;
const std::string& config =
this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
this->LocalGenerator->GetIncludeDirectories(includes,
this->GeneratorTarget,
"C", config);
for(std::vector<std::string>::iterator i = includes.begin();
i != includes.end(); ++i)
{
*this->InfoFileStream
<< " \""
<< this->LocalGenerator->Convert(*i,
cmLocalGenerator::HOME_OUTPUT)
<< "\"\n";
}
*this->InfoFileStream
<< " )\n";
*this->InfoFileStream
<< "set(CMAKE_CXX_TARGET_INCLUDE_PATH "
<< "${CMAKE_C_TARGET_INCLUDE_PATH})\n";
*this->InfoFileStream
<< "set(CMAKE_Fortran_TARGET_INCLUDE_PATH "
<< "${CMAKE_C_TARGET_INCLUDE_PATH})\n";
*this->InfoFileStream
<< "set(CMAKE_ASM_TARGET_INCLUDE_PATH "
<< "${CMAKE_C_TARGET_INCLUDE_PATH})\n";
// and now write the rule to use it
std::vector<std::string> depends;
std::vector<std::string> commands;

View File

@ -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"));

View File

@ -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, ";");
}

View File

@ -1979,7 +1979,8 @@ static void processIncludeDirectories(cmTarget const* tgt,
std::vector<std::string> &includes,
UNORDERED_SET<std::string> &uniqueIncludes,
cmGeneratorExpressionDAGChecker *dagChecker,
const std::string& config, bool debugIncludes)
const std::string& config, bool debugIncludes,
const std::string& language)
{
cmMakefile *mf = tgt->GetMakefile();
@ -1995,7 +1996,7 @@ static void processIncludeDirectories(cmTarget const* tgt,
config,
false,
tgt,
dagChecker),
dagChecker, language),
entryIncludes);
std::string usedIncludes;
@ -2106,7 +2107,8 @@ static void processIncludeDirectories(cmTarget const* tgt,
//----------------------------------------------------------------------------
std::vector<std::string>
cmTarget::GetIncludeDirectories(const std::string& config) const
cmTarget::GetIncludeDirectories(const std::string& config,
const std::string& language) const
{
std::vector<std::string> includes;
UNORDERED_SET<std::string> uniqueIncludes;
@ -2139,7 +2141,8 @@ cmTarget::GetIncludeDirectories(const std::string& config) const
uniqueIncludes,
&dagChecker,
config,
debugIncludes);
debugIncludes,
language);
std::vector<cmTargetInternals::TargetPropertyEntry*>
linkInterfaceIncludeDirectoriesEntries;
@ -2179,7 +2182,8 @@ cmTarget::GetIncludeDirectories(const std::string& config) const
uniqueIncludes,
&dagChecker,
config,
debugIncludes);
debugIncludes,
language);
deleteAndClear(linkInterfaceIncludeDirectoriesEntries);
@ -2192,7 +2196,8 @@ static void processCompileOptionsInternal(cmTarget const* tgt,
std::vector<std::string> &options,
UNORDERED_SET<std::string> &uniqueOptions,
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();
@ -2204,7 +2209,8 @@ static void processCompileOptionsInternal(cmTarget const* tgt,
config,
false,
tgt,
dagChecker),
dagChecker,
language),
entryOptions);
std::string usedOptions;
for(std::vector<std::string>::iterator
@ -2238,10 +2244,12 @@ static void processCompileOptions(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, "options");
dagChecker, config, debugOptions, "options",
language);
}
//----------------------------------------------------------------------------
@ -2271,7 +2279,8 @@ void cmTarget::GetAutoUicOptions(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;
@ -2303,7 +2312,8 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result,
uniqueOptions,
&dagChecker,
config,
debugOptions);
debugOptions,
language);
std::vector<cmTargetInternals::TargetPropertyEntry*>
linkInterfaceCompileOptionsEntries;
@ -2318,7 +2328,8 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result,
uniqueOptions,
&dagChecker,
config,
debugOptions);
debugOptions,
language);
deleteAndClear(linkInterfaceCompileOptionsEntries);
}
@ -2329,16 +2340,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");
"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;
@ -2370,7 +2383,8 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
uniqueOptions,
&dagChecker,
config,
debugDefines);
debugDefines,
language);
std::vector<cmTargetInternals::TargetPropertyEntry*>
linkInterfaceCompileDefinitionsEntries;
@ -2417,7 +2431,8 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
uniqueOptions,
&dagChecker,
config,
debugDefines);
debugDefines,
language);
deleteAndClear(linkInterfaceCompileDefinitionsEntries);
}
@ -2431,7 +2446,8 @@ static void processCompileFeatures(cmTarget const* tgt,
const std::string& config, bool debugOptions)
{
processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions, "features");
dagChecker, config, debugOptions, "features",
std::string());
}
//----------------------------------------------------------------------------

View File

@ -496,7 +496,8 @@ public:
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
@ -567,7 +568,8 @@ public:
bool contentOnly) const;
std::vector<std::string> GetIncludeDirectories(
const std::string& config) const;
const std::string& config,
const std::string& language) const;
void InsertInclude(const cmValueWithOrigin &entry,
bool before = false);
void InsertCompileOption(const cmValueWithOrigin &entry,
@ -577,7 +579,8 @@ public:
void AppendBuildInterfaceIncludes();
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,
const std::string& config) const;
void GetCompileFeatures(std::vector<std::string> &features,

View File

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

View File

@ -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)

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 @@
#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; }

View File

@ -23,6 +23,21 @@ add_executable(consumer
"${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
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
#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; }

View File

@ -42,6 +42,20 @@ add_executable(consumer
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
)
if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja")
target_sources(consumer PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
)
target_include_directories(consumer
PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only>
$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}/c_only>
)
target_compile_definitions(consumer
PRIVATE -DTEST_LANG_DEFINES
)
endif()
target_include_directories(consumer
PRIVATE
$<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>

View File

@ -0,0 +1,2 @@
#define C_ONLY_DEFINE

View File

@ -0,0 +1,10 @@
#ifdef TEST_LANG_DEFINES
#include "c_only.h"
#ifndef C_ONLY_DEFINE
#error Expected C_ONLY_DEFINE
#endif
#endif
int consumer_c() { return 0; }

View File

@ -4,6 +4,9 @@
#include "interfaceinclude.h"
#include "relative_dir.h"
#include "consumer.h"
#ifdef TEST_LANG_DEFINES
#include "cxx_only.h"
#endif
#ifdef PRIVATEINCLUDE_DEFINE
#error Unexpected PRIVATEINCLUDE_DEFINE
@ -29,4 +32,10 @@
#error Expected CONSUMER_DEFINE
#endif
#ifdef TEST_LANG_DEFINES
#ifndef CXX_ONLY_DEFINE
#error Expected CXX_ONLY_DEFINE
#endif
#endif
int main() { return 0; }

View File

@ -0,0 +1,2 @@
#define CXX_ONLY_DEFINE

View File

@ -208,3 +208,5 @@ add_RunCMake_test(IfacePaths_SOURCES TEST_DIR IfacePaths)
if(RPMBUILD_EXECUTABLE)
add_RunCMake_test(CPackRPM)
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,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\)

View File

@ -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\)

View File

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

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,8 @@
CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\):
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,9 @@
CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\):
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\)

View File

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

View File

@ -0,0 +1,20 @@
include(RunCMake)
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()
if (RunCMake_GENERATOR STREQUAL "Xcode")
set(RunCMake-stderr-file IncludeDirectories-stderr-Xcode.txt)
run_cmake(IncludeDirectories)
elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
set(RunCMake-stderr-file IncludeDirectories-stderr-VS.txt)
run_cmake(IncludeDirectories)
endif()

View File

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

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,12 @@
enable_language(CXX C)
add_library(empty empty.cpp empty.c)
target_compile_options(empty
PRIVATE LANG_IS_$<COMPILE_LANGUAGE>
)
file(GENERATE
OUTPUT opts-$<COMPILE_LANGUAGE>.txt
CONTENT "$<TARGET_PROPERTY:empty,COMPILE_OPTIONS>\n"
)

View File

@ -1,5 +1,5 @@
CMake Error in CMakeLists.txt:
Evaluation file to be written multiple times for different configurations
with different content:
or languages with different content:
.*output.txt

View File

@ -17,6 +17,16 @@ if (NOT file_contents MATCHES "generated.cpp.rule")
message(SEND_ERROR "Rule file not in target sources! ${file_contents}")
endif()
if (NOT RunCMake_GENERATOR MATCHES "Visual Studio")
run_cmake(COMPILE_LANGUAGE-genex)
foreach(l CXX C)
file(READ "${RunCMake_BINARY_DIR}/COMPILE_LANGUAGE-genex-build/opts-${l}.txt" l_defs)
if (NOT l_defs STREQUAL "LANG_IS_${l}\n")
message(FATAL_ERROR "File content does not match: ${l_defs}")
endif()
endforeach()
endif()
set(timeformat "%Y%j%H%M%S")
file(REMOVE "${RunCMake_BINARY_DIR}/WriteIfDifferent-build/output_file.txt")

View File

@ -0,0 +1,8 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty_c()
{
return 0;
}

View File

@ -0,0 +1,10 @@
CMake Error at COMPILE_LANGUAGE-add_custom_command.cmake:6 \(add_custom_command\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(C)
add_library(empty empty.c)
add_custom_command(TARGET empty PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_LANGUAGE>
)

View File

@ -0,0 +1,10 @@
CMake Error at COMPILE_LANGUAGE-add_custom_target.cmake:4 \(add_custom_target\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
enable_language(C)
add_custom_target(empty
COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_LANGUAGE>
)

View File

@ -0,0 +1,10 @@
CMake Error at COMPILE_LANGUAGE-add_executable.cmake:4 \(add_executable\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,4 @@
enable_language(C)
add_executable(empty empty.$<COMPILE_LANGUAGE>)

View File

@ -0,0 +1,10 @@
CMake Error at COMPILE_LANGUAGE-add_library.cmake:4 \(add_library\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,4 @@
enable_language(C)
add_library(empty empty.$<COMPILE_LANGUAGE>)

View File

@ -0,0 +1,10 @@
CMake Error at COMPILE_LANGUAGE-add_test.cmake:5 \(add_test\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,5 @@
include(CTest)
enable_testing()
add_test(NAME dummy COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_LANGUAGE>)

View File

@ -0,0 +1,8 @@
CMake Error:
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.

View File

@ -0,0 +1,5 @@
install(FILES
empty.$<COMPILE_LANGUAGE>
DESTINATION src
)

View File

@ -0,0 +1,10 @@
CMake Error at COMPILE_LANGUAGE-target_sources.cmake:5 \(target_sources\):
Error evaluating generator expression:
\$<COMPILE_LANGUAGE>
\$<COMPILE_LANGUAGE:...> may only be used to specify include directories
compile definitions, compile options and to evaluate components of the
file\(GENERATE\) command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,5 @@
enable_language(C)
add_library(empty empty.c)
target_sources(empty PRIVATE empty.$<COMPILE_LANGUAGE>)

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

@ -16,6 +16,14 @@ run_cmake(NonValidTarget-C_COMPILER_VERSION)
run_cmake(NonValidTarget-CXX_COMPILER_VERSION)
run_cmake(NonValidTarget-TARGET_PROPERTY)
run_cmake(NonValidTarget-TARGET_POLICY)
run_cmake(COMPILE_LANGUAGE-add_custom_target)
run_cmake(COMPILE_LANGUAGE-add_custom_command)
run_cmake(COMPILE_LANGUAGE-install)
run_cmake(COMPILE_LANGUAGE-target_sources)
run_cmake(COMPILE_LANGUAGE-add_executable)
run_cmake(COMPILE_LANGUAGE-add_library)
run_cmake(COMPILE_LANGUAGE-add_test)
run_cmake(COMPILE_LANGUAGE-unknown-lang)
if(LINKER_SUPPORTS_PDB)
run_cmake(NonValidTarget-TARGET_PDB_FILE)