mirror of
https://github.com/reactos/CMake.git
synced 2024-11-25 04:29:52 +00:00
Add COMPILE_OPTIONS target property.
This method reads generator expressions from the COMPILE_OPTIONS target property, as well as INTERFACE_COMPILE_OPTIONS from linked dependents.
This commit is contained in:
parent
7cb23084b2
commit
80ca9c4b41
@ -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 );
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ struct cmGeneratorExpressionDAGChecker
|
||||
bool EvaluatingLinkLibraries();
|
||||
bool EvaluatingIncludeDirectories() const;
|
||||
bool EvaluatingCompileDefinitions() const;
|
||||
bool EvaluatingCompileOptions() const;
|
||||
|
||||
private:
|
||||
Result checkGraph() const;
|
||||
|
@ -495,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,
|
||||
@ -702,7 +703,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
|
||||
else
|
||||
{
|
||||
assert(dagCheckerParent->EvaluatingIncludeDirectories()
|
||||
|| dagCheckerParent->EvaluatingCompileDefinitions());
|
||||
|| dagCheckerParent->EvaluatingCompileDefinitions()
|
||||
|| dagCheckerParent->EvaluatingCompileOptions());
|
||||
}
|
||||
}
|
||||
|
||||
@ -721,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
|
||||
|
@ -1334,6 +1334,14 @@ void cmLocalGenerator::GetCompileOptions(std::string& 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());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -140,14 +140,18 @@ public:
|
||||
const std::string TargetName;
|
||||
};
|
||||
std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
|
||||
std::vector<TargetPropertyEntry*> CompileOptionsEntries;
|
||||
std::vector<cmValueWithOrigin> LinkInterfacePropertyEntries;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -286,6 +292,32 @@ void cmTarget::DefineProperties(cmake *cm)
|
||||
"Per-configuration preprocessor definitions on a target.",
|
||||
"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.",
|
||||
@ -2731,6 +2763,17 @@ void cmTarget::SetProperty(const char* prop, const char* value)
|
||||
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())
|
||||
{
|
||||
cmOStringStream e;
|
||||
@ -2773,6 +2816,15 @@ void cmTarget::AppendProperty(const char* prop, const char* 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())
|
||||
{
|
||||
cmOStringStream e;
|
||||
@ -3093,6 +3145,159 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
|
||||
return includes;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
@ -3525,6 +3730,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)
|
||||
{
|
||||
@ -6109,6 +6332,7 @@ cmTargetInternalPointer
|
||||
cmTargetInternalPointer::~cmTargetInternalPointer()
|
||||
{
|
||||
deleteAndClear(this->Pointer->IncludeDirectoriesEntries);
|
||||
deleteAndClear(this->Pointer->CompileOptionsEntries);
|
||||
delete this->Pointer;
|
||||
}
|
||||
|
||||
|
@ -503,6 +503,9 @@ public:
|
||||
|
||||
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);
|
||||
@ -627,6 +630,7 @@ private:
|
||||
bool IsApple;
|
||||
bool IsImportedTarget;
|
||||
bool DebugIncludesDone;
|
||||
bool DebugCompileOptionsDone;
|
||||
mutable std::set<std::string> LinkImplicitNullProperties;
|
||||
bool BuildInterfaceIncludesAppended;
|
||||
|
||||
|
@ -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")
|
||||
|
16
Tests/CompileOptions/CMakeLists.txt
Normal file
16
Tests/CompileOptions/CMakeLists.txt
Normal file
@ -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()
|
11
Tests/CompileOptions/main.cpp
Normal file
11
Tests/CompileOptions/main.cpp
Normal file
@ -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;
|
||||
}
|
5
Tests/CompileOptions/other.cpp
Normal file
5
Tests/CompileOptions/other.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user