Merge topic 'INTERFACE_POSITION_INDEPENDENT_CODE'

3581b96 Process the INTERFACE_PIC property from linked dependencies
042ecf0 Add API to calculate link-interface-dependent bool properties or error.
bf5ece5 Keep track of properties used to determine linker libraries.
This commit is contained in:
Brad King 2013-01-10 10:22:52 -05:00 committed by CMake Topic Stage
commit 378899ce87
24 changed files with 303 additions and 10 deletions

View File

@ -94,7 +94,15 @@ const char *cmCompiledGeneratorExpression::Evaluate(
for ( ; it != end; ++it) for ( ; it != end; ++it)
{ {
this->Output += (*it)->Evaluate(&context, dagChecker); const std::string result = (*it)->Evaluate(&context, dagChecker);
this->Output += result;
for(std::set<cmStdString>::const_iterator
p = context.SeenTargetProperties.begin();
p != context.SeenTargetProperties.end(); ++p)
{
this->SeenTargetProperties[*p] += result + ";";
}
if (context.HadError) if (context.HadError)
{ {
this->Output = ""; this->Output = "";

View File

@ -83,6 +83,9 @@ public:
std::set<cmTarget*> const& GetTargets() const std::set<cmTarget*> const& GetTargets() const
{ return this->Targets; } { return this->Targets; }
std::map<cmStdString, cmStdString> const& GetSeenTargetProperties() const
{ return this->SeenTargetProperties; }
~cmCompiledGeneratorExpression(); ~cmCompiledGeneratorExpression();
std::string GetInput() const std::string GetInput() const
@ -110,6 +113,7 @@ private:
bool NeedsParsing; bool NeedsParsing;
mutable std::set<cmTarget*> Targets; mutable std::set<cmTarget*> Targets;
mutable std::map<cmStdString, cmStdString> SeenTargetProperties;
mutable std::string Output; mutable std::string Output;
}; };

View File

@ -380,6 +380,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
} }
} }
if (target == context->HeadTarget)
{
// Keep track of the properties seen while processing.
// The evaluation of the LINK_LIBRARIES generator expressions
// will check this to ensure that properties form a DAG.
context->SeenTargetProperties.insert(propertyName);
}
if (propertyName.empty()) if (propertyName.empty())
{ {
reportError(context, content->GetOriginalExpression(), reportError(context, content->GetOriginalExpression(),

View File

@ -24,6 +24,7 @@ struct cmGeneratorExpressionContext
{ {
cmListFileBacktrace Backtrace; cmListFileBacktrace Backtrace;
std::set<cmTarget*> Targets; std::set<cmTarget*> Targets;
std::set<cmStdString> SeenTargetProperties;
cmMakefile *Makefile; cmMakefile *Makefile;
const char *Config; const char *Config;
cmTarget *HeadTarget; // The target whose property is being evaluated. cmTarget *HeadTarget; // The target whose property is being evaluated.

View File

@ -1639,14 +1639,16 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
if(strcmp(lang, "CXX") == 0) if(strcmp(lang, "CXX") == 0)
{ {
this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName); this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
this->CurrentLocalGenerator->AddCMP0018Flags(cflags, &target, "C"); this->CurrentLocalGenerator->AddCMP0018Flags(cflags, &target,
"C", configName);
} }
// Add language-specific flags. // Add language-specific flags.
this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName); this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
// Add shared-library flags if needed. // Add shared-library flags if needed.
this->CurrentLocalGenerator->AddCMP0018Flags(flags, &target, lang); this->CurrentLocalGenerator->AddCMP0018Flags(flags, &target,
lang, configName);
} }
else if(binary) else if(binary)
{ {

View File

@ -1984,7 +1984,8 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target, void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target,
std::string const& lang) std::string const& lang,
const char *config)
{ {
int targetType = target->GetType(); int targetType = target->GetType();
@ -1997,11 +1998,21 @@ void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target,
} }
else else
{ {
// Add position independendent flags, if needed. if (target->GetType() == cmTarget::OBJECT_LIBRARY)
{
if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE"))
{ {
this->AddPositionIndependentFlags(flags, lang, targetType); this->AddPositionIndependentFlags(flags, lang, targetType);
} }
return;
}
if (target->GetLinkInterfaceDependentBoolProperty(
"POSITION_INDEPENDENT_CODE",
config))
{
this->AddPositionIndependentFlags(flags, lang, targetType);
}
if (shared) if (shared)
{ {
this->AppendFeatureOptions(flags, lang.c_str(), "DLL"); this->AppendFeatureOptions(flags, lang.c_str(), "DLL");

View File

@ -142,7 +142,7 @@ public:
void AddLanguageFlags(std::string& flags, const char* lang, void AddLanguageFlags(std::string& flags, const char* lang,
const char* config); const char* config);
void AddCMP0018Flags(std::string &flags, cmTarget* target, void AddCMP0018Flags(std::string &flags, cmTarget* target,
std::string const& lang); std::string const& lang, const char *config);
void AddConfigVariableFlags(std::string& flags, const char* var, void AddConfigVariableFlags(std::string& flags, const char* var,
const char* config); const char* config);
///! Append flags to a string. ///! Append flags to a string.

View File

@ -268,7 +268,8 @@ std::string cmMakefileTargetGenerator::GetFlags(const std::string &l)
this->AddFortranFlags(flags); this->AddFortranFlags(flags);
} }
this->LocalGenerator->AddCMP0018Flags(flags, this->Target, lang); this->LocalGenerator->AddCMP0018Flags(flags, this->Target,
lang, this->ConfigName);
// Add include directory flags. // Add include directory flags.
this->AddIncludeFlags(flags, lang); this->AddIncludeFlags(flags, lang);

View File

@ -147,7 +147,8 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source,
// Add shared-library flags if needed. // Add shared-library flags if needed.
this->LocalGenerator->AddCMP0018Flags(flags, this->Target, this->LocalGenerator->AddCMP0018Flags(flags, this->Target,
language.c_str()); language.c_str(),
this->GetConfigName());
// Add include directory flags. // Add include directory flags.
{ {

View File

@ -877,6 +877,20 @@ void cmTarget::DefineProperties(cmake *cm)
"CMAKE_POSITION_INDEPENDENT_CODE if it is set when a target is " "CMAKE_POSITION_INDEPENDENT_CODE if it is set when a target is "
"created."); "created.");
cm->DefineProperty
("INTERFACE_POSITION_INDEPENDENT_CODE", cmProperty::TARGET,
"Whether consumers need to create a position-independent target",
"The INTERFACE_POSITION_INDEPENDENT_CODE property informs consumers of "
"this target whether they must set their POSITION_INDEPENDENT_CODE "
"property to ON. If this property is set to ON, then the "
"POSITION_INDEPENDENT_CODE property on all consumers will be set to "
"ON. Similarly, if this property is set to OFF, then the "
"POSITION_INDEPENDENT_CODE property on all consumers will be set to "
"OFF. If this property is undefined, then consumers will determine "
"their POSITION_INDEPENDENT_CODE property by other means. Consumers "
"must ensure that the targets that they link to have a consistent "
"requirement for their INTERFACE_POSITION_INDEPENDENT_CODE property.");
cm->DefineProperty cm->DefineProperty
("POST_INSTALL_SCRIPT", cmProperty::TARGET, ("POST_INSTALL_SCRIPT", cmProperty::TARGET,
"Deprecated install support.", "Deprecated install support.",
@ -2164,16 +2178,19 @@ void cmTarget::GetDirectLinkLibraries(const char *config,
{ {
cmListFileBacktrace lfbt; cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt); cmGeneratorExpression ge(lfbt);
const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
cmGeneratorExpressionDAGChecker dagChecker(lfbt, cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(), this->GetName(),
"LINK_LIBRARIES", 0, 0); "LINK_LIBRARIES", 0, 0);
cmSystemTools::ExpandListArgument(ge.Parse(prop)->Evaluate(this->Makefile, cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile,
config, config,
false, false,
head, head,
&dagChecker), &dagChecker),
libs); libs);
this->AddLinkDependentTargetsForProperties(cge->GetSeenTargetProperties());
} }
} }
@ -4376,6 +4393,171 @@ const char* cmTarget::GetExportMacro()
} }
} }
//----------------------------------------------------------------------------
void cmTarget::GetLinkDependentTargetsForProperty(const std::string &p,
std::set<std::string> &targets)
{
const std::map<cmStdString, std::set<std::string> >::const_iterator findIt
= this->LinkDependentProperties.find(p);
if (findIt != this->LinkDependentProperties.end())
{
targets = findIt->second;
}
}
//----------------------------------------------------------------------------
bool cmTarget::IsNullImpliedByLinkLibraries(const std::string &p)
{
return this->LinkImplicitNullProperties.find(p)
!= this->LinkImplicitNullProperties.end();
}
//----------------------------------------------------------------------------
void cmTarget::AddLinkDependentTargetsForProperties(
const std::map<cmStdString, cmStdString> &map)
{
for (std::map<cmStdString, cmStdString>::const_iterator it = map.begin();
it != map.end(); ++it)
{
std::vector<std::string> targets;
cmSystemTools::ExpandListArgument(it->second.c_str(), targets);
this->LinkDependentProperties[it->first].insert(targets.begin(),
targets.end());
if (!this->GetProperty(it->first.c_str()))
{
this->LinkImplicitNullProperties.insert(it->first);
}
}
}
//----------------------------------------------------------------------------
bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
const char *config)
{
bool propContent = this->GetPropertyAsBool(p.c_str());
const bool explicitlySet = this->GetProperties()
.find(p.c_str())
!= this->GetProperties().end();
std::set<std::string> dependentTargets;
this->GetLinkDependentTargetsForProperty(p,
dependentTargets);
const bool impliedByUse =
this->IsNullImpliedByLinkLibraries(p);
assert((impliedByUse ^ explicitlySet)
|| (!impliedByUse && !explicitlySet));
cmComputeLinkInformation *info = this->GetLinkInformation(config);
const cmComputeLinkInformation::ItemVector &deps = info->GetItems();
bool propInitialized = explicitlySet;
for(cmComputeLinkInformation::ItemVector::const_iterator li =
deps.begin();
li != deps.end(); ++li)
{
// An error should be reported if one dependency
// has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
// has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
// target itself has a POSITION_INDEPENDENT_CODE which disagrees
// with a dependency.
if (!li->Target)
{
continue;
}
const bool ifaceIsSet = li->Target->GetProperties()
.find("INTERFACE_" + p)
!= li->Target->GetProperties().end();
const bool ifacePropContent = li->Target->GetPropertyAsBool(
("INTERFACE_" + p).c_str());
if (explicitlySet)
{
if (ifaceIsSet)
{
if (propContent != ifacePropContent)
{
cmOStringStream e;
e << "Property " << p << " on target \""
<< this->GetName() << "\" does\nnot match the "
"INTERFACE_" << p << " property requirement\nof "
"dependency \"" << li->Target->GetName() << "\".\n";
cmSystemTools::Error(e.str().c_str());
}
else
{
// Agree
continue;
}
}
else
{
// Explicitly set on target and not set in iface. Can't disagree.
continue;
}
}
else if (impliedByUse)
{
if (ifaceIsSet)
{
if (propContent != ifacePropContent)
{
cmOStringStream e;
e << "Property " << p << " on target \""
<< this->GetName() << "\" is\nimplied to be FALSE because it "
"was used to determine the link libraries\nalready. The "
"INTERFACE_" << p << " property on\ndependency \""
<< li->Target->GetName() << "\" is in conflict.\n";
cmSystemTools::Error(e.str().c_str());
}
else
{
// Agree
continue;
}
}
else
{
// Implicitly set on target and not set in iface. Can't disagree.
continue;
}
}
else
{
if (ifaceIsSet)
{
if (propInitialized)
{
if (propContent != ifacePropContent)
{
cmOStringStream e;
e << "The INTERFACE_" << p << " property of \""
<< li->Target->GetName() << "\" does\nnot agree with the value "
"of " << p << " already determined\nfor \""
<< this->GetName() << "\".\n";
cmSystemTools::Error(e.str().c_str());
}
else
{
// Agree.
continue;
}
}
else
{
propContent = ifacePropContent;
propInitialized = true;
}
}
else
{
// Not set. Nothing to agree on.
continue;
}
}
}
return propContent;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::GetLanguages(std::set<cmStdString>& languages) const void cmTarget::GetLanguages(std::set<cmStdString>& languages) const
{ {

View File

@ -487,6 +487,16 @@ public:
std::vector<std::string> GetIncludeDirectories(const char *config); std::vector<std::string> GetIncludeDirectories(const char *config);
void InsertInclude(const cmMakefileIncludeDirectoriesEntry &entry, void InsertInclude(const cmMakefileIncludeDirectoriesEntry &entry,
bool before = false); bool before = false);
void GetLinkDependentTargetsForProperty(const std::string &p,
std::set<std::string> &targets);
bool IsNullImpliedByLinkLibraries(const std::string &p);
void AddLinkDependentTargetsForProperties(
const std::map<cmStdString, cmStdString> &map);
bool GetLinkInterfaceDependentBoolProperty(const std::string &p,
const char *config);
private: private:
/** /**
* A list of direct dependencies. Use in conjunction with DependencyMap. * A list of direct dependencies. Use in conjunction with DependencyMap.
@ -596,6 +606,9 @@ private:
bool DLLPlatform; bool DLLPlatform;
bool IsApple; bool IsApple;
bool IsImportedTarget; bool IsImportedTarget;
mutable std::map<cmStdString, std::set<std::string> >
LinkDependentProperties;
mutable std::set<std::string> LinkImplicitNullProperties;
// Cache target output paths for each configuration. // Cache target output paths for each configuration.
struct OutputInfo; struct OutputInfo;

View File

@ -50,6 +50,9 @@ add_RunCMake_test(GeneratorExpression)
add_RunCMake_test(TargetPropertyGeneratorExpressions) add_RunCMake_test(TargetPropertyGeneratorExpressions)
add_RunCMake_test(Languages) add_RunCMake_test(Languages)
add_RunCMake_test(ObjectLibrary) add_RunCMake_test(ObjectLibrary)
if(NOT WIN32)
add_RunCMake_test(PositionIndependentCode)
endif()
add_RunCMake_test(build_command) add_RunCMake_test(build_command)
add_RunCMake_test(find_package) add_RunCMake_test(find_package)

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.8)
project(${RunCMake_TEST} CXX)
# MSVC creates extra targets which pollute the stderr unless we set this.
set(CMAKE_SUPPRESS_REGENERATION TRUE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
CMake Error: Property POSITION_INDEPENDENT_CODE on target "conflict" does
not match the INTERFACE_POSITION_INDEPENDENT_CODE property requirement
of dependency "piciface".

View File

@ -0,0 +1,7 @@
add_library(piciface UNKNOWN IMPORTED)
set_property(TARGET piciface PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_executable(conflict "main.cpp")
set_property(TARGET conflict PROPERTY POSITION_INDEPENDENT_CODE OFF)
target_link_libraries(conflict piciface)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
CMake Error: The INTERFACE_POSITION_INDEPENDENT_CODE property of "picoff" does
not agree with the value of POSITION_INDEPENDENT_CODE already determined
for "conflict".

View File

@ -0,0 +1,9 @@
add_library(picon UNKNOWN IMPORTED)
set_property(TARGET picon PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_library(picoff UNKNOWN IMPORTED)
set_property(TARGET picoff PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF)
add_executable(conflict "main.cpp")
target_link_libraries(conflict picon picoff)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
Property POSITION_INDEPENDENT_CODE on target "conflict" is
implied to be FALSE because it was used to determine the link libraries
already. The INTERFACE_POSITION_INDEPENDENT_CODE property on
dependency "picon" is in conflict.

View File

@ -0,0 +1,12 @@
add_library(picoff UNKNOWN IMPORTED)
add_library(picon UNKNOWN IMPORTED)
set_property(TARGET picon PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_executable(conflict "main.cpp")
target_link_libraries(conflict picon)
set_property(TARGET conflict APPEND PROPERTY
LINK_LIBRARIES
$<$<NOT:$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>>:picoff>
)

View File

@ -0,0 +1,5 @@
include(RunCMake)
run_cmake(Conflict1)
run_cmake(Conflict2)
run_cmake(Conflict3)

View File

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