install(EXPORT): Export find_dependency() calls

Issue: #20511
Co-Authored-by: Brad King <brad.king@kitware.com>
Co-Authored-by: Robert Maynard <rmaynard@nvidia.com>
This commit is contained in:
Kyle Edwards
2023-11-07 11:44:00 -05:00
parent 2837f592ab
commit c6e6861e63
53 changed files with 700 additions and 10 deletions
+93 -1
View File
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportFileGenerator.h"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstring>
@@ -9,12 +10,15 @@
#include <utility>
#include <cm/memory>
#include <cm/optional>
#include <cmext/string_view>
#include "cmsys/FStream.hxx"
#include "cmComputeLinkInformation.h"
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmFindPackageStack.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmLinkItem.h"
@@ -100,7 +104,20 @@ bool cmExportFileGenerator::GenerateImportFile()
this->GenerateImportHeaderCode(mainFileWithHeadersAndFootersBuffer);
// Create all the imported targets.
bool result = this->GenerateMainFile(mainFileWithHeadersAndFootersBuffer);
std::stringstream mainFileBuffer;
bool result = this->GenerateMainFile(mainFileBuffer);
// Export find_dependency() calls. Must be done after GenerateMainFile(),
// because that's when target dependencies are gathered, which we need for
// the find_dependency() calls.
if (!this->AppendMode && this->GetExportSet() &&
this->ExportPackageDependencies) {
this->SetRequiredCMakeVersion(3, 9, 0);
this->GenerateFindDependencyCalls(mainFileWithHeadersAndFootersBuffer);
}
// Write cached import code.
mainFileWithHeadersAndFootersBuffer << mainFileBuffer.rdbuf();
// End with the import file footer.
this->GenerateImportFooterCode(mainFileWithHeadersAndFootersBuffer);
@@ -615,6 +632,12 @@ bool cmExportFileGenerator::AddTargetNamespace(std::string& input,
return false;
}
cmFindPackageStack const& pkgStack = tgt->Target->GetFindPackageStack();
if (!pkgStack.Empty() ||
tgt->Target->GetProperty("EXPORT_FIND_PACKAGE_NAME")) {
this->ExternalTargets.emplace(tgt);
}
if (tgt->IsImported()) {
input = tgt->GetName();
return true;
@@ -862,12 +885,14 @@ void cmExportFileGenerator::SetImportDetailProperties(
// Export IMPORTED_LINK_DEPENDENT_LIBRARIES to help consuming linkers
// find private dependencies of shared libraries.
std::size_t oldMissingTargetsSize = this->MissingTargets.size();
auto oldExternalTargets = this->ExternalTargets;
this->SetImportLinkProperty(
suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps,
properties, ImportLinkPropertyTargetNames::Yes);
// Avoid enforcing shared library private dependencies as public package
// dependencies by ignoring missing targets added for them.
this->MissingTargets.resize(oldMissingTargetsSize);
this->ExternalTargets = std::move(oldExternalTargets);
if (iface->Multiplicity > 0) {
std::string prop =
@@ -1157,6 +1182,73 @@ void cmExportFileGenerator::GenerateImportPropertyCode(
<< "\n";
}
void cmExportFileGenerator::GenerateFindDependencyCalls(std::ostream& os)
{
os << "include(CMakeFindDependencyMacro)\n";
std::map<std::string, cmExportSet::PackageDependency> packageDependencies;
auto* exportSet = this->GetExportSet();
if (exportSet) {
packageDependencies = exportSet->GetPackageDependencies();
}
for (cmGeneratorTarget const* gt : this->ExternalTargets) {
std::string findPackageName;
auto exportFindPackageName = gt->GetProperty("EXPORT_FIND_PACKAGE_NAME");
cmFindPackageStack pkgStack = gt->Target->GetFindPackageStack();
if (!exportFindPackageName.IsEmpty()) {
findPackageName = *exportFindPackageName;
} else {
if (!pkgStack.Empty()) {
cmFindPackageCall const& fpc = pkgStack.Top();
findPackageName = fpc.Name;
}
}
if (!findPackageName.empty()) {
auto& dep = packageDependencies[findPackageName];
if (!pkgStack.Empty()) {
dep.FindPackageIndex = pkgStack.Top().Index;
}
if (dep.Enabled == cmExportSet::PackageDependencyExportEnabled::Auto) {
dep.Enabled = cmExportSet::PackageDependencyExportEnabled::On;
}
}
}
std::vector<std::pair<std::string, cmExportSet::PackageDependency>>
packageDependenciesSorted(packageDependencies.begin(),
packageDependencies.end());
std::sort(
packageDependenciesSorted.begin(), packageDependenciesSorted.end(),
[](const std::pair<std::string, cmExportSet::PackageDependency>& lhs,
const std::pair<std::string, cmExportSet::PackageDependency>& rhs)
-> bool {
if (lhs.second.SpecifiedIndex) {
if (rhs.second.SpecifiedIndex) {
return lhs.second.SpecifiedIndex < rhs.second.SpecifiedIndex;
}
assert(rhs.second.FindPackageIndex);
return true;
}
assert(lhs.second.FindPackageIndex);
if (rhs.second.SpecifiedIndex) {
return false;
}
assert(rhs.second.FindPackageIndex);
return lhs.second.FindPackageIndex < rhs.second.FindPackageIndex;
});
for (auto const& it : packageDependenciesSorted) {
if (it.second.Enabled == cmExportSet::PackageDependencyExportEnabled::On) {
os << "find_dependency(" << it.first << " REQUIRED";
for (auto const& arg : it.second.ExtraArguments) {
os << " " << cmOutputConverter::EscapeForCMake(arg);
}
os << ")\n";
}
}
os << "\n\n";
}
void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os)
{
if (this->MissingTargets.empty()) {