summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2013-06-03 13:57:44 (GMT)
committerCMake Topic Stage <kwrobot@kitware.com>2013-06-03 13:57:44 (GMT)
commite57b6a25211ea28b7b01aadfc3aaf1de79455bdb (patch)
tree3957355de7d91f18e663fc1ed13185bf31f35125
parentbcc29c56a599baa3e2d8bd1d56e3727911a1c7d7 (diff)
parent24466f22c0c0e3235f0a21bd2a298c39df50e2f3 (diff)
downloadCMake-e57b6a25211ea28b7b01aadfc3aaf1de79455bdb.zip
CMake-e57b6a25211ea28b7b01aadfc3aaf1de79455bdb.tar.gz
CMake-e57b6a25211ea28b7b01aadfc3aaf1de79455bdb.tar.bz2
Merge topic 'target-COMPILE_OPTIONS'
24466f2 Add target_compile_options command. 80ca9c4 Add COMPILE_OPTIONS target property. 7cb2308 cmTarget: Rename LinkInterfaceIncludeDirectoriesEntries 47f80d9 cmTarget: Rename struct to be more re-usable. 1319a14 Add <LANG>_COMPILER_ID generator expressions. 3549676 Add cmLocalGenerator::GetCompileOptions. f3ad863 VS6: Rename some variables to correspond to config values.
-rw-r--r--Source/cmCommands.cxx2
-rw-r--r--Source/cmDocumentGeneratorExpressions.h8
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx8
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx8
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h1
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx111
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx6
-rw-r--r--Source/cmLocalGenerator.cxx20
-rw-r--r--Source/cmLocalGenerator.h3
-rw-r--r--Source/cmLocalVisualStudio6Generator.cxx41
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx4
-rw-r--r--Source/cmMakefileTargetGenerator.cxx32
-rw-r--r--Source/cmNinjaTargetGenerator.cxx10
-rw-r--r--Source/cmTarget.cxx292
-rw-r--r--Source/cmTarget.h6
-rw-r--r--Source/cmTargetCompileOptionsCommand.cxx62
-rw-r--r--Source/cmTargetCompileOptionsCommand.h90
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx6
-rw-r--r--Tests/CMakeCommands/target_compile_options/CMakeLists.txt35
-rw-r--r--Tests/CMakeCommands/target_compile_options/consumer.cpp18
-rw-r--r--Tests/CMakeCommands/target_compile_options/main.cpp18
-rw-r--r--Tests/CMakeLists.txt2
-rw-r--r--Tests/CompileOptions/CMakeLists.txt16
-rw-r--r--Tests/CompileOptions/main.cpp11
-rw-r--r--Tests/CompileOptions/other.cpp5
25 files changed, 752 insertions, 63 deletions
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 227b226..75f2ae8 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -29,6 +29,7 @@
#include "cmSourceGroupCommand.cxx"
#include "cmSubdirDependsCommand.cxx"
#include "cmTargetCompileDefinitionsCommand.cxx"
+#include "cmTargetCompileOptionsCommand.cxx"
#include "cmTargetIncludeDirectoriesCommand.cxx"
#include "cmTargetPropCommandBase.cxx"
#include "cmUseMangledMesaCommand.cxx"
@@ -71,6 +72,7 @@ void GetPredefinedCommands(std::list<cmCommand*>&
commands.push_back(new cmSubdirDependsCommand);
commands.push_back(new cmTargetIncludeDirectoriesCommand);
commands.push_back(new cmTargetCompileDefinitionsCommand);
+ commands.push_back(new cmTargetCompileOptionsCommand);
commands.push_back(new cmUseMangledMesaCommand);
commands.push_back(new cmUtilitySourceCommand);
commands.push_back(new cmVariableRequiresCommand);
diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h
index 656810d..a8b3847 100644
--- a/Source/cmDocumentGeneratorExpressions.h
+++ b/Source/cmDocumentGeneratorExpressions.h
@@ -40,6 +40,14 @@
"is exported using export(), or when the target is used by another " \
"target in the same buildsystem. Expands to the empty string " \
"otherwise.\n" \
+ " $<C_COMPILER_ID> = The CMake-id of the C compiler " \
+ "used.\n" \
+ " $<C_COMPILER_ID:comp> = '1' if the CMake-id of the C " \
+ "compiler matches comp, otherwise '0'.\n" \
+ " $<CXX_COMPILER_ID> = The CMake-id of the CXX compiler " \
+ "used.\n" \
+ " $<CXX_COMPILER_ID:comp> = '1' if the CMake-id of the CXX " \
+ "compiler matches comp, otherwise '0'.\n" \
" $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \
" $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \
" $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 62e9194..29d86a6 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -429,7 +429,9 @@ cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source,
lg->AppendFlags(flags, makefile->GetDefineFlags());
// Add target-specific flags.
- if(target->GetProperty("COMPILE_FLAGS"))
+ std::string targetFlags;
+ lg->GetCompileOptions(targetFlags, target, config);
+ if (!targetFlags.empty())
{
std::string langIncludeExpr = "CMAKE_";
langIncludeExpr += language;
@@ -440,7 +442,7 @@ cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source,
cmsys::RegularExpression r(regex);
std::vector<std::string> args;
cmSystemTools::
- ParseWindowsCommandLine(target->GetProperty("COMPILE_FLAGS"), args);
+ ParseWindowsCommandLine(targetFlags.c_str(), args);
for(std::vector<std::string>::iterator i = args.begin();
i != args.end(); ++i)
{
@@ -452,7 +454,7 @@ cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source,
}
else
{
- lg->AppendFlags(flags, target->GetProperty("COMPILE_FLAGS"));
+ lg->AppendFlags(flags, targetFlags.c_str());
}
}
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index 5cb50b9..e5ffb0c 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -168,3 +168,11 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const
|| strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0
|| strncmp(prop, "COMPILE_DEFINITIONS_", 20) == 0);
}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::EvaluatingCompileOptions() const
+{
+ const char *prop = this->Property.c_str();
+ return (strcmp(prop, "COMPILE_OPTIONS") == 0
+ || strcmp(prop, "INTERFACE_COMPILE_OPTIONS") == 0 );
+}
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 62a5cdf..8d9fd76 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -40,6 +40,7 @@ struct cmGeneratorExpressionDAGChecker
bool EvaluatingLinkLibraries();
bool EvaluatingIncludeDirectories() const;
bool EvaluatingCompileDefinitions() const;
+ bool EvaluatingCompileOptions() const;
private:
Result checkGraph() const;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index df52368..5e7d00d 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -247,6 +247,104 @@ static const struct SemicolonNode : public cmGeneratorExpressionNode
} semicolonNode;
//----------------------------------------------------------------------------
+struct CompilerIdNode : public cmGeneratorExpressionNode
+{
+ CompilerIdNode() {}
+
+ virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
+
+ std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *,
+ const std::string &lang) const
+ {
+ const char *compilerId = context->Makefile ?
+ context->Makefile->GetSafeDefinition((
+ "CMAKE_" + lang + "_COMPILER_ID").c_str()) : "";
+ if (parameters.size() == 0)
+ {
+ return compilerId ? compilerId : "";
+ }
+ else
+ {
+ cmsys::RegularExpression compilerIdValidator;
+ compilerIdValidator.compile("^[A-Za-z0-9_]*$");
+ if (!compilerIdValidator.find(parameters.begin()->c_str()))
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+ if (!compilerId)
+ {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0)
+ {
+ return "1";
+ }
+ return "0";
+ }
+ }
+};
+
+//----------------------------------------------------------------------------
+static const struct CCompilerIdNode : public CompilerIdNode
+{
+ CCompilerIdNode() {}
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagChecker) const
+ {
+ if (parameters.size() != 0 && parameters.size() != 1)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<C_COMPILER_ID> expression requires one or two parameters");
+ return std::string();
+ }
+ if (!context->HeadTarget)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<C_COMPILER_ID> may only be used with targets. It may not "
+ "be used with add_custom_command.");
+ }
+ return this->EvaluateWithLanguage(parameters, context, content,
+ dagChecker, "C");
+ }
+} cCompilerIdNode;
+
+//----------------------------------------------------------------------------
+static const struct CXXCompilerIdNode : public CompilerIdNode
+{
+ CXXCompilerIdNode() {}
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagChecker) const
+ {
+ if (parameters.size() != 0 && parameters.size() != 1)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<CXX_COMPILER_ID> expression requires one or two parameters");
+ return std::string();
+ }
+ if (!context->HeadTarget)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<CXX_COMPILER_ID> may only be used with targets. It may not "
+ "be used with add_custom_command.");
+ }
+ return this->EvaluateWithLanguage(parameters, context, content,
+ dagChecker, "CXX");
+ }
+} cxxCompilerIdNode;
+
+//----------------------------------------------------------------------------
static const struct ConfigurationNode : public cmGeneratorExpressionNode
{
ConfigurationNode() {}
@@ -397,6 +495,7 @@ static const struct JoinNode : public cmGeneratorExpressionNode
static const char* targetPropertyTransitiveWhitelist[] = {
"INTERFACE_INCLUDE_DIRECTORIES"
, "INTERFACE_COMPILE_DEFINITIONS"
+ , "INTERFACE_COMPILE_OPTIONS"
};
std::string getLinkedTargetsContent(const std::vector<std::string> &libraries,
@@ -604,7 +703,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
else
{
assert(dagCheckerParent->EvaluatingIncludeDirectories()
- || dagCheckerParent->EvaluatingCompileDefinitions());
+ || dagCheckerParent->EvaluatingCompileDefinitions()
+ || dagCheckerParent->EvaluatingCompileOptions());
}
}
@@ -623,6 +723,11 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{
interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
}
+ else if (propertyName == "INTERFACE_COMPILE_OPTIONS"
+ || propertyName == "COMPILE_OPTIONS")
+ {
+ interfacePropertyName = "INTERFACE_COMPILE_OPTIONS";
+ }
const char **transBegin = targetPropertyTransitiveWhitelist;
const char **transEnd = targetPropertyTransitiveWhitelist
@@ -1055,6 +1160,10 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &orNode;
else if (identifier == "NOT")
return &notNode;
+ else if (identifier == "C_COMPILER_ID")
+ return &cCompilerIdNode;
+ else if (identifier == "CXX_COMPILER_ID")
+ return &cxxCompilerIdNode;
else if (identifier == "CONFIGURATION")
return &configurationNode;
else if (identifier == "CONFIG")
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d782a06..2d76c82 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -681,9 +681,11 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
{
// Add flags from target and source file properties.
std::string flags;
- if(cmtarget.GetProperty("COMPILE_FLAGS"))
+ std::string targetFlags;
+ lg->GetCompileOptions(targetFlags, &cmtarget, 0); // TODO: Config?
+ if(!targetFlags.empty())
{
- lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS"));
+ lg->AppendFlags(flags, targetFlags.c_str());
}
const char* srcfmt = sf->GetProperty("Fortran_FORMAT");
switch(this->CurrentLocalGenerator->GetFortranFormat(srcfmt))
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index d346f16..57e25a1 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1325,6 +1325,26 @@ std::string cmLocalGenerator::GetIncludeFlags(
}
//----------------------------------------------------------------------------
+void cmLocalGenerator::GetCompileOptions(std::string& flags,
+ cmTarget* target,
+ const char *config)
+{
+ // Add target-specific flags.
+ if(const char *prop = target->GetProperty("COMPILE_FLAGS"))
+ {
+ this->AppendFlags(flags, prop);
+ }
+
+ std::vector<std::string> opts; // TODO: Emitted.
+ target->GetCompileOptions(opts, config);
+ for(std::vector<std::string>::const_iterator li = opts.begin();
+ li != opts.end(); ++li)
+ {
+ this->AppendFlags(flags, li->c_str());
+ }
+}
+
+//----------------------------------------------------------------------------
void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
cmGeneratorTarget* target,
const char* lang,
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index a1c34f0..28c88e6 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -215,6 +215,9 @@ public:
cmGeneratorTarget* target,
const char* lang = "C", const char *config = 0,
bool stripImplicitInclDirs = true);
+ void GetCompileOptions(std::string& flags,
+ cmTarget* target,
+ const char *config);
/** Compute the language used to compile the given source file. */
const char* GetSourceFileLanguage(const cmSourceFile& source);
diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx
index dc94476..4c78f7f 100644
--- a/Source/cmLocalVisualStudio6Generator.cxx
+++ b/Source/cmLocalVisualStudio6Generator.cxx
@@ -1639,9 +1639,9 @@ void cmLocalVisualStudio6Generator
// store flags for each configuration
std::string flags = " ";
std::string flagsRelease = " ";
- std::string flagsMinSize = " ";
+ std::string flagsMinSizeRel = " ";
std::string flagsDebug = " ";
- std::string flagsDebugRel = " ";
+ std::string flagsRelWithDebInfo = " ";
if(target.GetType() >= cmTarget::EXECUTABLE &&
target.GetType() <= cmTarget::OBJECT_LIBRARY)
{
@@ -1664,16 +1664,16 @@ void cmLocalVisualStudio6Generator
flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" ";
flagVar = baseFlagVar + "_MINSIZEREL";
- flagsMinSize = this->Makefile->GetSafeDefinition(flagVar.c_str());
- flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" ";
+ flagsMinSizeRel = this->Makefile->GetSafeDefinition(flagVar.c_str());
+ flagsMinSizeRel += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" ";
flagVar = baseFlagVar + "_DEBUG";
flagsDebug = this->Makefile->GetSafeDefinition(flagVar.c_str());
flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" ";
flagVar = baseFlagVar + "_RELWITHDEBINFO";
- flagsDebugRel = this->Makefile->GetSafeDefinition(flagVar.c_str());
- flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" ";
+ flagsRelWithDebInfo = this->Makefile->GetSafeDefinition(flagVar.c_str());
+ flagsRelWithDebInfo += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" ";
}
// if _UNICODE and _SBCS are not found, then add -D_MBCS
@@ -1686,12 +1686,31 @@ void cmLocalVisualStudio6Generator
flags += " /D \"_MBCS\"";
}
+ {
+ std::string targetFlags;
+ this->GetCompileOptions(targetFlags, &target, 0);
// Add per-target flags.
- if(const char* targetFlags = target.GetProperty("COMPILE_FLAGS"))
+ if(!targetFlags.empty())
{
flags += " ";
flags += targetFlags;
}
+ }
+#define ADD_FLAGS(CONFIG) \
+ { \
+ std::string targetFlags; \
+ this->GetCompileOptions(targetFlags, &target, #CONFIG); \
+ if(!targetFlags.empty()) \
+ { \
+ flags ## CONFIG += " "; \
+ flags ## CONFIG += targetFlags; \
+ } \
+ }
+
+ ADD_FLAGS(Debug)
+ ADD_FLAGS(Release)
+ ADD_FLAGS(MinSizeRel)
+ ADD_FLAGS(RelWithDebInfo)
// Add per-target and per-configuration preprocessor definitions.
std::set<std::string> definesSet;
@@ -1731,19 +1750,19 @@ void cmLocalVisualStudio6Generator
flags += defines;
flagsDebug += debugDefines;
flagsRelease += releaseDefines;
- flagsMinSize += minsizeDefines;
- flagsDebugRel += debugrelDefines;
+ flagsMinSizeRel += minsizeDefines;
+ flagsRelWithDebInfo += debugrelDefines;
// 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
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL",
- flagsMinSize.c_str());
+ flagsMinSizeRel.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG",
flagsDebug.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELWITHDEBINFO",
- flagsDebugRel.c_str());
+ flagsRelWithDebInfo.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELEASE",
flagsRelease.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS", flags.c_str());
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 58d28da..e7badf0 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -723,8 +723,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
}
}
+ std::string targetFlags;
+ this->GetCompileOptions(targetFlags, &target, configName);
// Add the target-specific flags.
- if(const char* targetFlags = target.GetProperty("COMPILE_FLAGS"))
+ if(!targetFlags.empty())
{
flags += " ";
flags += targetFlags;
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 6fc88d6..699a7fd 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -332,21 +332,25 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
this->Makefile->GetSafeDefinition(compiler.c_str()) << "\n";
}
+ std::string targetFlags;
for(std::set<cmStdString>::const_iterator l = languages.begin();
l != languages.end(); ++l)
{
*this->FlagFileStream << *l << "_FLAGS = " << this->GetFlags(*l) << "\n\n";
*this->FlagFileStream << *l << "_DEFINES = " << this->GetDefines(*l) <<
"\n\n";
+ std::string targetLangFlags;
+ this->LocalGenerator->GetCompileOptions(targetLangFlags, this->Target,
+ this->LocalGenerator->ConfigurationName.c_str());
+ if (!targetFlags.empty() && targetFlags != targetLangFlags)
+ {
+ targetFlags += " " + targetLangFlags;
+ }
}
- // Add target-specific flags.
- if(this->Target->GetProperty("COMPILE_FLAGS"))
+ if (!targetFlags.empty())
{
- std::string flags;
- this->LocalGenerator->AppendFlags
- (flags, this->Target->GetProperty("COMPILE_FLAGS"));
- *this->FlagFileStream << "# TARGET_FLAGS = " << flags << "\n\n";
+ *this->FlagFileStream << "# TARGET_FLAGS = " << targetFlags << "\n\n";
}
}
@@ -532,8 +536,13 @@ cmMakefileTargetGenerator
langFlags += "_FLAGS)";
this->LocalGenerator->AppendFlags(flags, langFlags.c_str());
- // Add target-specific flags.
- if(this->Target->GetProperty("COMPILE_FLAGS"))
+ std::string configUpper =
+ cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName);
+
+ std::string targetFlags;
+ this->LocalGenerator->GetCompileOptions(targetFlags, this->Target,
+ configUpper.c_str());
+ if (!targetFlags.empty())
{
std::string langIncludeExpr = "CMAKE_";
langIncludeExpr += lang;
@@ -545,7 +554,7 @@ cmMakefileTargetGenerator
cmsys::RegularExpression r(regex);
std::vector<std::string> args;
cmSystemTools::ParseWindowsCommandLine(
- this->Target->GetProperty("COMPILE_FLAGS"),
+ targetFlags.c_str(),
args);
for(std::vector<std::string>::iterator i = args.begin();
i != args.end(); ++i)
@@ -559,8 +568,7 @@ cmMakefileTargetGenerator
}
else
{
- this->LocalGenerator->AppendFlags
- (flags, this->Target->GetProperty("COMPILE_FLAGS"));
+ this->LocalGenerator->AppendFlags(flags, targetFlags.c_str());
}
}
@@ -594,8 +602,6 @@ cmMakefileTargetGenerator
<< compile_defs << "\n"
<< "\n";
}
- std::string configUpper =
- cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName);
std::string defPropName = "COMPILE_DEFINITIONS_";
defPropName += configUpper;
if(const char* config_compile_defs =
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 532ee67..6f912b8 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -151,9 +151,9 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source,
this->GetConfigName());
// Add include directory flags.
+ const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
{
std::vector<std::string> includes;
- const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
this->LocalGenerator->GetIncludeDirectories(includes,
this->GeneratorTarget,
language.c_str(), config);
@@ -171,7 +171,9 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source,
this->LocalGenerator->AppendFlags(flags, this->Makefile->GetDefineFlags());
// Add target-specific flags.
- if(this->Target->GetProperty("COMPILE_FLAGS"))
+ std::string targetFlags;
+ this->LocalGenerator->GetCompileOptions(targetFlags, this->Target, config);
+ if(!targetFlags.empty())
{
std::string langIncludeExpr = "CMAKE_";
langIncludeExpr += language;
@@ -183,7 +185,7 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source,
cmsys::RegularExpression r(regex);
std::vector<std::string> args;
cmSystemTools::ParseWindowsCommandLine(
- this->Target->GetProperty("COMPILE_FLAGS"),
+ targetFlags.c_str(),
args);
for(std::vector<std::string>::iterator i = args.begin();
i != args.end(); ++i)
@@ -198,7 +200,7 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source,
else
{
this->LocalGenerator->AppendFlags
- (flags, this->Target->GetProperty("COMPILE_FLAGS"));
+ (flags, targetFlags.c_str());
}
}
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 5628971..f1d0ac3 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -130,31 +130,35 @@ public:
typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType;
SourceEntriesType SourceEntries;
- struct IncludeDirectoriesEntry {
- IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
+ struct TargetPropertyEntry {
+ TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
const std::string &targetName = std::string())
: ge(cge), TargetName(targetName)
{}
const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
- std::vector<std::string> CachedIncludes;
+ std::vector<std::string> CachedEntries;
const std::string TargetName;
};
- std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
- std::vector<cmValueWithOrigin> LinkInterfaceIncludeDirectoriesEntries;
+ std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
+ std::vector<TargetPropertyEntry*> CompileOptionsEntries;
+ std::vector<cmValueWithOrigin> LinkInterfacePropertyEntries;
- std::map<std::string, std::vector<IncludeDirectoriesEntry*> >
+ std::map<std::string, std::vector<TargetPropertyEntry*> >
CachedLinkInterfaceIncludeDirectoriesEntries;
+ std::map<std::string, std::vector<TargetPropertyEntry*> >
+ CachedLinkInterfaceCompileOptionsEntries;
std::map<std::string, std::string> CachedLinkInterfaceCompileDefinitions;
std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone;
std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone;
+ std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone;
};
//----------------------------------------------------------------------------
void deleteAndClear(
- std::vector<cmTargetInternals::IncludeDirectoriesEntry*> &entries)
+ std::vector<cmTargetInternals::TargetPropertyEntry*> &entries)
{
- for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator
+ for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
it = entries.begin(),
end = entries.end();
it != end; ++it)
@@ -167,10 +171,10 @@ void deleteAndClear(
//----------------------------------------------------------------------------
void deleteAndClear(
std::map<std::string,
- std::vector<cmTargetInternals::IncludeDirectoriesEntry*> > &entries)
+ std::vector<cmTargetInternals::TargetPropertyEntry*> > &entries)
{
for (std::map<std::string,
- std::vector<cmTargetInternals::IncludeDirectoriesEntry*> >::iterator
+ std::vector<cmTargetInternals::TargetPropertyEntry*> >::iterator
it = entries.begin(), end = entries.end(); it != end; ++it)
{
deleteAndClear(it->second);
@@ -181,6 +185,7 @@ void deleteAndClear(
cmTargetInternals::~cmTargetInternals()
{
deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries);
+ deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries);
}
//----------------------------------------------------------------------------
@@ -199,6 +204,7 @@ cmTarget::cmTarget()
this->IsImportedTarget = false;
this->BuildInterfaceIncludesAppended = false;
this->DebugIncludesDone = false;
+ this->DebugCompileOptionsDone = false;
}
//----------------------------------------------------------------------------
@@ -287,6 +293,32 @@ void cmTarget::DefineProperties(cmake *cm)
"This is the configuration-specific version of COMPILE_DEFINITIONS.");
cm->DefineProperty
+ ("COMPILE_OPTIONS", cmProperty::TARGET,
+ "List of options to pass to the compiler.",
+ "This property specifies the list of options specified "
+ "so far for this property. "
+ "This property exists on targets only. "
+ "\n"
+ "The target property values are used by the generators to set "
+ "the options for the compiler.\n"
+ "Contents of COMPILE_OPTIONS may use \"generator expressions\" with "
+ "the syntax \"$<...>\". "
+ CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
+ CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
+
+ cm->DefineProperty
+ ("INTERFACE_COMPILE_OPTIONS", cmProperty::TARGET,
+ "List of interface options to pass to the compiler.",
+ "Targets may populate this property to publish the compile options "
+ "required to compile against the headers for the target. Consuming "
+ "targets can add entries to their own COMPILE_OPTIONS property such "
+ "as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_OPTIONS> to use the "
+ "compile options specified in the interface of 'foo'."
+ "\n"
+ CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
+ CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
+
+ cm->DefineProperty
("DEFINE_SYMBOL", cmProperty::TARGET,
"Define a symbol when compiling this target's sources.",
"DEFINE_SYMBOL sets the name of the preprocessor symbol defined when "
@@ -2751,7 +2783,18 @@ void cmTarget::SetProperty(const char* prop, const char* value)
deleteAndClear(this->Internal->IncludeDirectoriesEntries);
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
this->Internal->IncludeDirectoriesEntries.push_back(
- new cmTargetInternals::IncludeDirectoriesEntry(cge));
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ return;
+ }
+ if(strcmp(prop,"COMPILE_OPTIONS") == 0)
+ {
+ cmListFileBacktrace lfbt;
+ this->Makefile->GetBacktrace(lfbt);
+ cmGeneratorExpression ge(lfbt);
+ deleteAndClear(this->Internal->CompileOptionsEntries);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+ this->Internal->CompileOptionsEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
return;
}
if(strcmp(prop,"EXPORT_NAME") == 0 && this->IsImported())
@@ -2764,14 +2807,14 @@ void cmTarget::SetProperty(const char* prop, const char* value)
}
if (strcmp(prop, "LINK_LIBRARIES") == 0)
{
- this->Internal->LinkInterfaceIncludeDirectoriesEntries.clear();
+ this->Internal->LinkInterfacePropertyEntries.clear();
if (cmGeneratorExpression::IsValidTargetName(value)
|| cmGeneratorExpression::Find(value) != std::string::npos)
{
cmListFileBacktrace lfbt;
this->Makefile->GetBacktrace(lfbt);
cmValueWithOrigin entry(value, lfbt);
- this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry);
+ this->Internal->LinkInterfacePropertyEntries.push_back(entry);
}
// Fall through
}
@@ -2793,7 +2836,16 @@ void cmTarget::AppendProperty(const char* prop, const char* value,
this->Makefile->GetBacktrace(lfbt);
cmGeneratorExpression ge(lfbt);
this->Internal->IncludeDirectoriesEntries.push_back(
- new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(value)));
+ new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+ return;
+ }
+ if(strcmp(prop,"COMPILE_OPTIONS") == 0)
+ {
+ cmListFileBacktrace lfbt;
+ this->Makefile->GetBacktrace(lfbt);
+ cmGeneratorExpression ge(lfbt);
+ this->Internal->CompileOptionsEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
return;
}
if(strcmp(prop,"EXPORT_NAME") == 0 && this->IsImported())
@@ -2812,7 +2864,7 @@ void cmTarget::AppendProperty(const char* prop, const char* value,
cmListFileBacktrace lfbt;
this->Makefile->GetBacktrace(lfbt);
cmValueWithOrigin entry(value, lfbt);
- this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry);
+ this->Internal->LinkInterfacePropertyEntries.push_back(entry);
}
// Fall through
}
@@ -2877,17 +2929,31 @@ void cmTarget::InsertInclude(const cmValueWithOrigin &entry,
{
cmGeneratorExpression ge(entry.Backtrace);
- std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::iterator position
+ std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position
= before ? this->Internal->IncludeDirectoriesEntries.begin()
: this->Internal->IncludeDirectoriesEntries.end();
this->Internal->IncludeDirectoriesEntries.insert(position,
- new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(entry.Value)));
+ new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry.Value)));
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::InsertCompileOption(const cmValueWithOrigin &entry,
+ bool before)
+{
+ cmGeneratorExpression ge(entry.Backtrace);
+
+ std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position
+ = before ? this->Internal->CompileOptionsEntries.begin()
+ : this->Internal->CompileOptionsEntries.end();
+
+ this->Internal->CompileOptionsEntries.insert(position,
+ new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry.Value)));
}
//----------------------------------------------------------------------------
static void processIncludeDirectories(cmTarget *tgt,
- const std::vector<cmTargetInternals::IncludeDirectoriesEntry*> &entries,
+ const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries,
std::vector<std::string> &includes,
std::set<std::string> &uniqueIncludes,
cmGeneratorExpressionDAGChecker *dagChecker,
@@ -2895,12 +2961,12 @@ static void processIncludeDirectories(cmTarget *tgt,
{
cmMakefile *mf = tgt->GetMakefile();
- for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator
+ for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
it = entries.begin(), end = entries.end(); it != end; ++it)
{
bool testIsOff = true;
bool cacheIncludes = false;
- std::vector<std::string> entryIncludes = (*it)->CachedIncludes;
+ std::vector<std::string> entryIncludes = (*it)->CachedEntries;
if(!entryIncludes.empty())
{
testIsOff = false;
@@ -3003,7 +3069,7 @@ static void processIncludeDirectories(cmTarget *tgt,
}
if (cacheIncludes)
{
- (*it)->CachedIncludes = entryIncludes;
+ (*it)->CachedEntries = entryIncludes;
}
if (!usedIncludes.empty())
{
@@ -3059,8 +3125,8 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
if (!this->Internal->CacheLinkInterfaceIncludeDirectoriesDone[configString])
{
for (std::vector<cmValueWithOrigin>::const_iterator
- it = this->Internal->LinkInterfaceIncludeDirectoriesEntries.begin(),
- end = this->Internal->LinkInterfaceIncludeDirectoriesEntries.end();
+ it = this->Internal->LinkInterfacePropertyEntries.begin(),
+ end = this->Internal->LinkInterfacePropertyEntries.end();
it != end; ++it)
{
{
@@ -3089,7 +3155,7 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
this->Internal
->CachedLinkInterfaceIncludeDirectoriesEntries[configString].push_back(
- new cmTargetInternals::IncludeDirectoriesEntry(cge,
+ new cmTargetInternals::TargetPropertyEntry(cge,
it->Value));
}
}
@@ -3117,6 +3183,159 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
}
//----------------------------------------------------------------------------
+static void processCompileOptions(cmTarget *tgt,
+ const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries,
+ std::vector<std::string> &options,
+ std::set<std::string> &uniqueOptions,
+ cmGeneratorExpressionDAGChecker *dagChecker,
+ const char *config, bool debugOptions)
+{
+ cmMakefile *mf = tgt->GetMakefile();
+
+ for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
+ it = entries.begin(), end = entries.end(); it != end; ++it)
+ {
+ bool cacheOptions = false;
+ std::vector<std::string> entryOptions = (*it)->CachedEntries;
+ if(entryOptions.empty())
+ {
+ cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(mf,
+ config,
+ false,
+ tgt,
+ dagChecker),
+ entryOptions);
+ if (mf->IsGeneratingBuildSystem()
+ && !(*it)->ge->GetHadContextSensitiveCondition())
+ {
+ cacheOptions = true;
+ }
+ }
+ std::string usedOptions;
+ for(std::vector<std::string>::iterator
+ li = entryOptions.begin(); li != entryOptions.end(); ++li)
+ {
+ std::string opt = *li;
+
+ if(uniqueOptions.insert(opt).second)
+ {
+ options.push_back(opt);
+ if (debugOptions)
+ {
+ usedOptions += " * " + opt + "\n";
+ }
+ }
+ }
+ if (cacheOptions)
+ {
+ (*it)->CachedEntries = entryOptions;
+ }
+ if (!usedOptions.empty())
+ {
+ mf->GetCMakeInstance()->IssueMessage(cmake::LOG,
+ std::string("Used compile options for target ")
+ + tgt->GetName() + ":\n"
+ + usedOptions, (*it)->ge->GetBacktrace());
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetCompileOptions(std::vector<std::string> &result,
+ const char *config)
+{
+ std::set<std::string> uniqueOptions;
+ cmListFileBacktrace lfbt;
+
+ cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+ this->GetName(),
+ "COMPILE_OPTIONS", 0, 0);
+
+ std::vector<std::string> debugProperties;
+ const char *debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp)
+ {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugOptions = !this->DebugCompileOptionsDone
+ && std::find(debugProperties.begin(),
+ debugProperties.end(),
+ "COMPILE_OPTIONS")
+ != debugProperties.end();
+
+ if (this->Makefile->IsGeneratingBuildSystem())
+ {
+ this->DebugCompileOptionsDone = true;
+ }
+
+ processCompileOptions(this,
+ this->Internal->CompileOptionsEntries,
+ result,
+ uniqueOptions,
+ &dagChecker,
+ config,
+ debugOptions);
+
+ std::string configString = config ? config : "";
+ if (!this->Internal->CacheLinkInterfaceCompileOptionsDone[configString])
+ {
+ for (std::vector<cmValueWithOrigin>::const_iterator
+ it = this->Internal->LinkInterfacePropertyEntries.begin(),
+ end = this->Internal->LinkInterfacePropertyEntries.end();
+ it != end; ++it)
+ {
+ {
+ cmGeneratorExpression ge(lfbt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(it->Value);
+ std::string targetResult = cge->Evaluate(this->Makefile, config,
+ false, this, 0, 0);
+ if (!this->Makefile->FindTargetToUse(targetResult.c_str()))
+ {
+ continue;
+ }
+ }
+ std::string optionGenex = "$<TARGET_PROPERTY:" +
+ it->Value + ",INTERFACE_COMPILE_OPTIONS>";
+ if (cmGeneratorExpression::Find(it->Value) != std::string::npos)
+ {
+ // Because it->Value is a generator expression, ensure that it
+ // evaluates to the non-empty string before being used in the
+ // TARGET_PROPERTY expression.
+ optionGenex = "$<$<BOOL:" + it->Value + ">:" + optionGenex + ">";
+ }
+ cmGeneratorExpression ge(it->Backtrace);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(
+ optionGenex);
+
+ this->Internal
+ ->CachedLinkInterfaceCompileOptionsEntries[configString].push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge,
+ it->Value));
+ }
+ }
+
+ processCompileOptions(this,
+ this->Internal->CachedLinkInterfaceCompileOptionsEntries[configString],
+ result,
+ uniqueOptions,
+ &dagChecker,
+ config,
+ debugOptions);
+
+ if (!this->Makefile->IsGeneratingBuildSystem())
+ {
+ deleteAndClear(this->Internal->CachedLinkInterfaceCompileOptionsEntries);
+ }
+ else
+ {
+ this->Internal->CacheLinkInterfaceCompileOptionsDone[configString] = true;
+ }
+}
+
+//----------------------------------------------------------------------------
std::string cmTarget::GetCompileDefinitions(const char *config)
{
const char *configProp = 0;
@@ -3541,9 +3760,9 @@ const char *cmTarget::GetProperty(const char* prop,
static std::string output;
output = "";
std::string sep;
- typedef cmTargetInternals::IncludeDirectoriesEntry
- IncludeDirectoriesEntry;
- for (std::vector<IncludeDirectoriesEntry*>::const_iterator
+ typedef cmTargetInternals::TargetPropertyEntry
+ TargetPropertyEntry;
+ for (std::vector<TargetPropertyEntry*>::const_iterator
it = this->Internal->IncludeDirectoriesEntries.begin(),
end = this->Internal->IncludeDirectoriesEntries.end();
it != end; ++it)
@@ -3554,6 +3773,24 @@ const char *cmTarget::GetProperty(const char* prop,
}
return output.c_str();
}
+ if(strcmp(prop,"COMPILE_OPTIONS") == 0)
+ {
+ static std::string output;
+ output = "";
+ std::string sep;
+ typedef cmTargetInternals::TargetPropertyEntry
+ TargetPropertyEntry;
+ for (std::vector<TargetPropertyEntry*>::const_iterator
+ it = this->Internal->CompileOptionsEntries.begin(),
+ end = this->Internal->CompileOptionsEntries.end();
+ it != end; ++it)
+ {
+ output += sep;
+ output += (*it)->ge->GetInput();
+ sep = ";";
+ }
+ return output.c_str();
+ }
if (strcmp(prop,"IMPORTED") == 0)
{
@@ -6263,6 +6500,7 @@ cmTargetInternalPointer
cmTargetInternalPointer::~cmTargetInternalPointer()
{
deleteAndClear(this->Pointer->IncludeDirectoriesEntries);
+ deleteAndClear(this->Pointer->CompileOptionsEntries);
delete this->Pointer;
}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 0bcc2a8..3bc0ab2 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -511,9 +511,14 @@ public:
std::vector<std::string> GetIncludeDirectories(const char *config);
void InsertInclude(const cmValueWithOrigin &entry,
bool before = false);
+ void InsertCompileOption(const cmValueWithOrigin &entry,
+ bool before = false);
void AppendBuildInterfaceIncludes();
+ void GetCompileOptions(std::vector<std::string> &result,
+ const char *config);
+
bool IsNullImpliedByLinkLibraries(const std::string &p);
bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
const char *config);
@@ -643,6 +648,7 @@ private:
bool IsApple;
bool IsImportedTarget;
bool DebugIncludesDone;
+ bool DebugCompileOptionsDone;
mutable std::set<std::string> LinkImplicitNullProperties;
bool BuildInterfaceIncludesAppended;
diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx
new file mode 100644
index 0000000..e80c845
--- /dev/null
+++ b/Source/cmTargetCompileOptionsCommand.cxx
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetCompileOptionsCommand.h"
+
+bool cmTargetCompileOptionsCommand
+::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+{
+ return this->HandleArguments(args, "COMPILE_OPTIONS", PROCESS_BEFORE);
+}
+
+void cmTargetCompileOptionsCommand
+::HandleImportedTarget(const std::string &tgt)
+{
+ cmOStringStream e;
+ e << "Cannot specify compile options for imported target \""
+ << tgt << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetCompileOptionsCommand
+::HandleMissingTarget(const std::string &name)
+{
+ cmOStringStream e;
+ e << "Cannot specify compile options for target \"" << name << "\" "
+ "which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+//----------------------------------------------------------------------------
+std::string cmTargetCompileOptionsCommand
+::Join(const std::vector<std::string> &content)
+{
+ std::string defs;
+ std::string sep;
+ for(std::vector<std::string>::const_iterator it = content.begin();
+ it != content.end(); ++it)
+ {
+ defs += sep + *it;
+ sep = ";";
+ }
+ return defs;
+}
+
+//----------------------------------------------------------------------------
+void cmTargetCompileOptionsCommand
+::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
+ bool)
+{
+ cmListFileBacktrace lfbt;
+ this->Makefile->GetBacktrace(lfbt);
+ cmValueWithOrigin entry(this->Join(content), lfbt);
+ tgt->InsertCompileOption(entry);
+}
diff --git a/Source/cmTargetCompileOptionsCommand.h b/Source/cmTargetCompileOptionsCommand.h
new file mode 100644
index 0000000..87fa1a7
--- /dev/null
+++ b/Source/cmTargetCompileOptionsCommand.h
@@ -0,0 +1,90 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmTargetCompileOptionsCommand_h
+#define cmTargetCompileOptionsCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetCompileOptionsCommand : public cmTargetPropCommandBase
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ virtual cmCommand* Clone()
+ {
+ return new cmTargetCompileOptionsCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus &status);
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual const char* GetName() const { return "target_compile_options";}
+
+ /**
+ * Succinct documentation.
+ */
+ virtual const char* GetTerseDocumentation() const
+ {
+ return
+ "Add compile options to a target.";
+ }
+
+ /**
+ * More documentation.
+ */
+ virtual const char* GetFullDocumentation() const
+ {
+ return
+ " target_compile_options(<target> [BEFORE] "
+ "<INTERFACE|PUBLIC|PRIVATE> [items1...]\n"
+ " [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])\n"
+ "Specify compile options to use when compiling a given target. "
+ "The named <target> must have been created by a command such as "
+ "add_executable or add_library and must not be an IMPORTED target. "
+ "If BEFORE is specified, the content will be prepended to the property "
+ "instead of being appended.\n"
+ "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify "
+ "the scope of the following arguments. PRIVATE and PUBLIC items will "
+ "populate the COMPILE_OPTIONS property of <target>. PUBLIC and "
+ "INTERFACE items will populate the INTERFACE_COMPILE_OPTIONS "
+ "property of <target>. "
+ "The following arguments specify compile opitions. "
+ "Repeated calls for the same <target> append items in the order called."
+ "\n"
+ "Arguments to target_compile_options may use \"generator "
+ "expressions\" with the syntax \"$<...>\". "
+ CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
+ ;
+ }
+
+ cmTypeMacro(cmTargetCompileOptionsCommand, cmTargetPropCommandBase);
+
+private:
+ virtual void HandleImportedTarget(const std::string &tgt);
+ virtual void HandleMissingTarget(const std::string &name);
+
+ virtual void HandleDirectContent(cmTarget *tgt,
+ const std::vector<std::string> &content,
+ bool prepend);
+ virtual std::string Join(const std::vector<std::string> &content);
+};
+
+#endif
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index d0ab976..f8de3a8 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1270,8 +1270,12 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
flags += " /TP ";
}
}
+
+ std::string targetFlags;
+ this->LocalGenerator->GetCompileOptions(targetFlags, this->Target,
+ configName.c_str());
// Add the target-specific flags.
- if(const char* targetFlags = this->Target->GetProperty("COMPILE_FLAGS"))
+ if(!targetFlags.empty())
{
flags += " ";
flags += targetFlags;
diff --git a/Tests/CMakeCommands/target_compile_options/CMakeLists.txt b/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
new file mode 100644
index 0000000..06a48fb
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
@@ -0,0 +1,35 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+project(target_compile_options)
+
+add_executable(target_compile_options
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+)
+target_compile_options(target_compile_options
+ PRIVATE $<$<CXX_COMPILER_ID:GNU>:-DMY_PRIVATE_DEFINE>
+ PUBLIC $<$<CXX_COMPILER_ID:GNU>:-DMY_PUBLIC_DEFINE>
+ INTERFACE $<$<CXX_COMPILER_ID:GNU>:-DMY_INTERFACE_DEFINE>
+)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(target_compile_options
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
+
+add_executable(consumer
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
+)
+
+target_compile_options(consumer
+ PRIVATE $<$<CXX_COMPILER_ID:GNU>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
+)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(consumer
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
diff --git a/Tests/CMakeCommands/target_compile_options/consumer.cpp b/Tests/CMakeCommands/target_compile_options/consumer.cpp
new file mode 100644
index 0000000..1299606
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/consumer.cpp
@@ -0,0 +1,18 @@
+
+#ifdef DO_GNU_TESTS
+
+# ifdef MY_PRIVATE_DEFINE
+# error Unexpected MY_PRIVATE_DEFINE
+# endif
+
+# ifndef MY_PUBLIC_DEFINE
+# error Expected MY_PUBLIC_DEFINE
+# endif
+
+# ifndef MY_INTERFACE_DEFINE
+# error Expected MY_INTERFACE_DEFINE
+# endif
+
+#endif
+
+int main() { return 0; }
diff --git a/Tests/CMakeCommands/target_compile_options/main.cpp b/Tests/CMakeCommands/target_compile_options/main.cpp
new file mode 100644
index 0000000..961c06d
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/main.cpp
@@ -0,0 +1,18 @@
+
+#ifdef DO_GNU_TESTS
+
+# ifndef MY_PRIVATE_DEFINE
+# error Expected MY_PRIVATE_DEFINE
+# endif
+
+# ifndef MY_PUBLIC_DEFINE
+# error Expected MY_PUBLIC_DEFINE
+# endif
+
+# ifdef MY_INTERFACE_DEFINE
+# error Unexpected MY_INTERFACE_DEFINE
+# endif
+
+#endif
+
+int main() { return 0; }
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index cd562c2..ee6c3e6 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -245,6 +245,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(PolicyScope PolicyScope)
ADD_TEST_MACRO(EmptyLibrary EmptyLibrary)
ADD_TEST_MACRO(CompileDefinitions CompileDefinitions)
+ ADD_TEST_MACRO(CompileOptions CompileOptions)
ADD_TEST_MACRO(CompatibleInterface CompatibleInterface)
set_tests_properties(EmptyLibrary PROPERTIES
PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target:test")
@@ -1990,6 +1991,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
ADD_TEST_MACRO(CMakeCommands.target_link_libraries target_link_libraries)
ADD_TEST_MACRO(CMakeCommands.target_include_directories target_include_directories)
ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions)
+ ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options)
configure_file(
"${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
diff --git a/Tests/CompileOptions/CMakeLists.txt b/Tests/CompileOptions/CMakeLists.txt
new file mode 100644
index 0000000..6d8a96a
--- /dev/null
+++ b/Tests/CompileOptions/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(CompileOptions)
+
+add_library(testlib other.cpp)
+
+add_executable(CompileOptions main.cpp)
+set_property(TARGET CompileOptions PROPERTY COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:GNU>:-DTEST_DEFINE>")
+target_link_libraries(CompileOptions testlib)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(CompileOptions
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
diff --git a/Tests/CompileOptions/main.cpp b/Tests/CompileOptions/main.cpp
new file mode 100644
index 0000000..0d39050
--- /dev/null
+++ b/Tests/CompileOptions/main.cpp
@@ -0,0 +1,11 @@
+
+#ifdef DO_GNU_TESTS
+# ifndef TEST_DEFINE
+# error Expected TEST_DEFINE
+# endif
+#endif
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
diff --git a/Tests/CompileOptions/other.cpp b/Tests/CompileOptions/other.cpp
new file mode 100644
index 0000000..0e34375
--- /dev/null
+++ b/Tests/CompileOptions/other.cpp
@@ -0,0 +1,5 @@
+
+void foo(void)
+{
+
+}