mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
LINK_LIBRARIES: Evaluate separately for linking and usage requirements
We evaluate `LINK_LIBRARIES` and `INTERFACE_LINK_LIBRARIES` for two purposes: * Constructing the link line. * Collecting usage requirements. We evaluate `INTERFACE_LINK_LIBRARIES` separately for each purpose in order to support the `$<LINK_ONLY:...>` generator expression used to express private link dependencies of a static library. Previously we only evaluated `LINK_LIBRARIES` for linking, and used that result for collecting usage requirements too. Therefore `$<LINK_ONLY:...>` does not work in `LINK_LIBRARIES`. With the introduction of `INTERFACE_LINK_LIBRARIES_DIRECT`, evaluation of `LINK_LIBRARIES` now needs to distinguish these two cases in order to honor link dependencies encountered through `$<LINK_ONLY:...>` without also exposing other usage requirements through private dependencies of a static library. Revise internal infrastructure to distinguish the two cases when evaluating `LINK_LIBRARIES`. Make the information available in code paths for `INTERFACE_LINK_LIBRARIES_DIRECT` and `LINK_ONLY`. Defer actually using the information to later commits. Issue: #22496
This commit is contained in:
@@ -677,8 +677,8 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
|
||||
void cmComputeLinkDepends::AddDirectLinkEntries()
|
||||
{
|
||||
// Add direct link dependencies in this configuration.
|
||||
cmLinkImplementation const* impl =
|
||||
this->Target->GetLinkImplementation(this->Config);
|
||||
cmLinkImplementation const* impl = this->Target->GetLinkImplementation(
|
||||
this->Config, cmGeneratorTarget::LinkInterfaceFor::Link);
|
||||
this->AddLinkEntries(-1, impl->Libraries);
|
||||
this->AddLinkObjects(impl->Objects);
|
||||
|
||||
|
||||
@@ -218,8 +218,8 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
|
||||
emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
|
||||
emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
|
||||
|
||||
if (cmLinkImplementation const* impl =
|
||||
depender->GetLinkImplementation(it)) {
|
||||
if (cmLinkImplementation const* impl = depender->GetLinkImplementation(
|
||||
it, cmGeneratorTarget::LinkInterfaceFor::Link)) {
|
||||
for (cmLinkImplItem const& lib : impl->Libraries) {
|
||||
// Don't emit the same library twice for this target.
|
||||
if (emitted.insert(lib).second) {
|
||||
|
||||
@@ -168,7 +168,8 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
|
||||
|
||||
// Tell the NDK build system if prebuilt static libraries use C++.
|
||||
if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
|
||||
cmLinkImplementation const* li = target->GetLinkImplementation(config);
|
||||
cmLinkImplementation const* li = target->GetLinkImplementation(
|
||||
config, cmGeneratorTarget::LinkInterfaceFor::Link);
|
||||
if (cm::contains(li->Languages, "CXX")) {
|
||||
os << "LOCAL_HAS_CPP := true\n";
|
||||
}
|
||||
|
||||
@@ -1415,7 +1415,8 @@ static std::string getLinkedTargetsContent(
|
||||
{
|
||||
std::string result;
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
target->GetLinkImplementationLibraries(context->Config)) {
|
||||
target->GetLinkImplementationLibraries(
|
||||
context->Config, cmGeneratorTarget::LinkInterfaceFor::Usage)) {
|
||||
for (cmLinkImplItem const& lib : impl->Libraries) {
|
||||
if (lib.Target) {
|
||||
// Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
|
||||
|
||||
@@ -752,6 +752,7 @@ void cmGeneratorTarget::ClearSourcesCache()
|
||||
this->Objects.clear();
|
||||
this->VisitedConfigsForObjects.clear();
|
||||
this->LinkImplMap.clear();
|
||||
this->LinkImplUsageRequirementsOnlyMap.clear();
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::ClearLinkInterfaceCache()
|
||||
@@ -1302,7 +1303,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(
|
||||
&dagChecker, result, excludeImported, language);
|
||||
}
|
||||
|
||||
cmLinkImplementation const* impl = this->GetLinkImplementation(config);
|
||||
cmLinkImplementation const* impl =
|
||||
this->GetLinkImplementation(config, LinkInterfaceFor::Usage);
|
||||
if (impl != nullptr) {
|
||||
auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language);
|
||||
if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) {
|
||||
@@ -1519,7 +1521,8 @@ void AddLangSpecificImplicitIncludeDirectories(
|
||||
const std::string& config, const std::string& propertyName,
|
||||
IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
|
||||
{
|
||||
if (const auto* libraries = target->GetLinkImplementationLibraries(config)) {
|
||||
if (const auto* libraries = target->GetLinkImplementationLibraries(
|
||||
config, LinkInterfaceFor::Usage)) {
|
||||
cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
|
||||
propertyName, nullptr, nullptr };
|
||||
|
||||
@@ -1609,7 +1612,7 @@ void AddInterfaceEntries(
|
||||
{
|
||||
if (searchRuntime == IncludeRuntimeInterface::Yes) {
|
||||
if (cmLinkImplementation const* impl =
|
||||
headTarget->GetLinkImplementation(config)) {
|
||||
headTarget->GetLinkImplementation(config, interfaceFor)) {
|
||||
entries.HadContextSensitiveCondition =
|
||||
impl->HadContextSensitiveCondition;
|
||||
|
||||
@@ -1623,7 +1626,7 @@ void AddInterfaceEntries(
|
||||
}
|
||||
} else {
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
headTarget->GetLinkImplementationLibraries(config)) {
|
||||
headTarget->GetLinkImplementationLibraries(config, interfaceFor)) {
|
||||
entries.HadContextSensitiveCondition =
|
||||
impl->HadContextSensitiveCondition;
|
||||
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
|
||||
@@ -1638,7 +1641,8 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget,
|
||||
EvaluatedTargetPropertyEntries& entries)
|
||||
{
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
headTarget->GetLinkImplementationLibraries(config)) {
|
||||
headTarget->GetLinkImplementationLibraries(config,
|
||||
LinkInterfaceFor::Usage)) {
|
||||
entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
|
||||
for (cmLinkImplItem const& lib : impl->Libraries) {
|
||||
if (lib.Target &&
|
||||
@@ -2821,7 +2825,7 @@ bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
|
||||
// Get languages built in this target.
|
||||
std::unordered_set<std::string> languages;
|
||||
cmLinkImplementation const* impl =
|
||||
this->GetLinkImplementation(config, secondPass);
|
||||
this->GetLinkImplementation(config, LinkInterfaceFor::Link, secondPass);
|
||||
assert(impl);
|
||||
languages.insert(impl->Languages.cbegin(), impl->Languages.cend());
|
||||
|
||||
@@ -3089,7 +3093,7 @@ cmGeneratorTarget::GetLinkImplementationClosure(
|
||||
std::set<cmGeneratorTarget const*> emitted;
|
||||
|
||||
cmLinkImplementationLibraries const* impl =
|
||||
this->GetLinkImplementationLibraries(config);
|
||||
this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Usage);
|
||||
assert(impl);
|
||||
|
||||
for (cmLinkImplItem const& lib : impl->Libraries) {
|
||||
@@ -3831,7 +3835,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
|
||||
|
||||
if (this->Makefile->IsOn("APPLE")) {
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
this->GetLinkImplementationLibraries(config)) {
|
||||
this->GetLinkImplementationLibraries(config,
|
||||
LinkInterfaceFor::Usage)) {
|
||||
for (cmLinkImplItem const& lib : impl->Libraries) {
|
||||
std::string libDir = cmSystemTools::CollapseFullPath(
|
||||
lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
|
||||
@@ -6845,8 +6850,8 @@ void cmGeneratorTarget::ComputeLinkInterface(
|
||||
emitted.insert(lib);
|
||||
}
|
||||
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
|
||||
cmLinkImplementation const* impl =
|
||||
this->GetLinkImplementation(config, secondPass);
|
||||
cmLinkImplementation const* impl = this->GetLinkImplementation(
|
||||
config, LinkInterfaceFor::Link, secondPass);
|
||||
for (cmLinkImplItem const& lib : impl->Libraries) {
|
||||
if (emitted.insert(lib).second) {
|
||||
if (lib.Target) {
|
||||
@@ -6868,15 +6873,16 @@ void cmGeneratorTarget::ComputeLinkInterface(
|
||||
this->GetPolicyStatusCMP0022() == cmPolicies::OLD) {
|
||||
// The link implementation is the default link interface.
|
||||
cmLinkImplementationLibraries const* impl =
|
||||
this->GetLinkImplementationLibrariesInternal(config, headTarget);
|
||||
this->GetLinkImplementationLibrariesInternal(config, headTarget,
|
||||
LinkInterfaceFor::Link);
|
||||
iface.ImplementationIsInterface = true;
|
||||
iface.WrongConfigLibraries = impl->WrongConfigLibraries;
|
||||
}
|
||||
|
||||
if (this->LinkLanguagePropagatesToDependents()) {
|
||||
// Targets using this archive need its language runtime libraries.
|
||||
if (cmLinkImplementation const* impl =
|
||||
this->GetLinkImplementation(config, secondPass)) {
|
||||
if (cmLinkImplementation const* impl = this->GetLinkImplementation(
|
||||
config, LinkInterfaceFor::Link, secondPass)) {
|
||||
iface.Languages = impl->Languages;
|
||||
}
|
||||
}
|
||||
@@ -7307,7 +7313,8 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
|
||||
|
||||
// The link implementation is the default link interface.
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
this->GetLinkImplementationLibrariesInternal(config, headTarget)) {
|
||||
this->GetLinkImplementationLibrariesInternal(config, headTarget,
|
||||
interfaceFor)) {
|
||||
iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(),
|
||||
impl->Libraries.end());
|
||||
if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
|
||||
@@ -7686,27 +7693,30 @@ cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
|
||||
}
|
||||
|
||||
const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
|
||||
const std::string& config) const
|
||||
const std::string& config, LinkInterfaceFor implFor) const
|
||||
{
|
||||
return this->GetLinkImplementation(config, false);
|
||||
return this->GetLinkImplementation(config, implFor, false);
|
||||
}
|
||||
|
||||
const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
|
||||
const std::string& config, bool secondPass) const
|
||||
const std::string& config, LinkInterfaceFor implFor, bool secondPass) const
|
||||
{
|
||||
// There is no link implementation for targets that cannot compile sources.
|
||||
if (!this->CanCompileSources()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cmOptionalLinkImplementation& impl =
|
||||
this->LinkImplMap[cmSystemTools::UpperCase(config)][this];
|
||||
HeadToLinkImplementationMap& hm =
|
||||
(implFor == LinkInterfaceFor::Usage
|
||||
? this->GetHeadToLinkImplementationUsageRequirementsMap(config)
|
||||
: this->GetHeadToLinkImplementationMap(config));
|
||||
cmOptionalLinkImplementation& impl = hm[this];
|
||||
if (secondPass) {
|
||||
impl = cmOptionalLinkImplementation();
|
||||
}
|
||||
if (!impl.LibrariesDone) {
|
||||
impl.LibrariesDone = true;
|
||||
this->ComputeLinkImplementationLibraries(config, impl, this);
|
||||
this->ComputeLinkImplementationLibraries(config, impl, this, implFor);
|
||||
}
|
||||
if (!impl.LanguagesDone) {
|
||||
impl.LanguagesDone = true;
|
||||
@@ -7716,6 +7726,21 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
|
||||
return &impl;
|
||||
}
|
||||
|
||||
cmGeneratorTarget::HeadToLinkImplementationMap&
|
||||
cmGeneratorTarget::GetHeadToLinkImplementationMap(
|
||||
std::string const& config) const
|
||||
{
|
||||
return this->LinkImplMap[cmSystemTools::UpperCase(config)];
|
||||
}
|
||||
|
||||
cmGeneratorTarget::HeadToLinkImplementationMap&
|
||||
cmGeneratorTarget::GetHeadToLinkImplementationUsageRequirementsMap(
|
||||
std::string const& config) const
|
||||
{
|
||||
return this
|
||||
->LinkImplUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
|
||||
std::vector<cmSourceFile*>& files) const
|
||||
{
|
||||
@@ -7956,7 +7981,7 @@ bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
|
||||
return true;
|
||||
}
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
this->GetLinkImplementationLibraries(config)) {
|
||||
this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Link)) {
|
||||
return !impl->Libraries.empty();
|
||||
}
|
||||
return false;
|
||||
@@ -7964,14 +7989,15 @@ bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
|
||||
|
||||
cmLinkImplementationLibraries const*
|
||||
cmGeneratorTarget::GetLinkImplementationLibraries(
|
||||
const std::string& config) const
|
||||
const std::string& config, LinkInterfaceFor implFor) const
|
||||
{
|
||||
return this->GetLinkImplementationLibrariesInternal(config, this);
|
||||
return this->GetLinkImplementationLibrariesInternal(config, this, implFor);
|
||||
}
|
||||
|
||||
cmLinkImplementationLibraries const*
|
||||
cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
|
||||
const std::string& config, cmGeneratorTarget const* head) const
|
||||
const std::string& config, cmGeneratorTarget const* head,
|
||||
LinkInterfaceFor implFor) const
|
||||
{
|
||||
// There is no link implementation for targets that cannot compile sources.
|
||||
if (!this->CanCompileSources()) {
|
||||
@@ -7980,7 +8006,9 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
|
||||
|
||||
// Populate the link implementation libraries for this configuration.
|
||||
HeadToLinkImplementationMap& hm =
|
||||
this->LinkImplMap[cmSystemTools::UpperCase(config)];
|
||||
(implFor == LinkInterfaceFor::Usage
|
||||
? this->GetHeadToLinkImplementationUsageRequirementsMap(config)
|
||||
: this->GetHeadToLinkImplementationMap(config));
|
||||
|
||||
// If the link implementation does not depend on the head target
|
||||
// then re-use the one from the head we computed first.
|
||||
@@ -7991,7 +8019,7 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
|
||||
cmOptionalLinkImplementation& impl = hm[head];
|
||||
if (!impl.LibrariesDone) {
|
||||
impl.LibrariesDone = true;
|
||||
this->ComputeLinkImplementationLibraries(config, impl, head);
|
||||
this->ComputeLinkImplementationLibraries(config, impl, head, implFor);
|
||||
}
|
||||
return &impl;
|
||||
}
|
||||
@@ -8110,8 +8138,9 @@ void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
|
||||
|
||||
void cmGeneratorTarget::ComputeLinkImplementationLibraries(
|
||||
const std::string& config, cmOptionalLinkImplementation& impl,
|
||||
cmGeneratorTarget const* head) const
|
||||
cmGeneratorTarget const* head, LinkInterfaceFor implFor) const
|
||||
{
|
||||
static_cast<void>(implFor);
|
||||
cmLocalGenerator const* lg = this->LocalGenerator;
|
||||
cmMakefile const* mf = lg->GetMakefile();
|
||||
cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries();
|
||||
|
||||
@@ -399,17 +399,18 @@ public:
|
||||
LinkClosure const* GetLinkClosure(const std::string& config) const;
|
||||
|
||||
cmLinkImplementation const* GetLinkImplementation(
|
||||
const std::string& config) const;
|
||||
const std::string& config, LinkInterfaceFor implFor) const;
|
||||
|
||||
void ComputeLinkImplementationLanguages(
|
||||
const std::string& config, cmOptionalLinkImplementation& impl) const;
|
||||
|
||||
cmLinkImplementationLibraries const* GetLinkImplementationLibraries(
|
||||
const std::string& config) const;
|
||||
const std::string& config, LinkInterfaceFor implFor) const;
|
||||
|
||||
void ComputeLinkImplementationLibraries(const std::string& config,
|
||||
cmOptionalLinkImplementation& impl,
|
||||
const cmGeneratorTarget* head) const;
|
||||
const cmGeneratorTarget* head,
|
||||
LinkInterfaceFor implFor) const;
|
||||
|
||||
struct TargetOrString
|
||||
{
|
||||
@@ -984,6 +985,7 @@ private:
|
||||
const cmGeneratorTarget* head,
|
||||
bool secondPass) const;
|
||||
cmLinkImplementation const* GetLinkImplementation(const std::string& config,
|
||||
LinkInterfaceFor implFor,
|
||||
bool secondPass) const;
|
||||
|
||||
enum class LinkItemRole
|
||||
@@ -1108,9 +1110,16 @@ private:
|
||||
};
|
||||
using LinkImplMapType = std::map<std::string, HeadToLinkImplementationMap>;
|
||||
mutable LinkImplMapType LinkImplMap;
|
||||
mutable LinkImplMapType LinkImplUsageRequirementsOnlyMap;
|
||||
|
||||
HeadToLinkImplementationMap& GetHeadToLinkImplementationMap(
|
||||
std::string const& config) const;
|
||||
HeadToLinkImplementationMap& GetHeadToLinkImplementationUsageRequirementsMap(
|
||||
std::string const& config) const;
|
||||
|
||||
cmLinkImplementationLibraries const* GetLinkImplementationLibrariesInternal(
|
||||
const std::string& config, const cmGeneratorTarget* head) const;
|
||||
const std::string& config, const cmGeneratorTarget* head,
|
||||
LinkInterfaceFor implFor) const;
|
||||
bool ComputeOutputDir(const std::string& config,
|
||||
cmStateEnums::ArtifactType artifact,
|
||||
std::string& out) const;
|
||||
|
||||
@@ -1627,7 +1627,10 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt)
|
||||
|
||||
// If the language is compiled as a source trust Xcode to link with it.
|
||||
for (auto const& Language :
|
||||
gtgt->GetLinkImplementation("NOCONFIG")->Languages) {
|
||||
gtgt
|
||||
->GetLinkImplementation("NOCONFIG",
|
||||
cmGeneratorTarget::LinkInterfaceFor::Link)
|
||||
->Languages) {
|
||||
if (Language == llang) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target,
|
||||
std::string const& config,
|
||||
DependencyMap& dependencies)
|
||||
{
|
||||
const auto* implementationLibraries =
|
||||
target.GetLinkImplementationLibraries(config);
|
||||
const auto* implementationLibraries = target.GetLinkImplementationLibraries(
|
||||
config, cmGeneratorTarget::LinkInterfaceFor::Link);
|
||||
if (implementationLibraries != nullptr) {
|
||||
for (auto const& lib : implementationLibraries->Libraries) {
|
||||
auto const& name = lib.AsStr();
|
||||
|
||||
@@ -136,7 +136,8 @@ void cmLinkLineDeviceComputer::ComputeLinkLibraries(
|
||||
linkLib.Value += " ";
|
||||
|
||||
const cmLinkImplementation* linkImpl =
|
||||
cli.GetTarget()->GetLinkImplementation(cli.GetConfig());
|
||||
cli.GetTarget()->GetLinkImplementation(
|
||||
cli.GetConfig(), cmGeneratorTarget::LinkInterfaceFor::Link);
|
||||
|
||||
for (const cmLinkImplItem& iter : linkImpl->Libraries) {
|
||||
if (iter.Target != nullptr &&
|
||||
|
||||
@@ -114,7 +114,8 @@ bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
|
||||
}
|
||||
// Collect all static_library dependencies from the test target
|
||||
cmLinkImplementationLibraries const* libs =
|
||||
testTarget->GetLinkImplementationLibraries(config);
|
||||
testTarget->GetLinkImplementationLibraries(
|
||||
config, cmGeneratorTarget::LinkInterfaceFor::Link);
|
||||
if (libs) {
|
||||
for (cmLinkItem const& item : libs->Libraries) {
|
||||
cmGeneratorTarget const* depTarget = item.Target;
|
||||
@@ -1266,7 +1267,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
|
||||
std::map<cmGeneratorTarget const*, std::size_t> commonTargets;
|
||||
for (std::string const& config : this->ConfigsList) {
|
||||
cmLinkImplementationLibraries const* libs =
|
||||
this->GenTarget->GetLinkImplementationLibraries(config);
|
||||
this->GenTarget->GetLinkImplementationLibraries(
|
||||
config, cmGeneratorTarget::LinkInterfaceFor::Link);
|
||||
if (libs) {
|
||||
for (cmLinkItem const& item : libs->Libraries) {
|
||||
cmGeneratorTarget const* libTarget = item.Target;
|
||||
|
||||
Reference in New Issue
Block a user