summaryrefslogtreecommitdiffstats
path: root/Source/cmExportFileGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmExportFileGenerator.cxx')
-rw-r--r--Source/cmExportFileGenerator.cxx214
1 files changed, 177 insertions, 37 deletions
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index f2742df..f332007 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"
@@ -30,6 +34,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmValue.h"
+#include "cmVersion.h"
static std::string cmExportFileGeneratorEscape(std::string const& str)
{
@@ -93,17 +98,35 @@ bool cmExportFileGenerator::GenerateImportFile()
return false;
}
std::ostream& os = *foutPtr;
+ std::stringstream mainFileWithHeadersAndFootersBuffer;
// Start with the import file header.
- this->GeneratePolicyHeaderCode(os);
- this->GenerateImportHeaderCode(os);
+ this->GenerateImportHeaderCode(mainFileWithHeadersAndFootersBuffer);
// Create all the imported targets.
- bool result = this->GenerateMainFile(os);
+ 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(os);
- this->GeneratePolicyFooterCode(os);
+ this->GenerateImportFooterCode(mainFileWithHeadersAndFootersBuffer);
+ this->GeneratePolicyFooterCode(mainFileWithHeadersAndFootersBuffer);
+
+ // This has to be done last, after the minimum CMake version has been
+ // determined.
+ this->GeneratePolicyHeaderCode(os);
+ os << mainFileWithHeadersAndFootersBuffer.rdbuf();
return result;
}
@@ -156,17 +179,6 @@ void cmExportFileGenerator::PopulateInterfaceProperty(
}
}
-void cmExportFileGenerator::GenerateRequiredCMakeVersion(
- std::ostream& os, const char* versionString)
-{
- /* clang-format off */
- os << "if(CMAKE_VERSION VERSION_LESS " << versionString << ")\n"
- " message(FATAL_ERROR \"This file relies on consumers using "
- "CMake " << versionString << " or greater.\")\n"
- "endif()\n\n";
- /* clang-format on */
-}
-
bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
cmGeneratorTarget const* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
@@ -620,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;
@@ -867,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 =
@@ -953,20 +973,29 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.8)\n"
<< " message(FATAL_ERROR \"CMake >= 2.8.0 required\")\n"
<< "endif()\n"
- << "if(CMAKE_VERSION VERSION_LESS \"2.8.3\")\n"
- << " message(FATAL_ERROR \"CMake >= 2.8.3 required\")\n"
+ << "if(CMAKE_VERSION VERSION_LESS \""
+ << this->RequiredCMakeVersionMajor << '.'
+ << this->RequiredCMakeVersionMinor << '.'
+ << this->RequiredCMakeVersionPatch << "\")\n"
+ << " message(FATAL_ERROR \"CMake >= "
+ << this->RequiredCMakeVersionMajor << '.'
+ << this->RequiredCMakeVersionMinor << '.'
+ << this->RequiredCMakeVersionPatch << " required\")\n"
<< "endif()\n";
/* clang-format on */
// Isolate the file policy level.
// Support CMake versions as far back as 2.6 but also support using NEW
- // policy settings for up to CMake 3.26 (this upper limit may be reviewed
+ // policy settings for up to CMake 3.27 (this upper limit may be reviewed
// and increased from time to time). This reduces the opportunity for CMake
// warnings when an older export file is later used with newer CMake
// versions.
/* clang-format off */
os << "cmake_policy(PUSH)\n"
- << "cmake_policy(VERSION 2.8.3...3.26)\n";
+ << "cmake_policy(VERSION "
+ << this->RequiredCMakeVersionMajor << '.'
+ << this->RequiredCMakeVersionMinor << '.'
+ << this->RequiredCMakeVersionPatch << "...3.27)\n";
/* clang-format on */
}
@@ -1125,8 +1154,9 @@ void cmExportFileGenerator::GenerateImportTargetCode(
}
void cmExportFileGenerator::GenerateImportPropertyCode(
- std::ostream& os, const std::string& config, cmGeneratorTarget const* target,
- ImportPropertyMap const& properties)
+ std::ostream& os, const std::string& config, const std::string& suffix,
+ cmGeneratorTarget const* target, ImportPropertyMap const& properties,
+ const std::string& importedXcFrameworkLocation)
{
// Construct the imported target name.
std::string targetName = this->Namespace;
@@ -1145,12 +1175,98 @@ void cmExportFileGenerator::GenerateImportPropertyCode(
}
os << ")\n";
os << "set_target_properties(" << targetName << " PROPERTIES\n";
+ std::string importedLocationProp = cmStrCat("IMPORTED_LOCATION", suffix);
for (auto const& property : properties) {
- os << " " << property.first << " "
- << cmExportFileGeneratorEscape(property.second) << "\n";
+ if (importedXcFrameworkLocation.empty() ||
+ property.first != importedLocationProp) {
+ os << " " << property.first << " "
+ << cmExportFileGeneratorEscape(property.second) << "\n";
+ }
}
- os << " )\n"
- << "\n";
+ os << " )\n";
+ if (!importedXcFrameworkLocation.empty()) {
+ auto importedLocationIt = properties.find(importedLocationProp);
+ if (importedLocationIt != properties.end()) {
+ os << "if(NOT CMAKE_VERSION VERSION_LESS \"3.28\" AND IS_DIRECTORY "
+ << cmExportFileGeneratorEscape(importedXcFrameworkLocation)
+ << ")\n"
+ " set_property(TARGET "
+ << targetName << " PROPERTY " << importedLocationProp << " "
+ << cmExportFileGeneratorEscape(importedXcFrameworkLocation)
+ << ")\nelse()\n set_property(TARGET " << targetName << " PROPERTY "
+ << importedLocationProp << " "
+ << cmExportFileGeneratorEscape(importedLocationIt->second)
+ << ")\nendif()\n";
+ }
+ }
+ os << "\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)
@@ -1214,10 +1330,16 @@ void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
/* clang-format off */
os << "# Loop over all imported files and verify that they actually exist\n"
"foreach(_cmake_target IN LISTS _cmake_import_check_targets)\n"
- " foreach(_cmake_file IN LISTS \"_cmake_import_check_files_for_${_cmake_target}\")\n"
- " if(NOT EXISTS \"${_cmake_file}\")\n"
- " message(FATAL_ERROR \"The imported target \\\"${_cmake_target}\\\""
- " references the file\n"
+ " if(CMAKE_VERSION VERSION_LESS \"3.28\"\n"
+ " OR NOT DEFINED "
+ "_cmake_import_check_xcframework_for_${_cmake_target}\n"
+ " OR NOT IS_DIRECTORY "
+ "\"${_cmake_import_check_xcframework_for_${_cmake_target}}\")\n"
+ " foreach(_cmake_file IN LISTS "
+ "\"_cmake_import_check_files_for_${_cmake_target}\")\n"
+ " if(NOT EXISTS \"${_cmake_file}\")\n"
+ " message(FATAL_ERROR \"The imported target "
+ "\\\"${_cmake_target}\\\" references the file\n"
" \\\"${_cmake_file}\\\"\n"
"but this file does not exist. Possible reasons include:\n"
"* The file was deleted, renamed, or moved to another location.\n"
@@ -1226,8 +1348,9 @@ void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
" \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
"but not all the files it references.\n"
"\")\n"
- " endif()\n"
- " endforeach()\n"
+ " endif()\n"
+ " endforeach()\n"
+ " endif()\n"
" unset(_cmake_file)\n"
" unset(\"_cmake_import_check_files_for_${_cmake_target}\")\n"
"endforeach()\n"
@@ -1240,15 +1363,18 @@ void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
void cmExportFileGenerator::GenerateImportedFileChecksCode(
std::ostream& os, cmGeneratorTarget* target,
ImportPropertyMap const& properties,
- const std::set<std::string>& importedLocations)
+ const std::set<std::string>& importedLocations,
+ const std::string& importedXcFrameworkLocation)
{
// Construct the imported target name.
std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
- os << "list(APPEND _cmake_import_check_targets " << targetName
- << " )\n"
- "list(APPEND _cmake_import_check_files_for_"
- << targetName << " ";
+ os << "list(APPEND _cmake_import_check_targets " << targetName << " )\n";
+ if (!importedXcFrameworkLocation.empty()) {
+ os << "set(_cmake_import_check_xcframework_for_" << targetName << ' '
+ << cmExportFileGeneratorEscape(importedXcFrameworkLocation) << ")\n";
+ }
+ os << "list(APPEND _cmake_import_check_files_for_" << targetName << " ";
for (std::string const& li : importedLocations) {
auto pi = properties.find(li);
@@ -1486,3 +1612,17 @@ void cmExportFileGenerator::GenerateCxxModuleInformation(
this->GenerateCxxModuleConfigInformation(name, ap);
}
+
+void cmExportFileGenerator::SetRequiredCMakeVersion(unsigned int major,
+ unsigned int minor,
+ unsigned int patch)
+{
+ if (CMake_VERSION_ENCODE(major, minor, patch) >
+ CMake_VERSION_ENCODE(this->RequiredCMakeVersionMajor,
+ this->RequiredCMakeVersionMinor,
+ this->RequiredCMakeVersionPatch)) {
+ this->RequiredCMakeVersionMajor = major;
+ this->RequiredCMakeVersionMinor = minor;
+ this->RequiredCMakeVersionPatch = patch;
+ }
+}