Genex: Add $<LINK_LANGUAGE:...> and $<LINK_LANG_AND_ID:...>

This MR may help to solve issues #19757 and #18008

Fixes: #19965
This commit is contained in:
Marc Chevrier
2019-12-13 22:55:00 +01:00
parent 54d1268ed4
commit 461efa7b51
182 changed files with 1619 additions and 55 deletions

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -19,6 +19,7 @@ cmGeneratorExpressionContext::cmGeneratorExpressionContext(
, HadError(false)
, HadContextSensitiveCondition(false)
, HadHeadSensitiveCondition(false)
, HadLinkLanguageSensitiveCondition(false)
, EvaluateForBuildsystem(evaluateForBuildsystem)
{
}

View File

@@ -40,6 +40,7 @@ struct cmGeneratorExpressionContext
bool HadError;
bool HadContextSensitiveCondition;
bool HadHeadSensitiveCondition;
bool HadLinkLanguageSensitiveCondition;
bool EvaluateForBuildsystem;
};

View File

@@ -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

View File

@@ -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;

View File

@@ -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 }
};

View File

@@ -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);
}
}
@@ -5540,6 +5607,13 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
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 ||
@@ -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);
}
@@ -6267,6 +6350,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()) {
@@ -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)) {

View File

@@ -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;

View File

@@ -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.