summaryrefslogtreecommitdiffstats
path: root/Source/cmExportFileGenerator.cxx
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2023-11-07 16:44:00 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2023-11-13 16:07:52 (GMT)
commitc6e6861e631ecfdc96c79f562a66021cb8971fcc (patch)
tree6cb0de03a6db5d0f997f5d351ac2a03bb060bff7 /Source/cmExportFileGenerator.cxx
parent2837f592ab7642e6a769949b4ddc1ffb37e21b9c (diff)
downloadCMake-c6e6861e631ecfdc96c79f562a66021cb8971fcc.zip
CMake-c6e6861e631ecfdc96c79f562a66021cb8971fcc.tar.gz
CMake-c6e6861e631ecfdc96c79f562a66021cb8971fcc.tar.bz2
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>
Diffstat (limited to 'Source/cmExportFileGenerator.cxx')
-rw-r--r--Source/cmExportFileGenerator.cxx94
1 files changed, 93 insertions, 1 deletions
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7bf9e5d..205bf08 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -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()) {