Merge topic 'LINK_LIBRARIES-property'

7653862 Add LINK_LIBRARIES property for direct target link dependencies
40cf3fb Make linking APIs aware of 'head' target
This commit is contained in:
Brad King 2013-01-08 14:32:41 -05:00 committed by CMake Topic Stage
commit a9f1bf4380
13 changed files with 282 additions and 86 deletions

View File

@ -172,10 +172,11 @@ satisfy dependencies.
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmComputeLinkDepends cmComputeLinkDepends
::cmComputeLinkDepends(cmTarget* target, const char* config) ::cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget* head)
{ {
// Store context information. // Store context information.
this->Target = target; this->Target = target;
this->HeadTarget = head;
this->Makefile = this->Target->GetMakefile(); this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->LocalGenerator = this->Makefile->GetLocalGenerator();
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
@ -352,7 +353,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
{ {
// Follow the target dependencies. // Follow the target dependencies.
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
entry.Target->GetLinkInterface(this->Config)) entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
// This target provides its own link interface information. // This target provides its own link interface information.
this->AddLinkEntries(depender_index, iface->Libraries); this->AddLinkEntries(depender_index, iface->Libraries);
@ -444,7 +445,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
if(entry.Target) if(entry.Target)
{ {
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
entry.Target->GetLinkInterface(this->Config)) entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
// Follow public and private dependencies transitively. // Follow public and private dependencies transitively.
this->FollowSharedDeps(index, iface, true); this->FollowSharedDeps(index, iface, true);
@ -533,7 +534,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
{ {
// Add direct link dependencies in this configuration. // Add direct link dependencies in this configuration.
cmTarget::LinkImplementation const* impl = cmTarget::LinkImplementation const* impl =
this->Target->GetLinkImplementation(this->Config); this->Target->GetLinkImplementation(this->Config, this->HeadTarget);
this->AddLinkEntries(-1, impl->Libraries); this->AddLinkEntries(-1, impl->Libraries);
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
wi = impl->WrongConfigLibraries.begin(); wi = impl->WrongConfigLibraries.begin();
@ -944,7 +945,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
if(cmTarget* target = this->EntryList[*ni].Target) if(cmTarget* target = this->EntryList[*ni].Target)
{ {
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
target->GetLinkInterface(this->Config)) target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
if(iface->Multiplicity > count) if(iface->Multiplicity > count)
{ {

View File

@ -32,7 +32,7 @@ class cmake;
class cmComputeLinkDepends class cmComputeLinkDepends
{ {
public: public:
cmComputeLinkDepends(cmTarget* target, const char* config); cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget *head);
~cmComputeLinkDepends(); ~cmComputeLinkDepends();
// Basic information about each link item. // Basic information about each link item.
@ -59,6 +59,7 @@ private:
// Context information. // Context information.
cmTarget* Target; cmTarget* Target;
cmTarget* HeadTarget;
cmMakefile* Makefile; cmMakefile* Makefile;
cmLocalGenerator* LocalGenerator; cmLocalGenerator* LocalGenerator;
cmGlobalGenerator* GlobalGenerator; cmGlobalGenerator* GlobalGenerator;

View File

@ -239,10 +239,12 @@ because this need be done only for shared libraries without soname-s.
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmComputeLinkInformation cmComputeLinkInformation
::cmComputeLinkInformation(cmTarget* target, const char* config) ::cmComputeLinkInformation(cmTarget* target, const char* config,
cmTarget *headTarget)
{ {
// Store context information. // Store context information.
this->Target = target; this->Target = target;
this->HeadTarget = headTarget;
this->Makefile = this->Target->GetMakefile(); this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->LocalGenerator = this->Makefile->GetLocalGenerator();
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
@ -265,7 +267,7 @@ cmComputeLinkInformation
this->OrderDependentRPath = 0; this->OrderDependentRPath = 0;
// Get the language used for linking this target. // Get the language used for linking this target.
this->LinkLanguage = this->Target->GetLinkerLanguage(config); this->LinkLanguage = this->Target->GetLinkerLanguage(config, headTarget);
if(!this->LinkLanguage) if(!this->LinkLanguage)
{ {
// The Compute method will do nothing, so skip the rest of the // The Compute method will do nothing, so skip the rest of the
@ -503,7 +505,7 @@ bool cmComputeLinkInformation::Compute()
} }
// Compute the ordered link line items. // Compute the ordered link line items.
cmComputeLinkDepends cld(this->Target, this->Config); cmComputeLinkDepends cld(this->Target, this->Config, this->HeadTarget);
cld.SetOldLinkDirMode(this->OldLinkDirMode); cld.SetOldLinkDirMode(this->OldLinkDirMode);
cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
@ -569,7 +571,8 @@ bool cmComputeLinkInformation::Compute()
void cmComputeLinkInformation::AddImplicitLinkInfo() void cmComputeLinkInformation::AddImplicitLinkInfo()
{ {
// The link closure lists all languages whose implicit info is needed. // The link closure lists all languages whose implicit info is needed.
cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config); cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config,
this->HeadTarget);
for(std::vector<std::string>::const_iterator li = lc->Languages.begin(); for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
li != lc->Languages.end(); ++li) li != lc->Languages.end(); ++li)
{ {

View File

@ -29,7 +29,8 @@ class cmOrderDirectories;
class cmComputeLinkInformation class cmComputeLinkInformation
{ {
public: public:
cmComputeLinkInformation(cmTarget* target, const char* config); cmComputeLinkInformation(cmTarget* target, const char* config,
cmTarget* headTarget);
~cmComputeLinkInformation(); ~cmComputeLinkInformation();
bool Compute(); bool Compute();
@ -74,6 +75,7 @@ private:
// Context information. // Context information.
cmTarget* Target; cmTarget* Target;
cmTarget* HeadTarget;
cmMakefile* Makefile; cmMakefile* Makefile;
cmLocalGenerator* LocalGenerator; cmLocalGenerator* LocalGenerator;
cmGlobalGenerator* GlobalGenerator; cmGlobalGenerator* GlobalGenerator;

View File

@ -200,25 +200,51 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
// Get the depender. // Get the depender.
cmTarget* depender = this->Targets[depender_index]; cmTarget* depender = this->Targets[depender_index];
// Loop over all targets linked directly. // Loop over all targets linked directly in all configs.
// We need to make targets depend on the union of all config-specific
// dependencies in all targets, because the generated build-systems can't
// deal with config-specific dependencies.
{ {
cmTarget::LinkLibraryVectorType const& tlibs =
depender->GetOriginalLinkLibraries();
std::set<cmStdString> emitted; std::set<cmStdString> emitted;
{
std::vector<std::string> tlibs;
depender->GetDirectLinkLibraries(0, tlibs, depender);
// A target should not depend on itself. // A target should not depend on itself.
emitted.insert(depender->GetName()); emitted.insert(depender->GetName());
for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); for(std::vector<std::string>::const_iterator lib = tlibs.begin();
lib != tlibs.end(); ++lib) lib != tlibs.end(); ++lib)
{ {
// Don't emit the same library twice for this target. // Don't emit the same library twice for this target.
if(emitted.insert(lib->first).second) if(emitted.insert(*lib).second)
{ {
this->AddTargetDepend(depender_index, lib->first.c_str(), true); this->AddTargetDepend(depender_index, lib->c_str(), true);
this->AddInterfaceDepends(depender_index, lib->first.c_str(), this->AddInterfaceDepends(depender_index, lib->c_str(),
true, emitted); true, emitted);
} }
} }
} }
std::vector<std::string> configs;
depender->GetMakefile()->GetConfigurations(configs);
for (std::vector<std::string>::const_iterator it = configs.begin();
it != configs.end(); ++it)
{
std::vector<std::string> tlibs;
depender->GetDirectLinkLibraries(it->c_str(), tlibs, depender);
// A target should not depend on itself.
emitted.insert(depender->GetName());
for(std::vector<std::string>::const_iterator lib = tlibs.begin();
lib != tlibs.end(); ++lib)
{
// Don't emit the same library twice for this target.
if(emitted.insert(*lib).second)
{
this->AddTargetDepend(depender_index, lib->c_str(), true);
this->AddInterfaceDepends(depender_index, lib->c_str(),
true, emitted);
}
}
}
}
// Loop over all utility dependencies. // Loop over all utility dependencies.
{ {
@ -244,8 +270,9 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index,
const char *config, const char *config,
std::set<cmStdString> &emitted) std::set<cmStdString> &emitted)
{ {
cmTarget* depender = this->Targets[depender_index];
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
dependee->GetLinkInterface(config)) dependee->GetLinkInterface(config, depender))
{ {
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
lib = iface->Libraries.begin(); lib = iface->Libraries.begin();

View File

@ -357,7 +357,8 @@ cmExportFileGenerator
} }
// Add the transitive link dependencies for this configuration. // Add the transitive link dependencies for this configuration.
if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config)) if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config,
target))
{ {
this->SetImportLinkProperty(suffix, target, this->SetImportLinkProperty(suffix, target,
"IMPORTED_LINK_INTERFACE_LANGUAGES", "IMPORTED_LINK_INTERFACE_LANGUAGES",

View File

@ -1206,7 +1206,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
// If the language is compiled as a source trust Xcode to link with it. // If the language is compiled as a source trust Xcode to link with it.
cmTarget::LinkImplementation const* impl = cmTarget::LinkImplementation const* impl =
cmtarget.GetLinkImplementation("NOCONFIG"); cmtarget.GetLinkImplementation("NOCONFIG", &cmtarget);
for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li) li != impl->Languages.end(); ++li)
{ {

View File

@ -72,6 +72,11 @@ struct cmTarget::ImportInfo
cmTarget::LinkInterface LinkInterface; cmTarget::LinkInterface LinkInterface;
}; };
struct TargetConfigPair : public std::pair<cmTarget*, std::string> {
TargetConfigPair(cmTarget* tgt, const std::string &config)
: std::pair<cmTarget*, std::string>(tgt, config) {}
};
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class cmTargetInternals class cmTargetInternals
{ {
@ -100,20 +105,24 @@ public:
OptionalLinkInterface(): Exists(false) {} OptionalLinkInterface(): Exists(false) {}
bool Exists; bool Exists;
}; };
typedef std::map<cmStdString, OptionalLinkInterface> LinkInterfaceMapType; typedef std::map<TargetConfigPair, OptionalLinkInterface>
LinkInterfaceMapType;
LinkInterfaceMapType LinkInterfaceMap; LinkInterfaceMapType LinkInterfaceMap;
typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType; typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType;
OutputInfoMapType OutputInfoMap; OutputInfoMapType OutputInfoMap;
typedef std::map<cmStdString, cmTarget::ImportInfo> ImportInfoMapType; typedef std::map<TargetConfigPair, cmTarget::ImportInfo>
ImportInfoMapType;
ImportInfoMapType ImportInfoMap; ImportInfoMapType ImportInfoMap;
// Cache link implementation computation from each configuration. // Cache link implementation computation from each configuration.
typedef std::map<cmStdString, cmTarget::LinkImplementation> LinkImplMapType; typedef std::map<TargetConfigPair,
cmTarget::LinkImplementation> LinkImplMapType;
LinkImplMapType LinkImplMap; LinkImplMapType LinkImplMap;
typedef std::map<cmStdString, cmTarget::LinkClosure> LinkClosureMapType; typedef std::map<TargetConfigPair, cmTarget::LinkClosure>
LinkClosureMapType;
LinkClosureMapType LinkClosureMap; LinkClosureMapType LinkClosureMap;
struct SourceEntry { std::vector<cmSourceFile*> Depends; }; struct SourceEntry { std::vector<cmSourceFile*> Depends; };
@ -510,6 +519,22 @@ void cmTarget::DefineProperties(cmake *cm)
"Installing a target with EXCLUDE_FROM_ALL set to true has " "Installing a target with EXCLUDE_FROM_ALL set to true has "
"undefined behavior."); "undefined behavior.");
cm->DefineProperty
("LINK_LIBRARIES", cmProperty::TARGET,
"List of direct link dependencies.",
"This property specifies the list of libraries or targets which will be "
"used for linking. "
"In addition to accepting values from the target_link_libraries "
"command, values may be set directly on any target using the "
"set_property command. "
"\n"
"The target property values are used by the generators to set "
"the link libraries for the compiler. "
"See also the target_link_libraries command.\n"
"Contents of LINK_LIBRARIES may use \"generator expressions\" with "
"the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS);
cm->DefineProperty cm->DefineProperty
("INCLUDE_DIRECTORIES", cmProperty::TARGET, ("INCLUDE_DIRECTORIES", cmProperty::TARGET,
"List of preprocessor include file search directories.", "List of preprocessor include file search directories.",
@ -2130,6 +2155,66 @@ bool cmTarget::NameResolvesToFramework(const std::string& libname)
NameResolvesToFramework(libname); NameResolvesToFramework(libname);
} }
//----------------------------------------------------------------------------
void cmTarget::GetDirectLinkLibraries(const char *config,
std::vector<std::string> &libs, cmTarget *head)
{
const char *prop = this->GetProperty("LINK_LIBRARIES");
if (prop)
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
"LINK_LIBRARIES", 0, 0);
cmSystemTools::ExpandListArgument(ge.Parse(prop)->Evaluate(this->Makefile,
config,
false,
head,
&dagChecker),
libs);
}
}
//----------------------------------------------------------------------------
std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value,
cmTarget::LinkLibraryType llt)
{
if (llt == GENERAL)
{
return value;
}
// Get the list of configurations considered to be DEBUG.
std::vector<std::string> const& debugConfigs =
this->Makefile->GetCMakeInstance()->GetDebugConfigs();
std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
if (debugConfigs.size() > 1)
{
for(std::vector<std::string>::const_iterator
li = debugConfigs.begin() + 1; li != debugConfigs.end(); ++li)
{
configString += ",$<CONFIG:" + *li + ">";
}
configString = "$<OR:" + configString + ">";
}
if (llt == OPTIMIZED)
{
configString = "$<NOT:" + configString + ">";
}
return "$<" + configString + ":" + value + ">";
}
//----------------------------------------------------------------------------
static std::string targetNameGenex(const char *lib)
{
return std::string("$<TARGET_NAME:") + lib + ">";
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::AddLinkLibrary(cmMakefile& mf, void cmTarget::AddLinkLibrary(cmMakefile& mf,
const char *target, const char* lib, const char *target, const char* lib,
@ -2140,6 +2225,18 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf,
{ {
return; return;
} }
{
cmTarget *tgt = this->Makefile->FindTargetToUse(lib);
const bool isNonImportedTarget = tgt && !tgt->IsImported();
std::string libName = isNonImportedTarget ? targetNameGenex(lib)
: std::string(lib);
this->AppendProperty("LINK_LIBRARIES",
this->GetDebugGeneratorExpressions(libName,
llt).c_str());
}
cmTarget::LibraryID tmp; cmTarget::LibraryID tmp;
tmp.first = lib; tmp.first = lib;
tmp.second = llt; tmp.second = llt;
@ -3024,8 +3121,11 @@ class cmTargetCollectLinkLanguages
{ {
public: public:
cmTargetCollectLinkLanguages(cmTarget* target, const char* config, cmTargetCollectLinkLanguages(cmTarget* target, const char* config,
std::set<cmStdString>& languages): std::set<cmStdString>& languages,
Config(config), Languages(languages) { this->Visited.insert(target); } cmTarget* head):
Config(config), Languages(languages), HeadTarget(head)
{ this->Visited.insert(target); }
void Visit(cmTarget* target) void Visit(cmTarget* target)
{ {
if(!target || !this->Visited.insert(target).second) if(!target || !this->Visited.insert(target).second)
@ -3034,7 +3134,7 @@ public:
} }
cmTarget::LinkInterface const* iface = cmTarget::LinkInterface const* iface =
target->GetLinkInterface(this->Config); target->GetLinkInterface(this->Config, this->HeadTarget);
if(!iface) { return; } if(!iface) { return; }
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
@ -3053,26 +3153,30 @@ public:
private: private:
const char* Config; const char* Config;
std::set<cmStdString>& Languages; std::set<cmStdString>& Languages;
cmTarget* HeadTarget;
std::set<cmTarget*> Visited; std::set<cmTarget*> Visited;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
const char* cmTarget::GetLinkerLanguage(const char* config) const char* cmTarget::GetLinkerLanguage(const char* config, cmTarget *head)
{ {
const char* lang = this->GetLinkClosure(config)->LinkerLanguage.c_str(); cmTarget *headTarget = head ? head : this;
const char* lang = this->GetLinkClosure(config, headTarget)
->LinkerLanguage.c_str();
return *lang? lang : 0; return *lang? lang : 0;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config) cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config,
cmTarget *head)
{ {
std::string key = cmSystemTools::UpperCase(config? config : ""); TargetConfigPair key(head, cmSystemTools::UpperCase(config ? config : ""));
cmTargetInternals::LinkClosureMapType::iterator cmTargetInternals::LinkClosureMapType::iterator
i = this->Internal->LinkClosureMap.find(key); i = this->Internal->LinkClosureMap.find(key);
if(i == this->Internal->LinkClosureMap.end()) if(i == this->Internal->LinkClosureMap.end())
{ {
LinkClosure lc; LinkClosure lc;
this->ComputeLinkClosure(config, lc); this->ComputeLinkClosure(config, lc, head);
cmTargetInternals::LinkClosureMapType::value_type entry(key, lc); cmTargetInternals::LinkClosureMapType::value_type entry(key, lc);
i = this->Internal->LinkClosureMap.insert(entry).first; i = this->Internal->LinkClosureMap.insert(entry).first;
} }
@ -3133,11 +3237,12 @@ public:
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc) void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc,
cmTarget *head)
{ {
// Get languages built in this target. // Get languages built in this target.
std::set<cmStdString> languages; std::set<cmStdString> languages;
LinkImplementation const* impl = this->GetLinkImplementation(config); LinkImplementation const* impl = this->GetLinkImplementation(config, head);
for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li) li != impl->Languages.end(); ++li)
{ {
@ -3145,7 +3250,7 @@ void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc)
} }
// Add interface languages from linked targets. // Add interface languages from linked targets.
cmTargetCollectLinkLanguages cll(this, config, languages); cmTargetCollectLinkLanguages cll(this, config, languages, head);
for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); for(std::vector<std::string>::const_iterator li = impl->Libraries.begin();
li != impl->Libraries.end(); ++li) li != impl->Libraries.end(); ++li)
{ {
@ -3284,7 +3389,8 @@ bool cmTarget::HasSOName(const char* config)
return ((this->GetType() == cmTarget::SHARED_LIBRARY || return ((this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY) && this->GetType() == cmTarget::MODULE_LIBRARY) &&
!this->GetPropertyAsBool("NO_SONAME") && !this->GetPropertyAsBool("NO_SONAME") &&
this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config))); this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config,
this)));
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -3293,7 +3399,7 @@ std::string cmTarget::GetSOName(const char* config)
if(this->IsImported()) if(this->IsImported())
{ {
// Lookup the imported soname. // Lookup the imported soname.
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
{ {
if(info->NoSOName) if(info->NoSOName)
{ {
@ -3330,7 +3436,7 @@ bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config)
{ {
if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY) if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
{ {
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
{ {
return info->NoSOName; return info->NoSOName;
} }
@ -3444,7 +3550,7 @@ std::string cmTarget::NormalGetFullPath(const char* config, bool implib,
std::string cmTarget::ImportedGetFullPath(const char* config, bool implib) std::string cmTarget::ImportedGetFullPath(const char* config, bool implib)
{ {
std::string result; std::string result;
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
{ {
result = implib? info->ImportLibrary : info->Location; result = implib? info->ImportLibrary : info->Location;
} }
@ -3529,7 +3635,7 @@ void cmTarget::GetFullNameInternal(const char* config,
const char* suffixVar = this->GetSuffixVariableInternal(implib); const char* suffixVar = this->GetSuffixVariableInternal(implib);
// Check for language-specific default prefix and suffix. // Check for language-specific default prefix and suffix.
if(const char* ll = this->GetLinkerLanguage(config)) if(const char* ll = this->GetLinkerLanguage(config, this))
{ {
if(!targetSuffix && suffixVar && *suffixVar) if(!targetSuffix && suffixVar && *suffixVar)
{ {
@ -3900,7 +4006,7 @@ bool cmTarget::NeedRelinkBeforeInstall(const char* config)
} }
// Check for rpath support on this platform. // Check for rpath support on this platform.
if(const char* ll = this->GetLinkerLanguage(config)) if(const char* ll = this->GetLinkerLanguage(config, this))
{ {
std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
flagVar += ll; flagVar += ll;
@ -4322,7 +4428,7 @@ bool cmTarget::IsChrpathUsed(const char* config)
// Enable if the rpath flag uses a separator and the target uses ELF // Enable if the rpath flag uses a separator and the target uses ELF
// binaries. // binaries.
if(const char* ll = this->GetLinkerLanguage(config)) if(const char* ll = this->GetLinkerLanguage(config, this))
{ {
std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
sepVar += ll; sepVar += ll;
@ -4346,7 +4452,7 @@ bool cmTarget::IsChrpathUsed(const char* config)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::ImportInfo const* cmTarget::ImportInfo const*
cmTarget::GetImportInfo(const char* config) cmTarget::GetImportInfo(const char* config, cmTarget *headTarget)
{ {
// There is no imported information for non-imported targets. // There is no imported information for non-imported targets.
if(!this->IsImported()) if(!this->IsImported())
@ -4365,14 +4471,16 @@ cmTarget::GetImportInfo(const char* config)
{ {
config_upper = "NOCONFIG"; config_upper = "NOCONFIG";
} }
TargetConfigPair key(headTarget, config_upper);
typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType; typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType;
ImportInfoMapType::const_iterator i = ImportInfoMapType::const_iterator i =
this->Internal->ImportInfoMap.find(config_upper); this->Internal->ImportInfoMap.find(key);
if(i == this->Internal->ImportInfoMap.end()) if(i == this->Internal->ImportInfoMap.end())
{ {
ImportInfo info; ImportInfo info;
this->ComputeImportInfo(config_upper, info); this->ComputeImportInfo(config_upper, info, headTarget);
ImportInfoMapType::value_type entry(config_upper, info); ImportInfoMapType::value_type entry(key, info);
i = this->Internal->ImportInfoMap.insert(entry).first; i = this->Internal->ImportInfoMap.insert(entry).first;
} }
@ -4511,8 +4619,10 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::ComputeImportInfo(std::string const& desired_config, void cmTarget::ComputeImportInfo(std::string const& desired_config,
ImportInfo& info) ImportInfo& info,
cmTarget *headTarget)
{ {
(void)headTarget;
// This method finds information about an imported target from its // This method finds information about an imported target from its
// properties. The "IMPORTED_" namespace is reserved for properties // properties. The "IMPORTED_" namespace is reserved for properties
// defined by the project exporting the target. // defined by the project exporting the target.
@ -4669,12 +4779,13 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config) cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config,
cmTarget *head)
{ {
// Imported targets have their own link interface. // Imported targets have their own link interface.
if(this->IsImported()) if(this->IsImported())
{ {
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head))
{ {
return &info->LinkInterface; return &info->LinkInterface;
} }
@ -4690,14 +4801,15 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
} }
// Lookup any existing link interface for this configuration. // Lookup any existing link interface for this configuration.
std::string key = cmSystemTools::UpperCase(config? config : ""); TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : ""));
cmTargetInternals::LinkInterfaceMapType::iterator cmTargetInternals::LinkInterfaceMapType::iterator
i = this->Internal->LinkInterfaceMap.find(key); i = this->Internal->LinkInterfaceMap.find(key);
if(i == this->Internal->LinkInterfaceMap.end()) if(i == this->Internal->LinkInterfaceMap.end())
{ {
// Compute the link interface for this configuration. // Compute the link interface for this configuration.
cmTargetInternals::OptionalLinkInterface iface; cmTargetInternals::OptionalLinkInterface iface;
iface.Exists = this->ComputeLinkInterface(config, iface); iface.Exists = this->ComputeLinkInterface(config, iface, head);
// Store the information for this configuration. // Store the information for this configuration.
cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface);
@ -4708,7 +4820,8 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
cmTarget *headTarget)
{ {
// Construct the property name suffix for this configuration. // Construct the property name suffix for this configuration.
std::string suffix = "_"; std::string suffix = "_";
@ -4765,7 +4878,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
{ {
emitted.insert(*li); emitted.insert(*li);
} }
LinkImplementation const* impl = this->GetLinkImplementation(config); LinkImplementation const* impl = this->GetLinkImplementation(config,
headTarget);
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li)
{ {
@ -4793,7 +4907,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
else else
{ {
// The link implementation is the default link interface. // The link implementation is the default link interface.
LinkImplementation const* impl = this->GetLinkImplementation(config); LinkImplementation const* impl = this->GetLinkImplementation(config,
headTarget);
iface.Libraries = impl->Libraries; iface.Libraries = impl->Libraries;
iface.WrongConfigLibraries = impl->WrongConfigLibraries; iface.WrongConfigLibraries = impl->WrongConfigLibraries;
if(this->GetType() == cmTarget::STATIC_LIBRARY) if(this->GetType() == cmTarget::STATIC_LIBRARY)
@ -4825,7 +4940,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::LinkImplementation const* cmTarget::LinkImplementation const*
cmTarget::GetLinkImplementation(const char* config) cmTarget::GetLinkImplementation(const char* config, cmTarget *head)
{ {
// There is no link implementation for imported targets. // There is no link implementation for imported targets.
if(this->IsImported()) if(this->IsImported())
@ -4834,14 +4949,15 @@ cmTarget::GetLinkImplementation(const char* config)
} }
// Lookup any existing link implementation for this configuration. // Lookup any existing link implementation for this configuration.
std::string key = cmSystemTools::UpperCase(config? config : ""); TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : ""));
cmTargetInternals::LinkImplMapType::iterator cmTargetInternals::LinkImplMapType::iterator
i = this->Internal->LinkImplMap.find(key); i = this->Internal->LinkImplMap.find(key);
if(i == this->Internal->LinkImplMap.end()) if(i == this->Internal->LinkImplMap.end())
{ {
// Compute the link implementation for this configuration. // Compute the link implementation for this configuration.
LinkImplementation impl; LinkImplementation impl;
this->ComputeLinkImplementation(config, impl); this->ComputeLinkImplementation(config, impl, head);
// Store the information for this configuration. // Store the information for this configuration.
cmTargetInternals::LinkImplMapType::value_type entry(key, impl); cmTargetInternals::LinkImplMapType::value_type entry(key, impl);
@ -4853,27 +4969,26 @@ cmTarget::GetLinkImplementation(const char* config)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::ComputeLinkImplementation(const char* config, void cmTarget::ComputeLinkImplementation(const char* config,
LinkImplementation& impl) LinkImplementation& impl,
cmTarget *head)
{ {
// Compute which library configuration to link. // Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
// Collect libraries directly linked in this configuration. // Collect libraries directly linked in this configuration.
LinkLibraryVectorType const& llibs = this->GetOriginalLinkLibraries(); std::vector<std::string> llibs;
for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin(); this->GetDirectLinkLibraries(config, llibs, head);
for(std::vector<std::string>::const_iterator li = llibs.begin();
li != llibs.end(); ++li) li != llibs.end(); ++li)
{ {
// Skip entries that resolve to the target itself or are empty. // Skip entries that resolve to the target itself or are empty.
std::string item = this->CheckCMP0004(li->first); std::string item = this->CheckCMP0004(*li);
if(item == this->GetName() || item.empty()) if(item == this->GetName() || item.empty())
{ {
continue; continue;
} }
if(li->second == cmTarget::GENERAL || li->second == linkType) // The entry is meant for this configuration.
{ impl.Libraries.push_back(item);
// The entry is meant for this configuration.
impl.Libraries.push_back(item);
}
} }
LinkLibraryVectorType const& oldllibs = this->GetOriginalLinkLibraries(); LinkLibraryVectorType const& oldllibs = this->GetOriginalLinkLibraries();
@ -4977,16 +5092,19 @@ std::string cmTarget::CheckCMP0004(std::string const& item)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmComputeLinkInformation* cmComputeLinkInformation*
cmTarget::GetLinkInformation(const char* config) cmTarget::GetLinkInformation(const char* config, cmTarget *head)
{ {
cmTarget *headTarget = head ? head : this;
// Lookup any existing information for this configuration. // Lookup any existing information for this configuration.
std::map<cmStdString, cmComputeLinkInformation*>::iterator TargetConfigPair key(headTarget,
i = this->LinkInformation.find(config?config:""); cmSystemTools::UpperCase(config?config:""));
cmTargetLinkInformationMap::iterator
i = this->LinkInformation.find(key);
if(i == this->LinkInformation.end()) if(i == this->LinkInformation.end())
{ {
// Compute information for this configuration. // Compute information for this configuration.
cmComputeLinkInformation* info = cmComputeLinkInformation* info =
new cmComputeLinkInformation(this, config); new cmComputeLinkInformation(this, config, headTarget);
if(!info || !info->Compute()) if(!info || !info->Compute())
{ {
delete info; delete info;
@ -4994,8 +5112,7 @@ cmTarget::GetLinkInformation(const char* config)
} }
// Store the information for this configuration. // Store the information for this configuration.
std::map<cmStdString, cmComputeLinkInformation*>::value_type cmTargetLinkInformationMap::value_type entry(key, info);
entry(config?config:"", info);
i = this->LinkInformation.insert(entry).first; i = this->LinkInformation.insert(entry).first;
} }
return i->second; return i->second;

View File

@ -25,11 +25,13 @@ class cmSourceFile;
class cmGlobalGenerator; class cmGlobalGenerator;
class cmComputeLinkInformation; class cmComputeLinkInformation;
class cmListFileBacktrace; class cmListFileBacktrace;
class cmTarget;
struct cmTargetLinkInformationMap: struct cmTargetLinkInformationMap:
public std::map<cmStdString, cmComputeLinkInformation*> public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*>
{ {
typedef std::map<cmStdString, cmComputeLinkInformation*> derived; typedef std::map<std::pair<cmTarget*, std::string>,
cmComputeLinkInformation*> derived;
cmTargetLinkInformationMap() {} cmTargetLinkInformationMap() {}
cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r); cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r);
~cmTargetLinkInformationMap(); ~cmTargetLinkInformationMap();
@ -166,6 +168,9 @@ public:
return this->LinkLibraries;} return this->LinkLibraries;}
const LinkLibraryVectorType &GetOriginalLinkLibraries() const const LinkLibraryVectorType &GetOriginalLinkLibraries() const
{return this->OriginalLinkLibraries;} {return this->OriginalLinkLibraries;}
void GetDirectLinkLibraries(const char *config,
std::vector<std::string> &,
cmTarget *head);
/** Compute the link type to use for the given configuration. */ /** Compute the link type to use for the given configuration. */
LinkLibraryType ComputeLinkType(const char* config); LinkLibraryType ComputeLinkType(const char* config);
@ -258,7 +263,8 @@ public:
/** Get the link interface for the given configuration. Returns 0 /** Get the link interface for the given configuration. Returns 0
if the target cannot be linked. */ if the target cannot be linked. */
LinkInterface const* GetLinkInterface(const char* config); LinkInterface const* GetLinkInterface(const char* config,
cmTarget *headTarget);
/** The link implementation specifies the direct library /** The link implementation specifies the direct library
dependencies needed by the object files of the target. */ dependencies needed by the object files of the target. */
@ -274,7 +280,8 @@ public:
// Needed only for OLD behavior of CMP0003. // Needed only for OLD behavior of CMP0003.
std::vector<std::string> WrongConfigLibraries; std::vector<std::string> WrongConfigLibraries;
}; };
LinkImplementation const* GetLinkImplementation(const char* config); LinkImplementation const* GetLinkImplementation(const char* config,
cmTarget *head);
/** Link information from the transitive closure of the link /** Link information from the transitive closure of the link
implementation and the interfaces of its dependencies. */ implementation and the interfaces of its dependencies. */
@ -286,7 +293,7 @@ public:
// Languages whose runtime libraries must be linked. // Languages whose runtime libraries must be linked.
std::vector<std::string> Languages; std::vector<std::string> Languages;
}; };
LinkClosure const* GetLinkClosure(const char* config); LinkClosure const* GetLinkClosure(const char* config, cmTarget *head);
/** Strip off leading and trailing whitespace from an item named in /** Strip off leading and trailing whitespace from an item named in
the link dependencies of this target. */ the link dependencies of this target. */
@ -331,7 +338,7 @@ public:
bool FindSourceFiles(); bool FindSourceFiles();
///! Return the preferred linker language for this target ///! Return the preferred linker language for this target
const char* GetLinkerLanguage(const char* config = 0); const char* GetLinkerLanguage(const char* config = 0, cmTarget *head = 0);
/** Get the full name of the target according to the settings in its /** Get the full name of the target according to the settings in its
makefile. */ makefile. */
@ -399,7 +406,8 @@ public:
std::string GetInstallNameDirForInstallTree(const char* config, std::string GetInstallNameDirForInstallTree(const char* config,
bool for_xcode = false); bool for_xcode = false);
cmComputeLinkInformation* GetLinkInformation(const char* config); cmComputeLinkInformation* GetLinkInformation(const char* config,
cmTarget *head = 0);
// Get the properties // Get the properties
cmPropertyMap &GetProperties() { return this->Properties; }; cmPropertyMap &GetProperties() { return this->Properties; };
@ -597,16 +605,19 @@ private:
// Cache import information from properties for each configuration. // Cache import information from properties for each configuration.
struct ImportInfo; struct ImportInfo;
ImportInfo const* GetImportInfo(const char* config); ImportInfo const* GetImportInfo(const char* config,
void ComputeImportInfo(std::string const& desired_config, ImportInfo& info); cmTarget *workingTarget);
void ComputeImportInfo(std::string const& desired_config, ImportInfo& info,
cmTarget *head);
cmTargetLinkInformationMap LinkInformation; cmTargetLinkInformationMap LinkInformation;
bool ComputeLinkInterface(const char* config, LinkInterface& iface); bool ComputeLinkInterface(const char* config, LinkInterface& iface,
cmTarget *head);
void ComputeLinkImplementation(const char* config, void ComputeLinkImplementation(const char* config,
LinkImplementation& impl); LinkImplementation& impl, cmTarget *head);
void ComputeLinkClosure(const char* config, LinkClosure& lc); void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget *head);
void ClearLinkMaps(); void ClearLinkMaps();
@ -614,6 +625,9 @@ private:
void ProcessSourceExpression(std::string const& expr); void ProcessSourceExpression(std::string const& expr);
std::string GetDebugGeneratorExpressions(const std::string &value,
cmTarget::LinkLibraryType llt);
// The cmMakefile instance that owns this target. This should // The cmMakefile instance that owns this target. This should
// always be set. // always be set.
cmMakefile* Makefile; cmMakefile* Makefile;

View File

@ -34,6 +34,13 @@ generate_export_header(depB)
target_link_libraries(depB LINK_PRIVATE depA) target_link_libraries(depB LINK_PRIVATE depA)
add_library(libgenex SHARED libgenex.cpp)
generate_export_header(libgenex)
set_property(TARGET depB APPEND PROPERTY
LINK_LIBRARIES $<1:libgenex>
)
add_library(depC SHARED depC.cpp) add_library(depC SHARED depC.cpp)
generate_export_header(depC) generate_export_header(depC)

View File

@ -3,9 +3,13 @@
#include "depA.h" #include "depA.h"
#include "libgenex.h"
int DepB::foo() int DepB::foo()
{ {
DepA a; DepA a;
return a.foo(); LibGenex lg;
return a.foo() + lg.foo();
} }

View File

@ -0,0 +1,7 @@
#include "libgenex.h"
int LibGenex::foo()
{
return 0;
}

View File

@ -0,0 +1,12 @@
#include "libgenex_export.h"
#ifndef LIBGENEX_H
#define LIBGENEX_H
struct LIBGENEX_EXPORT LibGenex
{
int foo();
};
#endif