diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index ae22d56037..f4ff1025b5 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -199,14 +199,22 @@ add_library( cmEvaluatedTargetProperty.cxx cmEvaluatedTargetProperty.h cmExprParserHelper.cxx + cmExportAndroidMKGenerator.h + cmExportAndroidMKGenerator.cxx cmExportBuildAndroidMKGenerator.h cmExportBuildAndroidMKGenerator.cxx + cmExportBuildCMakeConfigGenerator.h + cmExportBuildCMakeConfigGenerator.cxx cmExportBuildFileGenerator.h cmExportBuildFileGenerator.cxx + cmExportCMakeConfigGenerator.h + cmExportCMakeConfigGenerator.cxx cmExportFileGenerator.h cmExportFileGenerator.cxx cmExportInstallAndroidMKGenerator.h cmExportInstallAndroidMKGenerator.cxx + cmExportInstallCMakeConfigGenerator.h + cmExportInstallCMakeConfigGenerator.cxx cmExportInstallFileGenerator.h cmExportInstallFileGenerator.cxx cmExportTryCompileFileGenerator.h diff --git a/Source/cmExportAndroidMKGenerator.cxx b/Source/cmExportAndroidMKGenerator.cxx index 297c8b66e1..34dc1a7921 100644 --- a/Source/cmExportAndroidMKGenerator.cxx +++ b/Source/cmExportAndroidMKGenerator.cxx @@ -2,12 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportAndroidMKGenerator.h" -#include #include #include #include #include +#include #include "cmGeneratorTarget.h" #include "cmLinkItem.h" @@ -20,75 +20,44 @@ #include "cmSystemTools.h" #include "cmTarget.h" -cmExportAndroidMKGenerator::cmExportAndroidMKGenerator() +cmExportAndroidMKGenerator::cmExportAndroidMKGenerator() = default; + +cm::string_view cmExportAndroidMKGenerator::GetImportPrefixWithSlash() const { - this->LG = nullptr; - this->ExportSet = nullptr; + return "$(_IMPORT_PREFIX)/"_s; } -void cmExportAndroidMKGenerator::GenerateImportHeaderCode(std::ostream& os, - std::string const&) +bool cmExportAndroidMKGenerator::GenerateImportFile(std::ostream& os) { - os << "LOCAL_PATH := $(call my-dir)\n\n"; -} + if (!this->AppendMode) { + // Start with the import file header. + this->GenerateImportHeaderCode(os); + } -void cmExportAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) -{ -} + // Create all the imported targets. + std::stringstream mainFileBuffer; + bool result = this->GenerateMainFile(mainFileBuffer); -void cmExportAndroidMKGenerator::GenerateExpectedTargetsCode( - std::ostream&, std::string const&) -{ -} + // Write cached import code. + os << mainFileBuffer.rdbuf(); -void cmExportAndroidMKGenerator::GenerateImportTargetCode( - std::ostream& os, cmGeneratorTarget const* target, - cmStateEnums::TargetType /*targetType*/) -{ - std::string targetName = cmStrCat(this->Namespace, target->GetExportName()); - os << "include $(CLEAR_VARS)\n"; - os << "LOCAL_MODULE := "; - os << targetName << "\n"; - os << "LOCAL_SRC_FILES := "; - std::string const noConfig; // FIXME: What config to use here? - std::string path = - cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig)); - os << path << "\n"; -} - -void cmExportAndroidMKGenerator::GenerateImportPropertyCode( - std::ostream&, std::string const&, std::string const&, - cmGeneratorTarget const*, ImportPropertyMap const&, std::string const&) -{ -} - -void cmExportAndroidMKGenerator::GenerateMissingTargetsCheckCode(std::ostream&) -{ + return result; } void cmExportAndroidMKGenerator::GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, ImportPropertyMap const& properties) { - std::string config; - if (!this->Configurations.empty()) { - config = this->Configurations[0]; - } - cmExportAndroidMKGenerator::GenerateInterfaceProperties( - target, os, properties, cmExportAndroidMKGenerator::BUILD, config); -} + std::string const config = + (this->Configurations.empty() ? std::string{} : this->Configurations[0]); + GenerateType const type = this->GetGenerateType(); -void cmExportAndroidMKGenerator::GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties, GenerateType type, - std::string const& config) -{ bool const newCMP0022Behavior = target->GetPolicyStatusCMP0022() != cmPolicies::WARN && target->GetPolicyStatusCMP0022() != cmPolicies::OLD; if (!newCMP0022Behavior) { std::ostringstream w; - if (type == cmExportAndroidMKGenerator::BUILD) { + if (type == BUILD) { w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022"; } else { w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022"; @@ -123,7 +92,7 @@ void cmExportAndroidMKGenerator::GenerateInterfaceProperties( } } else { bool relpath = false; - if (type == cmExportAndroidMKGenerator::INSTALL) { + if (type == INSTALL) { relpath = cmHasLiteralPrefix(lib, "../"); } // check for full path or if it already has a -l, or diff --git a/Source/cmExportAndroidMKGenerator.h b/Source/cmExportAndroidMKGenerator.h index f1e74eeece..fb0f03b20b 100644 --- a/Source/cmExportAndroidMKGenerator.h +++ b/Source/cmExportAndroidMKGenerator.h @@ -5,58 +5,69 @@ #include "cmConfigure.h" // IWYU pragma: keep #include +#include #include -#include "cmExportBuildFileGenerator.h" +#include + +#include "cmExportFileGenerator.h" #include "cmStateTypes.h" class cmGeneratorTarget; /** \class cmExportAndroidMKGenerator - * \brief Generate a file exporting targets from a build tree. + * \brief Generate CMake configuration files exporting targets from a build or + * install tree. * - * cmExportAndroidMKGenerator generates a file exporting targets from - * a build tree. This exports the targets to the Android ndk build tool - * makefile format for prebuilt libraries. - * - * This is used to implement the export() command. + * cmExportAndroidMKGenerator is the superclass for + * cmExportBuildAndroidMKGenerator and cmExportInstallAndroidMKGenerator. + * It contains common code generation routines for the two kinds of export + * implementations. */ -class cmExportAndroidMKGenerator : public cmExportBuildFileGenerator +class cmExportAndroidMKGenerator : virtual public cmExportFileGenerator { public: cmExportAndroidMKGenerator(); - // this is so cmExportInstallAndroidMKGenerator can share this - // function as they are almost the same + + using cmExportFileGenerator::GenerateImportFile; + +protected: enum GenerateType { BUILD, INSTALL }; - static void GenerateInterfaceProperties(cmGeneratorTarget const* target, - std::ostream& os, - ImportPropertyMap const& properties, - GenerateType type, - std::string const& config); + virtual GenerateType GetGenerateType() const = 0; -protected: - // Implement virtual methods from the superclass. - void GeneratePolicyHeaderCode(std::ostream&) override {} - void GeneratePolicyFooterCode(std::ostream&) override {} - void GenerateImportHeaderCode(std::ostream& os, - std::string const& config = "") override; - void GenerateImportFooterCode(std::ostream& os) override; - void GenerateImportTargetCode( + using ImportPropertyMap = std::map; + + cm::string_view GetImportPrefixWithSlash() const override; + + void GenerateInterfaceProperties(cmGeneratorTarget const* target, + std::ostream& os, + ImportPropertyMap const& properties); + + // Methods to implement export file code generation. + bool GenerateImportFile(std::ostream& os) override; + virtual void GenerateImportHeaderCode(std::ostream& os, + std::string const& config = "") = 0; + virtual void GenerateImportTargetCode( std::ostream& os, cmGeneratorTarget const* target, - cmStateEnums::TargetType /*targetType*/) override; - void GenerateExpectedTargetsCode( - std::ostream& os, std::string const& expectedTargets) override; - void GenerateImportPropertyCode( - std::ostream& os, std::string const& config, std::string const& suffix, - cmGeneratorTarget const* target, ImportPropertyMap const& properties, - std::string const& importedXcFrameworkLocation) override; - void GenerateMissingTargetsCheckCode(std::ostream& os) override; - void GenerateFindDependencyCalls(std::ostream&) override {} - void GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties) override; + cmStateEnums::TargetType targetType) = 0; + + void GenerateImportTargetsConfig(std::ostream& /*os*/, + std::string const& /*config*/, + std::string const& /*suffix*/) override + { + } + + std::string GetCxxModuleFile(std::string const& /*name*/) const override + { + return {}; + } + + void GenerateCxxModuleConfigInformation(std::string const& /*name*/, + std::ostream& /*os*/) const override + { + } }; diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 4fdbbc45cf..a5f6ca39da 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -2,28 +2,50 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportBuildAndroidMKGenerator.h" -#include #include -#include #include -#include - +#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" -#include "cmLinkItem.h" -#include "cmList.h" -#include "cmMakefile.h" -#include "cmMessageType.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator() +cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator() = default; + +bool cmExportBuildAndroidMKGenerator::GenerateMainFile(std::ostream& os) { - this->LG = nullptr; - this->ExportSet = nullptr; + if (!this->CollectExports([&](cmGeneratorTarget const*) {})) { + return false; + } + + // Create all the imported targets. + for (auto const& exp : this->Exports) { + cmGeneratorTarget* gte = exp.Target; + + this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte)); + + gte->Target->AppendBuildInterfaceIncludes(); + + ImportPropertyMap properties; + if (!this->PopulateInterfaceProperties(gte, properties)) { + return false; + } + + bool const newCMP0022Behavior = + gte->GetPolicyStatusCMP0022() != cmPolicies::WARN && + gte->GetPolicyStatusCMP0022() != cmPolicies::OLD; + if (newCMP0022Behavior) { + this->PopulateInterfaceLinkLibrariesProperty( + gte, cmGeneratorExpression::BuildInterface, properties); + } + + this->GenerateInterfaceProperties(gte, os, properties); + } + + return true; } void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode( @@ -32,15 +54,6 @@ void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode( os << "LOCAL_PATH := $(call my-dir)\n\n"; } -void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) -{ -} - -void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode( - std::ostream&, std::string const&) -{ -} - void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( std::ostream& os, cmGeneratorTarget const* target, cmStateEnums::TargetType /*targetType*/) @@ -55,143 +68,3 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig)); os << path << "\n"; } - -void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode( - std::ostream&, std::string const&, std::string const&, - cmGeneratorTarget const*, ImportPropertyMap const&, std::string const&) -{ -} - -void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode( - std::ostream&) -{ -} - -void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties) -{ - std::string config; - if (!this->Configurations.empty()) { - config = this->Configurations[0]; - } - cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( - target, os, properties, cmExportBuildAndroidMKGenerator::BUILD, config); -} - -void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties, GenerateType type, - std::string const& config) -{ - bool const newCMP0022Behavior = - target->GetPolicyStatusCMP0022() != cmPolicies::WARN && - target->GetPolicyStatusCMP0022() != cmPolicies::OLD; - if (!newCMP0022Behavior) { - std::ostringstream w; - if (type == cmExportBuildAndroidMKGenerator::BUILD) { - w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022"; - } else { - w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022"; - } - w << " set to OLD for target " << target->Target->GetName() << ". " - << "The export will only work with CMP0022 set to NEW."; - target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); - } - if (!properties.empty()) { - os << "LOCAL_CPP_FEATURES := rtti exceptions\n"; - for (auto const& property : properties) { - if (property.first == "INTERFACE_COMPILE_OPTIONS") { - os << "LOCAL_CPP_FEATURES += "; - os << (property.second) << "\n"; - } else if (property.first == "INTERFACE_LINK_LIBRARIES") { - std::string staticLibs; - std::string sharedLibs; - std::string ldlibs; - cmLinkInterfaceLibraries const* linkIFace = - target->GetLinkInterfaceLibraries(config, target, - cmGeneratorTarget::UseTo::Link); - for (cmLinkItem const& item : linkIFace->Libraries) { - cmGeneratorTarget const* gt = item.Target; - std::string const& lib = item.AsStr(); - if (gt) { - - if (gt->GetType() == cmStateEnums::SHARED_LIBRARY || - gt->GetType() == cmStateEnums::MODULE_LIBRARY) { - sharedLibs += " " + lib; - } else { - staticLibs += " " + lib; - } - } else { - bool relpath = false; - if (type == cmExportBuildAndroidMKGenerator::INSTALL) { - relpath = cmHasLiteralPrefix(lib, "../"); - } - // check for full path or if it already has a -l, or - // in the case of an install check for relative paths - // if it is full or a link library then use string directly - if (cmSystemTools::FileIsFullPath(lib) || - cmHasLiteralPrefix(lib, "-l") || relpath) { - ldlibs += " " + lib; - // if it is not a path and does not have a -l then add -l - } else if (!lib.empty()) { - ldlibs += " -l" + lib; - } - } - } - if (!sharedLibs.empty()) { - os << "LOCAL_SHARED_LIBRARIES :=" << sharedLibs << "\n"; - } - if (!staticLibs.empty()) { - os << "LOCAL_STATIC_LIBRARIES :=" << staticLibs << "\n"; - } - if (!ldlibs.empty()) { - os << "LOCAL_EXPORT_LDLIBS :=" << ldlibs << "\n"; - } - } else if (property.first == "INTERFACE_INCLUDE_DIRECTORIES") { - std::string includes = property.second; - cmList includeList{ includes }; - os << "LOCAL_EXPORT_C_INCLUDES := "; - std::string end; - for (std::string const& i : includeList) { - os << end << i; - end = "\\\n"; - } - os << "\n"; - } else if (property.first == "INTERFACE_LINK_OPTIONS") { - os << "LOCAL_EXPORT_LDFLAGS := "; - cmList linkFlagsList{ property.second }; - os << linkFlagsList.join(" ") << "\n"; - } else { - os << "# " << property.first << " " << (property.second) << "\n"; - } - } - } - - // Tell the NDK build system if prebuilt static libraries use C++. - if (target->GetType() == cmStateEnums::STATIC_LIBRARY) { - cmLinkImplementation const* li = - target->GetLinkImplementation(config, cmGeneratorTarget::UseTo::Link); - if (cm::contains(li->Languages, "CXX")) { - os << "LOCAL_HAS_CPP := true\n"; - } - } - - switch (target->GetType()) { - case cmStateEnums::SHARED_LIBRARY: - case cmStateEnums::MODULE_LIBRARY: - os << "include $(PREBUILT_SHARED_LIBRARY)\n"; - break; - case cmStateEnums::STATIC_LIBRARY: - os << "include $(PREBUILT_STATIC_LIBRARY)\n"; - break; - case cmStateEnums::EXECUTABLE: - case cmStateEnums::UTILITY: - case cmStateEnums::OBJECT_LIBRARY: - case cmStateEnums::GLOBAL_TARGET: - case cmStateEnums::INTERFACE_LIBRARY: - case cmStateEnums::UNKNOWN_LIBRARY: - break; - } - os << "\n"; -} diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h index 2f5a301dde..deb389354e 100644 --- a/Source/cmExportBuildAndroidMKGenerator.h +++ b/Source/cmExportBuildAndroidMKGenerator.h @@ -7,6 +7,7 @@ #include #include +#include "cmExportAndroidMKGenerator.h" #include "cmExportBuildFileGenerator.h" #include "cmStateTypes.h" @@ -21,42 +22,26 @@ class cmGeneratorTarget; * * This is used to implement the export() command. */ -class cmExportBuildAndroidMKGenerator : public cmExportBuildFileGenerator +class cmExportBuildAndroidMKGenerator + : public cmExportBuildFileGenerator + , public cmExportAndroidMKGenerator { public: cmExportBuildAndroidMKGenerator(); - // this is so cmExportInstallAndroidMKGenerator can share this - // function as they are almost the same - enum GenerateType - { - BUILD, - INSTALL - }; - static void GenerateInterfaceProperties(cmGeneratorTarget const* target, - std::ostream& os, - ImportPropertyMap const& properties, - GenerateType type, - std::string const& config); + + /** Set whether to append generated code to the output file. */ + void SetAppendMode(bool append) { this->AppendMode = append; } protected: + GenerateType GetGenerateType() const override { return BUILD; } + // Implement virtual methods from the superclass. - void GeneratePolicyHeaderCode(std::ostream&) override {} - void GeneratePolicyFooterCode(std::ostream&) override {} + bool GenerateMainFile(std::ostream& os) override; void GenerateImportHeaderCode(std::ostream& os, std::string const& config = "") override; - void GenerateImportFooterCode(std::ostream& os) override; void GenerateImportTargetCode( std::ostream& os, cmGeneratorTarget const* target, cmStateEnums::TargetType /*targetType*/) override; - void GenerateExpectedTargetsCode( - std::ostream& os, std::string const& expectedTargets) override; - void GenerateImportPropertyCode( - std::ostream& os, std::string const& config, std::string const& suffix, - cmGeneratorTarget const* target, ImportPropertyMap const& properties, - std::string const& importedXcFrameworkLocation) override; - void GenerateMissingTargetsCheckCode(std::ostream& os) override; - void GenerateFindDependencyCalls(std::ostream&) override {} - void GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties) override; + + std::string GetCxxModulesDirectory() const override { return {}; } }; diff --git a/Source/cmExportBuildCMakeConfigGenerator.cxx b/Source/cmExportBuildCMakeConfigGenerator.cxx index cb4f80b7de..87aeb3cbb9 100644 --- a/Source/cmExportBuildCMakeConfigGenerator.cxx +++ b/Source/cmExportBuildCMakeConfigGenerator.cxx @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,6 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" -#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -30,11 +29,6 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -#include "cmTargetExport.h" -#include "cmValue.h" -#include "cmake.h" - -class cmSourceFile; cmExportBuildCMakeConfigGenerator::cmExportBuildCMakeConfigGenerator() { @@ -42,38 +36,22 @@ cmExportBuildCMakeConfigGenerator::cmExportBuildCMakeConfigGenerator() this->ExportSet = nullptr; } -void cmExportBuildCMakeConfigGenerator::Compute(cmLocalGenerator* lg) -{ - this->LG = lg; - if (this->ExportSet) { - this->ExportSet->Compute(lg); - } -} - bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os) { { std::string expectedTargets; std::string sep; - std::vector targets; bool generatedInterfaceRequired = false; - this->GetTargets(targets); - for (auto const& tei : targets) { - cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name); + auto visitor = [&](cmGeneratorTarget const* te) { expectedTargets += sep + this->Namespace + te->GetExportName(); sep = " "; - if (this->ExportedTargets.insert(te).second) { - this->Exports.emplace_back(te, tei.XcFrameworkLocation); - } else { - std::ostringstream e; - e << "given target \"" << te->GetName() << "\" more than once."; - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e.str(), - this->LG->GetMakefile()->GetBacktrace()); - return false; - } + generatedInterfaceRequired |= this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY; + }; + + if (!this->CollectExports(visitor)) { + return false; } if (generatedInterfaceRequired) { @@ -90,57 +68,7 @@ bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os) gte->Target->AppendBuildInterfaceIncludes(); ImportPropertyMap properties; - - this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, - properties); - - std::string errorMessage; - if (!this->PopulateCxxModuleExportProperties( - gte, properties, cmGeneratorExpression::BuildInterface, {}, - errorMessage)) { - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, errorMessage, - this->LG->GetMakefile()->GetBacktrace()); - return false; - } - - if (!this->PopulateExportProperties(gte, properties, errorMessage)) { - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, errorMessage, - this->LG->GetMakefile()->GetBacktrace()); + if (!this->PopulateInterfaceProperties(gte, properties)) { return false; } @@ -151,9 +79,6 @@ bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceLinkLibrariesProperty( gte, cmGeneratorExpression::BuildInterface, properties); } - this->PopulateCompatibleInterfaceProperties(gte, properties); - this->PopulateCustomTransitiveInterfaceProperties( - gte, cmGeneratorExpression::BuildInterface, properties); this->GenerateInterfaceProperties(gte, os, properties); @@ -239,185 +164,6 @@ void cmExportBuildCMakeConfigGenerator::GenerateImportTargetsConfig( } } -cmStateEnums::TargetType -cmExportBuildCMakeConfigGenerator::GetExportTargetType( - cmGeneratorTarget const* target) const -{ - cmStateEnums::TargetType targetType = target->GetType(); - // An object library exports as an interface library if we cannot - // tell clients where to find the objects. This is sufficient - // to support transitive usage requirements on other targets that - // use the object library. - if (targetType == cmStateEnums::OBJECT_LIBRARY && - !target->Target->HasKnownObjectFileLocation(nullptr)) { - targetType = cmStateEnums::INTERFACE_LIBRARY; - } - return targetType; -} - -void cmExportBuildCMakeConfigGenerator::SetExportSet(cmExportSet* exportSet) -{ - this->ExportSet = exportSet; -} - -void cmExportBuildCMakeConfigGenerator::SetImportLocationProperty( - std::string const& config, std::string const& suffix, - cmGeneratorTarget* target, ImportPropertyMap& properties) -{ - // Get the makefile in which to lookup target information. - cmMakefile* mf = target->Makefile; - - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix); - - // Compute all the object files inside this target and setup - // IMPORTED_OBJECTS as a list of object files - std::vector objectSources; - target->GetObjectSources(objectSources, config); - std::string const obj_dir = target->GetObjectDirectory(config); - std::vector objects; - for (cmSourceFile const* sf : objectSources) { - std::string const& obj = target->GetObjectName(sf); - objects.push_back(obj_dir + obj); - } - - // Store the property. - properties[prop] = cmList::to_string(objects); - } else { - // Add the main target file. - { - std::string prop = cmStrCat("IMPORTED_LOCATION", suffix); - std::string value; - if (target->IsAppBundleOnApple()) { - value = - target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact); - } else { - value = target->GetFullPath(config, - cmStateEnums::RuntimeBinaryArtifact, true); - } - properties[prop] = value; - } - - // Add the import library for windows DLLs. - if (target->HasImportLibrary(config)) { - std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix); - std::string value = - target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact, true); - if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { - target->GetImplibGNUtoMS(config, value, value, - "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); - } - properties[prop] = value; - } - } -} - -void cmExportBuildCMakeConfigGenerator::HandleMissingTarget( - std::string& link_libs, cmGeneratorTarget const* depender, - cmGeneratorTarget* dependee) -{ - // The target is not in the export. - if (!this->AppendMode) { - std::string const name = dependee->GetName(); - cmGlobalGenerator* gg = - dependee->GetLocalGenerator()->GetGlobalGenerator(); - auto exportInfo = this->FindBuildExportInfo(gg, name); - std::vector const& exportFiles = exportInfo.first; - - if (exportFiles.size() == 1) { - std::string missingTarget = exportInfo.second; - - missingTarget += dependee->GetExportName(); - link_libs += missingTarget; - this->MissingTargets.emplace_back(std::move(missingTarget)); - return; - } - // We are not appending, so all exported targets should be - // known here. This is probably user-error. - this->ComplainAboutMissingTarget(depender, dependee, exportFiles); - } - // Assume the target will be exported by another command. - // Append it with the export namespace. - link_libs += this->Namespace; - link_libs += dependee->GetExportName(); -} - -void cmExportBuildCMakeConfigGenerator::GetTargets( - std::vector& targets) const -{ - if (this->ExportSet) { - for (std::unique_ptr const& te : - this->ExportSet->GetTargetExports()) { - if (te->NamelinkOnly) { - continue; - } - targets.emplace_back(te->TargetName, te->XcFrameworkLocation); - } - return; - } - targets = this->Targets; -} - -std::pair, std::string> -cmExportBuildCMakeConfigGenerator::FindBuildExportInfo(cmGlobalGenerator* gg, - std::string const& name) -{ - std::vector exportFiles; - std::string ns; - - auto& exportSets = gg->GetBuildExportSets(); - - for (auto const& exp : exportSets) { - auto const& exportSet = exp.second; - std::vector targets; - exportSet->GetTargets(targets); - if (std::any_of( - targets.begin(), targets.end(), - [&name](TargetExport const& te) { return te.Name == name; })) { - exportFiles.push_back(exp.first); - ns = exportSet->GetNamespace(); - } - } - - return { exportFiles, ns }; -} - -void cmExportBuildCMakeConfigGenerator::ComplainAboutMissingTarget( - cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, - std::vector const& exportFiles) -{ - std::ostringstream e; - e << "export called with target \"" << depender->GetName() - << "\" which requires target \"" << dependee->GetName() << "\" "; - if (exportFiles.empty()) { - e << "that is not in any export set."; - } else { - e << "that is not in this export set, but in multiple other export sets: " - << cmJoin(exportFiles, ", ") << ".\n"; - e << "An exported target cannot depend upon another target which is " - "exported multiple times. Consider consolidating the exports of the " - "\"" - << dependee->GetName() << "\" target to a single export."; - } - - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e.str(), - this->LG->GetMakefile()->GetBacktrace()); -} - -std::string cmExportBuildCMakeConfigGenerator::InstallNameDir( - cmGeneratorTarget const* target, std::string const& config) -{ - std::string install_name_dir; - - cmMakefile* mf = target->Target->GetMakefile(); - if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - install_name_dir = target->GetInstallNameDirForBuildTree(config); - } - - return install_name_dir; -} - namespace { bool EntryIsContextSensitive( std::unique_ptr const& cge) @@ -427,7 +173,7 @@ bool EntryIsContextSensitive( } std::string cmExportBuildCMakeConfigGenerator::GetFileSetDirectories( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/) + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* /*te*/) { std::vector resultVector; @@ -475,7 +221,7 @@ std::string cmExportBuildCMakeConfigGenerator::GetFileSetDirectories( } std::string cmExportBuildCMakeConfigGenerator::GetFileSetFiles( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/) + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* /*te*/) { std::vector resultVector; @@ -536,11 +282,6 @@ std::string cmExportBuildCMakeConfigGenerator::GetFileSetFiles( return cmJoin(resultVector, " "); } -std::string cmExportBuildCMakeConfigGenerator::GetCxxModulesDirectory() const -{ - return this->CxxModulesDirectory; -} - void cmExportBuildCMakeConfigGenerator::GenerateCxxModuleConfigInformation( std::string const& name, std::ostream& os) const { diff --git a/Source/cmExportBuildCMakeConfigGenerator.h b/Source/cmExportBuildCMakeConfigGenerator.h index 0ba2a2bfb6..0648dc3a8f 100644 --- a/Source/cmExportBuildCMakeConfigGenerator.h +++ b/Source/cmExportBuildCMakeConfigGenerator.h @@ -6,130 +6,47 @@ #include #include -#include -#include -#include +#include "cmExportBuildFileGenerator.h" +#include "cmExportCMakeConfigGenerator.h" -#include "cmExportFileGenerator.h" -#include "cmStateTypes.h" - -class cmExportSet; class cmFileSet; class cmGeneratorTarget; -class cmGlobalGenerator; -class cmLocalGenerator; class cmTargetExport; /** \class cmExportBuildCMakeConfigGenerator * \brief Generate a file exporting targets from a build tree. * * cmExportBuildCMakeConfigGenerator generates a file exporting targets from - * a build tree. A single file exports information for all + * a build tree. This exports the targets to CMake's native package + * configuration format. A single file exports information for all * configurations built. * * This is used to implement the export() command. */ -class cmExportBuildCMakeConfigGenerator : public cmExportFileGenerator +class cmExportBuildCMakeConfigGenerator + : public cmExportCMakeConfigGenerator + , public cmExportBuildFileGenerator { public: - struct TargetExport - { - TargetExport(std::string name, std::string xcFrameworkLocation) - : Name(std::move(name)) - , XcFrameworkLocation(std::move(xcFrameworkLocation)) - { - } - - std::string Name; - std::string XcFrameworkLocation; - }; - cmExportBuildCMakeConfigGenerator(); - /** Set the list of targets to export. */ - void SetTargets(std::vector const& targets) - { - this->Targets = targets; - } - void GetTargets(std::vector& targets) const; - void AppendTargets(std::vector const& targets) - { - cm::append(this->Targets, targets); - } - void SetExportSet(cmExportSet*); - - /** Set the name of the C++ module directory. */ - void SetCxxModuleDirectory(std::string cxx_module_dir) - { - this->CxxModulesDirectory = std::move(cxx_module_dir); - } - std::string const& GetCxxModuleDirectory() const - { - return this->CxxModulesDirectory; - } - /** Set whether to append generated code to the output file. */ void SetAppendMode(bool append) { this->AppendMode = append; } - void Compute(cmLocalGenerator* lg); - protected: // Implement virtual methods from the superclass. bool GenerateMainFile(std::ostream& os) override; void GenerateImportTargetsConfig(std::ostream& os, std::string const& config, std::string const& suffix) override; - cmStateEnums::TargetType GetExportTargetType( - cmGeneratorTarget const* target) const; - void HandleMissingTarget(std::string& link_libs, - cmGeneratorTarget const* depender, - cmGeneratorTarget* dependee) override; - - void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, - cmGeneratorTarget const* dependee, - std::vector const& namespaces); - - /** Fill in properties indicating built file locations. */ - void SetImportLocationProperty(std::string const& config, - std::string const& suffix, - cmGeneratorTarget* target, - ImportPropertyMap& properties); - - std::string InstallNameDir(cmGeneratorTarget const* target, - std::string const& config) override; std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; + cmTargetExport const* te) override; std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; - cmExportSet* GetExportSet() const override { return this->ExportSet; } + cmTargetExport const* te) override; - std::string GetCxxModulesDirectory() const override; void GenerateCxxModuleConfigInformation(std::string const&, std::ostream&) const override; bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, std::string) const; - - std::pair, std::string> FindBuildExportInfo( - cmGlobalGenerator* gg, std::string const& name); - - struct TargetExportPrivate - { - TargetExportPrivate(cmGeneratorTarget* target, - std::string xcFrameworkLocation) - : Target(target) - , XcFrameworkLocation(std::move(xcFrameworkLocation)) - { - } - - cmGeneratorTarget* Target; - std::string XcFrameworkLocation; - }; - - std::vector Targets; - cmExportSet* ExportSet; - std::vector Exports; - cmLocalGenerator* LG; - // The directory for C++ module information. - std::string CxxModulesDirectory; }; diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 2885de0d32..73a458536b 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -3,20 +3,13 @@ #include "cmExportBuildFileGenerator.h" #include -#include #include #include #include #include #include -#include -#include - -#include "cmCryptoHash.h" #include "cmExportSet.h" -#include "cmFileSet.h" -#include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -24,11 +17,8 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" -#include "cmOutputConverter.h" -#include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" -#include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetExport.h" #include "cmValue.h" @@ -50,195 +40,6 @@ void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg) } } -bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) -{ - { - std::string expectedTargets; - std::string sep; - std::vector targets; - bool generatedInterfaceRequired = false; - this->GetTargets(targets); - for (auto const& tei : targets) { - cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name); - expectedTargets += sep + this->Namespace + te->GetExportName(); - sep = " "; - if (this->ExportedTargets.insert(te).second) { - this->Exports.emplace_back(te, tei.XcFrameworkLocation); - } else { - std::ostringstream e; - e << "given target \"" << te->GetName() << "\" more than once."; - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e.str(), - this->LG->GetMakefile()->GetBacktrace()); - return false; - } - generatedInterfaceRequired |= - this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY; - } - - if (generatedInterfaceRequired) { - this->SetRequiredCMakeVersion(3, 0, 0); - } - this->GenerateExpectedTargetsCode(os, expectedTargets); - } - - // Create all the imported targets. - for (auto const& exp : this->Exports) { - cmGeneratorTarget* gte = exp.Target; - this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte)); - - gte->Target->AppendBuildInterfaceIncludes(); - - ImportPropertyMap properties; - - this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte, - cmGeneratorExpression::BuildInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, - properties); - - std::string errorMessage; - if (!this->PopulateCxxModuleExportProperties( - gte, properties, cmGeneratorExpression::BuildInterface, {}, - errorMessage)) { - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, errorMessage, - this->LG->GetMakefile()->GetBacktrace()); - return false; - } - - if (!this->PopulateExportProperties(gte, properties, errorMessage)) { - this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, errorMessage, - this->LG->GetMakefile()->GetBacktrace()); - return false; - } - - bool const newCMP0022Behavior = - gte->GetPolicyStatusCMP0022() != cmPolicies::WARN && - gte->GetPolicyStatusCMP0022() != cmPolicies::OLD; - if (newCMP0022Behavior) { - this->PopulateInterfaceLinkLibrariesProperty( - gte, cmGeneratorExpression::BuildInterface, properties); - } - this->PopulateCompatibleInterfaceProperties(gte, properties); - this->PopulateCustomTransitiveInterfaceProperties( - gte, cmGeneratorExpression::BuildInterface, properties); - - this->GenerateInterfaceProperties(gte, os, properties); - - this->GenerateTargetFileSets(gte, os); - } - - std::string cxx_modules_name; - if (this->ExportSet) { - cxx_modules_name = this->ExportSet->GetName(); - } else { - cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); - constexpr std::size_t HASH_TRUNCATION = 12; - for (auto const& target : this->Targets) { - hasher.Append(target.Name); - } - cxx_modules_name = hasher.FinalizeHex().substr(0, HASH_TRUNCATION); - } - - this->GenerateCxxModuleInformation(cxx_modules_name, os); - - // Generate import file content for each configuration. - for (std::string const& c : this->Configurations) { - this->GenerateImportConfig(os, c); - } - - // Generate import file content for each configuration. - for (std::string const& c : this->Configurations) { - this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, c); - } - - this->GenerateMissingTargetsCheckCode(os); - - return true; -} - -void cmExportBuildFileGenerator::GenerateImportTargetsConfig( - std::ostream& os, std::string const& config, std::string const& suffix) -{ - for (auto const& exp : this->Exports) { - cmGeneratorTarget* target = exp.Target; - - // Collect import properties for this target. - ImportPropertyMap properties; - - if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) { - this->SetImportLocationProperty(config, suffix, target, properties); - } - if (!properties.empty()) { - // Get the rest of the target details. - if (this->GetExportTargetType(target) != - cmStateEnums::INTERFACE_LIBRARY) { - this->SetImportDetailProperties(config, suffix, target, properties); - this->SetImportLinkInterface(config, suffix, - cmGeneratorExpression::BuildInterface, - target, properties); - } - - // TODO: PUBLIC_HEADER_LOCATION - // This should wait until the build feature propagation stuff - // is done. Then this can be a propagated include directory. - // this->GenerateImportProperty(config, te->HeaderGenerator, - // properties); - - // Generate code in the export file. - std::string importedXcFrameworkLocation = exp.XcFrameworkLocation; - if (!importedXcFrameworkLocation.empty()) { - importedXcFrameworkLocation = cmGeneratorExpression::Preprocess( - importedXcFrameworkLocation, - cmGeneratorExpression::PreprocessContext::BuildInterface); - importedXcFrameworkLocation = cmGeneratorExpression::Evaluate( - importedXcFrameworkLocation, exp.Target->GetLocalGenerator(), config, - exp.Target, nullptr, exp.Target); - if (!importedXcFrameworkLocation.empty() && - !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation)) { - importedXcFrameworkLocation = - cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', - importedXcFrameworkLocation); - } - } - this->GenerateImportPropertyCode(os, config, suffix, target, properties, - importedXcFrameworkLocation); - } - } -} - cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType( cmGeneratorTarget const* target) const { @@ -311,13 +112,32 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( } } +bool cmExportBuildFileGenerator::CollectExports( + std::function visitor) +{ + std::vector targets; + this->GetTargets(targets); + for (auto const& tei : targets) { + cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name); + if (this->ExportedTargets.insert(te).second) { + this->Exports.emplace_back(te, tei.XcFrameworkLocation); + visitor(te); + } else { + this->ComplainAboutDuplicateTarget(te->GetName()); + return false; + } + } + + return true; +} + void cmExportBuildFileGenerator::HandleMissingTarget( std::string& link_libs, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) { // The target is not in the export. if (!this->AppendMode) { - std::string const name = dependee->GetName(); + std::string const& name = dependee->GetName(); cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator(); auto exportInfo = this->FindBuildExportInfo(gg, name); @@ -383,7 +203,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg, void cmExportBuildFileGenerator::ComplainAboutMissingTarget( cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, - std::vector const& exportFiles) + std::vector const& exportFiles) const { std::ostringstream e; e << "export called with target \"" << depender->GetName() @@ -399,8 +219,22 @@ void cmExportBuildFileGenerator::ComplainAboutMissingTarget( << dependee->GetName() << "\" target to a single export."; } + this->ReportError(e.str()); +} + +void cmExportBuildFileGenerator::ComplainAboutDuplicateTarget( + std::string const& targetName) const +{ + std::ostringstream e; + e << "given target \"" << targetName << "\" more than once."; + this->ReportError(e.str()); +} + +void cmExportBuildFileGenerator::ReportError( + std::string const& errorMessage) const +{ this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e.str(), + MessageType::FATAL_ERROR, errorMessage, this->LG->GetMakefile()->GetBacktrace()); } @@ -417,185 +251,22 @@ std::string cmExportBuildFileGenerator::InstallNameDir( return install_name_dir; } -namespace { -bool EntryIsContextSensitive( - std::unique_ptr const& cge) +bool cmExportBuildFileGenerator::PopulateInterfaceProperties( + cmGeneratorTarget const* target, ImportPropertyMap& properties) { - return cge->GetHadContextSensitiveCondition(); -} -} - -std::string cmExportBuildFileGenerator::GetFileSetDirectories( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/) -{ - std::vector resultVector; - - auto configs = - gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - auto directoryEntries = fileSet->CompileDirectoryEntries(); - - for (auto const& config : configs) { - auto directories = fileSet->EvaluateDirectoryEntries( - directoryEntries, gte->LocalGenerator, config, gte); - - bool const contextSensitive = - std::any_of(directoryEntries.begin(), directoryEntries.end(), - EntryIsContextSensitive); - - auto const& type = fileSet->GetType(); - // C++ modules do not support interface file sets which are dependent upon - // the configuration. - if (contextSensitive && type == "CXX_MODULES"_s) { - auto* mf = this->LG->GetMakefile(); - std::ostringstream e; - e << "The \"" << gte->GetName() << "\" target's interface file set \"" - << fileSet->GetName() << "\" of type \"" << type - << "\" contains context-sensitive base directory entries which is not " - "supported."; - mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return std::string{}; - } - - for (auto const& directory : directories) { - auto dest = cmOutputConverter::EscapeForCMake( - directory, cmOutputConverter::WrapQuotes::NoWrap); - - if (contextSensitive && configs.size() != 1) { - resultVector.push_back( - cmStrCat("\"$<$:", dest, ">\"")); - } else { - resultVector.emplace_back(cmStrCat('"', dest, '"')); - break; - } - } - } - - return cmJoin(resultVector, " "); -} - -std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte, - cmFileSet* fileSet, - cmTargetExport* /*te*/) -{ - std::vector resultVector; - - auto configs = - gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - - auto fileEntries = fileSet->CompileFileEntries(); - auto directoryEntries = fileSet->CompileDirectoryEntries(); - - for (auto const& config : configs) { - auto directories = fileSet->EvaluateDirectoryEntries( - directoryEntries, gte->LocalGenerator, config, gte); - - std::map> files; - for (auto const& entry : fileEntries) { - fileSet->EvaluateFileEntry(directories, files, entry, - gte->LocalGenerator, config, gte); - } - - bool const contextSensitive = - std::any_of(directoryEntries.begin(), directoryEntries.end(), - EntryIsContextSensitive) || - std::any_of(fileEntries.begin(), fileEntries.end(), - EntryIsContextSensitive); - - auto const& type = fileSet->GetType(); - // C++ modules do not support interface file sets which are dependent upon - // the configuration. - if (contextSensitive && type == "CXX_MODULES"_s) { - auto* mf = this->LG->GetMakefile(); - std::ostringstream e; - e << "The \"" << gte->GetName() << "\" target's interface file set \"" - << fileSet->GetName() << "\" of type \"" << type - << "\" contains context-sensitive file entries which is not " - "supported."; - mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return std::string{}; - } - - for (auto const& it : files) { - for (auto const& filename : it.second) { - auto escapedFile = cmOutputConverter::EscapeForCMake( - filename, cmOutputConverter::WrapQuotes::NoWrap); - if (contextSensitive && configs.size() != 1) { - resultVector.push_back( - cmStrCat("\"$<$:", escapedFile, ">\"")); - } else { - resultVector.emplace_back(cmStrCat('"', escapedFile, '"')); - } - } - } - - if (!(contextSensitive && configs.size() != 1)) { - break; - } - } - - return cmJoin(resultVector, " "); -} - -std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const -{ - return this->CxxModulesDirectory; -} - -void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation( - std::string const& name, std::ostream& os) const -{ - char const* opt = ""; - if (this->Configurations.size() > 1) { - // With more than one configuration, each individual file is optional. - opt = " OPTIONAL"; - } - - // Generate import file content for each configuration. - for (std::string c : this->Configurations) { - if (c.empty()) { - c = "noconfig"; - } - os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << '-' - << c << ".cmake\"" << opt << ")\n"; - } -} - -bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion( - std::string const& name, std::string config) const -{ - auto cxx_modules_dirname = this->GetCxxModulesDirectory(); - if (cxx_modules_dirname.empty()) { - return true; - } - - if (config.empty()) { - config = "noconfig"; - } - - std::string fileName = - cmStrCat(this->FileDir, '/', cxx_modules_dirname, "/cxx-modules-", name, - '-', config, ".cmake"); - - cmGeneratedFileStream os(fileName, true); - if (!os) { - std::string se = cmSystemTools::GetLastSystemError(); - std::ostringstream e; - e << "cannot write to file \"" << fileName << "\": " << se; - cmSystemTools::Error(e.str()); - return false; - } - os.SetCopyIfDifferent(true); - - for (auto const* tgt : this->ExportedTargets) { - // Only targets with C++ module sources will have a - // collator-generated install script. - if (!tgt->HaveCxx20ModuleSources()) { - continue; - } - - os << "include(\"${CMAKE_CURRENT_LIST_DIR}/target-" - << tgt->GetFilesystemExportName() << '-' << config << ".cmake\")\n"; - } - - return true; + this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", target, + cmGeneratorExpression::BuildInterface, + properties); + this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", target, + cmGeneratorExpression::BuildInterface, + properties); + this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", target, + cmGeneratorExpression::BuildInterface, + properties); + this->PopulateInterfaceProperty("INTERFACE_SOURCES", target, + cmGeneratorExpression::BuildInterface, + properties); + + return this->PopulateInterfaceProperties( + target, {}, cmGeneratorExpression::BuildInterface, properties); } diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 3c3d0b25a6..a4f8c5f870 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -4,7 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include +#include #include #include #include @@ -15,22 +15,19 @@ #include "cmStateTypes.h" class cmExportSet; -class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmLocalGenerator; -class cmTargetExport; -/** \class cmExportBuildFileGenerator +/** \class cmExportBuildCMakeConfigGenerator * \brief Generate a file exporting targets from a build tree. * - * cmExportBuildFileGenerator generates a file exporting targets from - * a build tree. A single file exports information for all - * configurations built. + * cmExportBuildCMakeConfigGenerator is the interface class for generating a + * file exporting targets from a build tree. * * This is used to implement the export() command. */ -class cmExportBuildFileGenerator : public cmExportFileGenerator +class cmExportBuildFileGenerator : virtual public cmExportFileGenerator { public: struct TargetExport @@ -69,25 +66,28 @@ public: return this->CxxModulesDirectory; } - /** Set whether to append generated code to the output file. */ - void SetAppendMode(bool append) { this->AppendMode = append; } - void Compute(cmLocalGenerator* lg); protected: - // Implement virtual methods from the superclass. - bool GenerateMainFile(std::ostream& os) override; - void GenerateImportTargetsConfig(std::ostream& os, std::string const& config, - std::string const& suffix) override; cmStateEnums::TargetType GetExportTargetType( cmGeneratorTarget const* target) const; + + /** Walk the list of targets to be exported. Returns true iff no duplicates + are found. */ + bool CollectExports(std::function visitor); + void HandleMissingTarget(std::string& link_libs, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) override; - void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, - cmGeneratorTarget const* dependee, - std::vector const& namespaces); + void ComplainAboutMissingTarget( + cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, + std::vector const& namespaces) const; + + void ComplainAboutDuplicateTarget( + std::string const& targetName) const override; + + void ReportError(std::string const& errorMessage) const override; /** Fill in properties indicating built file locations. */ void SetImportLocationProperty(std::string const& config, @@ -98,21 +98,20 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, std::string const& config) override; - std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; - std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; cmExportSet* GetExportSet() const override { return this->ExportSet; } - std::string GetCxxModulesDirectory() const override; - void GenerateCxxModuleConfigInformation(std::string const&, - std::ostream&) const override; - bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, - std::string) const; + std::string GetCxxModulesDirectory() const override + { + return this->CxxModulesDirectory; + } std::pair, std::string> FindBuildExportInfo( cmGlobalGenerator* gg, std::string const& name); + using cmExportFileGenerator::PopulateInterfaceProperties; + bool PopulateInterfaceProperties(cmGeneratorTarget const* target, + ImportPropertyMap& properties); + struct TargetExportPrivate { TargetExportPrivate(cmGeneratorTarget* target, diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx index b7849a0f41..4f4765c964 100644 --- a/Source/cmExportCMakeConfigGenerator.cxx +++ b/Source/cmExportCMakeConfigGenerator.cxx @@ -3,33 +3,26 @@ #include "cmExportCMakeConfigGenerator.h" #include -#include #include -#include #include #include +#include -#include #include #include #include -#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" -#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmPropertyMap.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -37,7 +30,7 @@ #include "cmValue.h" #include "cmVersion.h" -static std::string cmExportCMakeConfigGeneratorEscape(std::string const& str) +static std::string cmExportFileGeneratorEscape(std::string const& str) { // Escape a property value for writing into a .cmake file. std::string result = cmOutputConverter::EscapeForCMake(str); @@ -49,56 +42,15 @@ static std::string cmExportCMakeConfigGeneratorEscape(std::string const& str) return result; } -cmExportCMakeConfigGenerator::cmExportCMakeConfigGenerator() +cmExportCMakeConfigGenerator::cmExportCMakeConfigGenerator() = default; + +cm::string_view cmExportCMakeConfigGenerator::GetImportPrefixWithSlash() const { - this->AppendMode = false; - this->ExportOld = false; + return "${_IMPORT_PREFIX}/"_s; } -void cmExportCMakeConfigGenerator::AddConfiguration(std::string const& config) +bool cmExportCMakeConfigGenerator::GenerateImportFile(std::ostream& os) { - this->Configurations.push_back(config); -} - -void cmExportCMakeConfigGenerator::SetExportFile(char const* mainFile) -{ - this->MainImportFile = mainFile; - this->FileDir = cmSystemTools::GetFilenamePath(this->MainImportFile); - this->FileBase = - cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile); - this->FileExt = - cmSystemTools::GetFilenameLastExtension(this->MainImportFile); -} - -std::string const& cmExportCMakeConfigGenerator::GetMainExportFileName() const -{ - return this->MainImportFile; -} - -bool cmExportCMakeConfigGenerator::GenerateImportFile() -{ - // Open the output file to generate it. - std::unique_ptr foutPtr; - if (this->AppendMode) { - // Open for append. - auto openmodeApp = std::ios::app; - foutPtr = cm::make_unique(this->MainImportFile.c_str(), - openmodeApp); - } else { - // Generate atomically and with copy-if-different. - std::unique_ptr ap( - new cmGeneratedFileStream(this->MainImportFile, true)); - ap->SetCopyIfDifferent(true); - foutPtr = std::move(ap); - } - if (!foutPtr || !*foutPtr) { - std::string se = cmSystemTools::GetLastSystemError(); - std::ostringstream e; - e << "cannot write to file \"" << this->MainImportFile << "\": " << se; - cmSystemTools::Error(e.str()); - return false; - } - std::ostream& os = *foutPtr; std::stringstream mainFileWithHeadersAndFootersBuffer; // Start with the import file header. @@ -132,499 +84,6 @@ bool cmExportCMakeConfigGenerator::GenerateImportFile() return result; } -void cmExportCMakeConfigGenerator::GenerateImportConfig( - std::ostream& os, std::string const& config) -{ - // Construct the property configuration suffix. - std::string suffix = "_"; - if (!config.empty()) { - suffix += cmSystemTools::UpperCase(config); - } else { - suffix += "NOCONFIG"; - } - - // Generate the per-config target information. - this->GenerateImportTargetsConfig(os, config, suffix); -} - -void cmExportCMakeConfigGenerator::PopulateInterfaceProperty( - std::string const& propName, cmGeneratorTarget const* target, - ImportPropertyMap& properties) -{ - cmValue input = target->GetProperty(propName); - if (input) { - properties[propName] = *input; - } -} - -void cmExportCMakeConfigGenerator::PopulateInterfaceProperty( - std::string const& propName, std::string const& outputName, - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - cmValue input = target->GetProperty(propName); - if (input) { - if (input->empty()) { - // Set to empty - properties[outputName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target); - properties[outputName] = prepro; - } - } -} - -bool cmExportCMakeConfigGenerator::PopulateInterfaceLinkLibrariesProperty( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - if (!target->IsLinkable()) { - return false; - } - static std::array const linkIfaceProps = { - { "INTERFACE_LINK_LIBRARIES", "INTERFACE_LINK_LIBRARIES_DIRECT", - "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE" } - }; - bool hadINTERFACE_LINK_LIBRARIES = false; - for (std::string const& linkIfaceProp : linkIfaceProps) { - if (cmValue input = target->GetProperty(linkIfaceProp)) { - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, - ReplaceFreeTargets); - properties[linkIfaceProp] = prepro; - hadINTERFACE_LINK_LIBRARIES = true; - } - } - } - return hadINTERFACE_LINK_LIBRARIES; -} - -static bool isSubDirectory(std::string const& a, std::string const& b) -{ - return (cmSystemTools::ComparePath(a, b) || - cmSystemTools::IsSubDirectory(a, b)); -} - -static bool checkInterfaceDirs(std::string const& prepro, - cmGeneratorTarget const* target, - std::string const& prop) -{ - std::string const& installDir = - target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); - std::string const& topSourceDir = - target->GetLocalGenerator()->GetSourceDirectory(); - std::string const& topBinaryDir = - target->GetLocalGenerator()->GetBinaryDirectory(); - - std::vector parts; - cmGeneratorExpression::Split(prepro, parts); - - bool const inSourceBuild = topSourceDir == topBinaryDir; - - bool hadFatalError = false; - - for (std::string const& li : parts) { - size_t genexPos = cmGeneratorExpression::Find(li); - if (genexPos == 0) { - continue; - } - if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) { - continue; - } - MessageType messageType = MessageType::FATAL_ERROR; - std::ostringstream e; - if (genexPos != std::string::npos) { - if (prop == "INTERFACE_INCLUDE_DIRECTORIES") { - switch (target->GetPolicyStatusCMP0041()) { - case cmPolicies::WARN: - messageType = MessageType::WARNING; - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n"; - break; - case cmPolicies::OLD: - continue; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - hadFatalError = true; - break; // Issue fatal message. - } - } else { - hadFatalError = true; - } - } - if (!cmSystemTools::FileIsFullPath(li)) { - /* clang-format off */ - e << "Target \"" << target->GetName() << "\" " << prop << - " property contains relative path:\n" - " \"" << li << "\""; - /* clang-format on */ - target->GetLocalGenerator()->IssueMessage(messageType, e.str()); - } - bool inBinary = isSubDirectory(li, topBinaryDir); - bool inSource = isSubDirectory(li, topSourceDir); - if (isSubDirectory(li, installDir)) { - // The include directory is inside the install tree. If the - // install tree is not inside the source tree or build tree then - // fall through to the checks below that the include directory is not - // also inside the source tree or build tree. - bool shouldContinue = - (!inBinary || isSubDirectory(installDir, topBinaryDir)) && - (!inSource || isSubDirectory(installDir, topSourceDir)); - - if (prop == "INTERFACE_INCLUDE_DIRECTORIES") { - if (!shouldContinue) { - switch (target->GetPolicyStatusCMP0052()) { - case cmPolicies::WARN: { - std::ostringstream s; - s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n"; - s << "Directory:\n \"" << li - << "\"\nin " - "INTERFACE_INCLUDE_DIRECTORIES of target \"" - << target->GetName() - << "\" is a subdirectory of the install " - "directory:\n \"" - << installDir - << "\"\nhowever it is also " - "a subdirectory of the " - << (inBinary ? "build" : "source") << " tree:\n \"" - << (inBinary ? topBinaryDir : topSourceDir) << "\"\n"; - target->GetLocalGenerator()->IssueMessage( - MessageType::AUTHOR_WARNING, s.str()); - CM_FALLTHROUGH; - } - case cmPolicies::OLD: - shouldContinue = true; - break; - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::NEW: - break; - } - } - } - if (shouldContinue) { - continue; - } - } - if (inBinary) { - /* clang-format off */ - e << "Target \"" << target->GetName() << "\" " << prop << - " property contains path:\n" - " \"" << li << "\"\nwhich is prefixed in the build directory."; - /* clang-format on */ - target->GetLocalGenerator()->IssueMessage(messageType, e.str()); - } - if (!inSourceBuild) { - if (inSource) { - e << "Target \"" << target->GetName() << "\" " << prop - << " property contains path:\n" - " \"" - << li << "\"\nwhich is prefixed in the source directory."; - target->GetLocalGenerator()->IssueMessage(messageType, e.str()); - } - } - } - return !hadFatalError; -} - -static void prefixItems(std::string& exportDirs) -{ - std::vector entries; - cmGeneratorExpression::Split(exportDirs, entries); - exportDirs.clear(); - char const* sep = ""; - for (std::string const& e : entries) { - exportDirs += sep; - sep = ";"; - if (!cmSystemTools::FileIsFullPath(e) && - e.find("${_IMPORT_PREFIX}") == std::string::npos) { - exportDirs += "${_IMPORT_PREFIX}/"; - } - exportDirs += e; - } -} - -void cmExportCMakeConfigGenerator::PopulateSourcesInterface( - cmGeneratorTarget const* gt, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - char const* propName = "INTERFACE_SOURCES"; - cmValue input = gt->GetProperty(propName); - - if (!input) { - return; - } - - if (input->empty()) { - properties[propName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt); - - if (!checkInterfaceDirs(prepro, gt, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportCMakeConfigGenerator::PopulateIncludeDirectoriesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, cmTargetExport const& te, - std::string& includesDestinationDirs) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - includesDestinationDirs.clear(); - - char const* propName = "INTERFACE_INCLUDE_DIRECTORIES"; - cmValue input = target->GetProperty(propName); - - cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance()); - - std::string dirs = cmGeneratorExpression::Preprocess( - cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)), - preprocessRule, true); - this->ReplaceInstallPrefix(dirs); - std::unique_ptr cge = ge.Parse(dirs); - std::string exportDirs = - cge->Evaluate(target->GetLocalGenerator(), "", target); - - if (cge->GetHadContextSensitiveCondition()) { - cmLocalGenerator* lg = target->GetLocalGenerator(); - std::ostringstream e; - e << "Target \"" << target->GetName() - << "\" is installed with " - "INCLUDES DESTINATION set to a context sensitive path. Paths which " - "depend on the configuration, policy values or the link interface " - "are " - "not supported. Consider using target_include_directories instead."; - lg->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return; - } - - if (!input && exportDirs.empty()) { - return; - } - if ((input && input->empty()) && exportDirs.empty()) { - // Set to empty - properties[propName].clear(); - return; - } - - prefixItems(exportDirs); - includesDestinationDirs = exportDirs; - - std::string includes = (input ? *input : ""); - char const* sep = input ? ";" : ""; - includes += sep + exportDirs; - std::string prepro = - cmGeneratorExpression::Preprocess(includes, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target); - - if (!checkInterfaceDirs(prepro, target, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportCMakeConfigGenerator::PopulateLinkDependsInterface( - cmGeneratorTarget const* gt, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - char const* propName = "INTERFACE_LINK_DEPENDS"; - cmValue input = gt->GetProperty(propName); - - if (!input) { - return; - } - - if (input->empty()) { - properties[propName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt); - - if (!checkInterfaceDirs(prepro, gt, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportCMakeConfigGenerator::PopulateLinkDirectoriesInterface( - cmGeneratorTarget const* gt, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - char const* propName = "INTERFACE_LINK_DIRECTORIES"; - cmValue input = gt->GetProperty(propName); - - if (!input) { - return; - } - - if (input->empty()) { - properties[propName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt); - - if (!checkInterfaceDirs(prepro, gt, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportCMakeConfigGenerator::PopulateInterfaceProperty( - std::string const& propName, cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - this->PopulateInterfaceProperty(propName, propName, target, preprocessRule, - properties); -} - -static void getPropertyContents(cmGeneratorTarget const* tgt, - std::string const& prop, - std::set& ifaceProperties) -{ - cmValue p = tgt->GetProperty(prop); - if (!p) { - return; - } - cmList content{ *p }; - ifaceProperties.insert(content.begin(), content.end()); -} - -static void getCompatibleInterfaceProperties( - cmGeneratorTarget const* target, std::set& ifaceProperties, - std::string const& config) -{ - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - // object libraries have no link information, so nothing to compute - return; - } - - cmComputeLinkInformation* info = target->GetLinkInformation(config); - - if (!info) { - cmLocalGenerator* lg = target->GetLocalGenerator(); - std::ostringstream e; - e << "Exporting the target \"" << target->GetName() - << "\" is not " - "allowed since its linker language cannot be determined"; - lg->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return; - } - - cmComputeLinkInformation::ItemVector const& deps = info->GetItems(); - - for (auto const& dep : deps) { - if (!dep.Target || dep.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - continue; - } - getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_BOOL", - ifaceProperties); - getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_STRING", - ifaceProperties); - getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_NUMBER_MIN", - ifaceProperties); - getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_NUMBER_MAX", - ifaceProperties); - } -} - -void cmExportCMakeConfigGenerator::PopulateCompatibleInterfaceProperties( - cmGeneratorTarget const* gtarget, ImportPropertyMap& properties) -{ - this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget, - properties); - this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", gtarget, - properties); - this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MIN", gtarget, - properties); - this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MAX", gtarget, - properties); - - std::set ifaceProperties; - - getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties); - getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_STRING", ifaceProperties); - getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MIN", - ifaceProperties); - getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MAX", - ifaceProperties); - - if (gtarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - std::vector configNames = - gtarget->Target->GetMakefile()->GetGeneratorConfigs( - cmMakefile::IncludeEmptyConfig); - - for (std::string const& cn : configNames) { - getCompatibleInterfaceProperties(gtarget, ifaceProperties, cn); - } - } - - for (std::string const& ip : ifaceProperties) { - this->PopulateInterfaceProperty("INTERFACE_" + ip, gtarget, properties); - } -} - -void cmExportCMakeConfigGenerator::PopulateCustomTransitiveInterfaceProperties( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - this->PopulateInterfaceProperty("TRANSITIVE_COMPILE_PROPERTIES", target, - properties); - this->PopulateInterfaceProperty("TRANSITIVE_LINK_PROPERTIES", target, - properties); - std::set ifaceProperties; - for (std::string const& config : this->Configurations) { - for (auto const& i : target->GetCustomTransitiveProperties( - config, cmGeneratorTarget::PropertyFor::Interface)) { - ifaceProperties.emplace(i.second.InterfaceName); - } - } - for (std::string const& ip : ifaceProperties) { - this->PopulateInterfaceProperty(ip, target, preprocessRule, properties); - } -} - void cmExportCMakeConfigGenerator::GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, ImportPropertyMap const& properties) @@ -635,181 +94,12 @@ void cmExportCMakeConfigGenerator::GenerateInterfaceProperties( os << "set_target_properties(" << targetName << " PROPERTIES\n"; for (auto const& property : properties) { os << " " << property.first << " " - << cmExportCMakeConfigGeneratorEscape(property.second) << "\n"; + << cmExportFileGeneratorEscape(property.second) << "\n"; } os << ")\n\n"; } } -bool cmExportCMakeConfigGenerator::AddTargetNamespace( - std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg) -{ - cmGeneratorTarget::TargetOrString resolved = - target->ResolveTargetReference(input, lg); - - cmGeneratorTarget* tgt = resolved.Target; - if (!tgt) { - input = resolved.String; - 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; - } - if (this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) { - input = this->Namespace + tgt->GetExportName(); - } else { - std::string namespacedTarget; - this->HandleMissingTarget(namespacedTarget, target, tgt); - if (!namespacedTarget.empty()) { - input = namespacedTarget; - } else { - input = tgt->GetName(); - } - } - return true; -} - -void cmExportCMakeConfigGenerator::ResolveTargetsInGeneratorExpressions( - std::string& input, cmGeneratorTarget const* target, - FreeTargetsReplace replace) -{ - cmLocalGenerator const* lg = target->GetLocalGenerator(); - if (replace == NoReplaceFreeTargets) { - this->ResolveTargetsInGeneratorExpression(input, target, lg); - return; - } - std::vector parts; - cmGeneratorExpression::Split(input, parts); - - std::string sep; - input.clear(); - for (std::string& li : parts) { - if (target->IsLinkLookupScope(li, lg)) { - continue; - } - if (cmGeneratorExpression::Find(li) == std::string::npos) { - this->AddTargetNamespace(li, target, lg); - } else { - this->ResolveTargetsInGeneratorExpression(li, target, lg); - } - input += sep + li; - sep = ";"; - } -} - -void cmExportCMakeConfigGenerator::ResolveTargetsInGeneratorExpression( - std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg) -{ - std::string::size_type pos = 0; - std::string::size_type lastPos = pos; - - while ((pos = input.find("$', nameStartPos); - std::string::size_type commaPos = input.find(',', nameStartPos); - std::string::size_type nextOpenPos = input.find("$<", nameStartPos); - if (commaPos == std::string::npos // Implied 'this' target - || closePos == std::string::npos // Incomplete expression. - || closePos < commaPos // Implied 'this' target - || nextOpenPos < commaPos) // Non-literal - { - lastPos = nameStartPos; - continue; - } - - std::string targetName = - input.substr(nameStartPos, commaPos - nameStartPos); - - if (this->AddTargetNamespace(targetName, target, lg)) { - input.replace(nameStartPos, commaPos - nameStartPos, targetName); - } - lastPos = nameStartPos + targetName.size() + 1; - } - - std::string errorString; - pos = 0; - lastPos = pos; - while ((pos = input.find("$', nameStartPos); - if (endPos == std::string::npos) { - errorString = "$ expression incomplete"; - break; - } - std::string targetName = input.substr(nameStartPos, endPos - nameStartPos); - if (targetName.find("$<") != std::string::npos) { - errorString = "$ requires its parameter to be a " - "literal."; - break; - } - if (!this->AddTargetNamespace(targetName, target, lg)) { - errorString = "$ requires its parameter to be a " - "reachable target."; - break; - } - input.replace(pos, endPos - pos + 1, targetName); - lastPos = pos + targetName.size(); - } - - pos = 0; - lastPos = pos; - while (errorString.empty() && - (pos = input.find("$', nameStartPos); - if (endPos == std::string::npos) { - errorString = "$ expression incomplete"; - break; - } - std::string libName = input.substr(nameStartPos, endPos - nameStartPos); - if (cmGeneratorExpression::IsValidTargetName(libName) && - this->AddTargetNamespace(libName, target, lg)) { - input.replace(nameStartPos, endPos - nameStartPos, libName); - } - lastPos = nameStartPos + libName.size() + 1; - } - - while (errorString.empty() && - (pos = input.find("$', nameStartPos); - if (endPos == std::string::npos) { - errorString = "$ expression incomplete"; - break; - } - std::string libName = input.substr(nameStartPos, endPos - nameStartPos); - if (cmGeneratorExpression::IsValidTargetName(libName) && - this->AddTargetNamespace(libName, target, lg)) { - input.replace(nameStartPos, endPos - nameStartPos, libName); - } - lastPos = nameStartPos + libName.size() + 1; - } - - this->ReplaceInstallPrefix(input); - - if (!errorString.empty()) { - target->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR, - errorString); - } -} - -void cmExportCMakeConfigGenerator::ReplaceInstallPrefix( - std::string& /*unused*/) -{ - // Do nothing -} - void cmExportCMakeConfigGenerator::SetImportLinkInterface( std::string const& config, std::string const& suffix, cmGeneratorExpression::PreprocessContext preprocessRule, @@ -870,131 +160,16 @@ void cmExportCMakeConfigGenerator::SetImportLinkInterface( } } -void cmExportCMakeConfigGenerator::SetImportDetailProperties( - std::string const& config, std::string const& suffix, - cmGeneratorTarget* target, ImportPropertyMap& properties) -{ - // Get the makefile in which to lookup target information. - cmMakefile* mf = target->Makefile; - - // Add the soname for unix shared libraries. - if (target->GetType() == cmStateEnums::SHARED_LIBRARY || - target->GetType() == cmStateEnums::MODULE_LIBRARY) { - if (!target->IsDLLPlatform()) { - std::string prop; - std::string value; - if (target->HasSOName(config)) { - if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - value = this->InstallNameDir(target, config); - } - prop = "IMPORTED_SONAME"; - value += target->GetSOName(config); - } else { - prop = "IMPORTED_NO_SONAME"; - value = "TRUE"; - } - prop += suffix; - properties[prop] = value; - } - } - - // Add the transitive link dependencies for this configuration. - if (cmLinkInterface const* iface = - target->GetLinkInterface(config, target)) { - this->SetImportLinkProperty( - suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages, - properties, ImportLinkPropertyTargetNames::No); - - // 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 = - cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix); - properties[prop] = std::to_string(iface->Multiplicity); - } - } - - // Add information if this target is a managed target - if (target->GetManagedType(config) != - cmGeneratorTarget::ManagedType::Native) { - std::string prop = cmStrCat("IMPORTED_COMMON_LANGUAGE_RUNTIME", suffix); - std::string propval; - if (cmValue p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) { - propval = *p; - } else if (target->IsCSharpOnly()) { - // C# projects do not have the /clr flag, so we set the property - // here to mark the target as (only) managed (i.e. no .lib file - // to link to). Otherwise the COMMON_LANGUAGE_RUNTIME target - // property would have to be set manually for C# targets to make - // exporting/importing work. - propval = "CSharp"; - } - properties[prop] = propval; - } -} - -static std::string const& asString(std::string const& l) -{ - return l; -} - -static std::string const& asString(cmLinkItem const& l) -{ - return l.AsStr(); -} - -template -void cmExportCMakeConfigGenerator::SetImportLinkProperty( - std::string const& suffix, cmGeneratorTarget const* target, - std::string const& propName, std::vector const& entries, - ImportPropertyMap& properties, ImportLinkPropertyTargetNames targetNames) -{ - // Skip the property if there are no entries. - if (entries.empty()) { - return; - } - - cmLocalGenerator const* lg = target->GetLocalGenerator(); - - // Construct the property value. - std::string link_entries; - char const* sep = ""; - for (T const& l : entries) { - // Separate this from the previous entry. - link_entries += sep; - sep = ";"; - - if (targetNames == ImportLinkPropertyTargetNames::Yes) { - std::string temp = asString(l); - this->AddTargetNamespace(temp, target, lg); - link_entries += temp; - } else { - link_entries += asString(l); - } - } - - // Store the property. - std::string prop = cmStrCat(propName, suffix); - properties[prop] = link_entries; -} - void cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode(std::ostream& os) { // Protect that file against use with older CMake versions. /* clang-format off */ os << "# Generated by CMake\n\n"; os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.8)\n" - << " message(FATAL_ERROR \"CMake >= 2.8.0 required\")\n" + << " message(FATAL_ERROR \"CMake >= " + << this->RequiredCMakeVersionMajor << '.' + << this->RequiredCMakeVersionMinor << '.' + << this->RequiredCMakeVersionPatch << " required\")\n" << "endif()\n" << "if(CMAKE_VERSION VERSION_LESS \"" << this->RequiredCMakeVersionMajor << '.' @@ -1010,7 +185,7 @@ void cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode(std::ostream& os) // Isolate the file policy level. // Support CMake versions as far back as the // RequiredCMakeVersion{Major,Minor,Patch}, but also support using NEW - // policy settings for up to CMake 3.28 (this upper limit may be reviewed + // policy settings for up to CMake 3.29 (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. @@ -1019,7 +194,7 @@ void cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode(std::ostream& os) << "cmake_policy(VERSION " << this->RequiredCMakeVersionMajor << '.' << this->RequiredCMakeVersionMinor << '.' - << this->RequiredCMakeVersionPatch << "...3.28)\n"; + << this->RequiredCMakeVersionPatch << "...3.29)\n"; /* clang-format on */ } @@ -1162,8 +337,7 @@ void cmExportCMakeConfigGenerator::GenerateImportTargetCode( // generate DEPRECATION if (target->IsDeprecated()) { os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION " - << cmExportCMakeConfigGeneratorEscape(target->GetDeprecation()) - << ")\n"; + << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n"; } if (target->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) { @@ -1205,7 +379,7 @@ void cmExportCMakeConfigGenerator::GenerateImportPropertyCode( if (importedXcFrameworkLocation.empty() || property.first != importedLocationProp) { os << " " << property.first << " " - << cmExportCMakeConfigGeneratorEscape(property.second) << "\n"; + << cmExportFileGeneratorEscape(property.second) << "\n"; } } os << " )\n"; @@ -1213,14 +387,14 @@ void cmExportCMakeConfigGenerator::GenerateImportPropertyCode( auto importedLocationIt = properties.find(importedLocationProp); if (importedLocationIt != properties.end()) { os << "if(NOT CMAKE_VERSION VERSION_LESS \"3.28\" AND IS_DIRECTORY " - << cmExportCMakeConfigGeneratorEscape(importedXcFrameworkLocation) + << cmExportFileGeneratorEscape(importedXcFrameworkLocation) << ")\n" " set_property(TARGET " << targetName << " PROPERTY " << importedLocationProp << " " - << cmExportCMakeConfigGeneratorEscape(importedXcFrameworkLocation) + << cmExportFileGeneratorEscape(importedXcFrameworkLocation) << ")\nelse()\n set_property(TARGET " << targetName << " PROPERTY " << importedLocationProp << " " - << cmExportCMakeConfigGeneratorEscape(importedLocationIt->second) + << cmExportFileGeneratorEscape(importedLocationIt->second) << ")\nendif()\n"; } } @@ -1389,7 +563,7 @@ void cmExportCMakeConfigGenerator::GenerateImportedFileCheckLoop( } void cmExportCMakeConfigGenerator::GenerateImportedFileChecksCode( - std::ostream& os, cmGeneratorTarget* target, + std::ostream& os, cmGeneratorTarget const* target, ImportPropertyMap const& properties, std::set const& importedLocations, std::string const& importedXcFrameworkLocation) @@ -1400,193 +574,22 @@ void cmExportCMakeConfigGenerator::GenerateImportedFileChecksCode( os << "list(APPEND _cmake_import_check_targets " << targetName << " )\n"; if (!importedXcFrameworkLocation.empty()) { os << "set(_cmake_import_check_xcframework_for_" << targetName << ' ' - << cmExportCMakeConfigGeneratorEscape(importedXcFrameworkLocation) - << ")\n"; + << cmExportFileGeneratorEscape(importedXcFrameworkLocation) << ")\n"; } os << "list(APPEND _cmake_import_check_files_for_" << targetName << " "; for (std::string const& li : importedLocations) { auto pi = properties.find(li); if (pi != properties.end()) { - os << cmExportCMakeConfigGeneratorEscape(pi->second) << " "; + os << cmExportFileGeneratorEscape(pi->second) << " "; } } os << ")\n\n"; } -enum class ExportWhen -{ - Defined, - Always, -}; - -enum class PropertyType -{ - Strings, - Paths, - IncludePaths, -}; - -namespace { -bool PropertyTypeIsForPaths(PropertyType pt) -{ - switch (pt) { - case PropertyType::Strings: - return false; - case PropertyType::Paths: - case PropertyType::IncludePaths: - return true; - } - return false; -} -} - -struct ModuleTargetPropertyTable -{ - cm::static_string_view Name; - ExportWhen Cond; -}; - -struct ModulePropertyTable -{ - cm::static_string_view Name; - PropertyType Type; -}; - -bool cmExportCMakeConfigGenerator::PopulateCxxModuleExportProperties( - cmGeneratorTarget const* gte, ImportPropertyMap& properties, - cmGeneratorExpression::PreprocessContext ctx, - std::string const& includesDestinationDirs, std::string& errorMessage) -{ - if (!gte->HaveCxx20ModuleSources(&errorMessage)) { - return true; - } - - ModuleTargetPropertyTable const exportedDirectModuleProperties[] = { - { "CXX_EXTENSIONS"_s, ExportWhen::Defined }, - // Always define this property as it is an intrinsic property of the target - // and should not be inherited from the in-scope `CMAKE_CXX_MODULE_STD` - // variable. - // - // TODO(cxxmodules): A future policy may make this "ON" based on the target - // policies if unset. Add a new `ExportWhen` condition to handle it when - // this happens. - { "CXX_MODULE_STD"_s, ExportWhen::Always }, - }; - for (auto const& prop : exportedDirectModuleProperties) { - auto const propNameStr = std::string(prop.Name); - cmValue propValue = gte->Target->GetComputedProperty( - propNameStr, *gte->Target->GetMakefile()); - if (!propValue) { - propValue = gte->Target->GetProperty(propNameStr); - } - if (propValue) { - properties[propNameStr] = - cmGeneratorExpression::Preprocess(*propValue, ctx); - } else if (prop.Cond == ExportWhen::Always) { - properties[propNameStr] = ""; - } - } - - ModulePropertyTable const exportedModuleProperties[] = { - { "INCLUDE_DIRECTORIES"_s, PropertyType::IncludePaths }, - { "COMPILE_DEFINITIONS"_s, PropertyType::Strings }, - { "COMPILE_OPTIONS"_s, PropertyType::Strings }, - { "COMPILE_FEATURES"_s, PropertyType::Strings }, - }; - for (auto const& propEntry : exportedModuleProperties) { - auto const propNameStr = std::string(propEntry.Name); - cmValue prop = gte->Target->GetComputedProperty( - propNameStr, *gte->Target->GetMakefile()); - if (!prop) { - prop = gte->Target->GetProperty(propNameStr); - } - if (prop) { - auto const exportedPropName = - cmStrCat("IMPORTED_CXX_MODULES_", propEntry.Name); - properties[exportedPropName] = - cmGeneratorExpression::Preprocess(*prop, ctx); - if (ctx == cmGeneratorExpression::InstallInterface && - PropertyTypeIsForPaths(propEntry.Type)) { - this->ReplaceInstallPrefix(properties[exportedPropName]); - prefixItems(properties[exportedPropName]); - if (propEntry.Type == PropertyType::IncludePaths && - !includesDestinationDirs.empty()) { - if (!properties[exportedPropName].empty()) { - properties[exportedPropName] += ';'; - } - properties[exportedPropName] += includesDestinationDirs; - } - } - } - } - - cm::static_string_view const exportedLinkModuleProperties[] = { - "LINK_LIBRARIES"_s, - }; - for (auto const& propName : exportedLinkModuleProperties) { - auto const propNameStr = std::string(propName); - cmValue prop = gte->Target->GetComputedProperty( - propNameStr, *gte->Target->GetMakefile()); - if (!prop) { - prop = gte->Target->GetProperty(propNameStr); - } - if (prop) { - auto const exportedPropName = - cmStrCat("IMPORTED_CXX_MODULES_", propName); - auto value = cmGeneratorExpression::Preprocess(*prop, ctx); - this->ResolveTargetsInGeneratorExpressions( - value, gte, cmExportCMakeConfigGenerator::ReplaceFreeTargets); - properties[exportedPropName] = value; - } - } - - return true; -} - -bool cmExportCMakeConfigGenerator::PopulateExportProperties( - cmGeneratorTarget const* gte, ImportPropertyMap& properties, - std::string& errorMessage) -{ - auto const& targetProperties = gte->Target->GetProperties(); - if (cmValue exportProperties = - targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) { - for (auto& prop : cmList{ *exportProperties }) { - /* Black list reserved properties */ - if (cmHasLiteralPrefix(prop, "IMPORTED_") || - cmHasLiteralPrefix(prop, "INTERFACE_")) { - std::ostringstream e; - e << "Target \"" << gte->Target->GetName() << "\" contains property \"" - << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* " - << "properties are reserved."; - errorMessage = e.str(); - return false; - } - cmValue propertyValue = targetProperties.GetPropertyValue(prop); - if (!propertyValue) { - // Asked to export a property that isn't defined on the target. Do not - // consider this an error, there's just nothing to export. - continue; - } - std::string evaluatedValue = cmGeneratorExpression::Preprocess( - *propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions); - if (evaluatedValue != *propertyValue) { - std::ostringstream e; - e << "Target \"" << gte->Target->GetName() << "\" contains property \"" - << prop << "\" in EXPORT_PROPERTIES but this property contains a " - << "generator expression. This is not allowed."; - errorMessage = e.str(); - return false; - } - properties[prop] = *propertyValue; - } - } - return true; -} - void cmExportCMakeConfigGenerator::GenerateTargetFileSets( - cmGeneratorTarget* gte, std::ostream& os, cmTargetExport* te) + cmGeneratorTarget* gte, std::ostream& os, cmTargetExport const* te) { auto interfaceFileSets = gte->Target->GetAllInterfaceFileSets(); if (!interfaceFileSets.empty()) { diff --git a/Source/cmExportCMakeConfigGenerator.h b/Source/cmExportCMakeConfigGenerator.h index 331cd3f3bd..90f7aa74e1 100644 --- a/Source/cmExportCMakeConfigGenerator.h +++ b/Source/cmExportCMakeConfigGenerator.h @@ -8,73 +8,45 @@ #include #include #include -#include +#include + +#include "cmExportFileGenerator.h" #include "cmGeneratorExpression.h" #include "cmStateTypes.h" -#include "cmVersion.h" -#include "cmVersionConfig.h" -class cmExportSet; class cmFileSet; class cmGeneratorTarget; -class cmLocalGenerator; class cmTargetExport; -#define STRINGIFY_HELPER(X) #X -#define STRINGIFY(X) STRINGIFY_HELPER(X) - -#define DEVEL_CMAKE_VERSION(major, minor) \ - (CMake_VERSION_ENCODE(major, minor, 0) > \ - CMake_VERSION_ENCODE(CMake_VERSION_MAJOR, CMake_VERSION_MINOR, 0) \ - ? STRINGIFY(CMake_VERSION_MAJOR) "." STRINGIFY( \ - CMake_VERSION_MINOR) "." STRINGIFY(CMake_VERSION_PATCH) \ - : #major "." #minor ".0") - /** \class cmExportCMakeConfigGenerator - * \brief Generate a file exporting targets from a build or install tree. + * \brief Generate CMake configuration files exporting targets from a build or + * install tree. * * cmExportCMakeConfigGenerator is the superclass for - * cmExportBuildFileGenerator and cmExportInstallFileGenerator. It - * contains common code generation routines for the two kinds of - * export implementations. + * cmExportBuildCMakeConfigGenerator and cmExportInstallCMakeConfigGenerator. + * It contains common code generation routines for the two kinds of export + * implementations. */ -class cmExportCMakeConfigGenerator +class cmExportCMakeConfigGenerator : virtual public cmExportFileGenerator { public: cmExportCMakeConfigGenerator(); - virtual ~cmExportCMakeConfigGenerator() = default; - - /** Set the full path to the export file to generate. */ - void SetExportFile(char const* mainFile); - std::string const& GetMainExportFileName() const; - - /** Set the namespace in which to place exported target names. */ - void SetNamespace(std::string const& ns) { this->Namespace = ns; } - std::string GetNamespace() const { return this->Namespace; } void SetExportOld(bool exportOld) { this->ExportOld = exportOld; } - /** Add a configuration to be exported. */ - void AddConfiguration(std::string const& config); - - /** Actually generate the export file. Returns whether there was an - error. */ - bool GenerateImportFile(); - void SetExportPackageDependencies(bool exportPackageDependencies) { this->ExportPackageDependencies = exportPackageDependencies; } + using cmExportFileGenerator::GenerateImportFile; + protected: using ImportPropertyMap = std::map; - // Generate per-configuration target information to the given output - // stream. - void GenerateImportConfig(std::ostream& os, std::string const& config); - // Methods to implement export file code generation. + bool GenerateImportFile(std::ostream& os) override; virtual void GeneratePolicyHeaderCode(std::ostream& os); virtual void GeneratePolicyFooterCode(std::ostream& os); virtual void GenerateImportHeaderCode(std::ostream& os, @@ -89,7 +61,7 @@ protected: cmGeneratorTarget const* target, ImportPropertyMap const& properties, std::string const& importedXcFrameworkLocation); virtual void GenerateImportedFileChecksCode( - std::ostream& os, cmGeneratorTarget* target, + std::ostream& os, cmGeneratorTarget const* target, ImportPropertyMap const& properties, std::set const& importedLocations, std::string const& importedXcFrameworkLocation); @@ -100,165 +72,38 @@ protected: virtual void GenerateExpectedTargetsCode(std::ostream& os, std::string const& expectedTargets); - // Collect properties with detailed information about targets beyond - // their location on disk. - void SetImportDetailProperties(std::string const& config, - std::string const& suffix, - cmGeneratorTarget* target, - ImportPropertyMap& properties); + cm::string_view GetImportPrefixWithSlash() const override; - enum class ImportLinkPropertyTargetNames - { - Yes, - No, - }; - template - void SetImportLinkProperty(std::string const& suffix, - cmGeneratorTarget const* target, - std::string const& propName, - std::vector const& entries, - ImportPropertyMap& properties, - ImportLinkPropertyTargetNames targetNames); - - /** Each subclass knows how to generate its kind of export file. */ - virtual bool GenerateMainFile(std::ostream& os) = 0; - - /** Each subclass knows where the target files are located. */ - virtual void GenerateImportTargetsConfig(std::ostream& os, - std::string const& config, - std::string const& suffix) = 0; - - /** Each subclass knows how to deal with a target that is missing from an - * export set. */ - virtual void HandleMissingTarget(std::string& link_libs, - cmGeneratorTarget const* depender, - cmGeneratorTarget* dependee) = 0; - void PopulateInterfaceProperty(std::string const&, - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext, - ImportPropertyMap& properties); - bool PopulateInterfaceLinkLibrariesProperty( - cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, - ImportPropertyMap& properties); - void PopulateInterfaceProperty(std::string const& propName, - cmGeneratorTarget const* target, - ImportPropertyMap& properties); - void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target, - ImportPropertyMap& properties); - void PopulateCustomTransitiveInterfaceProperties( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); virtual void GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, ImportPropertyMap const& properties); - void PopulateIncludeDirectoriesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, cmTargetExport const& te, - std::string& includesDestinationDirs); - void PopulateSourcesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); - void PopulateLinkDirectoriesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); - void PopulateLinkDependsInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); void SetImportLinkInterface( std::string const& config, std::string const& suffix, cmGeneratorExpression::PreprocessContext preprocessRule, cmGeneratorTarget const* target, ImportPropertyMap& properties); - enum FreeTargetsReplace - { - ReplaceFreeTargets, - NoReplaceFreeTargets - }; - - void ResolveTargetsInGeneratorExpressions( - std::string& input, cmGeneratorTarget const* target, - FreeTargetsReplace replace = NoReplaceFreeTargets); - - bool PopulateCxxModuleExportProperties( - cmGeneratorTarget const* gte, ImportPropertyMap& properties, - cmGeneratorExpression::PreprocessContext ctx, - std::string const& includesDestinationDirs, std::string& errorMessage); - bool PopulateExportProperties(cmGeneratorTarget const* gte, - ImportPropertyMap& properties, - std::string& errorMessage); - void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, - cmTargetExport* te = nullptr); + cmTargetExport const* te = nullptr); + + std::string GetCxxModuleFile(std::string const& name) const override; void GenerateCxxModuleInformation(std::string const& name, std::ostream& os); virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) = 0; + cmTargetExport const* te) = 0; virtual std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) = 0; - - virtual cmExportSet* GetExportSet() const { return nullptr; } - - std::string GetCxxModuleFile(std::string const& name) const; + cmTargetExport const* te) = 0; void SetRequiredCMakeVersion(unsigned int major, unsigned int minor, unsigned int patch); - // The namespace in which the exports are placed in the generated file. - std::string Namespace; - - bool ExportOld; - - // The set of configurations to export. - std::vector Configurations; - - // The file to generate. - std::string MainImportFile; - std::string FileDir; - std::string FileBase; - std::string FileExt; - bool AppendMode; - - // The set of targets included in the export. - std::set ExportedTargets; - - std::vector MissingTargets; - - std::set ExternalTargets; + bool ExportOld = false; + bool ExportPackageDependencies = false; unsigned int RequiredCMakeVersionMajor = 2; unsigned int RequiredCMakeVersionMinor = 8; unsigned int RequiredCMakeVersionPatch = 3; - - bool ExportPackageDependencies = false; - -private: - void PopulateInterfaceProperty(std::string const&, std::string const&, - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext, - ImportPropertyMap& properties); - - bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg); - - void ResolveTargetsInGeneratorExpression(std::string& input, - cmGeneratorTarget const* target, - cmLocalGenerator const* lg); - - virtual void ReplaceInstallPrefix(std::string& input); - - virtual std::string InstallNameDir(cmGeneratorTarget const* target, - std::string const& config) = 0; - - virtual std::string GetCxxModulesDirectory() const = 0; - virtual void GenerateCxxModuleConfigInformation(std::string const&, - std::ostream& os) const = 0; }; diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 0cb0011075..00f3c7411a 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -19,6 +19,7 @@ #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportBuildAndroidMKGenerator.h" +#include "cmExportBuildCMakeConfigGenerator.h" #include "cmExportBuildFileGenerator.h" #include "cmExportSet.h" #include "cmGeneratedFileStream.h" @@ -318,21 +319,24 @@ bool cmExportCommand(std::vector const& args, // Setup export file generation. std::unique_ptr ebfg = nullptr; if (android) { - ebfg = cm::make_unique(); + auto ebag = cm::make_unique(); + ebag->SetAppendMode(arguments.Append); + ebfg = std::move(ebag); } else { - ebfg = cm::make_unique(); + auto ebcg = cm::make_unique(); + ebcg->SetAppendMode(arguments.Append); + ebcg->SetExportOld(arguments.ExportOld); + ebcg->SetExportPackageDependencies(arguments.ExportPackageDependencies); + ebfg = std::move(ebcg); } ebfg->SetExportFile(fname.c_str()); ebfg->SetNamespace(arguments.Namespace); ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory); - ebfg->SetAppendMode(arguments.Append); if (exportSet != nullptr) { ebfg->SetExportSet(exportSet); } else { ebfg->SetTargets(targets); } - ebfg->SetExportOld(arguments.ExportOld); - ebfg->SetExportPackageDependencies(arguments.ExportPackageDependencies); // Compute the set of configurations exported. std::vector configurationTypes = diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index e0d43b8a76..24ed273d08 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -2,23 +2,18 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportFileGenerator.h" -#include #include -#include -#include +#include #include #include #include -#include #include #include #include "cmsys/FStream.hxx" #include "cmComputeLinkInformation.h" -#include "cmExportSet.h" -#include "cmFileSet.h" #include "cmFindPackageStack.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" @@ -27,33 +22,14 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" -#include "cmOutputConverter.h" -#include "cmPolicies.h" #include "cmPropertyMap.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmValue.h" -#include "cmVersion.h" -static std::string cmExportFileGeneratorEscape(std::string const& str) -{ - // Escape a property value for writing into a .cmake file. - std::string result = cmOutputConverter::EscapeForCMake(str); - // Un-escape variable references generated by our own export code. - cmSystemTools::ReplaceString(result, "\\${_IMPORT_PREFIX}", - "${_IMPORT_PREFIX}"); - cmSystemTools::ReplaceString(result, "\\${CMAKE_IMPORT_LIBRARY_SUFFIX}", - "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); - return result; -} - -cmExportFileGenerator::cmExportFileGenerator() -{ - this->AppendMode = false; - this->ExportOld = false; -} +cmExportFileGenerator::cmExportFileGenerator() = default; void cmExportFileGenerator::AddConfiguration(std::string const& config) { @@ -98,38 +74,8 @@ bool cmExportFileGenerator::GenerateImportFile() cmSystemTools::Error(e.str()); return false; } - std::ostream& os = *foutPtr; - std::stringstream mainFileWithHeadersAndFootersBuffer; - // Start with the import file header. - this->GenerateImportHeaderCode(mainFileWithHeadersAndFootersBuffer); - - // Create all the imported targets. - 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); - 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; + return this->GenerateImportFile(*foutPtr); } void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, @@ -147,9 +93,50 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, this->GenerateImportTargetsConfig(os, config, suffix); } +bool cmExportFileGenerator::PopulateInterfaceProperties( + cmGeneratorTarget const* target, std::string const& includesDestinationDirs, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", target, + preprocessRule, properties); + this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", + target, properties); + + std::string errorMessage; + if (!this->PopulateCxxModuleExportProperties( + target, properties, preprocessRule, includesDestinationDirs, + errorMessage)) { + this->ReportError(errorMessage); + return false; + } + + if (!this->PopulateExportProperties(target, properties, errorMessage)) { + this->ReportError(errorMessage); + return false; + } + this->PopulateCompatibleInterfaceProperties(target, properties); + this->PopulateCustomTransitiveInterfaceProperties(target, preprocessRule, + properties); + + return true; +} + void cmExportFileGenerator::PopulateInterfaceProperty( std::string const& propName, cmGeneratorTarget const* target, - ImportPropertyMap& properties) + ImportPropertyMap& properties) const { cmValue input = target->GetProperty(propName); if (input) { @@ -180,6 +167,15 @@ void cmExportFileGenerator::PopulateInterfaceProperty( } } +void cmExportFileGenerator::PopulateInterfaceProperty( + std::string const& propName, cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + this->PopulateInterfaceProperty(propName, propName, target, preprocessRule, + properties); +} + bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, @@ -208,319 +204,27 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( return hadINTERFACE_LINK_LIBRARIES; } -static bool isSubDirectory(std::string const& a, std::string const& b) -{ - return (cmSystemTools::ComparePath(a, b) || - cmSystemTools::IsSubDirectory(a, b)); -} - -static bool checkInterfaceDirs(std::string const& prepro, - cmGeneratorTarget const* target, - std::string const& prop) -{ - std::string const& installDir = - target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); - std::string const& topSourceDir = - target->GetLocalGenerator()->GetSourceDirectory(); - std::string const& topBinaryDir = - target->GetLocalGenerator()->GetBinaryDirectory(); - - std::vector parts; - cmGeneratorExpression::Split(prepro, parts); - - bool const inSourceBuild = topSourceDir == topBinaryDir; - - bool hadFatalError = false; - - for (std::string const& li : parts) { - size_t genexPos = cmGeneratorExpression::Find(li); - if (genexPos == 0) { - continue; - } - if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) { - continue; - } - MessageType messageType = MessageType::FATAL_ERROR; - std::ostringstream e; - if (genexPos != std::string::npos) { - if (prop == "INTERFACE_INCLUDE_DIRECTORIES") { - switch (target->GetPolicyStatusCMP0041()) { - case cmPolicies::WARN: - messageType = MessageType::WARNING; - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n"; - break; - case cmPolicies::OLD: - continue; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - hadFatalError = true; - break; // Issue fatal message. - } - } else { - hadFatalError = true; - } - } - if (!cmSystemTools::FileIsFullPath(li)) { - /* clang-format off */ - e << "Target \"" << target->GetName() << "\" " << prop << - " property contains relative path:\n" - " \"" << li << "\""; - /* clang-format on */ - target->GetLocalGenerator()->IssueMessage(messageType, e.str()); - } - bool inBinary = isSubDirectory(li, topBinaryDir); - bool inSource = isSubDirectory(li, topSourceDir); - if (isSubDirectory(li, installDir)) { - // The include directory is inside the install tree. If the - // install tree is not inside the source tree or build tree then - // fall through to the checks below that the include directory is not - // also inside the source tree or build tree. - bool shouldContinue = - (!inBinary || isSubDirectory(installDir, topBinaryDir)) && - (!inSource || isSubDirectory(installDir, topSourceDir)); - - if (prop == "INTERFACE_INCLUDE_DIRECTORIES") { - if (!shouldContinue) { - switch (target->GetPolicyStatusCMP0052()) { - case cmPolicies::WARN: { - std::ostringstream s; - s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n"; - s << "Directory:\n \"" << li - << "\"\nin " - "INTERFACE_INCLUDE_DIRECTORIES of target \"" - << target->GetName() - << "\" is a subdirectory of the install " - "directory:\n \"" - << installDir - << "\"\nhowever it is also " - "a subdirectory of the " - << (inBinary ? "build" : "source") << " tree:\n \"" - << (inBinary ? topBinaryDir : topSourceDir) << "\"\n"; - target->GetLocalGenerator()->IssueMessage( - MessageType::AUTHOR_WARNING, s.str()); - CM_FALLTHROUGH; - } - case cmPolicies::OLD: - shouldContinue = true; - break; - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::NEW: - break; - } - } - } - if (shouldContinue) { - continue; - } - } - if (inBinary) { - /* clang-format off */ - e << "Target \"" << target->GetName() << "\" " << prop << - " property contains path:\n" - " \"" << li << "\"\nwhich is prefixed in the build directory."; - /* clang-format on */ - target->GetLocalGenerator()->IssueMessage(messageType, e.str()); - } - if (!inSourceBuild) { - if (inSource) { - e << "Target \"" << target->GetName() << "\" " << prop - << " property contains path:\n" - " \"" - << li << "\"\nwhich is prefixed in the source directory."; - target->GetLocalGenerator()->IssueMessage(messageType, e.str()); - } - } - } - return !hadFatalError; -} - -static void prefixItems(std::string& exportDirs) +void cmExportFileGenerator::AddImportPrefix(std::string& exportDirs) const { std::vector entries; cmGeneratorExpression::Split(exportDirs, entries); exportDirs.clear(); char const* sep = ""; + cm::string_view const& prefixWithSlash = this->GetImportPrefixWithSlash(); for (std::string const& e : entries) { exportDirs += sep; sep = ";"; if (!cmSystemTools::FileIsFullPath(e) && - e.find("${_IMPORT_PREFIX}") == std::string::npos) { - exportDirs += "${_IMPORT_PREFIX}/"; + !cmHasPrefix(e, prefixWithSlash)) { + exportDirs += prefixWithSlash; } exportDirs += e; } } -void cmExportFileGenerator::PopulateSourcesInterface( - cmGeneratorTarget const* gt, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - char const* propName = "INTERFACE_SOURCES"; - cmValue input = gt->GetProperty(propName); - - if (!input) { - return; - } - - if (input->empty()) { - properties[propName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt); - - if (!checkInterfaceDirs(prepro, gt, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, cmTargetExport const& te, - std::string& includesDestinationDirs) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - includesDestinationDirs.clear(); - - char const* propName = "INTERFACE_INCLUDE_DIRECTORIES"; - cmValue input = target->GetProperty(propName); - - cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance()); - - std::string dirs = cmGeneratorExpression::Preprocess( - cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)), - preprocessRule, true); - this->ReplaceInstallPrefix(dirs); - std::unique_ptr cge = ge.Parse(dirs); - std::string exportDirs = - cge->Evaluate(target->GetLocalGenerator(), "", target); - - if (cge->GetHadContextSensitiveCondition()) { - cmLocalGenerator* lg = target->GetLocalGenerator(); - std::ostringstream e; - e << "Target \"" << target->GetName() - << "\" is installed with " - "INCLUDES DESTINATION set to a context sensitive path. Paths which " - "depend on the configuration, policy values or the link interface " - "are " - "not supported. Consider using target_include_directories instead."; - lg->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return; - } - - if (!input && exportDirs.empty()) { - return; - } - if ((input && input->empty()) && exportDirs.empty()) { - // Set to empty - properties[propName].clear(); - return; - } - - prefixItems(exportDirs); - includesDestinationDirs = exportDirs; - - std::string includes = (input ? *input : ""); - char const* sep = input ? ";" : ""; - includes += sep + exportDirs; - std::string prepro = - cmGeneratorExpression::Preprocess(includes, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target); - - if (!checkInterfaceDirs(prepro, target, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportFileGenerator::PopulateLinkDependsInterface( - cmGeneratorTarget const* gt, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - char const* propName = "INTERFACE_LINK_DEPENDS"; - cmValue input = gt->GetProperty(propName); - - if (!input) { - return; - } - - if (input->empty()) { - properties[propName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt); - - if (!checkInterfaceDirs(prepro, gt, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportFileGenerator::PopulateLinkDirectoriesInterface( - cmGeneratorTarget const* gt, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - assert(preprocessRule == cmGeneratorExpression::InstallInterface); - - char const* propName = "INTERFACE_LINK_DIRECTORIES"; - cmValue input = gt->GetProperty(propName); - - if (!input) { - return; - } - - if (input->empty()) { - properties[propName].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule, true); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt); - - if (!checkInterfaceDirs(prepro, gt, propName)) { - return; - } - properties[propName] = prepro; - } -} - -void cmExportFileGenerator::PopulateInterfaceProperty( - std::string const& propName, cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties) -{ - this->PopulateInterfaceProperty(propName, propName, target, preprocessRule, - properties); -} - -static void getPropertyContents(cmGeneratorTarget const* tgt, - std::string const& prop, - std::set& ifaceProperties) +namespace { +void getPropertyContents(cmGeneratorTarget const* tgt, std::string const& prop, + std::set& ifaceProperties) { cmValue p = tgt->GetProperty(prop); if (!p) { @@ -530,9 +234,9 @@ static void getPropertyContents(cmGeneratorTarget const* tgt, ifaceProperties.insert(content.begin(), content.end()); } -static void getCompatibleInterfaceProperties( - cmGeneratorTarget const* target, std::set& ifaceProperties, - std::string const& config) +void getCompatibleInterfaceProperties(cmGeneratorTarget const* target, + std::set& ifaceProperties, + std::string const& config) { if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { // object libraries have no link information, so nothing to compute @@ -567,9 +271,10 @@ static void getCompatibleInterfaceProperties( ifaceProperties); } } +} void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( - cmGeneratorTarget const* gtarget, ImportPropertyMap& properties) + cmGeneratorTarget const* gtarget, ImportPropertyMap& properties) const { this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget, properties); @@ -626,22 +331,6 @@ void cmExportFileGenerator::PopulateCustomTransitiveInterfaceProperties( } } -void cmExportFileGenerator::GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties) -{ - if (!properties.empty()) { - std::string targetName = - cmStrCat(this->Namespace, target->GetExportName()); - os << "set_target_properties(" << targetName << " PROPERTIES\n"; - for (auto const& property : properties) { - os << " " << property.first << " " - << cmExportFileGeneratorEscape(property.second) << "\n"; - } - os << ")\n\n"; - } -} - bool cmExportFileGenerator::AddTargetNamespace(std::string& input, cmGeneratorTarget const* target, cmLocalGenerator const* lg) @@ -805,74 +494,14 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( } } -void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/) +void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/) const { // Do nothing } -void cmExportFileGenerator::SetImportLinkInterface( - std::string const& config, std::string const& suffix, - cmGeneratorExpression::PreprocessContext preprocessRule, - cmGeneratorTarget const* target, ImportPropertyMap& properties) -{ - // Add the transitive link dependencies for this configuration. - cmLinkInterface const* iface = target->GetLinkInterface(config, target); - if (!iface) { - return; - } - - if (iface->ImplementationIsInterface) { - // Policy CMP0022 must not be NEW. - this->SetImportLinkProperty( - suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", iface->Libraries, - properties, ImportLinkPropertyTargetNames::Yes); - return; - } - - cmValue propContent; - - if (cmValue prop_suffixed = - target->GetProperty("LINK_INTERFACE_LIBRARIES" + suffix)) { - propContent = prop_suffixed; - } else if (cmValue prop = target->GetProperty("LINK_INTERFACE_LIBRARIES")) { - propContent = prop; - } else { - return; - } - - bool const newCMP0022Behavior = - target->GetPolicyStatusCMP0022() != cmPolicies::WARN && - target->GetPolicyStatusCMP0022() != cmPolicies::OLD; - - if (newCMP0022Behavior && !this->ExportOld) { - cmLocalGenerator* lg = target->GetLocalGenerator(); - std::ostringstream e; - e << "Target \"" << target->GetName() - << "\" has policy CMP0022 enabled, " - "but also has old-style LINK_INTERFACE_LIBRARIES properties " - "populated, but it was exported without the " - "EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties"; - lg->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return; - } - - if (propContent->empty()) { - properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix].clear(); - return; - } - - std::string prepro = - cmGeneratorExpression::Preprocess(*propContent, preprocessRule); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, - ReplaceFreeTargets); - properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro; - } -} - void cmExportFileGenerator::SetImportDetailProperties( std::string const& config, std::string const& suffix, - cmGeneratorTarget* target, ImportPropertyMap& properties) + cmGeneratorTarget const* target, ImportPropertyMap& properties) { // Get the makefile in which to lookup target information. cmMakefile* mf = target->Makefile; @@ -943,15 +572,17 @@ void cmExportFileGenerator::SetImportDetailProperties( } } -static std::string const& asString(std::string const& l) +namespace { +std::string const& asString(std::string const& l) { return l; } -static std::string const& asString(cmLinkItem const& l) +std::string const& asString(cmLinkItem const& l) { return l.AsStr(); } +} template void cmExportFileGenerator::SetImportLinkProperty( @@ -988,431 +619,17 @@ void cmExportFileGenerator::SetImportLinkProperty( properties[prop] = link_entries; } -void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) -{ - // Protect that file against use with older CMake versions. - /* clang-format off */ - os << "# Generated by CMake\n\n"; - os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.8)\n" - << " message(FATAL_ERROR \"CMake >= " - << this->RequiredCMakeVersionMajor << '.' - << this->RequiredCMakeVersionMinor << '.' - << this->RequiredCMakeVersionPatch << " required\")\n" - << "endif()\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 */ +template void cmExportFileGenerator::SetImportLinkProperty( + std::string const&, cmGeneratorTarget const*, std::string const&, + std::vector const&, ImportPropertyMap& properties, + ImportLinkPropertyTargetNames); - // Isolate the file policy level. - // Support CMake versions as far back as the - // RequiredCMakeVersion{Major,Minor,Patch}, but also support using NEW - // policy settings for up to CMake 3.29 (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 " - << this->RequiredCMakeVersionMajor << '.' - << this->RequiredCMakeVersionMinor << '.' - << this->RequiredCMakeVersionPatch << "...3.29)\n"; - /* clang-format on */ -} - -void cmExportFileGenerator::GeneratePolicyFooterCode(std::ostream& os) -{ - os << "cmake_policy(POP)\n"; -} - -void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os, - std::string const& config) -{ - os << "#----------------------------------------------------------------\n" - << "# Generated CMake target import file"; - if (!config.empty()) { - os << " for configuration \"" << config << "\".\n"; - } else { - os << ".\n"; - } - os << "#----------------------------------------------------------------\n" - << "\n"; - this->GenerateImportVersionCode(os); -} - -void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os) -{ - os << "# Commands beyond this point should not need to know the version.\n" - << "set(CMAKE_IMPORT_FILE_VERSION)\n"; -} - -void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os) -{ - // Store an import file format version. This will let us change the - // format later while still allowing old import files to work. - /* clang-format off */ - os << "# Commands may need to know the format version.\n" - << "set(CMAKE_IMPORT_FILE_VERSION 1)\n" - << "\n"; - /* clang-format on */ -} - -void cmExportFileGenerator::GenerateExpectedTargetsCode( - std::ostream& os, std::string const& expectedTargets) -{ - /* clang-format off */ - os << "# Protect against multiple inclusion, which would fail when already " - "imported targets are added once more.\n" - "set(_cmake_targets_defined \"\")\n" - "set(_cmake_targets_not_defined \"\")\n" - "set(_cmake_expected_targets \"\")\n" - "foreach(_cmake_expected_target IN ITEMS " << expectedTargets << ")\n" - " list(APPEND _cmake_expected_targets \"${_cmake_expected_target}\")\n" - " if(TARGET \"${_cmake_expected_target}\")\n" - " list(APPEND _cmake_targets_defined \"${_cmake_expected_target}\")\n" - " else()\n" - " list(APPEND _cmake_targets_not_defined \"${_cmake_expected_target}\")\n" - " endif()\n" - "endforeach()\n" - "unset(_cmake_expected_target)\n" - "if(_cmake_targets_defined STREQUAL _cmake_expected_targets)\n" - " unset(_cmake_targets_defined)\n" - " unset(_cmake_targets_not_defined)\n" - " unset(_cmake_expected_targets)\n" - " unset(CMAKE_IMPORT_FILE_VERSION)\n" - " cmake_policy(POP)\n" - " return()\n" - "endif()\n" - "if(NOT _cmake_targets_defined STREQUAL \"\")\n" - " string(REPLACE \";\" \", \" _cmake_targets_defined_text \"${_cmake_targets_defined}\")\n" - " string(REPLACE \";\" \", \" _cmake_targets_not_defined_text \"${_cmake_targets_not_defined}\")\n" - " message(FATAL_ERROR \"Some (but not all) targets in this export " - "set were already defined.\\nTargets Defined: ${_cmake_targets_defined_text}\\n" - "Targets not yet defined: ${_cmake_targets_not_defined_text}\\n\")\n" - "endif()\n" - "unset(_cmake_targets_defined)\n" - "unset(_cmake_targets_not_defined)\n" - "unset(_cmake_expected_targets)\n" - "\n\n"; - /* clang-format on */ -} - -void cmExportFileGenerator::GenerateImportTargetCode( - std::ostream& os, cmGeneratorTarget const* target, - cmStateEnums::TargetType targetType) -{ - // Construct the imported target name. - std::string targetName = this->Namespace; - - targetName += target->GetExportName(); - - // Create the imported target. - os << "# Create imported target " << targetName << "\n"; - switch (targetType) { - case cmStateEnums::EXECUTABLE: - os << "add_executable(" << targetName << " IMPORTED)\n"; - break; - case cmStateEnums::STATIC_LIBRARY: - os << "add_library(" << targetName << " STATIC IMPORTED)\n"; - break; - case cmStateEnums::SHARED_LIBRARY: - os << "add_library(" << targetName << " SHARED IMPORTED)\n"; - break; - case cmStateEnums::MODULE_LIBRARY: - os << "add_library(" << targetName << " MODULE IMPORTED)\n"; - break; - case cmStateEnums::UNKNOWN_LIBRARY: - os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; - break; - case cmStateEnums::OBJECT_LIBRARY: - os << "add_library(" << targetName << " OBJECT IMPORTED)\n"; - break; - case cmStateEnums::INTERFACE_LIBRARY: - os << "add_library(" << targetName << " INTERFACE IMPORTED)\n"; - break; - default: // should never happen - break; - } - - // Mark the imported executable if it has exports. - if (target->IsExecutableWithExports() || - (target->IsSharedLibraryWithExports() && target->HasImportLibrary(""))) { - os << "set_property(TARGET " << targetName - << " PROPERTY ENABLE_EXPORTS 1)\n"; - } - - // Mark the imported library if it is a framework. - if (target->IsFrameworkOnApple()) { - os << "set_property(TARGET " << targetName << " PROPERTY FRAMEWORK 1)\n"; - } - - // Mark the imported executable if it is an application bundle. - if (target->IsAppBundleOnApple()) { - os << "set_property(TARGET " << targetName - << " PROPERTY MACOSX_BUNDLE 1)\n"; - } - - if (target->IsCFBundleOnApple()) { - os << "set_property(TARGET " << targetName << " PROPERTY BUNDLE 1)\n"; - } - - // generate DEPRECATION - if (target->IsDeprecated()) { - os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION " - << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n"; - } - - if (target->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) { - os << "set_property(TARGET " << targetName - << " PROPERTY IMPORTED_NO_SYSTEM 1)\n"; - } - - if (target->GetPropertyAsBool("EXPORT_NO_SYSTEM")) { - os << "set_property(TARGET " << targetName << " PROPERTY SYSTEM 0)\n"; - } - - os << "\n"; -} - -void cmExportFileGenerator::GenerateImportPropertyCode( - std::ostream& os, std::string const& config, std::string const& suffix, - cmGeneratorTarget const* target, ImportPropertyMap const& properties, - std::string const& importedXcFrameworkLocation) -{ - // Construct the imported target name. - std::string targetName = this->Namespace; - - targetName += target->GetExportName(); - - // Set the import properties. - os << "# Import target \"" << targetName << "\" for configuration \"" - << config << "\"\n"; - os << "set_property(TARGET " << targetName - << " APPEND PROPERTY IMPORTED_CONFIGURATIONS "; - if (!config.empty()) { - os << cmSystemTools::UpperCase(config); - } else { - os << "NOCONFIG"; - } - os << ")\n"; - os << "set_target_properties(" << targetName << " PROPERTIES\n"; - std::string importedLocationProp = cmStrCat("IMPORTED_LOCATION", suffix); - for (auto const& property : properties) { - if (importedXcFrameworkLocation.empty() || - property.first != importedLocationProp) { - os << " " << property.first << " " - << cmExportFileGeneratorEscape(property.second) << "\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 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> - packageDependenciesSorted(packageDependencies.begin(), - packageDependencies.end()); - std::sort( - packageDependenciesSorted.begin(), packageDependenciesSorted.end(), - [](std::pair const& lhs, - std::pair const& 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; - 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()) { - /* clang-format off */ - os << "# This file does not depend on other imported targets which have\n" - "# been exported from the same project but in a separate " - "export set.\n\n"; - /* clang-format on */ - return; - } - /* clang-format off */ - os << "# Make sure the targets which have been exported in some other\n" - "# export set exist.\n" - "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" - "foreach(_target "; - /* clang-format on */ - std::set emitted; - for (std::string const& missingTarget : this->MissingTargets) { - if (emitted.insert(missingTarget).second) { - os << "\"" << missingTarget << "\" "; - } - } - /* clang-format off */ - os << ")\n" - " if(NOT TARGET \"${_target}\" )\n" - " set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets \"" - "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets} ${_target}\")" - "\n" - " endif()\n" - "endforeach()\n" - "\n" - "if(DEFINED ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" - " if(CMAKE_FIND_PACKAGE_NAME)\n" - " set( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n" - " set( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE " - "\"The following imported targets are " - "referenced, but are missing: " - "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n" - " else()\n" - " message(FATAL_ERROR \"The following imported targets are " - "referenced, but are missing: " - "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n" - " endif()\n" - "endif()\n" - "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" - "\n"; - /* clang-format on */ -} - -void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os) -{ - // Add code which verifies at cmake time that the file which is being - // imported actually exists on disk. This should in theory always be theory - // case, but still when packages are split into normal and development - // packages this might get broken (e.g. the Config.cmake could be part of - // the non-development package, something similar happened to me without - // on SUSE with a mysql pkg-config file, which claimed everything is fine, - // but the development package was not installed.). - /* 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" - " 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" - "* An install or uninstall procedure did not complete successfully.\n" - "* The installation package was faulty and contained\n" - " \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n" - "but not all the files it references.\n" - "\")\n" - " endif()\n" - " endforeach()\n" - " endif()\n" - " unset(_cmake_file)\n" - " unset(\"_cmake_import_check_files_for_${_cmake_target}\")\n" - "endforeach()\n" - "unset(_cmake_target)\n" - "unset(_cmake_import_check_targets)\n" - "\n"; - /* clang-format on */ -} - -void cmExportFileGenerator::GenerateImportedFileChecksCode( - std::ostream& os, cmGeneratorTarget* target, - ImportPropertyMap const& properties, - std::set const& importedLocations, - std::string const& importedXcFrameworkLocation) -{ - // Construct the imported target name. - std::string targetName = cmStrCat(this->Namespace, target->GetExportName()); - - 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); - if (pi != properties.end()) { - os << cmExportFileGeneratorEscape(pi->second) << " "; - } - } - - os << ")\n\n"; -} +template void cmExportFileGenerator::SetImportLinkProperty( + std::string const&, cmGeneratorTarget const*, std::string const&, + std::vector const&, ImportPropertyMap& properties, + ImportLinkPropertyTargetNames); +namespace { enum class ExportWhen { Defined, @@ -1426,7 +643,6 @@ enum class PropertyType IncludePaths, }; -namespace { bool PropertyTypeIsForPaths(PropertyType pt) { switch (pt) { @@ -1440,18 +656,6 @@ bool PropertyTypeIsForPaths(PropertyType pt) } } -struct ModuleTargetPropertyTable -{ - cm::static_string_view Name; - ExportWhen Cond; -}; - -struct ModulePropertyTable -{ - cm::static_string_view Name; - PropertyType Type; -}; - bool cmExportFileGenerator::PopulateCxxModuleExportProperties( cmGeneratorTarget const* gte, ImportPropertyMap& properties, cmGeneratorExpression::PreprocessContext ctx, @@ -1461,6 +665,12 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties( return true; } + struct ModuleTargetPropertyTable + { + cm::static_string_view Name; + ExportWhen Cond; + }; + ModuleTargetPropertyTable const exportedDirectModuleProperties[] = { { "CXX_EXTENSIONS"_s, ExportWhen::Defined }, // Always define this property as it is an intrinsic property of the target @@ -1487,6 +697,12 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties( } } + struct ModulePropertyTable + { + cm::static_string_view Name; + PropertyType Type; + }; + ModulePropertyTable const exportedModuleProperties[] = { { "INCLUDE_DIRECTORIES"_s, PropertyType::IncludePaths }, { "COMPILE_DEFINITIONS"_s, PropertyType::Strings }, @@ -1508,7 +724,7 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties( if (ctx == cmGeneratorExpression::InstallInterface && PropertyTypeIsForPaths(propEntry.Type)) { this->ReplaceInstallPrefix(properties[exportedPropName]); - prefixItems(properties[exportedPropName]); + this->AddImportPrefix(properties[exportedPropName]); if (propEntry.Type == PropertyType::IncludePaths && !includesDestinationDirs.empty()) { if (!properties[exportedPropName].empty()) { @@ -1534,8 +750,8 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties( auto const exportedPropName = cmStrCat("IMPORTED_CXX_MODULES_", propName); auto value = cmGeneratorExpression::Preprocess(*prop, ctx); - this->ResolveTargetsInGeneratorExpressions( - value, gte, cmExportFileGenerator::ReplaceFreeTargets); + this->ResolveTargetsInGeneratorExpressions(value, gte, + ReplaceFreeTargets); properties[exportedPropName] = value; } } @@ -1545,7 +761,7 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties( bool cmExportFileGenerator::PopulateExportProperties( cmGeneratorTarget const* gte, ImportPropertyMap& properties, - std::string& errorMessage) + std::string& errorMessage) const { auto const& targetProperties = gte->Target->GetProperties(); if (cmValue exportProperties = @@ -1582,101 +798,3 @@ bool cmExportFileGenerator::PopulateExportProperties( } return true; } - -void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte, - std::ostream& os, - cmTargetExport* te) -{ - auto interfaceFileSets = gte->Target->GetAllInterfaceFileSets(); - if (!interfaceFileSets.empty()) { - std::string targetName = cmStrCat(this->Namespace, gte->GetExportName()); - os << "if(NOT CMAKE_VERSION VERSION_LESS \"3.23.0\")\n" - " target_sources(" - << targetName << "\n"; - - for (auto const& name : interfaceFileSets) { - auto* fileSet = gte->Target->GetFileSet(name); - if (!fileSet) { - gte->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("File set \"", name, - "\" is listed in interface file sets of ", gte->GetName(), - " but has not been created")); - return; - } - - os << " INTERFACE" - << "\n FILE_SET " << cmOutputConverter::EscapeForCMake(name) - << "\n TYPE " - << cmOutputConverter::EscapeForCMake(fileSet->GetType()) - << "\n BASE_DIRS " - << this->GetFileSetDirectories(gte, fileSet, te) << "\n FILES " - << this->GetFileSetFiles(gte, fileSet, te) << "\n"; - } - - os << " )\nelse()\n set_property(TARGET " << targetName - << "\n APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES"; - for (auto const& name : interfaceFileSets) { - auto* fileSet = gte->Target->GetFileSet(name); - if (!fileSet) { - gte->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("File set \"", name, - "\" is listed in interface file sets of ", gte->GetName(), - " but has not been created")); - return; - } - - if (fileSet->GetType() == "HEADERS"_s) { - os << "\n " << this->GetFileSetDirectories(gte, fileSet, te); - } - } - os << "\n )\nendif()\n\n"; - } -} - -std::string cmExportFileGenerator::GetCxxModuleFile( - std::string const& name) const -{ - auto const& cxxModuleDirname = this->GetCxxModulesDirectory(); - if (cxxModuleDirname.empty()) { - return {}; - } - - return cmStrCat(cmSystemTools::GetFilenamePath(this->MainImportFile), '/', - cxxModuleDirname, "/cxx-modules-", name, ".cmake"); -} - -void cmExportFileGenerator::GenerateCxxModuleInformation( - std::string const& name, std::ostream& os) -{ - auto const cxx_module_dirname = this->GetCxxModulesDirectory(); - if (cxx_module_dirname.empty()) { - return; - } - - // Write the include. - os << "# Include C++ module properties\n" - << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << cxx_module_dirname - << "/cxx-modules-" << name << ".cmake\")\n\n"; - - // Include all configuration-specific include files. - cmGeneratedFileStream ap(this->GetCxxModuleFile(name), true); - ap.SetCopyIfDifferent(true); - - 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; - } -} diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 7a100bd9c6..89295f5745 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -10,16 +10,13 @@ #include #include +#include + #include "cmGeneratorExpression.h" -#include "cmStateTypes.h" -#include "cmVersion.h" -#include "cmVersionConfig.h" class cmExportSet; -class cmFileSet; class cmGeneratorTarget; class cmLocalGenerator; -class cmTargetExport; #define STRINGIFY_HELPER(X) #X #define STRINGIFY(X) STRINGIFY_HELPER(X) @@ -32,12 +29,9 @@ class cmTargetExport; : #major "." #minor ".0") /** \class cmExportFileGenerator - * \brief Generate a file exporting targets from a build or install tree. + * \brief Generate files exporting targets from a build or install tree. * - * cmExportFileGenerator is the superclass for - * cmExportBuildFileGenerator and cmExportInstallFileGenerator. It - * contains common code generation routines for the two kinds of - * export implementations. + * cmExportFileGenerator is the interface class for generating export files. */ class cmExportFileGenerator { @@ -53,58 +47,21 @@ public: void SetNamespace(std::string const& ns) { this->Namespace = ns; } std::string GetNamespace() const { return this->Namespace; } - void SetExportOld(bool exportOld) { this->ExportOld = exportOld; } - /** Add a configuration to be exported. */ void AddConfiguration(std::string const& config); - /** Actually generate the export file. Returns whether there was an - error. */ + /** Create and actually generate the export file. Returns whether there was + an error. */ bool GenerateImportFile(); - void SetExportPackageDependencies(bool exportPackageDependencies) - { - this->ExportPackageDependencies = exportPackageDependencies; - } - protected: using ImportPropertyMap = std::map; - // Generate per-configuration target information to the given output - // stream. - void GenerateImportConfig(std::ostream& os, std::string const& config); - - // Methods to implement export file code generation. - virtual void GeneratePolicyHeaderCode(std::ostream& os); - virtual void GeneratePolicyFooterCode(std::ostream& os); - virtual void GenerateImportHeaderCode(std::ostream& os, - std::string const& config = ""); - virtual void GenerateImportFooterCode(std::ostream& os); - void GenerateImportVersionCode(std::ostream& os); - virtual void GenerateImportTargetCode(std::ostream& os, - cmGeneratorTarget const* target, - cmStateEnums::TargetType targetType); - virtual void GenerateImportPropertyCode( - std::ostream& os, std::string const& config, std::string const& suffix, - cmGeneratorTarget const* target, ImportPropertyMap const& properties, - std::string const& importedXcFrameworkLocation); - virtual void GenerateImportedFileChecksCode( - std::ostream& os, cmGeneratorTarget* target, - ImportPropertyMap const& properties, - std::set const& importedLocations, - std::string const& importedXcFrameworkLocation); - virtual void GenerateImportedFileCheckLoop(std::ostream& os); - virtual void GenerateMissingTargetsCheckCode(std::ostream& os); - virtual void GenerateFindDependencyCalls(std::ostream& os); - - virtual void GenerateExpectedTargetsCode(std::ostream& os, - std::string const& expectedTargets); - // Collect properties with detailed information about targets beyond // their location on disk. void SetImportDetailProperties(std::string const& config, std::string const& suffix, - cmGeneratorTarget* target, + cmGeneratorTarget const* target, ImportPropertyMap& properties); enum class ImportLinkPropertyTargetNames @@ -120,9 +77,17 @@ protected: ImportPropertyMap& properties, ImportLinkPropertyTargetNames targetNames); + /** Generate the export file to the given output stream. Returns whether + there was an error. */ + virtual bool GenerateImportFile(std::ostream& os) = 0; + /** Each subclass knows how to generate its kind of export file. */ virtual bool GenerateMainFile(std::ostream& os) = 0; + /** Generate per-configuration target information to the given output + stream. */ + void GenerateImportConfig(std::ostream& os, std::string const& config); + /** Each subclass knows where the target files are located. */ virtual void GenerateImportTargetsConfig(std::ostream& os, std::string const& config, @@ -133,47 +98,33 @@ protected: virtual void HandleMissingTarget(std::string& link_libs, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) = 0; - void PopulateInterfaceProperty(std::string const&, + + /** Complain when a duplicate target is encountered. */ + virtual void ComplainAboutDuplicateTarget( + std::string const& targetName) const = 0; + + virtual cm::string_view GetImportPrefixWithSlash() const = 0; + + void AddImportPrefix(std::string& exportDirs) const; + + void PopulateInterfaceProperty(std::string const& propName, + cmGeneratorTarget const* target, + ImportPropertyMap& properties) const; + void PopulateInterfaceProperty(std::string const& propName, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties); bool PopulateInterfaceLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties); - void PopulateInterfaceProperty(std::string const& propName, - cmGeneratorTarget const* target, - ImportPropertyMap& properties); - void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target, - ImportPropertyMap& properties); - void PopulateCustomTransitiveInterfaceProperties( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); - virtual void GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties); - void PopulateIncludeDirectoriesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, cmTargetExport const& te, - std::string& includesDestinationDirs); - void PopulateSourcesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); - void PopulateLinkDirectoriesInterface( - cmGeneratorTarget const* target, - cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties); - void PopulateLinkDependsInterface( + + bool PopulateInterfaceProperties( cmGeneratorTarget const* target, + std::string const& includesDestinationDirs, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties); - void SetImportLinkInterface( - std::string const& config, std::string const& suffix, - cmGeneratorExpression::PreprocessContext preprocessRule, - cmGeneratorTarget const* target, ImportPropertyMap& properties); + virtual void ReportError(std::string const& errorMessage) const = 0; enum FreeTargetsReplace { @@ -185,38 +136,26 @@ protected: std::string& input, cmGeneratorTarget const* target, FreeTargetsReplace replace = NoReplaceFreeTargets); - bool PopulateCxxModuleExportProperties( - cmGeneratorTarget const* gte, ImportPropertyMap& properties, - cmGeneratorExpression::PreprocessContext ctx, - std::string const& includesDestinationDirs, std::string& errorMessage); - bool PopulateExportProperties(cmGeneratorTarget const* gte, - ImportPropertyMap& properties, - std::string& errorMessage); - - void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, - cmTargetExport* te = nullptr); - - void GenerateCxxModuleInformation(std::string const& name, std::ostream& os); - - virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte, - cmFileSet* fileSet, - cmTargetExport* te) = 0; - virtual std::string GetFileSetFiles(cmGeneratorTarget* gte, - cmFileSet* fileSet, - cmTargetExport* te) = 0; - virtual cmExportSet* GetExportSet() const { return nullptr; } - std::string GetCxxModuleFile(std::string const& name) const; + virtual void ReplaceInstallPrefix(std::string& input) const; - void SetRequiredCMakeVersion(unsigned int major, unsigned int minor, - unsigned int patch); + virtual std::string InstallNameDir(cmGeneratorTarget const* target, + std::string const& config) = 0; + + /** Get the temporary location of the config-agnostic C++ module file. */ + virtual std::string GetCxxModuleFile(std::string const& name) const = 0; + + virtual std::string GetCxxModulesDirectory() const = 0; + virtual void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream& os) const = 0; + + bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target, + cmLocalGenerator const* lg); // The namespace in which the exports are placed in the generated file. std::string Namespace; - bool ExportOld; - // The set of configurations to export. std::vector Configurations; @@ -225,40 +164,47 @@ protected: std::string FileDir; std::string FileBase; std::string FileExt; - bool AppendMode; + bool AppendMode = false; // The set of targets included in the export. - std::set ExportedTargets; + std::set ExportedTargets; std::vector MissingTargets; std::set ExternalTargets; - unsigned int RequiredCMakeVersionMajor = 2; - unsigned int RequiredCMakeVersionMinor = 8; - unsigned int RequiredCMakeVersionPatch = 3; - - bool ExportPackageDependencies = false; - private: - void PopulateInterfaceProperty(std::string const&, std::string const&, + void PopulateInterfaceProperty(std::string const& propName, + std::string const& outputName, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties); - bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg); + void PopulateCompatibleInterfaceProperties( + cmGeneratorTarget const* target, ImportPropertyMap& properties) const; + void PopulateCustomTransitiveInterfaceProperties( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); + bool PopulateCxxModuleExportProperties( + cmGeneratorTarget const* gte, ImportPropertyMap& properties, + cmGeneratorExpression::PreprocessContext ctx, + std::string const& includesDestinationDirs, std::string& errorMessage); + bool PopulateExportProperties(cmGeneratorTarget const* gte, + ImportPropertyMap& properties, + std::string& errorMessage) const; void ResolveTargetsInGeneratorExpression(std::string& input, cmGeneratorTarget const* target, cmLocalGenerator const* lg); - - virtual void ReplaceInstallPrefix(std::string& input); - - virtual std::string InstallNameDir(cmGeneratorTarget const* target, - std::string const& config) = 0; - - virtual std::string GetCxxModulesDirectory() const = 0; - virtual void GenerateCxxModuleConfigInformation(std::string const&, - std::ostream& os) const = 0; }; + +extern template void cmExportFileGenerator::SetImportLinkProperty( + std::string const&, cmGeneratorTarget const*, std::string const&, + std::vector const&, ImportPropertyMap& properties, + ImportLinkPropertyTargetNames); + +extern template void cmExportFileGenerator::SetImportLinkProperty( + std::string const&, cmGeneratorTarget const*, std::string const&, + std::vector const&, ImportPropertyMap& properties, + ImportLinkPropertyTargetNames); diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx index b172bbad9d..c9c2f4e529 100644 --- a/Source/cmExportInstallAndroidMKGenerator.cxx +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -4,14 +4,15 @@ #include #include -#include +#include #include -#include "cmExportBuildAndroidMKGenerator.h" #include "cmExportSet.h" +#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmInstallExportGenerator.h" #include "cmInstallTargetGenerator.h" +#include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -24,6 +25,53 @@ cmExportInstallAndroidMKGenerator::cmExportInstallAndroidMKGenerator( { } +void cmExportInstallAndroidMKGenerator::ReportDuplicateTarget( + std::string const& targetName) const +{ + std::ostringstream e; + e << "install(EXPORT_ANDROID_MK \"" << this->GetExportSet()->GetName() + << "\" ...) " + << "includes target \"" << targetName + << "\" more than once in the export set."; + this->ReportError(e.str()); +} + +bool cmExportInstallAndroidMKGenerator::GenerateMainFile(std::ostream& os) +{ + std::vector allTargets; + { + auto visitor = [&](cmTargetExport const* te) { allTargets.push_back(te); }; + + if (!this->CollectExports(visitor)) { + return false; + } + } + + // Create all the imported targets. + for (cmTargetExport const* te : allTargets) { + cmGeneratorTarget const* gt = te->Target; + + this->GenerateImportTargetCode(os, gt, this->GetExportTargetType(te)); + + ImportPropertyMap properties; + if (!this->PopulateInterfaceProperties(te, properties)) { + return false; + } + + bool const newCMP0022Behavior = + gt->GetPolicyStatusCMP0022() != cmPolicies::WARN && + gt->GetPolicyStatusCMP0022() != cmPolicies::OLD; + if (newCMP0022Behavior) { + this->PopulateInterfaceLinkLibrariesProperty( + gt, cmGeneratorExpression::InstallInterface, properties); + } + + this->GenerateInterfaceProperties(gt, os, properties); + } + + return true; +} + void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode( std::ostream& os, std::string const&) { @@ -53,10 +101,6 @@ void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode( } } -void cmExportInstallAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) -{ -} - void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode( std::ostream& os, cmGeneratorTarget const* target, cmStateEnums::TargetType /*targetType*/) @@ -73,61 +117,3 @@ void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode( } os << target->GetFullName(config) << "\n"; } - -void cmExportInstallAndroidMKGenerator::GenerateExpectedTargetsCode( - std::ostream&, std::string const&) -{ -} - -void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode( - std::ostream&, std::string const&, std::string const&, - cmGeneratorTarget const*, ImportPropertyMap const&, std::string const&) -{ -} - -void cmExportInstallAndroidMKGenerator::GenerateMissingTargetsCheckCode( - std::ostream&) -{ -} - -void cmExportInstallAndroidMKGenerator::GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties) -{ - std::string config; - if (!this->Configurations.empty()) { - config = this->Configurations[0]; - } - cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( - target, os, properties, cmExportBuildAndroidMKGenerator::INSTALL, config); -} - -void cmExportInstallAndroidMKGenerator::LoadConfigFiles(std::ostream&) -{ -} - -void cmExportInstallAndroidMKGenerator::GenerateImportPrefix(std::ostream&) -{ -} - -void cmExportInstallAndroidMKGenerator::CleanupTemporaryVariables( - std::ostream&) -{ -} - -void cmExportInstallAndroidMKGenerator::GenerateImportedFileCheckLoop( - std::ostream&) -{ -} - -void cmExportInstallAndroidMKGenerator::GenerateImportedFileChecksCode( - std::ostream&, cmGeneratorTarget*, ImportPropertyMap const&, - std::set const&, std::string const&) -{ -} - -bool cmExportInstallAndroidMKGenerator::GenerateImportFileConfig( - std::string const&) -{ - return true; -} diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h index 0c3eef6786..8fa3d3e8fe 100644 --- a/Source/cmExportInstallAndroidMKGenerator.h +++ b/Source/cmExportInstallAndroidMKGenerator.h @@ -5,9 +5,10 @@ #include "cmConfigure.h" // IWYU pragma: keep #include -#include #include +#include +#include "cmExportAndroidMKGenerator.h" #include "cmExportInstallFileGenerator.h" #include "cmStateTypes.h" @@ -15,52 +16,49 @@ class cmGeneratorTarget; class cmInstallExportGenerator; /** \class cmExportInstallAndroidMKGenerator - * \brief Generate a file exporting targets from an install tree. + * \brief Generate files exporting targets from an install tree. * * cmExportInstallAndroidMKGenerator generates files exporting targets from - * install an installation tree. The files are placed in a temporary - * location for installation by cmInstallExportGenerator. The file format - * is for the ndk build system and is a makefile fragment specifying prebuilt - * libraries to the ndk build system. + * an installation tree. The files are placed in a temporary location for + * installation by cmInstallExportGenerator. The file format is for the ndk + * build system and is a makefile fragment specifying prebuilt libraries to the + * ndk build system. * * This is used to implement the INSTALL(EXPORT_ANDROID_MK) command. */ -class cmExportInstallAndroidMKGenerator : public cmExportInstallFileGenerator +class cmExportInstallAndroidMKGenerator + : public cmExportAndroidMKGenerator + , public cmExportInstallFileGenerator { public: /** Construct with the export installer that will install the files. */ cmExportInstallAndroidMKGenerator(cmInstallExportGenerator* iegen); + std::string GetConfigImportFileGlob() const override { return {}; } + protected: + GenerateType GetGenerateType() const override { return INSTALL; } + // Implement virtual methods from the superclass. - void GeneratePolicyHeaderCode(std::ostream&) override {} - void GeneratePolicyFooterCode(std::ostream&) override {} + void ReportDuplicateTarget(std::string const& targetName) const; + bool GenerateMainFile(std::ostream& os) override; void GenerateImportHeaderCode(std::ostream& os, std::string const& config = "") override; - void GenerateImportFooterCode(std::ostream& os) override; void GenerateImportTargetCode( std::ostream& os, cmGeneratorTarget const* target, cmStateEnums::TargetType /*targetType*/) override; - void GenerateExpectedTargetsCode( - std::ostream& os, std::string const& expectedTargets) override; - void GenerateImportPropertyCode( - std::ostream& os, std::string const& config, std::string const& suffix, - cmGeneratorTarget const* target, ImportPropertyMap const& properties, - std::string const& importedXcFrameworkLocation) override; - void GenerateMissingTargetsCheckCode(std::ostream& os) override; - void GenerateFindDependencyCalls(std::ostream&) override {} - void GenerateInterfaceProperties( - cmGeneratorTarget const* target, std::ostream& os, - ImportPropertyMap const& properties) override; - void GenerateImportPrefix(std::ostream& os) override; - void LoadConfigFiles(std::ostream&) override; - void CleanupTemporaryVariables(std::ostream&) override; - void GenerateImportedFileCheckLoop(std::ostream& os) override; - void GenerateImportedFileChecksCode( - std::ostream& os, cmGeneratorTarget* target, - ImportPropertyMap const& properties, - std::set const& importedLocations, - std::string const& importedXcFrameworkLocation) override; - bool GenerateImportFileConfig(std::string const& config) override; + + void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, + cmGeneratorTarget const* dependee, + std::vector const& namespaces); + + void GenerateImportTargetsConfig(std::ostream& os, std::string const& config, + std::string const& suffix) override + { + this->cmExportAndroidMKGenerator::GenerateImportTargetsConfig(os, config, + suffix); + } + + std::string GetCxxModulesDirectory() const override { return {}; } }; diff --git a/Source/cmExportInstallCMakeConfigGenerator.cxx b/Source/cmExportInstallCMakeConfigGenerator.cxx index 940a42b831..e2185ed214 100644 --- a/Source/cmExportInstallCMakeConfigGenerator.cxx +++ b/Source/cmExportInstallCMakeConfigGenerator.cxx @@ -3,9 +3,12 @@ #include "cmExportInstallCMakeConfigGenerator.h" #include +#include #include +#include #include #include +#include #include #include @@ -15,11 +18,8 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" #include "cmInstallExportGenerator.h" #include "cmInstallFileSetGenerator.h" -#include "cmInstallTargetGenerator.h" -#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -28,17 +28,17 @@ #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmTarget.h" #include "cmTargetExport.h" #include "cmValue.h" cmExportInstallCMakeConfigGenerator::cmExportInstallCMakeConfigGenerator( cmInstallExportGenerator* iegen) - : IEGen(iegen) + : cmExportInstallFileGenerator(iegen) { } std::string cmExportInstallCMakeConfigGenerator::GetConfigImportFileGlob() + const { std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt); return glob; @@ -46,28 +46,18 @@ std::string cmExportInstallCMakeConfigGenerator::GetConfigImportFileGlob() bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os) { - std::vector allTargets; + std::vector allTargets; { std::string expectedTargets; std::string sep; - for (std::unique_ptr const& te : - this->GetExportSet()->GetTargetExports()) { - if (te->NamelinkOnly) { - continue; - } + auto visitor = [&](cmTargetExport const* te) { + allTargets.push_back(te); expectedTargets += sep + this->Namespace + te->Target->GetExportName(); sep = " "; - if (this->ExportedTargets.insert(te->Target).second) { - allTargets.push_back(te.get()); - } else { - std::ostringstream e; - e << "install(EXPORT \"" << this->GetExportSet()->GetName() - << "\" ...) " - << "includes target \"" << te->Target->GetName() - << "\" more than once in the export set."; - cmSystemTools::Error(e.str()); - return false; - } + }; + + if (!this->CollectExports(visitor)) { + return false; } this->GenerateExpectedTargetsCode(os, expectedTargets); @@ -78,7 +68,7 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os) bool requiresConfigFiles = false; // Create all the imported targets. - for (cmTargetExport* te : allTargets) { + for (cmTargetExport const* te : allTargets) { cmGeneratorTarget* gt = te->Target; cmStateEnums::TargetType targetType = this->GetExportTargetType(te); @@ -88,52 +78,7 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os) this->GenerateImportTargetCode(os, gt, targetType); ImportPropertyMap properties; - - std::string includesDestinationDirs; - this->PopulateIncludeDirectoriesInterface( - gt, cmGeneratorExpression::InstallInterface, properties, *te, - includesDestinationDirs); - this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateLinkDirectoriesInterface( - gt, cmGeneratorExpression::InstallInterface, properties); - this->PopulateLinkDependsInterface( - gt, cmGeneratorExpression::InstallInterface, properties); - - std::string errorMessage; - if (!this->PopulateCxxModuleExportProperties( - gt, properties, cmGeneratorExpression::InstallInterface, - includesDestinationDirs, errorMessage)) { - cmSystemTools::Error(errorMessage); - return false; - } - - if (!this->PopulateExportProperties(gt, properties, errorMessage)) { - cmSystemTools::Error(errorMessage); + if (!this->PopulateInterfaceProperties(te, properties)) { return false; } @@ -156,13 +101,6 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os) this->SetRequiredCMakeVersion(3, 1, 0); } - this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt, - properties); - - this->PopulateCompatibleInterfaceProperties(gt, properties); - this->PopulateCustomTransitiveInterfaceProperties( - gt, cmGeneratorExpression::InstallInterface, properties); - this->GenerateInterfaceProperties(gt, os, properties); this->GenerateTargetFileSets(gt, os, te); @@ -286,12 +224,6 @@ void cmExportInstallCMakeConfigGenerator::LoadConfigFiles(std::ostream& os) /* clang-format on */ } -void cmExportInstallCMakeConfigGenerator::ReplaceInstallPrefix( - std::string& input) -{ - cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}"); -} - bool cmExportInstallCMakeConfigGenerator::GenerateImportFileConfig( std::string const& config) { @@ -351,53 +283,20 @@ void cmExportInstallCMakeConfigGenerator::GenerateImportTargetsConfig( ImportPropertyMap properties; std::set importedLocations; - this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->LibraryGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->BundleGenerator, - properties, importedLocations); + this->PopulateImportProperties(config, suffix, te.get(), properties, + importedLocations); // If any file location was set for the target add it to the // import file. if (!properties.empty()) { - // Get the rest of the target details. - cmGeneratorTarget* gtgt = te->Target; - this->SetImportDetailProperties(config, suffix, gtgt, properties); + cmGeneratorTarget const* const gtgt = te->Target; + std::string const importedXcFrameworkLocation = + this->GetImportXcFrameworkLocation(config, te.get()); this->SetImportLinkInterface(config, suffix, cmGeneratorExpression::InstallInterface, gtgt, properties); - // TODO: PUBLIC_HEADER_LOCATION - // This should wait until the build feature propagation stuff - // is done. Then this can be a propagated include directory. - // this->GenerateImportProperty(config, te->HeaderGenerator, - // properties); - - // Generate code in the export file. - std::string importedXcFrameworkLocation = te->XcFrameworkLocation; - if (!importedXcFrameworkLocation.empty()) { - importedXcFrameworkLocation = cmGeneratorExpression::Preprocess( - importedXcFrameworkLocation, - cmGeneratorExpression::PreprocessContext::InstallInterface, true); - importedXcFrameworkLocation = cmGeneratorExpression::Evaluate( - importedXcFrameworkLocation, te->Target->GetLocalGenerator(), config, - te->Target, nullptr, te->Target); - if (!importedXcFrameworkLocation.empty() && - !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) && - !cmHasLiteralPrefix(importedXcFrameworkLocation, - "${_IMPORT_PREFIX}/")) { - importedXcFrameworkLocation = - cmStrCat("${_IMPORT_PREFIX}/", importedXcFrameworkLocation); - } - } this->GenerateImportPropertyCode(os, config, suffix, gtgt, properties, importedXcFrameworkLocation); this->GenerateImportedFileChecksCode( @@ -406,193 +305,6 @@ void cmExportInstallCMakeConfigGenerator::GenerateImportTargetsConfig( } } -void cmExportInstallCMakeConfigGenerator::SetImportLocationProperty( - std::string const& config, std::string const& suffix, - cmInstallTargetGenerator* itgen, ImportPropertyMap& properties, - std::set& importedLocations) -{ - // Skip rules that do not match this configuration. - if (!(itgen && itgen->InstallsForConfig(config))) { - return; - } - - // Get the target to be installed. - cmGeneratorTarget* target = itgen->GetTarget(); - - // Construct the installed location of the target. - std::string dest = itgen->GetDestination(config); - std::string value; - if (!cmSystemTools::FileIsFullPath(dest)) { - // The target is installed relative to the installation prefix. - value = "${_IMPORT_PREFIX}/"; - } - value += dest; - value += "/"; - - if (itgen->IsImportLibrary()) { - // Construct the property name. - std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix); - - // Append the installed file name. - value += cmInstallTargetGenerator::GetInstallFilename( - target, config, cmInstallTargetGenerator::NameImplibReal); - - // Store the property. - properties[prop] = value; - importedLocations.insert(prop); - } else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) { - // Construct the property name. - std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix); - - // Compute all the object files inside this target and setup - // IMPORTED_OBJECTS as a list of object files - std::vector objects; - itgen->GetInstallObjectNames(config, objects); - for (std::string& obj : objects) { - obj = cmStrCat(value, obj); - } - - // Store the property. - properties[prop] = cmList::to_string(objects); - importedLocations.insert(prop); - } else { - if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) { - // store as well IMPLIB value - auto importProp = cmStrCat("IMPORTED_IMPLIB", suffix); - auto importValue = - cmStrCat(value, - cmInstallTargetGenerator::GetInstallFilename( - target, config, cmInstallTargetGenerator::NameImplibReal)); - - // Store the property. - properties[importProp] = importValue; - importedLocations.insert(importProp); - } - - // Construct the property name. - std::string prop = cmStrCat("IMPORTED_LOCATION", suffix); - - // Append the installed file name. - if (target->IsAppBundleOnApple()) { - value += cmInstallTargetGenerator::GetInstallFilename(target, config); - value += ".app/"; - if (!target->Makefile->PlatformIsAppleEmbedded()) { - value += "Contents/MacOS/"; - } - value += cmInstallTargetGenerator::GetInstallFilename(target, config); - } else { - value += cmInstallTargetGenerator::GetInstallFilename( - target, config, cmInstallTargetGenerator::NameReal); - } - - // Store the property. - properties[prop] = value; - importedLocations.insert(prop); - } -} - -cmStateEnums::TargetType -cmExportInstallCMakeConfigGenerator::GetExportTargetType( - cmTargetExport const* targetExport) const -{ - cmStateEnums::TargetType targetType = targetExport->Target->GetType(); - // An OBJECT library installed with no OBJECTS DESTINATION - // is transformed to an INTERFACE library. - if (targetType == cmStateEnums::OBJECT_LIBRARY && - targetExport->ObjectsGenerator == nullptr) { - targetType = cmStateEnums::INTERFACE_LIBRARY; - } - return targetType; -} - -void cmExportInstallCMakeConfigGenerator::HandleMissingTarget( - std::string& link_libs, cmGeneratorTarget const* depender, - cmGeneratorTarget* dependee) -{ - std::string const name = dependee->GetName(); - cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator(); - auto exportInfo = this->FindNamespaces(gg, name); - std::vector const& exportFiles = exportInfo.first; - if (exportFiles.size() == 1) { - std::string missingTarget = exportInfo.second; - - missingTarget += dependee->GetExportName(); - link_libs += missingTarget; - this->MissingTargets.emplace_back(std::move(missingTarget)); - } else { - // All exported targets should be known here and should be unique. - // This is probably user-error. - this->ComplainAboutMissingTarget(depender, dependee, exportFiles); - } -} - -std::pair, std::string> -cmExportInstallCMakeConfigGenerator::FindNamespaces(cmGlobalGenerator* gg, - std::string const& name) -{ - std::vector exportFiles; - std::string ns; - cmExportSetMap const& exportSets = gg->GetExportSets(); - - for (auto const& expIt : exportSets) { - cmExportSet const& exportSet = expIt.second; - - bool containsTarget = false; - for (auto const& target : exportSet.GetTargetExports()) { - if (name == target->TargetName) { - containsTarget = true; - break; - } - } - - if (containsTarget) { - std::vector const* installs = - exportSet.GetInstallations(); - for (cmInstallExportGenerator const* install : *installs) { - exportFiles.push_back(install->GetDestinationFile()); - ns = install->GetNamespace(); - } - } - } - - return { exportFiles, ns }; -} - -void cmExportInstallCMakeConfigGenerator::ComplainAboutMissingTarget( - cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, - std::vector const& exportFiles) -{ - std::ostringstream e; - e << "install(EXPORT \"" << this->GetExportSet()->GetName() << "\" ...) " - << "includes target \"" << depender->GetName() - << "\" which requires target \"" << dependee->GetName() << "\" "; - if (exportFiles.empty()) { - e << "that is not in any export set."; - } else { - e << "that is not in this export set, but in multiple other export sets: " - << cmJoin(exportFiles, ", ") << ".\n"; - e << "An exported target cannot depend upon another target which is " - "exported multiple times. Consider consolidating the exports of the " - "\"" - << dependee->GetName() << "\" target to a single export."; - } - cmSystemTools::Error(e.str()); -} - -std::string cmExportInstallCMakeConfigGenerator::InstallNameDir( - cmGeneratorTarget const* target, std::string const& config) -{ - std::string install_name_dir; - - cmMakefile* mf = target->Target->GetMakefile(); - if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - install_name_dir = - target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}"); - } - - return install_name_dir; -} - namespace { bool EntryIsContextSensitive( std::unique_ptr const& cge) @@ -602,7 +314,7 @@ bool EntryIsContextSensitive( } std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* te) { std::vector resultVector; @@ -647,7 +359,7 @@ std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories( } std::string cmExportInstallCMakeConfigGenerator::GetFileSetFiles( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* te) { std::vector resultVector; @@ -745,11 +457,6 @@ void cmExportInstallCMakeConfigGenerator::GenerateCxxModuleConfigInformation( /* clang-format on */ } -std::string cmExportInstallCMakeConfigGenerator::GetCxxModuleFile() const -{ - return this->GetCxxModuleFile(this->GetExportSet()->GetName()); -} - bool cmExportInstallCMakeConfigGenerator:: GenerateImportCxxModuleConfigTargetInclusion(std::string const& name, std::string const& config) diff --git a/Source/cmExportInstallCMakeConfigGenerator.h b/Source/cmExportInstallCMakeConfigGenerator.h index 57d29690f5..2ef9af0b42 100644 --- a/Source/cmExportInstallCMakeConfigGenerator.h +++ b/Source/cmExportInstallCMakeConfigGenerator.h @@ -5,30 +5,25 @@ #include "cmConfigure.h" // IWYU pragma: keep #include -#include -#include #include -#include -#include -#include "cmExportFileGenerator.h" -#include "cmInstallExportGenerator.h" -#include "cmStateTypes.h" +#include "cmExportCMakeConfigGenerator.h" +#include "cmExportInstallFileGenerator.h" -class cmExportSet; class cmFileSet; class cmGeneratorTarget; -class cmGlobalGenerator; -class cmInstallTargetGenerator; +class cmInstallExportGenerator; class cmTargetExport; /** \class cmExportInstallCMakeConfigGenerator - * \brief Generate a file exporting targets from an install tree. + * \brief Generate files exporting targets from an install tree. * * cmExportInstallCMakeConfigGenerator generates files exporting targets from - * install an installation tree. The files are placed in a temporary - * location for installation by cmInstallExportGenerator. One main - * file is generated that creates the imported targets and loads + * an installation tree. The files are placed in a temporary location for + * installation by cmInstallExportGenerator. The file format is CMake's native + * package configuration format. + * + * One main file is generated that creates the imported targets and loads * per-configuration files. Target locations and settings for each * configuration are written to these per-configuration files. After * installation the main file loads the configurations that have been @@ -36,64 +31,24 @@ class cmTargetExport; * * This is used to implement the INSTALL(EXPORT) command. */ -class cmExportInstallCMakeConfigGenerator : public cmExportFileGenerator +class cmExportInstallCMakeConfigGenerator + : public cmExportCMakeConfigGenerator + , public cmExportInstallFileGenerator { public: /** Construct with the export installer that will install the files. */ cmExportInstallCMakeConfigGenerator(cmInstallExportGenerator* iegen); - /** Get the per-config file generated for each configuration. This - maps from the configuration name to the file temporary location - for installation. */ - std::map const& GetConfigImportFiles() - { - return this->ConfigImportFiles; - } - - /** Get the temporary location of the config-agnostic C++ module file. */ - std::string GetCxxModuleFile() const; - - /** Get the per-config C++ module file generated for each configuration. - This maps from the configuration name to the file temporary location - for installation. */ - std::map const& GetConfigCxxModuleFiles() - { - return this->ConfigCxxModuleFiles; - } - - /** Get the per-config C++ module file generated for each configuration. - This maps from the configuration name to the file temporary location - for installation for each target in the export set. */ - std::map> const& - GetConfigCxxModuleTargetFiles() - { - return this->ConfigCxxModuleTargetFiles; - } - /** Compute the globbing expression used to load per-config import files from the main file. */ - std::string GetConfigImportFileGlob(); + std::string GetConfigImportFileGlob() const override; protected: // Implement virtual methods from the superclass. bool GenerateMainFile(std::ostream& os) override; void GenerateImportTargetsConfig(std::ostream& os, std::string const& config, std::string const& suffix) override; - cmStateEnums::TargetType GetExportTargetType( - cmTargetExport const* targetExport) const; - void HandleMissingTarget(std::string& link_libs, - cmGeneratorTarget const* depender, - cmGeneratorTarget* dependee) override; - - void ReplaceInstallPrefix(std::string& input) override; - - void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, - cmGeneratorTarget const* dependee, - std::vector const& exportFiles); - - std::pair, std::string> FindNamespaces( - cmGlobalGenerator* gg, std::string const& name); /** Generate the relative import prefix. */ virtual void GenerateImportPrefix(std::ostream&); @@ -106,40 +61,14 @@ protected: /** Generate a per-configuration file for the targets. */ virtual bool GenerateImportFileConfig(std::string const& config); - /** Fill in properties indicating installed file locations. */ - void SetImportLocationProperty(std::string const& config, - std::string const& suffix, - cmInstallTargetGenerator* itgen, - ImportPropertyMap& properties, - std::set& importedLocations); - - std::string InstallNameDir(cmGeneratorTarget const* target, - std::string const& config) override; - std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; + cmTargetExport const* te) override; std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; - - using cmExportFileGenerator::GetCxxModuleFile; + cmTargetExport const* te) override; std::string GetCxxModulesDirectory() const override; void GenerateCxxModuleConfigInformation(std::string const&, std::ostream&) const override; bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, std::string const&); - - cmExportSet* GetExportSet() const override - { - return this->IEGen->GetExportSet(); - } - - cmInstallExportGenerator* IEGen; - - // The import file generated for each configuration. - std::map ConfigImportFiles; - // The C++ module property file generated for each configuration. - std::map ConfigCxxModuleFiles; - // The C++ module property target files generated for each configuration. - std::map> ConfigCxxModuleTargetFiles; }; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index c71a1f4e7c..374b5eddf9 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -2,30 +2,21 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportInstallFileGenerator.h" -#include +#include +#include #include +#include #include -#include - -#include -#include #include "cmExportSet.h" -#include "cmFileSet.h" -#include "cmGeneratedFileStream.h" -#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" -#include "cmInstallExportGenerator.h" -#include "cmInstallFileSetGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" -#include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -38,369 +29,71 @@ cmExportInstallFileGenerator::cmExportInstallFileGenerator( { } -std::string cmExportInstallFileGenerator::GetConfigImportFileGlob() +void cmExportInstallFileGenerator::ReplaceInstallPrefix( + std::string& input) const { - std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt); - return glob; + cmGeneratorExpression::ReplaceInstallPrefix(input, this->GetInstallPrefix()); } -bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) +void cmExportInstallFileGenerator::PopulateImportProperties( + std::string const& config, std::string const& suffix, + cmTargetExport const* targetExport, ImportPropertyMap& properties, + std::set& importedLocations) { - std::vector allTargets; - { - std::string expectedTargets; - std::string sep; - for (std::unique_ptr const& te : - this->GetExportSet()->GetTargetExports()) { - if (te->NamelinkOnly) { - continue; - } - expectedTargets += sep + this->Namespace + te->Target->GetExportName(); - sep = " "; - if (this->ExportedTargets.insert(te->Target).second) { - allTargets.push_back(te.get()); - } else { - std::ostringstream e; - e << "install(EXPORT \"" << this->GetExportSet()->GetName() - << "\" ...) " - << "includes target \"" << te->Target->GetName() - << "\" more than once in the export set."; - cmSystemTools::Error(e.str()); - return false; - } - } + this->SetImportLocationProperty(config, suffix, + targetExport->ArchiveGenerator, properties, + importedLocations); + this->SetImportLocationProperty(config, suffix, + targetExport->LibraryGenerator, properties, + importedLocations); + this->SetImportLocationProperty(config, suffix, + targetExport->RuntimeGenerator, properties, + importedLocations); + this->SetImportLocationProperty(config, suffix, + targetExport->ObjectsGenerator, properties, + importedLocations); + this->SetImportLocationProperty(config, suffix, + targetExport->FrameworkGenerator, properties, + importedLocations); + this->SetImportLocationProperty(config, suffix, + targetExport->BundleGenerator, properties, + importedLocations); - this->GenerateExpectedTargetsCode(os, expectedTargets); - } + // If any file location was set for the target add it to the + // import file. + if (!properties.empty()) { + // Get the rest of the target details. + cmGeneratorTarget const* const gtgt = targetExport->Target; + this->SetImportDetailProperties(config, suffix, gtgt, properties); - // Compute the relative import prefix for the file - this->GenerateImportPrefix(os); - - bool requiresConfigFiles = false; - // Create all the imported targets. - for (cmTargetExport* te : allTargets) { - cmGeneratorTarget* gt = te->Target; - cmStateEnums::TargetType targetType = this->GetExportTargetType(te); - - requiresConfigFiles = - requiresConfigFiles || targetType != cmStateEnums::INTERFACE_LIBRARY; - - this->GenerateImportTargetCode(os, gt, targetType); - - ImportPropertyMap properties; - - std::string includesDestinationDirs; - this->PopulateIncludeDirectoriesInterface( - gt, cmGeneratorExpression::InstallInterface, properties, *te, - includesDestinationDirs); - this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt, - cmGeneratorExpression::InstallInterface, - properties); - this->PopulateLinkDirectoriesInterface( - gt, cmGeneratorExpression::InstallInterface, properties); - this->PopulateLinkDependsInterface( - gt, cmGeneratorExpression::InstallInterface, properties); - - std::string errorMessage; - if (!this->PopulateCxxModuleExportProperties( - gt, properties, cmGeneratorExpression::InstallInterface, - includesDestinationDirs, errorMessage)) { - cmSystemTools::Error(errorMessage); - return false; - } - - if (!this->PopulateExportProperties(gt, properties, errorMessage)) { - cmSystemTools::Error(errorMessage); - return false; - } - - bool const newCMP0022Behavior = - gt->GetPolicyStatusCMP0022() != cmPolicies::WARN && - gt->GetPolicyStatusCMP0022() != cmPolicies::OLD; - if (newCMP0022Behavior) { - if (this->PopulateInterfaceLinkLibrariesProperty( - gt, cmGeneratorExpression::InstallInterface, properties) && - !this->ExportOld) { - this->SetRequiredCMakeVersion(2, 8, 12); - } - } - if (targetType == cmStateEnums::INTERFACE_LIBRARY) { - this->SetRequiredCMakeVersion(3, 0, 0); - } - if (gt->GetProperty("INTERFACE_SOURCES")) { - // We can only generate INTERFACE_SOURCES in CMake 3.3, but CMake 3.1 - // can consume them. - this->SetRequiredCMakeVersion(3, 1, 0); - } - - this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt, - properties); - - this->PopulateCompatibleInterfaceProperties(gt, properties); - this->PopulateCustomTransitiveInterfaceProperties( - gt, cmGeneratorExpression::InstallInterface, properties); - - this->GenerateInterfaceProperties(gt, os, properties); - - this->GenerateTargetFileSets(gt, os, te); - } - - this->LoadConfigFiles(os); - - bool result = true; - - std::string cxx_modules_name = this->GetExportSet()->GetName(); - this->GenerateCxxModuleInformation(cxx_modules_name, os); - if (requiresConfigFiles) { - for (std::string const& c : this->Configurations) { - if (!this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, - c)) { - result = false; - } - } - } - - this->CleanupTemporaryVariables(os); - this->GenerateImportedFileCheckLoop(os); - - // Generate an import file for each configuration. - // Don't do this if we only export INTERFACE_LIBRARY targets. - if (requiresConfigFiles) { - for (std::string const& c : this->Configurations) { - if (!this->GenerateImportFileConfig(c)) { - result = false; - } - } - } - - this->GenerateMissingTargetsCheckCode(os); - - return result; -} - -void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream& os) -{ - // Set an _IMPORT_PREFIX variable for import location properties - // to reference if they are relative to the install prefix. - std::string installPrefix = - this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition( - "CMAKE_INSTALL_PREFIX"); - std::string const& expDest = this->IEGen->GetDestination(); - if (cmSystemTools::FileIsFullPath(expDest)) { - // The export file is being installed to an absolute path so the - // package is not relocatable. Use the configured install prefix. - /* clang-format off */ - os << - "# The installation prefix configured by this project.\n" - "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n" - "\n"; - /* clang-format on */ - } else { - // Add code to compute the installation prefix relative to the - // import file location. - std::string absDest = installPrefix + "/" + expDest; - std::string absDestS = absDest + "/"; - os << "# Compute the installation prefix relative to this file.\n" - << "get_filename_component(_IMPORT_PREFIX" - << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"; - if (cmHasLiteralPrefix(absDestS, "/lib/") || - cmHasLiteralPrefix(absDestS, "/lib64/") || - cmHasLiteralPrefix(absDestS, "/libx32/") || - cmHasLiteralPrefix(absDestS, "/usr/lib/") || - cmHasLiteralPrefix(absDestS, "/usr/lib64/") || - cmHasLiteralPrefix(absDestS, "/usr/libx32/")) { - // Handle "/usr move" symlinks created by some Linux distros. - /* clang-format off */ - os << - "# Use original install prefix when loaded through a\n" - "# cross-prefix symbolic link such as /lib -> /usr/lib.\n" - "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n" - "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n" - "if(_realCurr STREQUAL _realOrig)\n" - " set(_IMPORT_PREFIX \"" << absDest << "\")\n" - "endif()\n" - "unset(_realOrig)\n" - "unset(_realCurr)\n"; - /* clang-format on */ - } - std::string dest = expDest; - while (!dest.empty()) { - os << "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" " - "PATH)\n"; - dest = cmSystemTools::GetFilenamePath(dest); - } - os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n" - << " set(_IMPORT_PREFIX \"\")\n" - << "endif()\n" - << "\n"; + // TODO: PUBLIC_HEADER_LOCATION + // This should wait until the build feature propagation stuff is done. + // Then this can be a propagated include directory. + // this->GenerateImportProperty(config, te->HeaderGenerator, properties); } } -void cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream& os) +std::string cmExportInstallFileGenerator::GetImportXcFrameworkLocation( + std::string const& config, cmTargetExport const* targetExport) const { - /* clang-format off */ - os << "# Cleanup temporary variables.\n" - << "set(_IMPORT_PREFIX)\n" - << "\n"; - /* clang-format on */ -} - -void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream& os) -{ - // Now load per-configuration properties for them. - /* clang-format off */ - os << "# Load information for each installed configuration.\n" - << "file(GLOB _cmake_config_files \"${CMAKE_CURRENT_LIST_DIR}/" - << this->GetConfigImportFileGlob() << "\")\n" - << "foreach(_cmake_config_file IN LISTS _cmake_config_files)\n" - << " include(\"${_cmake_config_file}\")\n" - << "endforeach()\n" - << "unset(_cmake_config_file)\n" - << "unset(_cmake_config_files)\n" - << "\n"; - /* clang-format on */ -} - -void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input) -{ - cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}"); -} - -bool cmExportInstallFileGenerator::GenerateImportFileConfig( - std::string const& config) -{ - // Skip configurations not enabled for this export. - if (!this->IEGen->InstallsForConfig(config)) { - return true; - } - - // Construct the name of the file to generate. - std::string fileName = cmStrCat(this->FileDir, '/', this->FileBase, '-'); - if (!config.empty()) { - fileName += cmSystemTools::LowerCase(config); - } else { - fileName += "noconfig"; - } - fileName += this->FileExt; - - // Open the output file to generate it. - cmGeneratedFileStream exportFileStream(fileName, true); - if (!exportFileStream) { - std::string se = cmSystemTools::GetLastSystemError(); - std::ostringstream e; - e << "cannot write to file \"" << fileName << "\": " << se; - cmSystemTools::Error(e.str()); - return false; - } - exportFileStream.SetCopyIfDifferent(true); - std::ostream& os = exportFileStream; - - // Start with the import file header. - this->GenerateImportHeaderCode(os, config); - - // Generate the per-config target information. - this->GenerateImportConfig(os, config); - - // End with the import file footer. - this->GenerateImportFooterCode(os); - - // Record this per-config import file. - this->ConfigImportFiles[config] = fileName; - - return true; -} - -void cmExportInstallFileGenerator::GenerateImportTargetsConfig( - std::ostream& os, std::string const& config, std::string const& suffix) -{ - // Add each target in the set to the export. - for (std::unique_ptr const& te : - this->GetExportSet()->GetTargetExports()) { - // Collect import properties for this target. - if (this->GetExportTargetType(te.get()) == - cmStateEnums::INTERFACE_LIBRARY) { - continue; - } - - ImportPropertyMap properties; - std::set importedLocations; - - this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->LibraryGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator, - properties, importedLocations); - this->SetImportLocationProperty(config, suffix, te->BundleGenerator, - properties, importedLocations); - - // If any file location was set for the target add it to the - // import file. - if (!properties.empty()) { - // Get the rest of the target details. - cmGeneratorTarget* gtgt = te->Target; - this->SetImportDetailProperties(config, suffix, gtgt, properties); - - this->SetImportLinkInterface(config, suffix, - cmGeneratorExpression::InstallInterface, - gtgt, properties); - - // TODO: PUBLIC_HEADER_LOCATION - // This should wait until the build feature propagation stuff - // is done. Then this can be a propagated include directory. - // this->GenerateImportProperty(config, te->HeaderGenerator, - // properties); - - // Generate code in the export file. - std::string importedXcFrameworkLocation = te->XcFrameworkLocation; - if (!importedXcFrameworkLocation.empty()) { - importedXcFrameworkLocation = cmGeneratorExpression::Preprocess( - importedXcFrameworkLocation, - cmGeneratorExpression::PreprocessContext::InstallInterface, true); - importedXcFrameworkLocation = cmGeneratorExpression::Evaluate( - importedXcFrameworkLocation, te->Target->GetLocalGenerator(), config, - te->Target, nullptr, te->Target); - if (!importedXcFrameworkLocation.empty() && - !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) && - !cmHasLiteralPrefix(importedXcFrameworkLocation, - "${_IMPORT_PREFIX}/")) { - importedXcFrameworkLocation = - cmStrCat("${_IMPORT_PREFIX}/", importedXcFrameworkLocation); - } - } - this->GenerateImportPropertyCode(os, config, suffix, gtgt, properties, - importedXcFrameworkLocation); - this->GenerateImportedFileChecksCode( - os, gtgt, properties, importedLocations, importedXcFrameworkLocation); + std::string importedXcFrameworkLocation = targetExport->XcFrameworkLocation; + if (!importedXcFrameworkLocation.empty()) { + importedXcFrameworkLocation = cmGeneratorExpression::Preprocess( + importedXcFrameworkLocation, + cmGeneratorExpression::PreprocessContext::InstallInterface, true); + importedXcFrameworkLocation = cmGeneratorExpression::Evaluate( + importedXcFrameworkLocation, targetExport->Target->GetLocalGenerator(), + config, targetExport->Target, nullptr, targetExport->Target); + if (!importedXcFrameworkLocation.empty() && + !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) && + !cmHasPrefix(importedXcFrameworkLocation, + this->GetImportPrefixWithSlash())) { + return cmStrCat(this->GetImportPrefixWithSlash(), + importedXcFrameworkLocation); } } + + return importedXcFrameworkLocation; } void cmExportInstallFileGenerator::SetImportLocationProperty( @@ -501,11 +194,16 @@ cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType( return targetType; } +std::string const& cmExportInstallFileGenerator::GetExportName() const +{ + return this->GetExportSet()->GetName(); +} + void cmExportInstallFileGenerator::HandleMissingTarget( std::string& link_libs, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) { - std::string const name = dependee->GetName(); + std::string const& name = dependee->GetName(); cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator(); auto exportInfo = this->FindNamespaces(gg, name); std::vector const& exportFiles = exportInfo.first; @@ -524,7 +222,7 @@ void cmExportInstallFileGenerator::HandleMissingTarget( std::pair, std::string> cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg, - std::string const& name) + std::string const& name) const { std::vector exportFiles; std::string ns; @@ -556,10 +254,11 @@ cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg, void cmExportInstallFileGenerator::ComplainAboutMissingTarget( cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, - std::vector const& exportFiles) + std::vector const& exportFiles) const { std::ostringstream e; - e << "install(EXPORT \"" << this->GetExportSet()->GetName() << "\" ...) " + e << "install(" << this->IEGen->InstallSubcommand() << " \"" + << this->GetExportName() << "\" ...) " << "includes target \"" << depender->GetName() << "\" which requires target \"" << dependee->GetName() << "\" "; if (exportFiles.empty()) { @@ -572,7 +271,24 @@ void cmExportInstallFileGenerator::ComplainAboutMissingTarget( "\"" << dependee->GetName() << "\" target to a single export."; } - cmSystemTools::Error(e.str()); + this->ReportError(e.str()); +} + +void cmExportInstallFileGenerator::ComplainAboutDuplicateTarget( + std::string const& targetName) const +{ + std::ostringstream e; + e << "install(" << this->IEGen->InstallSubcommand() << " \"" + << this->GetExportName() << "\" ...) " + << "includes target \"" << targetName + << "\" more than once in the export set."; + this->ReportError(e.str()); +} + +void cmExportInstallFileGenerator::ReportError( + std::string const& errorMessage) const +{ + cmSystemTools::Error(errorMessage); } std::string cmExportInstallFileGenerator::InstallNameDir( @@ -582,215 +298,341 @@ std::string cmExportInstallFileGenerator::InstallNameDir( cmMakefile* mf = target->Target->GetMakefile(); if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - install_name_dir = - target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}"); + auto const& prefix = this->GetInstallPrefix(); + install_name_dir = target->GetInstallNameDirForInstallTree(config, prefix); } return install_name_dir; } -namespace { -bool EntryIsContextSensitive( - std::unique_ptr const& cge) -{ - return cge->GetHadContextSensitiveCondition(); -} -} - -std::string cmExportInstallFileGenerator::GetFileSetDirectories( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) -{ - std::vector resultVector; - - auto configs = - gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - - cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance()); - auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); - - for (auto const& config : configs) { - auto unescapedDest = cge->Evaluate(gte->LocalGenerator, config, gte); - auto dest = cmOutputConverter::EscapeForCMake( - unescapedDest, cmOutputConverter::WrapQuotes::NoWrap); - if (!cmSystemTools::FileIsFullPath(unescapedDest)) { - dest = cmStrCat("${_IMPORT_PREFIX}/", dest); - } - - auto const& type = fileSet->GetType(); - // C++ modules do not support interface file sets which are dependent upon - // the configuration. - if (cge->GetHadContextSensitiveCondition() && type == "CXX_MODULES"_s) { - auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile(); - std::ostringstream e; - e << "The \"" << gte->GetName() << "\" target's interface file set \"" - << fileSet->GetName() << "\" of type \"" << type - << "\" contains context-sensitive base file entries which is not " - "supported."; - mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return std::string{}; - } - - if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) { - resultVector.push_back( - cmStrCat("\"$<$:", dest, ">\"")); - } else { - resultVector.emplace_back(cmStrCat('"', dest, '"')); - break; - } - } - - return cmJoin(resultVector, " "); -} - -std::string cmExportInstallFileGenerator::GetFileSetFiles( - cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) -{ - std::vector resultVector; - - auto configs = - gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - - auto fileEntries = fileSet->CompileFileEntries(); - auto directoryEntries = fileSet->CompileDirectoryEntries(); - - cmGeneratorExpression destGe(*gte->Makefile->GetCMakeInstance()); - auto destCge = - destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); - - for (auto const& config : configs) { - auto directories = fileSet->EvaluateDirectoryEntries( - directoryEntries, gte->LocalGenerator, config, gte); - - std::map> files; - for (auto const& entry : fileEntries) { - fileSet->EvaluateFileEntry(directories, files, entry, - gte->LocalGenerator, config, gte); - } - auto unescapedDest = destCge->Evaluate(gte->LocalGenerator, config, gte); - auto dest = - cmStrCat(cmOutputConverter::EscapeForCMake( - unescapedDest, cmOutputConverter::WrapQuotes::NoWrap), - '/'); - if (!cmSystemTools::FileIsFullPath(unescapedDest)) { - dest = cmStrCat("${_IMPORT_PREFIX}/", dest); - } - - bool const contextSensitive = destCge->GetHadContextSensitiveCondition() || - std::any_of(directoryEntries.begin(), directoryEntries.end(), - EntryIsContextSensitive) || - std::any_of(fileEntries.begin(), fileEntries.end(), - EntryIsContextSensitive); - - auto const& type = fileSet->GetType(); - // C++ modules do not support interface file sets which are dependent upon - // the configuration. - if (contextSensitive && type == "CXX_MODULES"_s) { - auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile(); - std::ostringstream e; - e << "The \"" << gte->GetName() << "\" target's interface file set \"" - << fileSet->GetName() << "\" of type \"" << type - << "\" contains context-sensitive base file entries which is not " - "supported."; - mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return std::string{}; - } - - for (auto const& it : files) { - auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/'); - for (auto const& filename : it.second) { - auto relFile = - cmStrCat(prefix, cmSystemTools::GetFilenameName(filename)); - auto escapedFile = - cmStrCat(dest, - cmOutputConverter::EscapeForCMake( - relFile, cmOutputConverter::WrapQuotes::NoWrap)); - if (contextSensitive && configs.size() != 1) { - resultVector.push_back( - cmStrCat("\"$<$:", escapedFile, ">\"")); - } else { - resultVector.emplace_back(cmStrCat('"', escapedFile, '"')); - } - } - } - - if (!(contextSensitive && configs.size() != 1)) { - break; - } - } - - return cmJoin(resultVector, " "); -} - -std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const -{ - return IEGen->GetCxxModuleDirectory(); -} - -void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation( - std::string const& name, std::ostream& os) const -{ - // Now load per-configuration properties for them. - /* clang-format off */ - os << "# Load information for each installed configuration.\n" - "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << "-*.cmake\")\n" - "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n" - " include(\"${_cmake_cxx_module_include}\")\n" - "endforeach()\n" - "unset(_cmake_cxx_module_include)\n" - "unset(_cmake_cxx_module_includes)\n"; - /* clang-format on */ -} - std::string cmExportInstallFileGenerator::GetCxxModuleFile() const { return this->GetCxxModuleFile(this->GetExportSet()->GetName()); } -bool cmExportInstallFileGenerator:: - GenerateImportCxxModuleConfigTargetInclusion(std::string const& name, - std::string const& config) +bool cmExportInstallFileGenerator::CollectExports( + std::function const& visitor) { - auto cxx_modules_dirname = this->GetCxxModulesDirectory(); - if (cxx_modules_dirname.empty()) { - return true; - } - - std::string filename_config = config; - if (filename_config.empty()) { - filename_config = "noconfig"; - } - - std::string const dest = - cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/'); - std::string fileName = - cmStrCat(dest, "cxx-modules-", name, '-', filename_config, ".cmake"); - - cmGeneratedFileStream os(fileName, true); - if (!os) { - std::string se = cmSystemTools::GetLastSystemError(); - std::ostringstream e; - e << "cannot write to file \"" << fileName << "\": " << se; - cmSystemTools::Error(e.str()); - return false; - } - os.SetCopyIfDifferent(true); - - // Record this per-config import file. - this->ConfigCxxModuleFiles[config] = fileName; - - auto& prop_files = this->ConfigCxxModuleTargetFiles[config]; - for (auto const* tgt : this->ExportedTargets) { - // Only targets with C++ module sources will have a - // collator-generated install script. - if (!tgt->HaveCxx20ModuleSources()) { + for (auto const& te : this->GetExportSet()->GetTargetExports()) { + if (te->NamelinkOnly) { continue; } - - auto prop_filename = cmStrCat("target-", tgt->GetFilesystemExportName(), - '-', filename_config, ".cmake"); - prop_files.emplace_back(cmStrCat(dest, prop_filename)); - os << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << prop_filename << "\")\n"; + if (this->ExportedTargets.insert(te->Target).second) { + visitor(te.get()); + } else { + this->ComplainAboutDuplicateTarget(te->Target->GetName()); + return false; + } } - return true; } + +bool cmExportInstallFileGenerator::PopulateInterfaceProperties( + cmTargetExport const* targetExport, ImportPropertyMap& properties) +{ + cmGeneratorTarget const* const gt = targetExport->Target; + + std::string includesDestinationDirs; + this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt, + cmGeneratorExpression::InstallInterface, + properties); + this->PopulateIncludeDirectoriesInterface( + gt, cmGeneratorExpression::InstallInterface, properties, *targetExport, + includesDestinationDirs); + this->PopulateLinkDirectoriesInterface( + gt, cmGeneratorExpression::InstallInterface, properties); + this->PopulateLinkDependsInterface( + gt, cmGeneratorExpression::InstallInterface, properties); + this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface, + properties); + + return this->PopulateInterfaceProperties( + gt, includesDestinationDirs, cmGeneratorExpression::InstallInterface, + properties); +} + +namespace { +bool isSubDirectory(std::string const& a, std::string const& b) +{ + return (cmSystemTools::ComparePath(a, b) || + cmSystemTools::IsSubDirectory(a, b)); +} + +bool checkInterfaceDirs(std::string const& prepro, + cmGeneratorTarget const* target, + std::string const& prop) +{ + std::string const& installDir = + target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); + std::string const& topSourceDir = + target->GetLocalGenerator()->GetSourceDirectory(); + std::string const& topBinaryDir = + target->GetLocalGenerator()->GetBinaryDirectory(); + + std::vector parts; + cmGeneratorExpression::Split(prepro, parts); + + bool const inSourceBuild = topSourceDir == topBinaryDir; + + bool hadFatalError = false; + + for (std::string const& li : parts) { + size_t genexPos = cmGeneratorExpression::Find(li); + if (genexPos == 0) { + continue; + } + if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) { + continue; + } + MessageType messageType = MessageType::FATAL_ERROR; + std::ostringstream e; + if (genexPos != std::string::npos) { + if (prop == "INTERFACE_INCLUDE_DIRECTORIES") { + switch (target->GetPolicyStatusCMP0041()) { + case cmPolicies::WARN: + messageType = MessageType::WARNING; + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n"; + break; + case cmPolicies::OLD: + continue; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + hadFatalError = true; + break; // Issue fatal message. + } + } else { + hadFatalError = true; + } + } + if (!cmSystemTools::FileIsFullPath(li)) { + /* clang-format off */ + e << "Target \"" << target->GetName() << "\" " << prop << + " property contains relative path:\n" + " \"" << li << "\""; + /* clang-format on */ + target->GetLocalGenerator()->IssueMessage(messageType, e.str()); + } + bool inBinary = isSubDirectory(li, topBinaryDir); + bool inSource = isSubDirectory(li, topSourceDir); + if (isSubDirectory(li, installDir)) { + // The include directory is inside the install tree. If the + // install tree is not inside the source tree or build tree then + // fall through to the checks below that the include directory is not + // also inside the source tree or build tree. + bool shouldContinue = + (!inBinary || isSubDirectory(installDir, topBinaryDir)) && + (!inSource || isSubDirectory(installDir, topSourceDir)); + + if (prop == "INTERFACE_INCLUDE_DIRECTORIES") { + if (!shouldContinue) { + switch (target->GetPolicyStatusCMP0052()) { + case cmPolicies::WARN: { + std::ostringstream s; + s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n"; + s << "Directory:\n \"" << li + << "\"\nin " + "INTERFACE_INCLUDE_DIRECTORIES of target \"" + << target->GetName() + << "\" is a subdirectory of the install " + "directory:\n \"" + << installDir + << "\"\nhowever it is also " + "a subdirectory of the " + << (inBinary ? "build" : "source") << " tree:\n \"" + << (inBinary ? topBinaryDir : topSourceDir) << "\"\n"; + target->GetLocalGenerator()->IssueMessage( + MessageType::AUTHOR_WARNING, s.str()); + CM_FALLTHROUGH; + } + case cmPolicies::OLD: + shouldContinue = true; + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + break; + } + } + } + if (shouldContinue) { + continue; + } + } + if (inBinary) { + /* clang-format off */ + e << "Target \"" << target->GetName() << "\" " << prop << + " property contains path:\n" + " \"" << li << "\"\nwhich is prefixed in the build directory."; + /* clang-format on */ + target->GetLocalGenerator()->IssueMessage(messageType, e.str()); + } + if (!inSourceBuild) { + if (inSource) { + e << "Target \"" << target->GetName() << "\" " << prop + << " property contains path:\n" + " \"" + << li << "\"\nwhich is prefixed in the source directory."; + target->GetLocalGenerator()->IssueMessage(messageType, e.str()); + } + } + } + return !hadFatalError; +} +} + +void cmExportInstallFileGenerator::PopulateSourcesInterface( + cmGeneratorTarget const* gt, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + assert(preprocessRule == cmGeneratorExpression::InstallInterface); + + char const* const propName = "INTERFACE_SOURCES"; + cmValue input = gt->GetProperty(propName); + + if (!input) { + return; + } + + if (input->empty()) { + properties[propName].clear(); + return; + } + + std::string prepro = + cmGeneratorExpression::Preprocess(*input, preprocessRule, true); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, gt); + + if (!checkInterfaceDirs(prepro, gt, propName)) { + return; + } + properties[propName] = prepro; + } +} + +void cmExportInstallFileGenerator::PopulateIncludeDirectoriesInterface( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties, cmTargetExport const& te, + std::string& includesDestinationDirs) +{ + assert(preprocessRule == cmGeneratorExpression::InstallInterface); + + includesDestinationDirs.clear(); + + char const* const propName = "INTERFACE_INCLUDE_DIRECTORIES"; + cmValue input = target->GetProperty(propName); + + cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance()); + + std::string dirs = cmGeneratorExpression::Preprocess( + cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)), + preprocessRule, true); + this->ReplaceInstallPrefix(dirs); + std::unique_ptr cge = ge.Parse(dirs); + std::string exportDirs = + cge->Evaluate(target->GetLocalGenerator(), "", target); + + if (cge->GetHadContextSensitiveCondition()) { + cmLocalGenerator* lg = target->GetLocalGenerator(); + std::ostringstream e; + e << "Target \"" << target->GetName() + << "\" is installed with " + "INCLUDES DESTINATION set to a context sensitive path. Paths which " + "depend on the configuration, policy values or the link interface " + "are " + "not supported. Consider using target_include_directories instead."; + lg->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return; + } + + if (!input && exportDirs.empty()) { + return; + } + if ((input && input->empty()) && exportDirs.empty()) { + // Set to empty + properties[propName].clear(); + return; + } + + this->AddImportPrefix(exportDirs); + includesDestinationDirs = exportDirs; + + std::string includes = (input ? *input : ""); + char const* const sep = input ? ";" : ""; + includes += sep + exportDirs; + std::string prepro = + cmGeneratorExpression::Preprocess(includes, preprocessRule, true); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, target); + + if (!checkInterfaceDirs(prepro, target, propName)) { + return; + } + properties[propName] = prepro; + } +} + +void cmExportInstallFileGenerator::PopulateLinkDependsInterface( + cmGeneratorTarget const* gt, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + assert(preprocessRule == cmGeneratorExpression::InstallInterface); + + char const* const propName = "INTERFACE_LINK_DEPENDS"; + cmValue input = gt->GetProperty(propName); + + if (!input) { + return; + } + + if (input->empty()) { + properties[propName].clear(); + return; + } + + std::string prepro = + cmGeneratorExpression::Preprocess(*input, preprocessRule, true); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, gt); + + if (!checkInterfaceDirs(prepro, gt, propName)) { + return; + } + properties[propName] = prepro; + } +} + +void cmExportInstallFileGenerator::PopulateLinkDirectoriesInterface( + cmGeneratorTarget const* gt, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + assert(preprocessRule == cmGeneratorExpression::InstallInterface); + + char const* const propName = "INTERFACE_LINK_DIRECTORIES"; + cmValue input = gt->GetProperty(propName); + + if (!input) { + return; + } + + if (input->empty()) { + properties[propName].clear(); + return; + } + + std::string prepro = + cmGeneratorExpression::Preprocess(*input, preprocessRule, true); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, gt); + + if (!checkInterfaceDirs(prepro, gt, propName)) { + return; + } + properties[propName] = prepro; + } +} diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 5bcaacaafd..24cda9dd5d 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -4,19 +4,21 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include +#include #include #include #include #include #include +#include + #include "cmExportFileGenerator.h" +#include "cmGeneratorExpression.h" #include "cmInstallExportGenerator.h" #include "cmStateTypes.h" class cmExportSet; -class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmInstallTargetGenerator; @@ -25,18 +27,10 @@ class cmTargetExport; /** \class cmExportInstallFileGenerator * \brief Generate a file exporting targets from an install tree. * - * cmExportInstallFileGenerator generates files exporting targets from - * install an installation tree. The files are placed in a temporary - * location for installation by cmInstallExportGenerator. One main - * file is generated that creates the imported targets and loads - * per-configuration files. Target locations and settings for each - * configuration are written to these per-configuration files. After - * installation the main file loads the configurations that have been - * installed. - * - * This is used to implement the INSTALL(EXPORT) command. + * cmExportInstallFileGenerator is the generic interface class for generating + * export files for an install tree. */ -class cmExportInstallFileGenerator : public cmExportFileGenerator +class cmExportInstallFileGenerator : virtual public cmExportFileGenerator { public: /** Construct with the export installer that will install the @@ -73,38 +67,37 @@ public: /** Compute the globbing expression used to load per-config import files from the main file. */ - std::string GetConfigImportFileGlob(); + virtual std::string GetConfigImportFileGlob() const = 0; protected: - // Implement virtual methods from the superclass. - bool GenerateMainFile(std::ostream& os) override; - void GenerateImportTargetsConfig(std::ostream& os, std::string const& config, - std::string const& suffix) override; cmStateEnums::TargetType GetExportTargetType( cmTargetExport const* targetExport) const; + + virtual std::string const& GetExportName() const; + + std::string GetInstallPrefix() const + { + cm::string_view const& prefixWithSlash = this->GetImportPrefixWithSlash(); + return std::string(prefixWithSlash.data(), prefixWithSlash.length() - 1); + } + void HandleMissingTarget(std::string& link_libs, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) override; - void ReplaceInstallPrefix(std::string& input) override; + void ReplaceInstallPrefix(std::string& input) const override; - void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, - cmGeneratorTarget const* dependee, - std::vector const& exportFiles); + void ComplainAboutMissingTarget( + cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, + std::vector const& exportFiles) const; + + void ComplainAboutDuplicateTarget( + std::string const& targetName) const override; std::pair, std::string> FindNamespaces( - cmGlobalGenerator* gg, std::string const& name); + cmGlobalGenerator* gg, std::string const& name) const; - /** Generate the relative import prefix. */ - virtual void GenerateImportPrefix(std::ostream&); - - /** Generate the relative import prefix. */ - virtual void LoadConfigFiles(std::ostream&); - - virtual void CleanupTemporaryVariables(std::ostream&); - - /** Generate a per-configuration file for the targets. */ - virtual bool GenerateImportFileConfig(std::string const& config); + void ReportError(std::string const& errorMessage) const override; /** Fill in properties indicating installed file locations. */ void SetImportLocationProperty(std::string const& config, @@ -116,24 +109,31 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, std::string const& config) override; - std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; - std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, - cmTargetExport* te) override; - using cmExportFileGenerator::GetCxxModuleFile; - std::string GetCxxModulesDirectory() const override; - void GenerateCxxModuleConfigInformation(std::string const&, - std::ostream&) const override; - bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, - std::string const&); + /** Walk the list of targets to be exported. Returns true iff no duplicates + are found. */ + bool CollectExports( + std::function const& visitor); cmExportSet* GetExportSet() const override { return this->IEGen->GetExportSet(); } + std::string GetImportXcFrameworkLocation( + std::string const& config, cmTargetExport const* targetExport) const; + + using cmExportFileGenerator::PopulateInterfaceProperties; + bool PopulateInterfaceProperties(cmTargetExport const* targetExport, + ImportPropertyMap& properties); + + void PopulateImportProperties(std::string const& config, + std::string const& suffix, + cmTargetExport const* targetExport, + ImportPropertyMap& properties, + std::set& importedLocations); + cmInstallExportGenerator* IEGen; // The import file generated for each configuration. @@ -142,4 +142,29 @@ protected: std::map ConfigCxxModuleFiles; // The C++ module property target files generated for each configuration. std::map> ConfigCxxModuleTargetFiles; + +private: + void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target, + ImportPropertyMap& properties); + void PopulateCustomTransitiveInterfaceProperties( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); + void PopulateIncludeDirectoriesInterface( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties, cmTargetExport const& te, + std::string& includesDestinationDirs); + void PopulateSourcesInterface( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); + void PopulateLinkDirectoriesInterface( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); + void PopulateLinkDependsInterface( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); }; diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index 65068226c6..021e071153 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -19,6 +19,7 @@ #include "cmOutputConverter.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmTarget.h" #include "cmValue.h" @@ -32,6 +33,12 @@ cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator( gg->CreateImportedGenerationObjects(mf, targets, this->Exports); } +void cmExportTryCompileFileGenerator::ReportError( + std::string const& errorMessage) const +{ + cmSystemTools::Error(errorMessage); +} + bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os) { std::set emitted; @@ -153,14 +160,14 @@ std::string cmExportTryCompileFileGenerator::InstallNameDir( } std::string cmExportTryCompileFileGenerator::GetFileSetDirectories( - cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport const* /*te*/) { return cmOutputConverter::EscapeForCMake( cmList::to_string(fileSet->GetDirectoryEntries())); } std::string cmExportTryCompileFileGenerator::GetFileSetFiles( - cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport const* /*te*/) { return cmOutputConverter::EscapeForCMake( cmList::to_string(fileSet->GetFileEntries())); diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index e96d33263c..4b290e6b2a 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -9,7 +9,7 @@ #include #include -#include "cmExportFileGenerator.h" +#include "cmExportCMakeConfigGenerator.h" class cmFileSet; class cmGeneratorTarget; @@ -17,7 +17,7 @@ class cmGlobalGenerator; class cmMakefile; class cmTargetExport; -class cmExportTryCompileFileGenerator : public cmExportFileGenerator +class cmExportTryCompileFileGenerator : public cmExportCMakeConfigGenerator { public: cmExportTryCompileFileGenerator(cmGlobalGenerator* gg, @@ -30,6 +30,10 @@ public: protected: // Implement virtual methods from the superclass. + void ComplainAboutDuplicateTarget( + std::string const& /*targetName*/) const override{}; + void ReportError(std::string const& errorMessage) const override; + bool GenerateMainFile(std::ostream& os) override; void GenerateImportTargetsConfig(std::ostream&, std::string const&, @@ -50,10 +54,10 @@ protected: std::string GetFileSetDirectories(cmGeneratorTarget* target, cmFileSet* fileSet, - cmTargetExport* te) override; + cmTargetExport const* te) override; std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet, - cmTargetExport* te) override; + cmTargetExport const* te) override; std::string GetCxxModulesDirectory() const override { return {}; } void GenerateCxxModuleConfigInformation(std::string const&, diff --git a/Source/cmInstallAndroidMKExportGenerator.cxx b/Source/cmInstallAndroidMKExportGenerator.cxx index 2c52f569ad..b038ac1694 100644 --- a/Source/cmInstallAndroidMKExportGenerator.cxx +++ b/Source/cmInstallAndroidMKExportGenerator.cxx @@ -16,23 +16,15 @@ cmInstallAndroidMKExportGenerator::cmInstallAndroidMKExportGenerator( cmExportSet* exportSet, std::string destination, std::string filePermissions, std::vector const& configurations, std::string component, MessageLevel message, bool excludeFromAll, std::string filename, - std::string targetNamespace, bool exportOld, cmListFileBacktrace backtrace) + std::string targetNamespace, cmListFileBacktrace backtrace) : cmInstallExportGenerator(exportSet, std::move(destination), std::move(filePermissions), configurations, std::move(component), message, excludeFromAll, std::move(filename), std::move(targetNamespace), std::string{}, std::move(backtrace)) - , ExportOld(exportOld) { this->EFGen = cm::make_unique(this); } cmInstallAndroidMKExportGenerator::~cmInstallAndroidMKExportGenerator() = default; - -void cmInstallAndroidMKExportGenerator::GenerateScript(std::ostream& os) -{ - this->EFGen->SetExportOld(this->ExportOld); - - this->cmInstallExportGenerator::GenerateScript(os); -} diff --git a/Source/cmInstallAndroidMKExportGenerator.h b/Source/cmInstallAndroidMKExportGenerator.h index dcff756335..4ee80d4c61 100644 --- a/Source/cmInstallAndroidMKExportGenerator.h +++ b/Source/cmInstallAndroidMKExportGenerator.h @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once -#include #include #include @@ -22,8 +21,7 @@ public: std::string filePermissions, std::vector const& configurations, std::string component, MessageLevel message, bool excludeFromAll, std::string filename, - std::string targetNamespace, bool exportOld, - cmListFileBacktrace backtrace); + std::string targetNamespace, cmListFileBacktrace backtrace); cmInstallAndroidMKExportGenerator(cmInstallAndroidMKExportGenerator const&) = delete; ~cmInstallAndroidMKExportGenerator() override; @@ -31,10 +29,8 @@ public: cmInstallAndroidMKExportGenerator& operator=( cmInstallAndroidMKExportGenerator const&) = delete; -protected: - char const* InstallSubcommand() const override { return "EXPORT"; } - - void GenerateScript(std::ostream& os) override; - - bool const ExportOld; + char const* InstallSubcommand() const override + { + return "EXPORT_ANDROID_MK"; + } }; diff --git a/Source/cmInstallCMakeConfigExportGenerator.cxx b/Source/cmInstallCMakeConfigExportGenerator.cxx index bb7a1a0f0d..e247e5b443 100644 --- a/Source/cmInstallCMakeConfigExportGenerator.cxx +++ b/Source/cmInstallCMakeConfigExportGenerator.cxx @@ -6,6 +6,7 @@ #include +#include "cmExportInstallCMakeConfigGenerator.h" #include "cmExportInstallFileGenerator.h" #include "cmListFileCache.h" @@ -25,7 +26,7 @@ cmInstallCMakeConfigExportGenerator::cmInstallCMakeConfigExportGenerator( , ExportOld(exportOld) , ExportPackageDependencies(exportPackageDependencies) { - this->EFGen = cm::make_unique(this); + this->EFGen = cm::make_unique(this); } cmInstallCMakeConfigExportGenerator::~cmInstallCMakeConfigExportGenerator() = @@ -33,8 +34,10 @@ cmInstallCMakeConfigExportGenerator::~cmInstallCMakeConfigExportGenerator() = void cmInstallCMakeConfigExportGenerator::GenerateScript(std::ostream& os) { - this->EFGen->SetExportOld(this->ExportOld); - this->EFGen->SetExportPackageDependencies(this->ExportPackageDependencies); + auto* const efgen = + static_cast(this->EFGen.get()); + efgen->SetExportOld(this->ExportOld); + efgen->SetExportPackageDependencies(this->ExportPackageDependencies); this->cmInstallExportGenerator::GenerateScript(os); } diff --git a/Source/cmInstallCMakeConfigExportGenerator.h b/Source/cmInstallCMakeConfigExportGenerator.h index 8f019b1351..03296de07d 100644 --- a/Source/cmInstallCMakeConfigExportGenerator.h +++ b/Source/cmInstallCMakeConfigExportGenerator.h @@ -32,9 +32,9 @@ public: cmInstallCMakeConfigExportGenerator& operator=( cmInstallCMakeConfigExportGenerator const&) = delete; -protected: char const* InstallSubcommand() const override { return "EXPORT"; } +protected: void GenerateScript(std::ostream& os) override; bool const ExportOld; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 1dffd4301c..31605851a1 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -2033,7 +2033,7 @@ bool HandleExportAndroidMKMode(std::vector const& args, &exportSet, ica.GetDestination(), ica.GetPermissions(), ica.GetConfigurations(), ica.GetComponent(), message, ica.GetExcludeFromAll(), std::move(fname), std::move(name_space), - exportOld, helper.Makefile->GetBacktrace())); + helper.Makefile->GetBacktrace())); return true; #else diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index b351fbe928..9828bf207b 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -136,7 +136,8 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, auto const cxxModuleDestination = cmStrCat(this->Destination, '/', this->CxxModulesDirectory); auto const cxxModuleInstallFilePath = this->EFGen->GetCxxModuleFile(); - if (!cxxModuleInstallFilePath.empty()) { + auto const configImportFilesGlob = this->EFGen->GetConfigImportFileGlob(); + if (!cxxModuleInstallFilePath.empty() && !configImportFilesGlob.empty()) { auto const cxxModuleFilename = cmSystemTools::GetFilenameName(cxxModuleInstallFilePath); @@ -149,17 +150,20 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, Indent indentN = indent.Next(); Indent indentNN = indentN.Next(); Indent indentNNN = indentNN.Next(); - /* clang-format off */ os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n" << indentN << " \"" << installedFile << "\"\n" << indentN << " \"" << cxxModuleInstallFilePath << "\")\n"; os << indentN << "if(_cmake_export_file_changed)\n"; os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir - << this->EFGen->GetConfigImportFileGlob() << "\")\n"; + << configImportFilesGlob << "\")\n"; os << indentNN << "if(_cmake_old_config_files)\n"; - os << indentNNN << "string(REPLACE \";\" \", \" _cmake_old_config_files_text \"${_cmake_old_config_files}\")\n"; - os << indentNNN << R"(message(STATUS "Old C++ module export file \")" << installedFile - << "\\\" will be replaced. Removing files [${_cmake_old_config_files_text}].\")\n"; + os << indentNNN + << "string(REPLACE \";\" \", \" _cmake_old_config_files_text " + "\"${_cmake_old_config_files}\")\n"; + os << indentNNN << R"(message(STATUS "Old C++ module export file \")" + << installedFile + << "\\\" will be replaced. " + "Removing files [${_cmake_old_config_files_text}].\")\n"; os << indentNNN << "unset(_cmake_old_config_files_text)\n"; os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n"; os << indentNN << "endif()\n"; @@ -167,7 +171,6 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, os << indentN << "endif()\n"; os << indentN << "unset(_cmake_export_file_changed)\n"; os << indent << "endif()\n"; - /* clang-format on */ // All of these files are siblings; get its location to know where the // "anchor" file is. @@ -201,33 +204,37 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os, Indent indent) { - // Remove old per-configuration export files if the main changes. - std::string installedDir = cmStrCat( - "$ENV{DESTDIR}", ConvertToAbsoluteDestination(this->Destination), '/'); - std::string installedFile = cmStrCat(installedDir, this->FileName); - os << indent << "if(EXISTS \"" << installedFile << "\")\n"; - Indent indentN = indent.Next(); - Indent indentNN = indentN.Next(); - Indent indentNNN = indentNN.Next(); - /* clang-format off */ - os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n" - << indentN << " \"" << installedFile << "\"\n" - << indentN << " \"" << this->MainImportFile << "\")\n"; - os << indentN << "if(_cmake_export_file_changed)\n"; - os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir - << this->EFGen->GetConfigImportFileGlob() << "\")\n"; - os << indentNN << "if(_cmake_old_config_files)\n"; - os << indentNNN << "string(REPLACE \";\" \", \" _cmake_old_config_files_text \"${_cmake_old_config_files}\")\n"; - os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile - << "\\\" will be replaced. Removing files [${_cmake_old_config_files_text}].\")\n"; - os << indentNNN << "unset(_cmake_old_config_files_text)\n"; - os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n"; - os << indentNN << "endif()\n"; - os << indentNN << "unset(_cmake_old_config_files)\n"; - os << indentN << "endif()\n"; - os << indentN << "unset(_cmake_export_file_changed)\n"; - os << indent << "endif()\n"; - /* clang-format on */ + auto const configImportFilesGlob = this->EFGen->GetConfigImportFileGlob(); + if (!configImportFilesGlob.empty()) { + // Remove old per-configuration export files if the main changes. + std::string installedDir = cmStrCat( + "$ENV{DESTDIR}", ConvertToAbsoluteDestination(this->Destination), '/'); + std::string installedFile = cmStrCat(installedDir, this->FileName); + os << indent << "if(EXISTS \"" << installedFile << "\")\n"; + Indent indentN = indent.Next(); + Indent indentNN = indentN.Next(); + Indent indentNNN = indentNN.Next(); + os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n" + << indentN << " \"" << installedFile << "\"\n" + << indentN << " \"" << this->MainImportFile << "\")\n"; + os << indentN << "if(_cmake_export_file_changed)\n"; + os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir + << configImportFilesGlob << "\")\n"; + os << indentNN << "if(_cmake_old_config_files)\n"; + os << indentNNN + << "string(REPLACE \";\" \", \" _cmake_old_config_files_text " + "\"${_cmake_old_config_files}\")\n"; + os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile + << "\\\" will be replaced. " + "Removing files [${_cmake_old_config_files_text}].\")\n"; + os << indentNNN << "unset(_cmake_old_config_files_text)\n"; + os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n"; + os << indentNN << "endif()\n"; + os << indentNN << "unset(_cmake_old_config_files)\n"; + os << indentN << "endif()\n"; + os << indentN << "unset(_cmake_export_file_changed)\n"; + os << indent << "endif()\n"; + } // Install the main export file. std::vector files; diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index b2a74acaf8..610061020a 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -36,6 +36,8 @@ public: cmInstallExportGenerator& operator=(const cmInstallExportGenerator&) = delete; + virtual char const* InstallSubcommand() const = 0; + cmExportSet* GetExportSet() { return this->ExportSet; } bool Compute(cmLocalGenerator* lg) override; @@ -56,8 +58,6 @@ public: } protected: - virtual char const* InstallSubcommand() const = 0; - void GenerateScript(std::ostream& os) override; void GenerateScriptConfigs(std::ostream& os, Indent indent) override; void GenerateScriptActions(std::ostream& os, Indent indent) override; diff --git a/bootstrap b/bootstrap index 241f44b280..682cca0fa4 100755 --- a/bootstrap +++ b/bootstrap @@ -345,8 +345,11 @@ CMAKE_CXX_SOURCES="\ cmExecuteProcessCommand \ cmExpandedCommandArgument \ cmExperimental \ + cmExportBuildCMakeConfigGenerator \ cmExportBuildFileGenerator \ + cmExportCMakeConfigGenerator \ cmExportFileGenerator \ + cmExportInstallCMakeConfigGenerator \ cmExportInstallFileGenerator \ cmExportSet \ cmExportTryCompileFileGenerator \