diff options
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 1221 |
1 files changed, 1209 insertions, 12 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 25fc8a7..4a1a7a2 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -34,6 +34,18 @@ #define UNORDERED_SET std::set #endif +class cmGeneratorTarget::TargetPropertyEntry { + static cmLinkImplItem NoLinkImplItem; +public: + TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge, + cmLinkImplItem const& item = NoLinkImplItem) + : ge(cge), LinkImplItem(item) + {} + const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge; + cmLinkImplItem const& LinkImplItem; +}; +cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem; + //---------------------------------------------------------------------------- void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib, cmGeneratorTarget const* target, cmake *cm) @@ -227,18 +239,64 @@ struct TagVisitor } }; +void CreatePropertyGeneratorExpressions( + cmStringRange const& entries, + cmBacktraceRange const& backtraces, + std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items, + bool evaluateForBuildsystem = false) +{ + std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin(); + for (std::vector<std::string>::const_iterator it = entries.begin(); + it != entries.end(); ++it, ++btIt) + { + cmGeneratorExpression ge(*btIt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it); + cge->SetEvaluateForBuildsystem(evaluateForBuildsystem); + items.push_back(new cmGeneratorTarget::TargetPropertyEntry(cge)); + } +} + //---------------------------------------------------------------------------- cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) : Target(t), - SourceFileFlagsConstructed(false) + SourceFileFlagsConstructed(false), + PolicyWarnedCMP0022(false), + DebugIncludesDone(false), + DebugCompileOptionsDone(false), + DebugCompileFeaturesDone(false), + DebugCompileDefinitionsDone(false) { this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = lg; this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); + + CreatePropertyGeneratorExpressions( + t->GetIncludeDirectoriesEntries(), + t->GetIncludeDirectoriesBacktraces(), + this->IncludeDirectoriesEntries); + + CreatePropertyGeneratorExpressions( + t->GetCompileOptionsEntries(), + t->GetCompileOptionsBacktraces(), + this->CompileOptionsEntries); + + CreatePropertyGeneratorExpressions( + t->GetCompileFeaturesEntries(), + t->GetCompileFeaturesBacktraces(), + this->CompileFeaturesEntries); + + CreatePropertyGeneratorExpressions( + t->GetCompileDefinitionsEntries(), + t->GetCompileDefinitionsBacktraces(), + this->CompileDefinitionsEntries); } cmGeneratorTarget::~cmGeneratorTarget() { + cmDeleteAll(this->IncludeDirectoriesEntries); + cmDeleteAll(this->CompileOptionsEntries); + cmDeleteAll(this->CompileFeaturesEntries); + cmDeleteAll(this->CompileDefinitionsEntries); cmDeleteAll(this->LinkInformation); this->LinkInformation.clear(); } @@ -851,7 +909,7 @@ cmGeneratorTarget::NeedRelinkBeforeInstall(const std::string& config) const // If either a build or install tree rpath is set then the rpath // will likely change between the build tree and install tree and // this target must be relinked. - return this->Target->HaveBuildTreeRPATH(config) + return this->HaveBuildTreeRPATH(config) || this->Target->HaveInstallTreeRPATH(); } @@ -1172,9 +1230,11 @@ public: { return; } - - cmTarget::LinkInterface const* iface = - item.Target->GetLinkInterface(this->Config, this->HeadTarget); + cmGeneratorTarget* gtgt = + this->Target->GetLocalGenerator()->GetGlobalGenerator() + ->GetGeneratorTarget(item.Target); + cmLinkInterface const* iface = + gtgt->GetLinkInterface(this->Config, this->HeadTarget); if(!iface) { return; } for(std::vector<std::string>::const_iterator @@ -1275,8 +1335,8 @@ void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, { // Get languages built in this target. UNORDERED_SET<std::string> languages; - cmTarget::LinkImplementation const* impl = - this->Target->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config); assert(impl); for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); li != impl->Languages.end(); ++li) @@ -1505,20 +1565,22 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string> &result, void processILibs(const std::string& config, cmTarget const* headTarget, cmLinkItem const& item, + cmGlobalGenerator* gg, std::vector<cmTarget const*>& tgts, std::set<cmTarget const*>& emitted) { if (item.Target && emitted.insert(item.Target).second) { tgts.push_back(item.Target); - if(cmTarget::LinkInterfaceLibraries const* iface = - item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) + cmGeneratorTarget* gt = gg->GetGeneratorTarget(item.Target); + if(cmLinkInterfaceLibraries const* iface = + gt->GetLinkInterfaceLibraries(config, headTarget, true)) { for(std::vector<cmLinkItem>::const_iterator it = iface->Libraries.begin(); it != iface->Libraries.end(); ++it) { - processILibs(config, headTarget, *it, tgts, emitted); + processILibs(config, headTarget, *it, gg, tgts, emitted); } } } @@ -1543,7 +1605,9 @@ cmGeneratorTarget::GetLinkImplementationClosure( it = impl->Libraries.begin(); it != impl->Libraries.end(); ++it) { - processILibs(config, this->Target, *it, tgts , emitted); + processILibs(config, this->Target, *it, + this->LocalGenerator->GetGlobalGenerator(), + tgts , emitted); } } return tgts; @@ -1957,13 +2021,536 @@ cmGeneratorTarget::GetCreateRuleVariable(std::string const& lang, } return ""; } +//---------------------------------------------------------------------------- +static void processIncludeDirectories(cmGeneratorTarget const* tgt, + const std::vector<cmGeneratorTarget::TargetPropertyEntry*> &entries, + std::vector<std::string> &includes, + UNORDERED_SET<std::string> &uniqueIncludes, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string& config, bool debugIncludes, + const std::string& language) +{ + cmMakefile *mf = tgt->Target->GetMakefile(); + + for (std::vector<cmGeneratorTarget::TargetPropertyEntry*>::const_iterator + it = entries.begin(), end = entries.end(); it != end; ++it) + { + cmLinkImplItem const& item = (*it)->LinkImplItem; + std::string const& targetName = item; + bool const fromImported = item.Target && item.Target->IsImported(); + bool const checkCMP0027 = item.FromGenex; + std::vector<std::string> entryIncludes; + cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(mf, + config, + false, + tgt->Target, + dagChecker, language), + entryIncludes); + + std::string usedIncludes; + for(std::vector<std::string>::iterator + li = entryIncludes.begin(); li != entryIncludes.end(); ++li) + { + if (fromImported + && !cmSystemTools::FileExists(li->c_str())) + { + std::ostringstream e; + cmake::MessageType messageType = cmake::FATAL_ERROR; + if (checkCMP0027) + { + switch(tgt->Target->GetPolicyStatusCMP0027()) + { + case cmPolicies::WARN: + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n"; + case cmPolicies::OLD: + messageType = cmake::AUTHOR_WARNING; + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + break; + } + } + e << "Imported target \"" << targetName << "\" includes " + "non-existent path\n \"" << *li << "\"\nin its " + "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n" + "* The path was deleted, renamed, or moved to another " + "location.\n" + "* An install or uninstall procedure did not complete " + "successfully.\n" + "* The installation package was faulty and references files it " + "does not provide.\n"; + tgt->GetLocalGenerator()->IssueMessage(messageType, e.str()); + return; + } + + if (!cmSystemTools::FileIsFullPath(li->c_str())) + { + std::ostringstream e; + bool noMessage = false; + cmake::MessageType messageType = cmake::FATAL_ERROR; + if (!targetName.empty()) + { + e << "Target \"" << targetName << "\" contains relative " + "path in its INTERFACE_INCLUDE_DIRECTORIES:\n" + " \"" << *li << "\""; + } + else + { + switch(tgt->Target->GetPolicyStatusCMP0021()) + { + case cmPolicies::WARN: + { + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n"; + messageType = cmake::AUTHOR_WARNING; + } + break; + case cmPolicies::OLD: + noMessage = true; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Issue the fatal message. + break; + } + e << "Found relative path while evaluating include directories of " + "\"" << tgt->GetName() << "\":\n \"" << *li << "\"\n"; + } + if (!noMessage) + { + tgt->GetLocalGenerator()->IssueMessage(messageType, e.str()); + if (messageType == cmake::FATAL_ERROR) + { + return; + } + } + } + + if (!cmSystemTools::IsOff(li->c_str())) + { + cmSystemTools::ConvertToUnixSlashes(*li); + } + std::string inc = *li; + + if(uniqueIncludes.insert(inc).second) + { + includes.push_back(inc); + if (debugIncludes) + { + usedIncludes += " * " + inc + "\n"; + } + } + } + if (!usedIncludes.empty()) + { + mf->GetCMakeInstance()->IssueMessage(cmake::LOG, + std::string("Used includes for target ") + + tgt->GetName() + ":\n" + + usedIncludes, (*it)->ge->GetBacktrace()); + } + } +} + + +//---------------------------------------------------------------------------- +static void AddInterfaceEntries( + cmGeneratorTarget const* thisTarget, std::string const& config, + std::string const& prop, + std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries) +{ + if(cmLinkImplementationLibraries const* impl = + thisTarget->Target->GetLinkImplementationLibraries(config)) + { + for (std::vector<cmLinkImplItem>::const_iterator + it = impl->Libraries.begin(), end = impl->Libraries.end(); + it != end; ++it) + { + if(it->Target) + { + std::string genex = + "$<TARGET_PROPERTY:" + *it + "," + prop + ">"; + cmGeneratorExpression ge(it->Backtrace); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); + cge->SetEvaluateForBuildsystem(true); + entries.push_back( + new cmGeneratorTarget::TargetPropertyEntry(cge, *it)); + } + } + } +} //---------------------------------------------------------------------------- std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(const std::string& config, const std::string& lang) const { - return this->Target->GetIncludeDirectories(config, lang); + std::vector<std::string> includes; + UNORDERED_SET<std::string> uniqueIncludes; + + cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), + "INCLUDE_DIRECTORIES", 0, 0); + + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) + { + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugIncludes = !this->DebugIncludesDone + && std::find(debugProperties.begin(), + debugProperties.end(), + "INCLUDE_DIRECTORIES") + != debugProperties.end(); + + if (this->Makefile->IsConfigured()) + { + this->DebugIncludesDone = true; + } + + processIncludeDirectories(this, + this->IncludeDirectoriesEntries, + includes, + uniqueIncludes, + &dagChecker, + config, + debugIncludes, + lang); + + std::vector<cmGeneratorTarget::TargetPropertyEntry*> + linkInterfaceIncludeDirectoriesEntries; + AddInterfaceEntries( + this, config, "INTERFACE_INCLUDE_DIRECTORIES", + linkInterfaceIncludeDirectoriesEntries); + + if(this->Makefile->IsOn("APPLE")) + { + cmLinkImplementationLibraries const* impl = + this->Target->GetLinkImplementationLibraries(config); + for(std::vector<cmLinkImplItem>::const_iterator + it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + std::string libDir = cmSystemTools::CollapseFullPath(*it); + + static cmsys::RegularExpression + frameworkCheck("(.*\\.framework)(/Versions/[^/]+)?/[^/]+$"); + if(!frameworkCheck.find(libDir)) + { + continue; + } + + libDir = frameworkCheck.match(1); + + cmGeneratorExpression ge; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(libDir.c_str()); + linkInterfaceIncludeDirectoriesEntries + .push_back(new cmGeneratorTarget::TargetPropertyEntry(cge)); + } + } + + processIncludeDirectories(this, + linkInterfaceIncludeDirectoriesEntries, + includes, + uniqueIncludes, + &dagChecker, + config, + debugIncludes, + lang); + + cmDeleteAll(linkInterfaceIncludeDirectoriesEntries); + + return includes; +} + +//---------------------------------------------------------------------------- +static void processCompileOptionsInternal(cmGeneratorTarget const* tgt, + const std::vector<cmGeneratorTarget::TargetPropertyEntry*> &entries, + std::vector<std::string> &options, + UNORDERED_SET<std::string> &uniqueOptions, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string& config, bool debugOptions, const char *logName, + std::string const& language) +{ + cmMakefile *mf = tgt->Target->GetMakefile(); + + for (std::vector<cmGeneratorTarget::TargetPropertyEntry*>::const_iterator + it = entries.begin(), end = entries.end(); it != end; ++it) + { + std::vector<std::string> entryOptions; + cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(mf, + config, + false, + tgt->Target, + dagChecker, + language), + entryOptions); + std::string usedOptions; + for(std::vector<std::string>::iterator + li = entryOptions.begin(); li != entryOptions.end(); ++li) + { + std::string const& opt = *li; + + if(uniqueOptions.insert(opt).second) + { + options.push_back(opt); + if (debugOptions) + { + usedOptions += " * " + opt + "\n"; + } + } + } + if (!usedOptions.empty()) + { + mf->GetCMakeInstance()->IssueMessage(cmake::LOG, + std::string("Used compile ") + logName + + std::string(" for target ") + + tgt->GetName() + ":\n" + + usedOptions, (*it)->ge->GetBacktrace()); + } + } +} + +//---------------------------------------------------------------------------- +static void processCompileOptions(cmGeneratorTarget const* tgt, + const std::vector<cmGeneratorTarget::TargetPropertyEntry*> &entries, + std::vector<std::string> &options, + UNORDERED_SET<std::string> &uniqueOptions, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string& config, bool debugOptions, + std::string const& language) +{ + processCompileOptionsInternal(tgt, entries, options, uniqueOptions, + dagChecker, config, debugOptions, "options", + language); +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetCompileOptions(std::vector<std::string> &result, + const std::string& config, + const std::string& language) const +{ + UNORDERED_SET<std::string> uniqueOptions; + + cmGeneratorExpressionDAGChecker dagChecker(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->IsConfigured()) + { + this->DebugCompileOptionsDone = true; + } + + processCompileOptions(this, + this->CompileOptionsEntries, + result, + uniqueOptions, + &dagChecker, + config, + debugOptions, + language); + + std::vector<cmGeneratorTarget::TargetPropertyEntry*> + linkInterfaceCompileOptionsEntries; + + AddInterfaceEntries( + this, config, "INTERFACE_COMPILE_OPTIONS", + linkInterfaceCompileOptionsEntries); + + processCompileOptions(this, + linkInterfaceCompileOptionsEntries, + result, + uniqueOptions, + &dagChecker, + config, + debugOptions, + language); + + cmDeleteAll(linkInterfaceCompileOptionsEntries); +} + +//---------------------------------------------------------------------------- +static void processCompileFeatures(cmGeneratorTarget const* tgt, + const std::vector<cmGeneratorTarget::TargetPropertyEntry*> &entries, + std::vector<std::string> &options, + UNORDERED_SET<std::string> &uniqueOptions, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string& config, bool debugOptions) +{ + processCompileOptionsInternal(tgt, entries, options, uniqueOptions, + dagChecker, config, debugOptions, "features", + std::string()); +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string> &result, + const std::string& config) const +{ + UNORDERED_SET<std::string> uniqueFeatures; + + cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), + "COMPILE_FEATURES", + 0, 0); + + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) + { + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugFeatures = !this->DebugCompileFeaturesDone + && std::find(debugProperties.begin(), + debugProperties.end(), + "COMPILE_FEATURES") + != debugProperties.end(); + + if (this->Makefile->IsConfigured()) + { + this->DebugCompileFeaturesDone = true; + } + + processCompileFeatures(this, + this->CompileFeaturesEntries, + result, + uniqueFeatures, + &dagChecker, + config, + debugFeatures); + + std::vector<cmGeneratorTarget::TargetPropertyEntry*> + linkInterfaceCompileFeaturesEntries; + AddInterfaceEntries( + this, config, "INTERFACE_COMPILE_FEATURES", + linkInterfaceCompileFeaturesEntries); + + processCompileFeatures(this, + linkInterfaceCompileFeaturesEntries, + result, + uniqueFeatures, + &dagChecker, + config, + debugFeatures); + + cmDeleteAll(linkInterfaceCompileFeaturesEntries); +} + +//---------------------------------------------------------------------------- +static void processCompileDefinitions(cmGeneratorTarget const* tgt, + const std::vector<cmGeneratorTarget::TargetPropertyEntry*> &entries, + std::vector<std::string> &options, + UNORDERED_SET<std::string> &uniqueOptions, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string& config, bool debugOptions, + std::string const& language) +{ + processCompileOptionsInternal(tgt, entries, options, uniqueOptions, + dagChecker, config, debugOptions, + "definitions", language); +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetCompileDefinitions(std::vector<std::string> &list, + const std::string& config, + const std::string& language) const +{ + UNORDERED_SET<std::string> uniqueOptions; + + cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), + "COMPILE_DEFINITIONS", 0, 0); + + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) + { + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugDefines = !this->DebugCompileDefinitionsDone + && std::find(debugProperties.begin(), + debugProperties.end(), + "COMPILE_DEFINITIONS") + != debugProperties.end(); + + if (this->Makefile->IsConfigured()) + { + this->DebugCompileDefinitionsDone = true; + } + + processCompileDefinitions(this, + this->CompileDefinitionsEntries, + list, + uniqueOptions, + &dagChecker, + config, + debugDefines, + language); + + std::vector<cmGeneratorTarget::TargetPropertyEntry*> + linkInterfaceCompileDefinitionsEntries; + AddInterfaceEntries( + this, config, "INTERFACE_COMPILE_DEFINITIONS", + linkInterfaceCompileDefinitionsEntries); + if (!config.empty()) + { + std::string configPropName = "COMPILE_DEFINITIONS_" + + cmSystemTools::UpperCase(config); + const char *configProp = this->Target->GetProperty(configPropName); + if (configProp) + { + switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) + { + case cmPolicies::WARN: + { + std::ostringstream e; + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0043); + this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, + e.str()); + } + case cmPolicies::OLD: + { + cmGeneratorExpression ge; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(configProp); + linkInterfaceCompileDefinitionsEntries + .push_back(new cmGeneratorTarget::TargetPropertyEntry(cge)); + } + break; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + break; + } + } + } + + processCompileDefinitions(this, + linkInterfaceCompileDefinitionsEntries, + list, + uniqueOptions, + &dagChecker, + config, + debugDefines, + language); + + cmDeleteAll(linkInterfaceCompileDefinitionsEntries); } //---------------------------------------------------------------------------- @@ -3354,3 +3941,613 @@ cmGeneratorTarget::ReportPropertyOrigin(const std::string &p, this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, areport); } + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, + std::vector<cmLinkItem>& items) const +{ + for(std::vector<std::string>::const_iterator i = names.begin(); + i != names.end(); ++i) + { + std::string name = this->Target->CheckCMP0004(*i); + if(name == this->GetName() || name.empty()) + { + continue; + } + items.push_back(cmLinkItem(name, this->Target->FindTargetToLink(name))); + } +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, + std::string const& value, + std::string const& config, + cmTarget const* headTarget, + bool usage_requirements_only, + std::vector<cmLinkItem>& items, + bool& hadHeadSensitiveCondition) const +{ + cmGeneratorExpression ge; + cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), prop, 0, 0); + // The $<LINK_ONLY> expression may be in a link interface to specify private + // link dependencies that are otherwise excluded from usage requirements. + if(usage_requirements_only) + { + dagChecker.SetTransitivePropertiesOnly(); + } + std::vector<std::string> libs; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); + cmSystemTools::ExpandListArgument(cge->Evaluate( + this->Makefile, + config, + false, + headTarget, + this->Target, &dagChecker), libs); + this->LookupLinkItems(libs, items); + hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); +} + +//---------------------------------------------------------------------------- +cmLinkInterface const* +cmGeneratorTarget::GetLinkInterface(const std::string& config, + cmTarget const* head) const +{ + // Imported targets have their own link interface. + if(this->IsImported()) + { + return this->GetImportLinkInterface(config, head, false); + } + + // Link interfaces are not supported for executables that do not + // export symbols. + if(this->GetType() == cmTarget::EXECUTABLE && + !this->Target->IsExecutableWithExports()) + { + return 0; + } + + // Lookup any existing link interface for this configuration. + cmHeadToLinkInterfaceMap& hm = + this->GetHeadToLinkInterfaceMap(config); + + // If the link interface does not depend on the head target + // then return the one we computed first. + if(!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) + { + return &hm.begin()->second; + } + + cmOptionalLinkInterface& iface = hm[head]; + if(!iface.LibrariesDone) + { + iface.LibrariesDone = true; + this->ComputeLinkInterfaceLibraries( + config, iface, head, false); + } + if(!iface.AllDone) + { + iface.AllDone = true; + if(iface.Exists) + { + this->ComputeLinkInterface(config, iface, head); + } + } + + return iface.Exists? &iface : 0; +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ComputeLinkInterface(const std::string& config, + cmOptionalLinkInterface &iface, + cmTarget const* headTarget) const +{ + if(iface.ExplicitLibraries) + { + if(this->GetType() == cmTarget::SHARED_LIBRARY + || this->GetType() == cmTarget::STATIC_LIBRARY + || this->GetType() == cmTarget::INTERFACE_LIBRARY) + { + // Shared libraries may have runtime implementation dependencies + // on other shared libraries that are not in the interface. + UNORDERED_SET<std::string> emitted; + for(std::vector<cmLinkItem>::const_iterator + li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) + { + emitted.insert(*li); + } + if (this->GetType() != cmTarget::INTERFACE_LIBRARY) + { + cmLinkImplementation const* impl = + this->GetLinkImplementation(config); + for(std::vector<cmLinkImplItem>::const_iterator + li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) + { + if(emitted.insert(*li).second) + { + if(li->Target) + { + // This is a runtime dependency on another shared library. + if(li->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + iface.SharedDeps.push_back(*li); + } + } + else + { + // TODO: Recognize shared library file names. Perhaps this + // should be moved to cmComputeLinkInformation, but that creates + // a chicken-and-egg problem since this list is needed for its + // construction. + } + } + } + } + } + } + else if (this->Target->GetPolicyStatusCMP0022() == cmPolicies::WARN + || this->Target->GetPolicyStatusCMP0022() == cmPolicies::OLD) + { + // The link implementation is the default link interface. + cmLinkImplementationLibraries const* + impl = this->Target->GetLinkImplementationLibrariesInternal(config, + headTarget); + iface.ImplementationIsInterface = true; + iface.WrongConfigLibraries = impl->WrongConfigLibraries; + } + + if(this->Target->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + if(cmLinkImplementation const* impl = + this->GetLinkImplementation(config)) + { + iface.Languages = impl->Languages; + } + } + + if(this->GetType() == cmTarget::STATIC_LIBRARY) + { + // Construct the property name suffix for this configuration. + std::string suffix = "_"; + if(!config.empty()) + { + suffix += cmSystemTools::UpperCase(config); + } + else + { + suffix += "NOCONFIG"; + } + + // How many repetitions are needed if this library has cyclic + // dependencies? + std::string propName = "LINK_INTERFACE_MULTIPLICITY"; + propName += suffix; + if(const char* config_reps = this->GetProperty(propName)) + { + sscanf(config_reps, "%u", &iface.Multiplicity); + } + else if(const char* reps = + this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) + { + sscanf(reps, "%u", &iface.Multiplicity); + } + } +} + +//---------------------------------------------------------------------------- +const cmLinkInterfaceLibraries * +cmGeneratorTarget::GetLinkInterfaceLibraries(const std::string& config, + cmTarget const* head, + bool usage_requirements_only) const +{ + // Imported targets have their own link interface. + if(this->IsImported()) + { + return this->GetImportLinkInterface(config, head, + usage_requirements_only); + } + + // Link interfaces are not supported for executables that do not + // export symbols. + if(this->GetType() == cmTarget::EXECUTABLE && + !this->Target->IsExecutableWithExports()) + { + return 0; + } + + // Lookup any existing link interface for this configuration. + std::string CONFIG = cmSystemTools::UpperCase(config); + cmHeadToLinkInterfaceMap& hm = + (usage_requirements_only ? + this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : + this->GetHeadToLinkInterfaceMap(config)); + + // If the link interface does not depend on the head target + // then return the one we computed first. + if(!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) + { + return &hm.begin()->second; + } + + cmOptionalLinkInterface& iface = hm[head]; + if(!iface.LibrariesDone) + { + iface.LibrariesDone = true; + this->ComputeLinkInterfaceLibraries( + config, iface, head, usage_requirements_only); + } + + return iface.Exists? &iface : 0; +} + +//---------------------------------------------------------------------------- +void +cmGeneratorTarget::ComputeLinkInterfaceLibraries( + const std::string& config, + cmOptionalLinkInterface& iface, + cmTarget const* headTarget, + bool usage_requirements_only) const +{ + // Construct the property name suffix for this configuration. + std::string suffix = "_"; + if(!config.empty()) + { + suffix += cmSystemTools::UpperCase(config); + } + else + { + suffix += "NOCONFIG"; + } + + // An explicit list of interface libraries may be set for shared + // libraries and executables that export symbols. + const char* explicitLibraries = 0; + std::string linkIfaceProp; + if(this->Target->GetPolicyStatusCMP0022() != cmPolicies::OLD && + this->Target->GetPolicyStatusCMP0022() != cmPolicies::WARN) + { + // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES. + linkIfaceProp = "INTERFACE_LINK_LIBRARIES"; + explicitLibraries = this->GetProperty(linkIfaceProp); + } + else if(this->GetType() == cmTarget::SHARED_LIBRARY || + this->Target->IsExecutableWithExports()) + { + // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a + // shared lib or executable. + + // Lookup the per-configuration property. + linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; + linkIfaceProp += suffix; + explicitLibraries = this->GetProperty(linkIfaceProp); + + // If not set, try the generic property. + if(!explicitLibraries) + { + linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; + explicitLibraries = this->GetProperty(linkIfaceProp); + } + } + + if(explicitLibraries && + this->Target->GetPolicyStatusCMP0022() == cmPolicies::WARN && + !this->PolicyWarnedCMP0022) + { + // Compare the explicitly set old link interface properties to the + // preferred new link interface property one and warn if different. + const char* newExplicitLibraries = + this->GetProperty("INTERFACE_LINK_LIBRARIES"); + if (newExplicitLibraries + && strcmp(newExplicitLibraries, explicitLibraries) != 0) + { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" + "Target \"" << this->GetName() << "\" has an " + "INTERFACE_LINK_LIBRARIES property which differs from its " << + linkIfaceProp << " properties." + "\n" + "INTERFACE_LINK_LIBRARIES:\n" + " " << newExplicitLibraries << "\n" << + linkIfaceProp << ":\n" + " " << (explicitLibraries ? explicitLibraries : "(empty)") << "\n"; + this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + this->PolicyWarnedCMP0022 = true; + } + } + + // There is no implicit link interface for executables or modules + // so if none was explicitly set then there is no link interface. + if(!explicitLibraries && + (this->GetType() == cmTarget::EXECUTABLE || + (this->GetType() == cmTarget::MODULE_LIBRARY))) + { + return; + } + iface.Exists = true; + iface.ExplicitLibraries = explicitLibraries; + + if(explicitLibraries) + { + // The interface libraries have been explicitly set. + this->ExpandLinkItems(linkIfaceProp, explicitLibraries, + config, + headTarget, usage_requirements_only, + iface.Libraries, + iface.HadHeadSensitiveCondition); + } + else if (this->Target->GetPolicyStatusCMP0022() == cmPolicies::WARN + || this->Target->GetPolicyStatusCMP0022() == cmPolicies::OLD) + // If CMP0022 is NEW then the plain tll signature sets the + // INTERFACE_LINK_LIBRARIES, so if we get here then the project + // cleared the property explicitly and we should not fall back + // to the link implementation. + { + // The link implementation is the default link interface. + cmLinkImplementationLibraries const* impl = + this->Target->GetLinkImplementationLibrariesInternal(config, + headTarget); + iface.Libraries.insert(iface.Libraries.end(), + impl->Libraries.begin(), impl->Libraries.end()); + if(this->Target->GetPolicyStatusCMP0022() == cmPolicies::WARN && + !this->PolicyWarnedCMP0022 && !usage_requirements_only) + { + // Compare the link implementation fallback link interface to the + // preferred new link interface property and warn if different. + std::vector<cmLinkItem> ifaceLibs; + static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; + if(const char* newExplicitLibraries = this->GetProperty(newProp)) + { + bool hadHeadSensitiveConditionDummy = false; + this->ExpandLinkItems(newProp, newExplicitLibraries, config, + headTarget, usage_requirements_only, + ifaceLibs, hadHeadSensitiveConditionDummy); + } + if (ifaceLibs != iface.Libraries) + { + std::string oldLibraries = cmJoin(impl->Libraries, ";"); + std::string newLibraries = cmJoin(ifaceLibs, ";"); + if(oldLibraries.empty()) + { oldLibraries = "(empty)"; } + if(newLibraries.empty()) + { newLibraries = "(empty)"; } + + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" + "Target \"" << this->GetName() << "\" has an " + "INTERFACE_LINK_LIBRARIES property. " + "This should be preferred as the source of the link interface " + "for this library but because CMP0022 is not set CMake is " + "ignoring the property and using the link implementation " + "as the link interface instead." + "\n" + "INTERFACE_LINK_LIBRARIES:\n" + " " << newLibraries << "\n" + "Link implementation:\n" + " " << oldLibraries << "\n"; + this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + this->PolicyWarnedCMP0022 = true; + } + } + } +} + +//---------------------------------------------------------------------------- +const cmLinkInterface * +cmGeneratorTarget::GetImportLinkInterface(const std::string& config, + cmTarget const* headTarget, + bool usage_requirements_only) const +{ + cmTarget::ImportInfo const* info = this->Target->GetImportInfo(config); + if(!info) + { + return 0; + } + + std::string CONFIG = cmSystemTools::UpperCase(config); + cmHeadToLinkInterfaceMap& hm = + (usage_requirements_only ? + this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : + this->GetHeadToLinkInterfaceMap(config)); + + // If the link interface does not depend on the head target + // then return the one we computed first. + if(!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) + { + return &hm.begin()->second; + } + + cmOptionalLinkInterface& iface = hm[headTarget]; + if(!iface.AllDone) + { + iface.AllDone = true; + iface.Multiplicity = info->Multiplicity; + cmSystemTools::ExpandListArgument(info->Languages, iface.Languages); + this->ExpandLinkItems(info->LibrariesProp, info->Libraries, + config, + headTarget, usage_requirements_only, + iface.Libraries, + iface.HadHeadSensitiveCondition); + std::vector<std::string> deps; + cmSystemTools::ExpandListArgument(info->SharedDeps, deps); + this->LookupLinkItems(deps, iface.SharedDeps); + } + + return &iface; +} + +cmHeadToLinkInterfaceMap& +cmGeneratorTarget::GetHeadToLinkInterfaceMap(const std::string &config) const +{ + std::string CONFIG = cmSystemTools::UpperCase(config); + return this->LinkInterfaceMap[CONFIG]; +} + +cmHeadToLinkInterfaceMap& +cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( + const std::string &config) const +{ + std::string CONFIG = cmSystemTools::UpperCase(config); + return this->LinkInterfaceUsageRequirementsOnlyMap[CONFIG]; +} + +//---------------------------------------------------------------------------- +const cmLinkImplementation * +cmGeneratorTarget::GetLinkImplementation(const std::string& config) const +{ + // There is no link implementation for imported targets. + if(this->Target->IsImported()) + { + return 0; + } + + cmOptionalLinkImplementation& impl = this->Target->GetLinkImplMap(config); + if(!impl.LibrariesDone) + { + impl.LibrariesDone = true; + this->Target->ComputeLinkImplementationLibraries(config, impl, + this->Target); + } + if(!impl.LanguagesDone) + { + impl.LanguagesDone = true; + this->ComputeLinkImplementationLanguages(config, impl); + } + return &impl; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::GetConfigCommonSourceFiles( + std::vector<cmSourceFile*>& files) const +{ + std::vector<std::string> configs; + this->Makefile->GetConfigurations(configs); + if (configs.empty()) + { + configs.push_back(""); + } + + std::vector<std::string>::const_iterator it = configs.begin(); + const std::string& firstConfig = *it; + this->Target->GetSourceFiles(files, firstConfig); + + for ( ; it != configs.end(); ++it) + { + std::vector<cmSourceFile*> configFiles; + this->Target->GetSourceFiles(configFiles, *it); + if (configFiles != files) + { + std::string firstConfigFiles; + const char* sep = ""; + for (std::vector<cmSourceFile*>::const_iterator fi = files.begin(); + fi != files.end(); ++fi) + { + firstConfigFiles += sep; + firstConfigFiles += (*fi)->GetFullPath(); + sep = "\n "; + } + + std::string thisConfigFiles; + sep = ""; + for (std::vector<cmSourceFile*>::const_iterator fi = configFiles.begin(); + fi != configFiles.end(); ++fi) + { + thisConfigFiles += sep; + thisConfigFiles += (*fi)->GetFullPath(); + sep = "\n "; + } + std::ostringstream e; + e << "Target \"" << this->GetName() + << "\" has source files which vary by " + "configuration. This is not supported by the \"" + << this->GlobalGenerator->GetName() + << "\" generator.\n" + "Config \"" << firstConfig << "\":\n" + " " << firstConfigFiles << "\n" + "Config \"" << *it << "\":\n" + " " << thisConfigFiles << "\n"; + this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + } + return true; +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages, + const std::string& config) const +{ + std::vector<cmSourceFile*> sourceFiles; + this->GetSourceFiles(sourceFiles, config); + for(std::vector<cmSourceFile*>::const_iterator + i = sourceFiles.begin(); i != sourceFiles.end(); ++i) + { + const std::string& lang = (*i)->GetLanguage(); + if(!lang.empty()) + { + languages.insert(lang); + } + } + + std::vector<cmGeneratorTarget*> objectLibraries; + std::vector<cmSourceFile const*> externalObjects; + if (!this->Makefile->IsConfigured()) + { + std::vector<cmTarget*> objectTargets; + this->Target->GetObjectLibrariesCMP0026(objectTargets); + objectLibraries.reserve(objectTargets.size()); + for (std::vector<cmTarget*>::const_iterator it = objectTargets.begin(); + it != objectTargets.end(); ++it) + { + objectLibraries.push_back(this->GlobalGenerator + ->GetGeneratorTarget(*it)); + } + } + else + { + this->GetExternalObjects(externalObjects, config); + for(std::vector<cmSourceFile const*>::const_iterator + i = externalObjects.begin(); i != externalObjects.end(); ++i) + { + std::string objLib = (*i)->GetObjectLibrary(); + if (cmTarget* tgt = this->Makefile->FindTargetToUse(objLib)) + { + objectLibraries.push_back(this->GlobalGenerator + ->GetGeneratorTarget(tgt)); + } + } + } + for(std::vector<cmGeneratorTarget*>::const_iterator + i = objectLibraries.begin(); i != objectLibraries.end(); ++i) + { + (*i)->GetLanguages(languages, config); + } +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ComputeLinkImplementationLanguages( + const std::string& config, + cmOptionalLinkImplementation& impl) const +{ + // This target needs runtime libraries for its source languages. + std::set<std::string> languages; + // Get languages used in our source files. + this->GetLanguages(languages, config); + // Copy the set of langauges to the link implementation. + impl.Languages.insert(impl.Languages.begin(), + languages.begin(), languages.end()); +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const +{ + if (this->Target->GetPropertyAsBool("SKIP_BUILD_RPATH")) + { + return false; + } + if(cmLinkImplementationLibraries const* impl = + this->Target->GetLinkImplementationLibraries(config)) + { + return !impl->Libraries.empty(); + } + return false; +} |