diff options
Diffstat (limited to 'Source/cmExportFileGenerator.cxx')
-rw-r--r-- | Source/cmExportFileGenerator.cxx | 214 |
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; + } +} |