mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 13:51:33 -06:00
Merge topic 'Genex-LINK_LANGUAGE'
461efa7b51 Genex: Add $<LINK_LANGUAGE:...> and $<LINK_LANG_AND_ID:...>
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4244
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <cm/memory>
|
||||
#include <cm/string_view>
|
||||
#include <cmext/algorithm>
|
||||
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
@@ -308,6 +309,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;
|
||||
@@ -2223,11 +2231,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);
|
||||
}
|
||||
@@ -2269,11 +2278,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);
|
||||
@@ -2284,12 +2296,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(
|
||||
@@ -2320,7 +2339,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) {
|
||||
@@ -2353,40 +2372,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.
|
||||
@@ -2394,12 +2409,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(
|
||||
@@ -5492,7 +5545,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;
|
||||
@@ -5504,19 +5558,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
|
||||
@@ -5529,6 +5592,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) {
|
||||
@@ -5543,7 +5610,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5553,6 +5620,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 ||
|
||||
@@ -5565,7 +5639,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) {
|
||||
@@ -5595,7 +5670,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;
|
||||
}
|
||||
}
|
||||
@@ -5991,7 +6066,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
|
||||
@@ -6011,9 +6087,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, ";");
|
||||
@@ -6050,7 +6128,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) {
|
||||
@@ -6063,6 +6141,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) {
|
||||
@@ -6076,7 +6158,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);
|
||||
}
|
||||
@@ -6280,6 +6363,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()) {
|
||||
@@ -6288,6 +6377,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);
|
||||
@@ -6585,11 +6677,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)) {
|
||||
|
||||
Reference in New Issue
Block a user