diff options
author | Marc Chevrier <marc.chevrier@gmail.com> | 2019-12-13 21:55:00 (GMT) |
---|---|---|
committer | Marc Chevrier <marc.chevrier@gmail.com> | 2020-02-26 15:38:42 (GMT) |
commit | 461efa7b51f5d63ab5e366af3a615a469ac0e65f (patch) | |
tree | d703f0e23d718fe225b70fffd09e028576c4d4e9 /Source | |
parent | 54d1268ed466c68845e01d28fc17f162f384ac39 (diff) | |
download | CMake-461efa7b51f5d63ab5e366af3a615a469ac0e65f.zip CMake-461efa7b51f5d63ab5e366af3a615a469ac0e65f.tar.gz CMake-461efa7b51f5d63ab5e366af3a615a469ac0e65f.tar.bz2 |
Genex: Add $<LINK_LANGUAGE:...> and $<LINK_LANG_AND_ID:...>
This MR may help to solve issues #19757 and #18008
Fixes: #19965
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmGeneratorExpression.cxx | 3 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.h | 5 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionContext.cxx | 1 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionContext.h | 1 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionDAGChecker.cxx | 34 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionDAGChecker.h | 1 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionNode.cxx | 149 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 164 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 27 | ||||
-rw-r--r-- | Source/cmLinkItem.h | 6 |
10 files changed, 344 insertions, 47 deletions
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 81d1e46..03c2a0c 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -103,6 +103,8 @@ const std::string& cmCompiledGeneratorExpression::EvaluateWithContext( if (!context.HadError) { this->HadContextSensitiveCondition = context.HadContextSensitiveCondition; this->HadHeadSensitiveCondition = context.HadHeadSensitiveCondition; + this->HadLinkLanguageSensitiveCondition = + context.HadLinkLanguageSensitiveCondition; this->SourceSensitiveTargets = context.SourceSensitiveTargets; } @@ -119,6 +121,7 @@ cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( , Quiet(false) , HadContextSensitiveCondition(false) , HadHeadSensitiveCondition(false) + , HadLinkLanguageSensitiveCondition(false) { cmGeneratorExpressionLexer l; std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input); diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index c4be3a1..a0e40c3 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -137,6 +137,10 @@ public: { return this->HadHeadSensitiveCondition; } + bool GetHadLinkLanguageSensitiveCondition() const + { + return this->HadLinkLanguageSensitiveCondition; + } std::set<cmGeneratorTarget const*> GetSourceSensitiveTargets() const { return this->SourceSensitiveTargets; @@ -178,6 +182,7 @@ private: mutable std::string Output; mutable bool HadContextSensitiveCondition; mutable bool HadHeadSensitiveCondition; + mutable bool HadLinkLanguageSensitiveCondition; mutable std::set<cmGeneratorTarget const*> SourceSensitiveTargets; }; diff --git a/Source/cmGeneratorExpressionContext.cxx b/Source/cmGeneratorExpressionContext.cxx index 6d97331..42cbe2a 100644 --- a/Source/cmGeneratorExpressionContext.cxx +++ b/Source/cmGeneratorExpressionContext.cxx @@ -19,6 +19,7 @@ cmGeneratorExpressionContext::cmGeneratorExpressionContext( , HadError(false) , HadContextSensitiveCondition(false) , HadHeadSensitiveCondition(false) + , HadLinkLanguageSensitiveCondition(false) , EvaluateForBuildsystem(evaluateForBuildsystem) { } diff --git a/Source/cmGeneratorExpressionContext.h b/Source/cmGeneratorExpressionContext.h index 4709fa0..bceff12 100644 --- a/Source/cmGeneratorExpressionContext.h +++ b/Source/cmGeneratorExpressionContext.h @@ -40,6 +40,7 @@ struct cmGeneratorExpressionContext bool HadError; bool HadContextSensitiveCondition; bool HadHeadSensitiveCondition; + bool HadLinkLanguageSensitiveCondition; bool EvaluateForBuildsystem; }; diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 643ba34..2c73289 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -6,6 +6,10 @@ #include <sstream> #include <utility> +#include <cm/string_view> + +#include "cm_static_string_view.hxx" + #include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorTarget.h" @@ -170,6 +174,21 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() return top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; } +bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() +{ + const cmGeneratorExpressionDAGChecker* top = this; + const cmGeneratorExpressionDAGChecker* parent = this->Parent; + while (parent) { + top = parent; + parent = parent->Parent; + } + + cm::string_view property(top->Property); + + return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || + property == "LINK_DEPENDS"_s; +} + bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( cmGeneratorTarget const* tgt) { @@ -180,18 +199,17 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( parent = parent->Parent; } - const char* prop = top->Property.c_str(); + cm::string_view prop(top->Property); if (tgt) { - return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0; + return top->Target == tgt && prop == "LINK_LIBRARIES"_s; } - return (strcmp(prop, "LINK_LIBRARIES") == 0 || - strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0 || - strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 || - cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") || - cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_")) || - strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0; + return prop == "LINK_LIBRARIES"_s || prop == "LINK_INTERFACE_LIBRARIES"_s || + prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s || + cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") || + cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_") || + prop == "INTERFACE_LINK_LIBRARIES"_s; } cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index f2c49bb..2a06596 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -68,6 +68,7 @@ struct cmGeneratorExpressionDAGChecker bool EvaluatingGenexExpression(); bool EvaluatingPICExpression(); + bool EvaluatingLinkExpression(); bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr); #define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 14478c2..8831d0f 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -62,6 +62,9 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression( if (cge->GetHadHeadSensitiveCondition()) { context->HadHeadSensitiveCondition = true; } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + context->HadLinkLanguageSensitiveCondition = true; + } return result; } @@ -1039,6 +1042,150 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode } } languageAndIdNode; +static const struct LinkLanguageNode : public cmGeneratorExpressionNode +{ + LinkLanguageNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return ZeroOrMoreParameters; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + if (!context->HeadTarget || !dagChecker || + !(dagChecker->EvaluatingLinkExpression() || + dagChecker->EvaluatingLinkLibraries())) { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE:...> may only be used with binary targets " + "to specify link libraries, link directories, link options " + "and link depends."); + return std::string(); + } + if (dagChecker->EvaluatingLinkLibraries() && parameters.empty()) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE> is not supported in link libraries expression."); + return std::string(); + } + + cmGlobalGenerator* gg = context->LG->GetGlobalGenerator(); + std::string genName = gg->GetName(); + if (genName.find("Makefiles") == std::string::npos && + genName.find("Ninja") == std::string::npos && + genName.find("Visual Studio") == std::string::npos && + genName.find("Xcode") == std::string::npos && + genName.find("Watcom WMake") == std::string::npos) { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE:...> not supported for this generator."); + return std::string(); + } + + if (dagChecker->EvaluatingLinkLibraries()) { + context->HadHeadSensitiveCondition = true; + context->HadLinkLanguageSensitiveCondition = true; + } + + if (parameters.empty()) { + return context->Language; + } + + for (auto& param : parameters) { + if (context->Language == param) { + return "1"; + } + } + return "0"; + } +} linkLanguageNode; + +namespace { +struct LinkerId +{ + static std::string Evaluate(const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + const std::string& lang) + { + std::string const& linkerId = + context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang + + "_COMPILER_ID"); + if (parameters.empty()) { + return linkerId; + } + if (linkerId.empty()) { + return parameters.front().empty() ? "1" : "0"; + } + static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$"); + + for (auto& param : parameters) { + if (!linkerIdValidator.find(param)) { + reportError(context, content->GetOriginalExpression(), + "Expression syntax not recognized."); + return std::string(); + } + + if (param == linkerId) { + return "1"; + } + } + return "0"; + } +}; +} + +static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode +{ + LinkLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return TwoOrMoreParameters; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + if (!context->HeadTarget || !dagChecker || + !(dagChecker->EvaluatingLinkExpression() || + dagChecker->EvaluatingLinkLibraries())) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets " + "to specify link libraries, link directories, link options, and link " + "depends."); + return std::string(); + } + + cmGlobalGenerator* gg = context->LG->GetGlobalGenerator(); + std::string genName = gg->GetName(); + if (genName.find("Makefiles") == std::string::npos && + genName.find("Ninja") == std::string::npos && + genName.find("Visual Studio") == std::string::npos && + genName.find("Xcode") == std::string::npos && + genName.find("Watcom WMake") == std::string::npos) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LANG_AND_ID:lang,id> not supported for this generator."); + return std::string(); + } + + if (dagChecker->EvaluatingLinkLibraries()) { + context->HadHeadSensitiveCondition = true; + context->HadLinkLanguageSensitiveCondition = true; + } + + const std::string& lang = context->Language; + if (lang == parameters.front()) { + std::vector<std::string> idParameter((parameters.cbegin() + 1), + parameters.cend()); + return LinkerId::Evaluate(idParameter, context, content, lang); + } + return "0"; + } +} linkLanguageAndIdNode; + std::string getLinkedTargetsContent( cmGeneratorTarget const* target, std::string const& prop, cmGeneratorExpressionContext* context, @@ -2314,6 +2461,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "LINK_ONLY", &linkOnlyNode }, { "COMPILE_LANG_AND_ID", &languageAndIdNode }, { "COMPILE_LANGUAGE", &languageNode }, + { "LINK_LANG_AND_ID", &linkLanguageAndIdNode }, + { "LINK_LANGUAGE", &linkLanguageNode }, { "SHELL_PATH", &shellPathNode } }; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 5ef882c..95b1c54 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -17,6 +17,7 @@ #include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> #include "cmsys/RegularExpression.hxx" @@ -307,6 +308,13 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->PolicyMap = t->GetPolicyMap(); + + // Get hard-coded linker language + if (this->Target->GetProperty("HAS_CXX")) { + this->LinkerLanguage = "CXX"; + } else { + this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE"); + } } cmGeneratorTarget::~cmGeneratorTarget() = default; @@ -2222,11 +2230,12 @@ public: cmTargetCollectLinkLanguages(cmGeneratorTarget const* target, std::string config, std::unordered_set<std::string>& languages, - cmGeneratorTarget const* head) + cmGeneratorTarget const* head, bool secondPass) : Config(std::move(config)) , Languages(languages) , HeadTarget(head) , Target(target) + , SecondPass(secondPass) { this->Visited.insert(target); } @@ -2268,11 +2277,14 @@ public: if (!this->Visited.insert(item.Target).second) { return; } - cmLinkInterface const* iface = - item.Target->GetLinkInterface(this->Config, this->HeadTarget); + cmLinkInterface const* iface = item.Target->GetLinkInterface( + this->Config, this->HeadTarget, this->SecondPass); if (!iface) { return; } + if (iface->HadLinkLanguageSensitiveCondition) { + this->HadLinkLanguageSensitiveCondition = true; + } for (std::string const& language : iface->Languages) { this->Languages.insert(language); @@ -2283,12 +2295,19 @@ public: } } + bool GetHadLinkLanguageSensitiveCondition() + { + return HadLinkLanguageSensitiveCondition; + } + private: std::string Config; std::unordered_set<std::string>& Languages; cmGeneratorTarget const* HeadTarget; const cmGeneratorTarget* Target; std::set<cmGeneratorTarget const*> Visited; + bool SecondPass; + bool HadLinkLanguageSensitiveCondition = false; }; cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure( @@ -2319,7 +2338,7 @@ public: { this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator(); } - void Consider(const char* lang) + void Consider(const std::string& lang) { int preference = this->GG->GetLinkerPreference(lang); if (preference > this->Preference) { @@ -2352,40 +2371,36 @@ public: } }; -void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, - LinkClosure& lc) const +bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc, + bool secondPass) const { // Get languages built in this target. std::unordered_set<std::string> languages; - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, secondPass); assert(impl); - for (std::string const& li : impl->Languages) { - languages.insert(li); - } + languages.insert(impl->Languages.cbegin(), impl->Languages.cend()); // Add interface languages from linked targets. - cmTargetCollectLinkLanguages cll(this, config, languages, this); + // cmTargetCollectLinkLanguages cll(this, config, languages, this, + // secondPass); + cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { cll.Visit(lib); } // Store the transitive closure of languages. - for (std::string const& lang : languages) { - lc.Languages.push_back(lang); - } + cm::append(lc.Languages, languages); // Choose the language whose linker should be used. - if (this->GetProperty("HAS_CXX")) { - lc.LinkerLanguage = "CXX"; - } else if (const char* linkerLang = this->GetProperty("LINKER_LANGUAGE")) { - lc.LinkerLanguage = linkerLang; - } else { + if (secondPass || lc.LinkerLanguage.empty()) { // Find the language with the highest preference value. cmTargetSelectLinker tsl(this); // First select from the languages compiled directly in this target. for (std::string const& l : impl->Languages) { - tsl.Consider(l.c_str()); + tsl.Consider(l); } // Now consider languages that propagate from linked targets. @@ -2393,12 +2408,50 @@ void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, std::string propagates = "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES"; if (this->Makefile->IsOn(propagates)) { - tsl.Consider(lang.c_str()); + tsl.Consider(lang); } } lc.LinkerLanguage = tsl.Choose(); } + + return impl->HadLinkLanguageSensitiveCondition || + cll.GetHadLinkLanguageSensitiveCondition(); +} + +void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc) const +{ + bool secondPass = false; + + { + LinkClosure linkClosure; + linkClosure.LinkerLanguage = this->LinkerLanguage; + + // Get languages built in this target. + secondPass = this->ComputeLinkClosure(config, linkClosure, false); + this->LinkerLanguage = linkClosure.LinkerLanguage; + if (!secondPass) { + lc = std::move(linkClosure); + } + } + + if (secondPass) { + LinkClosure linkClosure; + + this->ComputeLinkClosure(config, linkClosure, secondPass); + lc = std::move(linkClosure); + + // linker language must not be changed between the two passes + if (this->LinkerLanguage != lc.LinkerLanguage) { + std::ostringstream e; + e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> " + "changes\nthe linker language for target \"" + << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '" + << lc.LinkerLanguage << "') which is invalid."; + cmSystemTools::Error(e.str()); + } + } } void cmGeneratorTarget::GetFullNameComponents( @@ -5479,7 +5532,8 @@ void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, void cmGeneratorTarget::ExpandLinkItems( std::string const& prop, std::string const& value, std::string const& config, cmGeneratorTarget const* headTarget, bool usage_requirements_only, - std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const + std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition, + bool& hadLinkLanguageSensitiveCondition) const { // Keep this logic in sync with ComputeLinkImplementationLibraries. cmGeneratorExpression ge; @@ -5491,19 +5545,28 @@ void cmGeneratorTarget::ExpandLinkItems( } std::vector<std::string> libs; std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - cmExpandList( - cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker, this), - libs); + cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget, + &dagChecker, this, headTarget->LinkerLanguage), + libs); this->LookupLinkItems(libs, cge->GetBacktrace(), items); hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); + hadLinkLanguageSensitiveCondition = + cge->GetHadLinkLanguageSensitiveCondition(); } cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( const std::string& config, cmGeneratorTarget const* head) const { + return this->GetLinkInterface(config, head, false); +} + +cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( + const std::string& config, cmGeneratorTarget const* head, + bool secondPass) const +{ // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, false); + return this->GetImportLinkInterface(config, head, false, secondPass); } // Link interfaces are not supported for executables that do not @@ -5516,6 +5579,10 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config); + if (secondPass) { + hm.erase(head); + } + // 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) { @@ -5530,7 +5597,7 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( if (!iface.AllDone) { iface.AllDone = true; if (iface.Exists) { - this->ComputeLinkInterface(config, iface, head); + this->ComputeLinkInterface(config, iface, head, secondPass); } } @@ -5541,6 +5608,13 @@ void cmGeneratorTarget::ComputeLinkInterface( const std::string& config, cmOptionalLinkInterface& iface, cmGeneratorTarget const* headTarget) const { + this->ComputeLinkInterface(config, iface, headTarget, false); +} + +void cmGeneratorTarget::ComputeLinkInterface( + const std::string& config, cmOptionalLinkInterface& iface, + cmGeneratorTarget const* headTarget, bool secondPass) const +{ if (iface.Explicit) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -5552,7 +5626,8 @@ void cmGeneratorTarget::ComputeLinkInterface( emitted.insert(lib); } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { if (emitted.insert(lib).second) { if (lib.Target) { @@ -5582,7 +5657,7 @@ void cmGeneratorTarget::ComputeLinkInterface( if (this->LinkLanguagePropagatesToDependents()) { // Targets using this archive need its language runtime libraries. if (cmLinkImplementation const* impl = - this->GetLinkImplementation(config)) { + this->GetLinkImplementation(config, secondPass)) { iface.Languages = impl->Languages; } } @@ -5978,7 +6053,8 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // The interface libraries have been explicitly set. this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, headTarget, usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + iface.HadHeadSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); } else if (!cmp0022NEW) // If CMP0022 is NEW then the plain tll signature sets the // INTERFACE_LINK_LIBRARIES, so if we get here then the project @@ -5998,9 +6074,11 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; if (const char* newExplicitLibraries = this->GetProperty(newProp)) { bool hadHeadSensitiveConditionDummy = false; + bool hadLinkLanguageSensitiveConditionDummy = false; this->ExpandLinkItems(newProp, newExplicitLibraries, config, headTarget, usage_requirements_only, ifaceLibs, - hadHeadSensitiveConditionDummy); + hadHeadSensitiveConditionDummy, + hadLinkLanguageSensitiveConditionDummy); } if (ifaceLibs != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); @@ -6037,7 +6115,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( const std::string& config, cmGeneratorTarget const* headTarget, - bool usage_requirements_only) const + bool usage_requirements_only, bool secondPass) const { cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config); if (!info) { @@ -6050,6 +6128,10 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); + if (secondPass) { + hm.erase(headTarget); + } + // 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) { @@ -6063,7 +6145,8 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( cmExpandList(info->Languages, iface.Languages); this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, headTarget, usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + iface.HadHeadSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps); } @@ -6268,6 +6351,12 @@ cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( const std::string& config) const { + return this->GetLinkImplementation(config, false); +} + +const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( + const std::string& config, bool secondPass) const +{ // There is no link implementation for imported targets. if (this->IsImported()) { return nullptr; @@ -6275,6 +6364,9 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( std::string CONFIG = cmSystemTools::UpperCase(config); cmOptionalLinkImplementation& impl = this->LinkImplMap[CONFIG][this]; + if (secondPass) { + impl = cmOptionalLinkImplementation(); + } if (!impl.LibrariesDone) { impl.LibrariesDone = true; this->ComputeLinkImplementationLibraries(config, impl, this); @@ -6572,11 +6664,15 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cmGeneratorExpression ge(*btIt); std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le); std::string const& evaluated = - cge->Evaluate(this->LocalGenerator, config, head, &dagChecker); + cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, + this->LinkerLanguage); cmExpandList(evaluated, llibs); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + impl.HadLinkLanguageSensitiveCondition = true; + } for (std::string const& lib : llibs) { if (this->IsLinkLookupScope(lib, lg)) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index d81bb3d..9f90cec 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -357,7 +357,6 @@ public: }; LinkClosure const* GetLinkClosure(const std::string& config) const; - void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; cmLinkImplementation const* GetLinkImplementation( const std::string& config) const; @@ -816,6 +815,7 @@ private: std::string& outPrefix, std::string& outBase, std::string& outSuffix) const; + mutable std::string LinkerLanguage; using LinkClosureMapType = std::map<std::string, LinkClosure>; mutable LinkClosureMapType LinkClosureMap; @@ -850,6 +850,10 @@ private: void CheckPropertyCompatibility(cmComputeLinkInformation& info, const std::string& config) const; + void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; + bool ComputeLinkClosure(const std::string& config, LinkClosure& lc, + bool secondPass) const; + struct LinkImplClosure : public std::vector<cmGeneratorTarget const*> { bool Done = false; @@ -868,6 +872,17 @@ private: std::string GetLinkInterfaceDependentStringAsBoolProperty( const std::string& p, const std::string& config) const; + friend class cmTargetCollectLinkLanguages; + cmLinkInterface const* GetLinkInterface(const std::string& config, + const cmGeneratorTarget* headTarget, + bool secondPass) const; + void ComputeLinkInterface(const std::string& config, + cmOptionalLinkInterface& iface, + const cmGeneratorTarget* head, + bool secondPass) const; + cmLinkImplementation const* GetLinkImplementation(const std::string& config, + bool secondPass) const; + // Cache import information from properties for each configuration. struct ImportInfo { @@ -894,9 +909,10 @@ private: the link dependencies of this target. */ std::string CheckCMP0004(std::string const& item) const; - cmLinkInterface const* GetImportLinkInterface( - const std::string& config, const cmGeneratorTarget* head, - bool usage_requirements_only) const; + cmLinkInterface const* GetImportLinkInterface(const std::string& config, + const cmGeneratorTarget* head, + bool usage_requirements_only, + bool secondPass = false) const; using KindedSourcesMapType = std::map<std::string, KindedSources>; mutable KindedSourcesMapType KindedSourcesMap; @@ -940,7 +956,8 @@ private: const cmGeneratorTarget* headTarget, bool usage_requirements_only, std::vector<cmLinkItem>& items, - bool& hadHeadSensitiveCondition) const; + bool& hadHeadSensitiveCondition, + bool& hadLinkLanguageSensitiveCondition) const; void LookupLinkItems(std::vector<std::string> const& names, cmListFileBacktrace const& bt, std::vector<cmLinkItem>& items) const; diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 0ea25c0..ae87e45 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -81,6 +81,9 @@ struct cmLinkInterface : public cmLinkInterfaceLibraries std::vector<cmLinkItem> WrongConfigLibraries; bool ImplementationIsInterface = false; + + // Whether the list depends on a link language genex. + bool HadLinkLanguageSensitiveCondition = false; }; struct cmOptionalLinkInterface : public cmLinkInterface @@ -100,6 +103,9 @@ struct cmLinkImplementation : public cmLinkImplementationLibraries { // Languages whose runtime libraries must be linked. std::vector<std::string> Languages; + + // Whether the list depends on a link language genex. + bool HadLinkLanguageSensitiveCondition = false; }; // Cache link implementation computation from each configuration. |