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