summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CMakeLists.txt12
-rw-r--r--Source/cmExportAndroidMKGenerator.cxx165
-rw-r--r--Source/cmExportAndroidMKGenerator.h73
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.cxx195
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.h41
-rw-r--r--Source/cmExportBuildCMakeConfigGenerator.cxx343
-rw-r--r--Source/cmExportBuildCMakeConfigGenerator.h52
-rw-r--r--Source/cmExportBuildFileGenerator.cxx448
-rw-r--r--Source/cmExportBuildFileGenerator.h61
-rw-r--r--Source/cmExportCMakeConfigGenerator.cxx686
-rw-r--r--Source/cmExportCMakeConfigGenerator.h109
-rw-r--r--Source/cmExportCommand.cxx14
-rw-r--r--Source/cmExportFileGenerator.cxx1099
-rw-r--r--Source/cmExportFileGenerator.h204
-rw-r--r--Source/cmExportInstallAndroidMKGenerator.cxx116
-rw-r--r--Source/cmExportInstallAndroidMKGenerator.h62
-rw-r--r--Source/cmExportInstallCMakeConfigGenerator.cxx507
-rw-r--r--Source/cmExportInstallCMakeConfigGenerator.h74
-rw-r--r--Source/cmExportInstallFileGenerator.cxx910
-rw-r--r--Source/cmExportInstallFileGenerator.h118
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx21
-rw-r--r--Source/cmExportTryCompileFileGenerator.h26
-rw-r--r--Source/cmInstallAndroidMKExportGenerator.cxx30
-rw-r--r--Source/cmInstallAndroidMKExportGenerator.h36
-rw-r--r--Source/cmInstallCMakeConfigExportGenerator.cxx43
-rw-r--r--Source/cmInstallCMakeConfigExportGenerator.h42
-rw-r--r--Source/cmInstallCommand.cxx13
-rw-r--r--Source/cmInstallExportGenerator.cxx151
-rw-r--r--Source/cmInstallExportGenerator.h23
-rwxr-xr-xbootstrap4
30 files changed, 3161 insertions, 2517 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1d2b7dd..f4ff102 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
@@ -311,6 +319,10 @@ add_library(
cmGraphVizWriter.h
cmImportedCxxModuleInfo.cxx
cmImportedCxxModuleInfo.h
+ cmInstallAndroidMKExportGenerator.cxx
+ cmInstallAndroidMKExportGenerator.h
+ cmInstallCMakeConfigExportGenerator.cxx
+ cmInstallCMakeConfigExportGenerator.h
cmInstallGenerator.h
cmInstallGenerator.cxx
cmInstallGetRuntimeDependenciesGenerator.h
diff --git a/Source/cmExportAndroidMKGenerator.cxx b/Source/cmExportAndroidMKGenerator.cxx
new file mode 100644
index 0000000..34dc1a7
--- /dev/null
+++ b/Source/cmExportAndroidMKGenerator.cxx
@@ -0,0 +1,165 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportAndroidMKGenerator.h"
+
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#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"
+
+cmExportAndroidMKGenerator::cmExportAndroidMKGenerator() = default;
+
+cm::string_view cmExportAndroidMKGenerator::GetImportPrefixWithSlash() const
+{
+ return "$(_IMPORT_PREFIX)/"_s;
+}
+
+bool cmExportAndroidMKGenerator::GenerateImportFile(std::ostream& os)
+{
+ if (!this->AppendMode) {
+ // Start with the import file header.
+ this->GenerateImportHeaderCode(os);
+ }
+
+ // Create all the imported targets.
+ std::stringstream mainFileBuffer;
+ bool result = this->GenerateMainFile(mainFileBuffer);
+
+ // Write cached import code.
+ os << mainFileBuffer.rdbuf();
+
+ return result;
+}
+
+void cmExportAndroidMKGenerator::GenerateInterfaceProperties(
+ cmGeneratorTarget const* target, std::ostream& os,
+ ImportPropertyMap const& properties)
+{
+ std::string const config =
+ (this->Configurations.empty() ? std::string{} : this->Configurations[0]);
+ GenerateType const type = this->GetGenerateType();
+
+ bool const newCMP0022Behavior =
+ target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+ if (!newCMP0022Behavior) {
+ std::ostringstream w;
+ if (type == 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 == 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/cmExportAndroidMKGenerator.h b/Source/cmExportAndroidMKGenerator.h
new file mode 100644
index 0000000..fb0f03b
--- /dev/null
+++ b/Source/cmExportAndroidMKGenerator.h
@@ -0,0 +1,73 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <map>
+#include <string>
+
+#include <cm/string_view>
+
+#include "cmExportFileGenerator.h"
+#include "cmStateTypes.h"
+
+class cmGeneratorTarget;
+
+/** \class cmExportAndroidMKGenerator
+ * \brief Generate CMake configuration files exporting targets from a build or
+ * install tree.
+ *
+ * cmExportAndroidMKGenerator is the superclass for
+ * cmExportBuildAndroidMKGenerator and cmExportInstallAndroidMKGenerator.
+ * It contains common code generation routines for the two kinds of export
+ * implementations.
+ */
+class cmExportAndroidMKGenerator : virtual public cmExportFileGenerator
+{
+public:
+ cmExportAndroidMKGenerator();
+
+ using cmExportFileGenerator::GenerateImportFile;
+
+protected:
+ enum GenerateType
+ {
+ BUILD,
+ INSTALL
+ };
+ virtual GenerateType GetGenerateType() const = 0;
+
+ using ImportPropertyMap = std::map<std::string, std::string>;
+
+ 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) = 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 cbc05dd..a5f6ca3 100644
--- a/Source/cmExportBuildAndroidMKGenerator.cxx
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -2,43 +2,56 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportBuildAndroidMKGenerator.h"
-#include <map>
#include <sstream>
-#include <utility>
#include <vector>
-#include <cmext/algorithm>
-
+#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()
-{
- this->LG = nullptr;
- this->ExportSet = nullptr;
-}
+cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator() = default;
-void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
- std::ostream& os, const std::string&)
+bool cmExportBuildAndroidMKGenerator::GenerateMainFile(std::ostream& os)
{
- os << "LOCAL_PATH := $(call my-dir)\n\n";
-}
+ if (!this->CollectExports([&](cmGeneratorTarget const*) {})) {
+ return false;
+ }
-void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
-{
+ // 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::GenerateExpectedTargetsCode(
- std::ostream&, const std::string&)
+void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
+ std::ostream& os, std::string const&)
{
+ os << "LOCAL_PATH := $(call my-dir)\n\n";
}
void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
@@ -55,143 +68,3 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
os << path << "\n";
}
-
-void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode(
- std::ostream&, const std::string&, const std::string&,
- cmGeneratorTarget const*, ImportPropertyMap const&, const std::string&)
-{
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode(
- std::ostream&)
-{
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
- const cmGeneratorTarget* target, std::ostream& os,
- const ImportPropertyMap& properties)
-{
- std::string config;
- if (!this->Configurations.empty()) {
- config = this->Configurations[0];
- }
- cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
- target, os, properties, cmExportBuildAndroidMKGenerator::BUILD, config);
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
- const cmGeneratorTarget* target, std::ostream& os,
- const ImportPropertyMap& properties, GenerateType type,
- std::string const& config)
-{
- const bool 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 9562cee..deb3893 100644
--- a/Source/cmExportBuildAndroidMKGenerator.h
+++ b/Source/cmExportBuildAndroidMKGenerator.h
@@ -7,6 +7,7 @@
#include <iosfwd>
#include <string>
+#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,
- const ImportPropertyMap& 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,
- const std::string& config = "") override;
- void GenerateImportFooterCode(std::ostream& os) override;
+ std::string const& config = "") override;
void GenerateImportTargetCode(
std::ostream& os, cmGeneratorTarget const* target,
cmStateEnums::TargetType /*targetType*/) override;
- void GenerateExpectedTargetsCode(
- std::ostream& os, const std::string& expectedTargets) override;
- void GenerateImportPropertyCode(
- std::ostream& os, const std::string& config, const std::string& suffix,
- cmGeneratorTarget const* target, ImportPropertyMap const& properties,
- const std::string& importedXcFrameworkLocation) override;
- void GenerateMissingTargetsCheckCode(std::ostream& os) override;
- void GenerateFindDependencyCalls(std::ostream&) override {}
- void GenerateInterfaceProperties(
- cmGeneratorTarget const* target, std::ostream& os,
- const ImportPropertyMap& properties) override;
+
+ std::string GetCxxModulesDirectory() const override { return {}; }
};
diff --git a/Source/cmExportBuildCMakeConfigGenerator.cxx b/Source/cmExportBuildCMakeConfigGenerator.cxx
new file mode 100644
index 0000000..87aeb3c
--- /dev/null
+++ b/Source/cmExportBuildCMakeConfigGenerator.cxx
@@ -0,0 +1,343 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportBuildCMakeConfigGenerator.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmCryptoHash.h"
+#include "cmExportSet.h"
+#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.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"
+
+cmExportBuildCMakeConfigGenerator::cmExportBuildCMakeConfigGenerator()
+{
+ this->LG = nullptr;
+ this->ExportSet = nullptr;
+}
+
+bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
+{
+ {
+ std::string expectedTargets;
+ std::string sep;
+ bool generatedInterfaceRequired = false;
+ auto visitor = [&](cmGeneratorTarget const* te) {
+ expectedTargets += sep + this->Namespace + te->GetExportName();
+ sep = " ";
+
+ generatedInterfaceRequired |=
+ this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY;
+ };
+
+ if (!this->CollectExports(visitor)) {
+ return false;
+ }
+
+ 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;
+ 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);
+
+ 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 cmExportBuildCMakeConfigGenerator::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);
+ }
+ }
+}
+
+namespace {
+bool EntryIsContextSensitive(
+ std::unique_ptr<cmCompiledGeneratorExpression> const& cge)
+{
+ return cge->GetHadContextSensitiveCondition();
+}
+}
+
+std::string cmExportBuildCMakeConfigGenerator::GetFileSetDirectories(
+ cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* /*te*/)
+{
+ std::vector<std::string> 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("\"$<$<CONFIG:", config, ">:", dest, ">\""));
+ } else {
+ resultVector.emplace_back(cmStrCat('"', dest, '"'));
+ break;
+ }
+ }
+ }
+
+ return cmJoin(resultVector, " ");
+}
+
+std::string cmExportBuildCMakeConfigGenerator::GetFileSetFiles(
+ cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* /*te*/)
+{
+ std::vector<std::string> 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<std::string, std::vector<std::string>> 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("\"$<$<CONFIG:", config, ">:", escapedFile, ">\""));
+ } else {
+ resultVector.emplace_back(cmStrCat('"', escapedFile, '"'));
+ }
+ }
+ }
+
+ if (!(contextSensitive && configs.size() != 1)) {
+ break;
+ }
+ }
+
+ return cmJoin(resultVector, " ");
+}
+
+void cmExportBuildCMakeConfigGenerator::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 cmExportBuildCMakeConfigGenerator::
+ 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;
+}
diff --git a/Source/cmExportBuildCMakeConfigGenerator.h b/Source/cmExportBuildCMakeConfigGenerator.h
new file mode 100644
index 0000000..0648dc3
--- /dev/null
+++ b/Source/cmExportBuildCMakeConfigGenerator.h
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportCMakeConfigGenerator.h"
+
+class cmFileSet;
+class cmGeneratorTarget;
+class cmTargetExport;
+
+/** \class cmExportBuildCMakeConfigGenerator
+ * \brief Generate a file exporting targets from a build tree.
+ *
+ * cmExportBuildCMakeConfigGenerator generates a file exporting targets from
+ * 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 cmExportCMakeConfigGenerator
+ , public cmExportBuildFileGenerator
+{
+public:
+ cmExportBuildCMakeConfigGenerator();
+
+ /** Set whether to append generated code to the output file. */
+ void SetAppendMode(bool append) { this->AppendMode = append; }
+
+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;
+
+ std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
+ cmTargetExport const* te) override;
+ std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
+ cmTargetExport const* te) override;
+
+ void GenerateCxxModuleConfigInformation(std::string const&,
+ std::ostream&) const override;
+ bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
+ std::string) const;
+};
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index d877d76..eefc516 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -3,20 +3,13 @@
#include "cmExportBuildFileGenerator.h"
#include <algorithm>
-#include <cstddef>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <utility>
-#include <cm/string_view>
-#include <cmext/string_view>
-
-#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<TargetExport> 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;
- }
-
- const bool 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, const std::string& 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
{
@@ -260,7 +61,7 @@ void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet)
}
void cmExportBuildFileGenerator::SetImportLocationProperty(
- const std::string& config, std::string const& suffix,
+ std::string const& config, std::string const& suffix,
cmGeneratorTarget* target, ImportPropertyMap& properties)
{
// Get the makefile in which to lookup target information.
@@ -276,7 +77,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
std::string const obj_dir = target->GetObjectDirectory(config);
std::vector<std::string> objects;
for (cmSourceFile const* sf : objectSources) {
- const std::string& obj = target->GetObjectName(sf);
+ std::string const& obj = target->GetObjectName(sf);
objects.push_back(obj_dir + obj);
}
@@ -311,13 +112,33 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
}
}
+bool cmExportBuildFileGenerator::CollectExports(
+ std::function<void(cmGeneratorTarget const*)> visitor)
+{
+ auto pred = [&](cmExportBuildFileGenerator::TargetExport& tei) -> bool {
+ cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name);
+ if (this->ExportedTargets.insert(te).second) {
+ this->Exports.emplace_back(te, tei.XcFrameworkLocation);
+ visitor(te);
+ return true;
+ }
+
+ this->ComplainAboutDuplicateTarget(te->GetName());
+ return false;
+ };
+
+ std::vector<TargetExport> targets;
+ this->GetTargets(targets);
+ return std::all_of(targets.begin(), targets.end(), pred);
+}
+
void cmExportBuildFileGenerator::HandleMissingTarget(
std::string& link_libs, cmGeneratorTarget const* depender,
cmGeneratorTarget* dependee)
{
// The target is not in the export.
if (!this->AppendMode) {
- const std::string name = dependee->GetName();
+ std::string const& name = dependee->GetName();
cmGlobalGenerator* gg =
dependee->GetLocalGenerator()->GetGlobalGenerator();
auto exportInfo = this->FindBuildExportInfo(gg, name);
@@ -359,7 +180,7 @@ void cmExportBuildFileGenerator::GetTargets(
std::pair<std::vector<std::string>, std::string>
cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
- const std::string& name)
+ std::string const& name)
{
std::vector<std::string> exportFiles;
std::string ns;
@@ -367,12 +188,12 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
auto& exportSets = gg->GetBuildExportSets();
for (auto const& exp : exportSets) {
- const auto& exportSet = exp.second;
+ auto const& exportSet = exp.second;
std::vector<TargetExport> targets;
exportSet->GetTargets(targets);
if (std::any_of(
targets.begin(), targets.end(),
- [&name](const TargetExport& te) { return te.Name == name; })) {
+ [&name](TargetExport const& te) { return te.Name == name; })) {
exportFiles.push_back(exp.first);
ns = exportSet->GetNamespace();
}
@@ -383,7 +204,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
- std::vector<std::string> const& exportFiles)
+ std::vector<std::string> const& exportFiles) const
{
std::ostringstream e;
e << "export called with target \"" << depender->GetName()
@@ -399,13 +220,27 @@ 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());
}
std::string cmExportBuildFileGenerator::InstallNameDir(
- cmGeneratorTarget const* target, const std::string& config)
+ cmGeneratorTarget const* target, std::string const& config)
{
std::string install_name_dir;
@@ -417,185 +252,22 @@ std::string cmExportBuildFileGenerator::InstallNameDir(
return install_name_dir;
}
-namespace {
-bool EntryIsContextSensitive(
- const std::unique_ptr<cmCompiledGeneratorExpression>& cge)
-{
- return cge->GetHadContextSensitiveCondition();
-}
-}
-
-std::string cmExportBuildFileGenerator::GetFileSetDirectories(
- cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/)
-{
- std::vector<std::string> 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("\"$<$<CONFIG:", config, ">:", dest, ">\""));
- } else {
- resultVector.emplace_back(cmStrCat('"', dest, '"'));
- break;
- }
- }
- }
-
- return cmJoin(resultVector, " ");
-}
-
-std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte,
- cmFileSet* fileSet,
- cmTargetExport* /*te*/)
+bool cmExportBuildFileGenerator::PopulateInterfaceProperties(
+ cmGeneratorTarget const* target, ImportPropertyMap& properties)
{
- std::vector<std::string> 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<std::string, std::vector<std::string>> 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("\"$<$<CONFIG:", config, ">:", 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
-{
- const char* 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 ee4779f..a4f8c5f 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -4,7 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <iosfwd>
+#include <functional>
#include <string>
#include <utility>
#include <vector>
@@ -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
@@ -64,54 +61,56 @@ public:
{
this->CxxModulesDirectory = std::move(cxx_module_dir);
}
- const std::string& GetCxxModuleDirectory() const
+ 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, const std::string& 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<void(cmGeneratorTarget const*)> visitor);
+
void HandleMissingTarget(std::string& link_libs,
cmGeneratorTarget const* depender,
cmGeneratorTarget* dependee) override;
- void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
- cmGeneratorTarget const* dependee,
- std::vector<std::string> const& namespaces);
+ void ComplainAboutMissingTarget(
+ cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
+ std::vector<std::string> 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(const std::string& config,
+ void SetImportLocationProperty(std::string const& config,
std::string const& suffix,
cmGeneratorTarget* target,
ImportPropertyMap& properties);
std::string InstallNameDir(cmGeneratorTarget const* target,
- const std::string& config) override;
+ 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::vector<std::string>, std::string> FindBuildExportInfo(
- cmGlobalGenerator* gg, const std::string& name);
+ cmGlobalGenerator* gg, std::string const& name);
+
+ using cmExportFileGenerator::PopulateInterfaceProperties;
+ bool PopulateInterfaceProperties(cmGeneratorTarget const* target,
+ ImportPropertyMap& properties);
struct TargetExportPrivate
{
diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx
new file mode 100644
index 0000000..4f4765c
--- /dev/null
+++ b/Source/cmExportCMakeConfigGenerator.cxx
@@ -0,0 +1,686 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportCMakeConfigGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmExportSet.h"
+#include "cmFileSet.h"
+#include "cmFindPackageStack.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmLinkItem.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"
+#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;
+}
+
+cmExportCMakeConfigGenerator::cmExportCMakeConfigGenerator() = default;
+
+cm::string_view cmExportCMakeConfigGenerator::GetImportPrefixWithSlash() const
+{
+ return "${_IMPORT_PREFIX}/"_s;
+}
+
+bool cmExportCMakeConfigGenerator::GenerateImportFile(std::ostream& os)
+{
+ 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;
+}
+
+void cmExportCMakeConfigGenerator::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";
+ }
+}
+
+void cmExportCMakeConfigGenerator::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 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 >= "
+ << 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 */
+
+ // 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 cmExportCMakeConfigGenerator::GeneratePolicyFooterCode(std::ostream& os)
+{
+ os << "cmake_policy(POP)\n";
+}
+
+void cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::GenerateImportFooterCode(std::ostream& os)
+{
+ os << "# Commands beyond this point should not need to know the version.\n"
+ << "set(CMAKE_IMPORT_FILE_VERSION)\n";
+}
+
+void cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::GenerateFindDependencyCalls(
+ std::ostream& os)
+{
+ os << "include(CMakeFindDependencyMacro)\n";
+ std::map<std::string, cmExportSet::PackageDependency> packageDependencies;
+ auto* exportSet = this->GetExportSet();
+ if (exportSet) {
+ packageDependencies = exportSet->GetPackageDependencies();
+ }
+
+ for (cmGeneratorTarget const* gt : this->ExternalTargets) {
+ std::string findPackageName;
+ auto exportFindPackageName = gt->GetProperty("EXPORT_FIND_PACKAGE_NAME");
+ cmFindPackageStack pkgStack = gt->Target->GetFindPackageStack();
+ if (!exportFindPackageName.IsEmpty()) {
+ findPackageName = *exportFindPackageName;
+ } else {
+ if (!pkgStack.Empty()) {
+ cmFindPackageCall const& fpc = pkgStack.Top();
+ findPackageName = fpc.Name;
+ }
+ }
+ if (!findPackageName.empty()) {
+ auto& dep = packageDependencies[findPackageName];
+ if (!pkgStack.Empty()) {
+ dep.FindPackageIndex = pkgStack.Top().Index;
+ }
+ if (dep.Enabled == cmExportSet::PackageDependencyExportEnabled::Auto) {
+ dep.Enabled = cmExportSet::PackageDependencyExportEnabled::On;
+ }
+ }
+ }
+
+ std::vector<std::pair<std::string, cmExportSet::PackageDependency>>
+ packageDependenciesSorted(packageDependencies.begin(),
+ packageDependencies.end());
+ std::sort(
+ packageDependenciesSorted.begin(), packageDependenciesSorted.end(),
+ [](std::pair<std::string, cmExportSet::PackageDependency> const& lhs,
+ std::pair<std::string, cmExportSet::PackageDependency> 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 cmExportCMakeConfigGenerator::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<std::string> 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 cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::GenerateImportedFileChecksCode(
+ std::ostream& os, cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties,
+ std::set<std::string> 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";
+}
+
+void cmExportCMakeConfigGenerator::GenerateTargetFileSets(
+ cmGeneratorTarget* gte, std::ostream& os, cmTargetExport const* 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 cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::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 cmExportCMakeConfigGenerator::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/cmExportCMakeConfigGenerator.h b/Source/cmExportCMakeConfigGenerator.h
new file mode 100644
index 0000000..90f7aa7
--- /dev/null
+++ b/Source/cmExportCMakeConfigGenerator.h
@@ -0,0 +1,109 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+
+#include <cm/string_view>
+
+#include "cmExportFileGenerator.h"
+#include "cmGeneratorExpression.h"
+#include "cmStateTypes.h"
+
+class cmFileSet;
+class cmGeneratorTarget;
+class cmTargetExport;
+
+/** \class cmExportCMakeConfigGenerator
+ * \brief Generate CMake configuration files exporting targets from a build or
+ * install tree.
+ *
+ * cmExportCMakeConfigGenerator is the superclass for
+ * cmExportBuildCMakeConfigGenerator and cmExportInstallCMakeConfigGenerator.
+ * It contains common code generation routines for the two kinds of export
+ * implementations.
+ */
+class cmExportCMakeConfigGenerator : virtual public cmExportFileGenerator
+{
+public:
+ cmExportCMakeConfigGenerator();
+
+ void SetExportOld(bool exportOld) { this->ExportOld = exportOld; }
+
+ void SetExportPackageDependencies(bool exportPackageDependencies)
+ {
+ this->ExportPackageDependencies = exportPackageDependencies;
+ }
+
+ using cmExportFileGenerator::GenerateImportFile;
+
+protected:
+ using ImportPropertyMap = std::map<std::string, std::string>;
+
+ // 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,
+ 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 const* target,
+ ImportPropertyMap const& properties,
+ std::set<std::string> 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);
+
+ cm::string_view GetImportPrefixWithSlash() const override;
+
+ virtual void GenerateInterfaceProperties(
+ cmGeneratorTarget const* target, std::ostream& os,
+ ImportPropertyMap const& properties);
+
+ void SetImportLinkInterface(
+ std::string const& config, std::string const& suffix,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ cmGeneratorTarget const* target, ImportPropertyMap& properties);
+
+ void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
+ 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 const* te) = 0;
+ virtual std::string GetFileSetFiles(cmGeneratorTarget* gte,
+ cmFileSet* fileSet,
+ cmTargetExport const* te) = 0;
+
+ void SetRequiredCMakeVersion(unsigned int major, unsigned int minor,
+ unsigned int patch);
+
+ bool ExportOld = false;
+ bool ExportPackageDependencies = false;
+
+ unsigned int RequiredCMakeVersionMajor = 2;
+ unsigned int RequiredCMakeVersionMinor = 8;
+ unsigned int RequiredCMakeVersionPatch = 3;
+};
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 0cb0011..00f3c74 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<std::string> const& args,
// Setup export file generation.
std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
if (android) {
- ebfg = cm::make_unique<cmExportBuildAndroidMKGenerator>();
+ auto ebag = cm::make_unique<cmExportBuildAndroidMKGenerator>();
+ ebag->SetAppendMode(arguments.Append);
+ ebfg = std::move(ebag);
} else {
- ebfg = cm::make_unique<cmExportBuildFileGenerator>();
+ auto ebcg = cm::make_unique<cmExportBuildCMakeConfigGenerator>();
+ 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<std::string> configurationTypes =
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 4dddefa..24ed273 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 <algorithm>
#include <array>
-#include <cassert>
-#include <cstring>
+#include <cstddef>
#include <sstream>
#include <utility>
#include <cm/memory>
-#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmsys/FStream.hxx"
#include "cmComputeLinkInformation.h"
-#include "cmExportSet.h"
-#include "cmFileSet.h"
#include "cmFindPackageStack.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
@@ -27,40 +22,21 @@
#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(const std::string& config)
+void cmExportFileGenerator::AddConfiguration(std::string const& config)
{
this->Configurations.push_back(config);
}
-void cmExportFileGenerator::SetExportFile(const char* mainFile)
+void cmExportFileGenerator::SetExportFile(char const* mainFile)
{
this->MainImportFile = mainFile;
this->FileDir = cmSystemTools::GetFilenamePath(this->MainImportFile);
@@ -70,7 +46,7 @@ void cmExportFileGenerator::SetExportFile(const char* mainFile)
cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
}
-const std::string& cmExportFileGenerator::GetMainExportFileName() const
+std::string const& cmExportFileGenerator::GetMainExportFileName() const
{
return this->MainImportFile;
}
@@ -98,42 +74,12 @@ 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,
- const std::string& config)
+ std::string const& config)
{
// Construct the property configuration suffix.
std::string suffix = "_";
@@ -147,10 +93,51 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os,
this->GenerateImportTargetsConfig(os, config, suffix);
}
-void cmExportFileGenerator::PopulateInterfaceProperty(
- const std::string& propName, cmGeneratorTarget const* target,
+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) const
+{
cmValue input = target->GetProperty(propName);
if (input) {
properties[propName] = *input;
@@ -158,7 +145,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(
}
void cmExportFileGenerator::PopulateInterfaceProperty(
- const std::string& propName, const std::string& outputName,
+ std::string const& propName, std::string const& outputName,
cmGeneratorTarget const* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties)
@@ -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,
@@ -188,7 +184,7 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
if (!target->IsLinkable()) {
return false;
}
- static const std::array<std::string, 3> linkIfaceProps = {
+ static std::array<std::string, 3> const linkIfaceProps = {
{ "INTERFACE_LINK_LIBRARIES", "INTERFACE_LINK_LIBRARIES_DIRECT",
"INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE" }
};
@@ -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(const std::string& prepro,
- cmGeneratorTarget const* target,
- const std::string& 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<std::string> parts;
- cmGeneratorExpression::Split(prepro, parts);
-
- const bool 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<std::string> entries;
cmGeneratorExpression::Split(exportDirs, entries);
exportDirs.clear();
- const char* sep = "";
+ 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);
-
- const char* 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();
-
- const char* 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<cmCompiledGeneratorExpression> 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 : "");
- const char* 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);
-
- const char* 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);
-
- const char* 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(
- const std::string& propName, cmGeneratorTarget const* target,
- cmGeneratorExpression::PreprocessContext preprocessRule,
- ImportPropertyMap& properties)
-{
- this->PopulateInterfaceProperty(propName, propName, target, preprocessRule,
- properties);
-}
-
-static void getPropertyContents(cmGeneratorTarget const* tgt,
- const std::string& prop,
- std::set<std::string>& ifaceProperties)
+namespace {
+void getPropertyContents(cmGeneratorTarget const* tgt, std::string const& prop,
+ std::set<std::string>& 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<std::string>& ifaceProperties,
- const std::string& config)
+void getCompatibleInterfaceProperties(cmGeneratorTarget const* target,
+ std::set<std::string>& ifaceProperties,
+ std::string const& config)
{
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
// object libraries have no link information, so nothing to compute
@@ -551,7 +255,7 @@ static void getCompatibleInterfaceProperties(
return;
}
- const cmComputeLinkInformation::ItemVector& deps = info->GetItems();
+ cmComputeLinkInformation::ItemVector const& deps = info->GetItems();
for (auto const& dep : deps) {
if (!dep.Target || dep.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
@@ -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(
- const cmGeneratorTarget* target, std::ostream& os,
- const ImportPropertyMap& 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(
- const std::string& 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;
- }
-
- const bool 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(
- const std::string& config, std::string const& suffix,
- cmGeneratorTarget* target, ImportPropertyMap& properties)
+ std::string const& config, std::string const& suffix,
+ cmGeneratorTarget const* target, ImportPropertyMap& properties)
{
// Get the makefile in which to lookup target information.
cmMakefile* mf = target->Makefile;
@@ -943,20 +572,22 @@ 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 <typename T>
void cmExportFileGenerator::SetImportLinkProperty(
std::string const& suffix, cmGeneratorTarget const* target,
- const std::string& propName, std::vector<T> const& entries,
+ std::string const& propName, std::vector<T> const& entries,
ImportPropertyMap& properties, ImportLinkPropertyTargetNames targetNames)
{
// Skip the property if there are no entries.
@@ -968,7 +599,7 @@ void cmExportFileGenerator::SetImportLinkProperty(
// Construct the property value.
std::string link_entries;
- const char* sep = "";
+ char const* sep = "";
for (T const& l : entries) {
// Separate this from the previous entry.
link_entries += sep;
@@ -988,428 +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 >= 2.8.0 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 */
-
- // 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,
- const std::string& 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, const std::string& 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, const std::string& config, const std::string& suffix,
- cmGeneratorTarget const* target, ImportPropertyMap const& properties,
- const std::string& importedXcFrameworkLocation)
-{
- // Construct the imported target name.
- std::string targetName = this->Namespace;
-
- 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<std::string, cmExportSet::PackageDependency> packageDependencies;
- auto* exportSet = this->GetExportSet();
- if (exportSet) {
- packageDependencies = exportSet->GetPackageDependencies();
- }
+template void cmExportFileGenerator::SetImportLinkProperty<std::string>(
+ std::string const&, cmGeneratorTarget const*, std::string const&,
+ std::vector<std::string> const&, ImportPropertyMap& properties,
+ ImportLinkPropertyTargetNames);
- for (cmGeneratorTarget const* gt : this->ExternalTargets) {
- std::string findPackageName;
- auto exportFindPackageName = gt->GetProperty("EXPORT_FIND_PACKAGE_NAME");
- cmFindPackageStack pkgStack = gt->Target->GetFindPackageStack();
- if (!exportFindPackageName.IsEmpty()) {
- findPackageName = *exportFindPackageName;
- } else {
- if (!pkgStack.Empty()) {
- cmFindPackageCall const& fpc = pkgStack.Top();
- findPackageName = fpc.Name;
- }
- }
- if (!findPackageName.empty()) {
- auto& dep = packageDependencies[findPackageName];
- if (!pkgStack.Empty()) {
- dep.FindPackageIndex = pkgStack.Top().Index;
- }
- if (dep.Enabled == cmExportSet::PackageDependencyExportEnabled::Auto) {
- dep.Enabled = cmExportSet::PackageDependencyExportEnabled::On;
- }
- }
- }
-
- std::vector<std::pair<std::string, cmExportSet::PackageDependency>>
- packageDependenciesSorted(packageDependencies.begin(),
- packageDependencies.end());
- std::sort(
- packageDependenciesSorted.begin(), packageDependenciesSorted.end(),
- [](const std::pair<std::string, cmExportSet::PackageDependency>& lhs,
- const std::pair<std::string, cmExportSet::PackageDependency>& rhs)
- -> bool {
- if (lhs.second.SpecifiedIndex) {
- if (rhs.second.SpecifiedIndex) {
- return lhs.second.SpecifiedIndex < rhs.second.SpecifiedIndex;
- }
- assert(rhs.second.FindPackageIndex);
- return true;
- }
- assert(lhs.second.FindPackageIndex);
- if (rhs.second.SpecifiedIndex) {
- return false;
- }
- assert(rhs.second.FindPackageIndex);
- return lhs.second.FindPackageIndex < rhs.second.FindPackageIndex;
- });
-
- for (auto const& it : packageDependenciesSorted) {
- if (it.second.Enabled == cmExportSet::PackageDependencyExportEnabled::On) {
- os << "find_dependency(" << it.first;
- 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<std::string> 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,
- const std::set<std::string>& importedLocations,
- const std::string& importedXcFrameworkLocation)
-{
- // Construct the imported target name.
- std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
-
- os << "list(APPEND _cmake_import_check_targets " << targetName << " )\n";
- 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<cmLinkItem>(
+ std::string const&, cmGeneratorTarget const*, std::string const&,
+ std::vector<cmLinkItem> const&, ImportPropertyMap& properties,
+ ImportLinkPropertyTargetNames);
+namespace {
enum class ExportWhen
{
Defined,
@@ -1423,7 +643,6 @@ enum class PropertyType
IncludePaths,
};
-namespace {
bool PropertyTypeIsForPaths(PropertyType pt)
{
switch (pt) {
@@ -1437,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,
@@ -1458,7 +665,13 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties(
return true;
}
- const ModuleTargetPropertyTable exportedDirectModuleProperties[] = {
+ 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
// and should not be inherited from the in-scope `CMAKE_CXX_MODULE_STD`
@@ -1484,7 +697,13 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties(
}
}
- const ModulePropertyTable exportedModuleProperties[] = {
+ struct ModulePropertyTable
+ {
+ cm::static_string_view Name;
+ PropertyType Type;
+ };
+
+ ModulePropertyTable const exportedModuleProperties[] = {
{ "INCLUDE_DIRECTORIES"_s, PropertyType::IncludePaths },
{ "COMPILE_DEFINITIONS"_s, PropertyType::Strings },
{ "COMPILE_OPTIONS"_s, PropertyType::Strings },
@@ -1505,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()) {
@@ -1517,7 +736,7 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties(
}
}
- const cm::static_string_view exportedLinkModuleProperties[] = {
+ cm::static_string_view const exportedLinkModuleProperties[] = {
"LINK_LIBRARIES"_s,
};
for (auto const& propName : exportedLinkModuleProperties) {
@@ -1531,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;
}
}
@@ -1542,9 +761,9 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties(
bool cmExportFileGenerator::PopulateExportProperties(
cmGeneratorTarget const* gte, ImportPropertyMap& properties,
- std::string& errorMessage)
+ std::string& errorMessage) const
{
- const auto& targetProperties = gte->Target->GetProperties();
+ auto const& targetProperties = gte->Target->GetProperties();
if (cmValue exportProperties =
targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
for (auto& prop : cmList{ *exportProperties }) {
@@ -1579,95 +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";
- }
-}
-
-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";
-
- // Get the path to the file we're going to write.
- std::string path = this->MainImportFile;
- path = cmSystemTools::GetFilenamePath(path);
- auto trampoline_path =
- cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules-", name, ".cmake");
-
- // Include all configuration-specific include files.
- cmGeneratedFileStream ap(trampoline_path, 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 f275a12..89295f5 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -10,16 +10,13 @@
#include <string>
#include <vector>
+#include <cm/string_view>
+
#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
{
@@ -46,65 +40,28 @@ public:
virtual ~cmExportFileGenerator() = default;
/** Set the full path to the export file to generate. */
- void SetExportFile(const char* mainFile);
- const std::string& GetMainExportFileName() const;
+ void SetExportFile(char const* mainFile);
+ std::string const& GetMainExportFileName() const;
/** Set the namespace in which to place exported target names. */
- void SetNamespace(const std::string& ns) { this->Namespace = ns; }
+ 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(const std::string& config);
+ 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<std::string, std::string>;
- // Generate per-configuration target information to the given output
- // stream.
- void GenerateImportConfig(std::ostream& os, const std::string& 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,
- const std::string& 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, const std::string& config, const std::string& suffix,
- cmGeneratorTarget const* target, ImportPropertyMap const& properties,
- const std::string& importedXcFrameworkLocation);
- virtual void GenerateImportedFileChecksCode(
- std::ostream& os, cmGeneratorTarget* target,
- ImportPropertyMap const& properties,
- const std::set<std::string>& importedLocations,
- const std::string& 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,
- const std::string& expectedTargets);
-
// Collect properties with detailed information about targets beyond
// their location on disk.
- void SetImportDetailProperties(const std::string& config,
+ void SetImportDetailProperties(std::string const& config,
std::string const& suffix,
- cmGeneratorTarget* target,
+ cmGeneratorTarget const* target,
ImportPropertyMap& properties);
enum class ImportLinkPropertyTargetNames
@@ -115,17 +72,25 @@ protected:
template <typename T>
void SetImportLinkProperty(std::string const& suffix,
cmGeneratorTarget const* target,
- const std::string& propName,
+ std::string const& propName,
std::vector<T> const& entries,
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,
- const std::string& config,
+ std::string const& config,
std::string const& suffix) = 0;
/** Each subclass knows how to deal with a target that is missing from an
@@ -133,47 +98,33 @@ protected:
virtual void HandleMissingTarget(std::string& link_libs,
cmGeneratorTarget const* depender,
cmGeneratorTarget* dependee) = 0;
- void PopulateInterfaceProperty(const std::string&,
+
+ /** 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(const std::string& 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,
- const 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(
+
+ bool PopulateInterfaceProperties(
cmGeneratorTarget const* target,
+ std::string const& includesDestinationDirs,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties);
- void SetImportLinkInterface(
- const std::string& 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,36 +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);
+ virtual cmExportSet* GetExportSet() const { return nullptr; }
- void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
- cmTargetExport* te = nullptr);
+ virtual void ReplaceInstallPrefix(std::string& input) const;
- void GenerateCxxModuleInformation(std::string const& name, std::ostream& os);
+ virtual std::string InstallNameDir(cmGeneratorTarget const* target,
+ std::string const& config) = 0;
- virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
- cmFileSet* fileSet,
- cmTargetExport* te) = 0;
- virtual std::string GetFileSetFiles(cmGeneratorTarget* gte,
- cmFileSet* fileSet,
- cmTargetExport* te) = 0;
+ /** Get the temporary location of the config-agnostic C++ module file. */
+ virtual std::string GetCxxModuleFile(std::string const& name) const = 0;
- virtual cmExportSet* GetExportSet() const { return nullptr; }
+ virtual std::string GetCxxModulesDirectory() const = 0;
+ virtual void GenerateCxxModuleConfigInformation(std::string const&,
+ std::ostream& os) const = 0;
- void SetRequiredCMakeVersion(unsigned int major, unsigned int minor,
- unsigned int patch);
+ 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<std::string> Configurations;
@@ -223,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<cmGeneratorTarget*> ExportedTargets;
+ std::set<cmGeneratorTarget const*> ExportedTargets;
std::vector<std::string> MissingTargets;
std::set<cmGeneratorTarget const*> ExternalTargets;
- unsigned int RequiredCMakeVersionMajor = 2;
- unsigned int RequiredCMakeVersionMinor = 8;
- unsigned int RequiredCMakeVersionPatch = 3;
-
- bool ExportPackageDependencies = false;
-
private:
- void PopulateInterfaceProperty(const std::string&, const std::string&,
+ 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,
- const std::string& config) = 0;
+extern template void cmExportFileGenerator::SetImportLinkProperty<std::string>(
+ std::string const&, cmGeneratorTarget const*, std::string const&,
+ std::vector<std::string> const&, ImportPropertyMap& properties,
+ ImportLinkPropertyTargetNames);
- virtual std::string GetCxxModulesDirectory() const = 0;
- virtual void GenerateCxxModuleConfigInformation(std::string const&,
- std::ostream& os) const = 0;
-};
+extern template void cmExportFileGenerator::SetImportLinkProperty<cmLinkItem>(
+ std::string const&, cmGeneratorTarget const*, std::string const&,
+ std::vector<cmLinkItem> const&, ImportPropertyMap& properties,
+ ImportLinkPropertyTargetNames);
diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx
index eaa85f3..c9c2f4e 100644
--- a/Source/cmExportInstallAndroidMKGenerator.cxx
+++ b/Source/cmExportInstallAndroidMKGenerator.cxx
@@ -4,14 +4,15 @@
#include <cstddef>
#include <memory>
-#include <ostream>
+#include <sstream>
#include <vector>
-#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,8 +25,55 @@ 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<cmTargetExport const*> 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, const std::string&)
+ std::ostream& os, std::string const&)
{
std::string installDir = this->IEGen->GetDestination();
os << "LOCAL_PATH := $(call my-dir)\n";
@@ -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&, const std::string&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode(
- std::ostream&, const std::string&, const std::string&,
- cmGeneratorTarget const*, ImportPropertyMap const&, const std::string&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateMissingTargetsCheckCode(
- std::ostream&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateInterfaceProperties(
- cmGeneratorTarget const* target, std::ostream& os,
- const ImportPropertyMap& 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&,
- const std::set<std::string>&, const std::string&)
-{
-}
-
-bool cmExportInstallAndroidMKGenerator::GenerateImportFileConfig(
- const std::string&)
-{
- return true;
-}
diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h
index b1778ef..8fa3d3e 100644
--- a/Source/cmExportInstallAndroidMKGenerator.h
+++ b/Source/cmExportInstallAndroidMKGenerator.h
@@ -5,9 +5,10 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
-#include <set>
#include <string>
+#include <vector>
+#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,
- const std::string& config = "") override;
- void GenerateImportFooterCode(std::ostream& os) override;
+ std::string const& config = "") override;
void GenerateImportTargetCode(
std::ostream& os, cmGeneratorTarget const* target,
cmStateEnums::TargetType /*targetType*/) override;
- void GenerateExpectedTargetsCode(
- std::ostream& os, const std::string& expectedTargets) override;
- void GenerateImportPropertyCode(
- std::ostream& os, const std::string& config, const std::string& suffix,
- cmGeneratorTarget const* target, ImportPropertyMap const& properties,
- const std::string& importedXcFrameworkLocation) override;
- void GenerateMissingTargetsCheckCode(std::ostream& os) override;
- void GenerateFindDependencyCalls(std::ostream&) override {}
- void GenerateInterfaceProperties(
- cmGeneratorTarget const* target, std::ostream& os,
- const ImportPropertyMap& 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,
- const std::set<std::string>& importedLocations,
- const std::string& importedXcFrameworkLocation) override;
- bool GenerateImportFileConfig(const std::string& config) override;
+
+ void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
+ cmGeneratorTarget const* dependee,
+ std::vector<std::string> 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
new file mode 100644
index 0000000..e2185ed
--- /dev/null
+++ b/Source/cmExportInstallCMakeConfigGenerator.cxx
@@ -0,0 +1,507 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportInstallCMakeConfigGenerator.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmExportSet.h"
+#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.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 "cmTargetExport.h"
+#include "cmValue.h"
+
+cmExportInstallCMakeConfigGenerator::cmExportInstallCMakeConfigGenerator(
+ cmInstallExportGenerator* iegen)
+ : cmExportInstallFileGenerator(iegen)
+{
+}
+
+std::string cmExportInstallCMakeConfigGenerator::GetConfigImportFileGlob()
+ const
+{
+ std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt);
+ return glob;
+}
+
+bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
+{
+ std::vector<cmTargetExport const*> allTargets;
+ {
+ std::string expectedTargets;
+ std::string sep;
+ auto visitor = [&](cmTargetExport const* te) {
+ allTargets.push_back(te);
+ expectedTargets += sep + this->Namespace + te->Target->GetExportName();
+ sep = " ";
+ };
+
+ if (!this->CollectExports(visitor)) {
+ return false;
+ }
+
+ this->GenerateExpectedTargetsCode(os, expectedTargets);
+ }
+
+ // Compute the relative import prefix for the file
+ this->GenerateImportPrefix(os);
+
+ bool requiresConfigFiles = false;
+ // Create all the imported targets.
+ for (cmTargetExport const* 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;
+ if (!this->PopulateInterfaceProperties(te, properties)) {
+ 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->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 cmExportInstallCMakeConfigGenerator::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";
+ }
+}
+
+void cmExportInstallCMakeConfigGenerator::CleanupTemporaryVariables(
+ std::ostream& os)
+{
+ /* clang-format off */
+ os << "# Cleanup temporary variables.\n"
+ << "set(_IMPORT_PREFIX)\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmExportInstallCMakeConfigGenerator::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 */
+}
+
+bool cmExportInstallCMakeConfigGenerator::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 cmExportInstallCMakeConfigGenerator::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<cmTargetExport> const& te :
+ this->GetExportSet()->GetTargetExports()) {
+ // Collect import properties for this target.
+ if (this->GetExportTargetType(te.get()) ==
+ cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ ImportPropertyMap properties;
+ std::set<std::string> 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()) {
+ cmGeneratorTarget const* const gtgt = te->Target;
+ std::string const importedXcFrameworkLocation =
+ this->GetImportXcFrameworkLocation(config, te.get());
+
+ this->SetImportLinkInterface(config, suffix,
+ cmGeneratorExpression::InstallInterface,
+ gtgt, properties);
+
+ this->GenerateImportPropertyCode(os, config, suffix, gtgt, properties,
+ importedXcFrameworkLocation);
+ this->GenerateImportedFileChecksCode(
+ os, gtgt, properties, importedLocations, importedXcFrameworkLocation);
+ }
+ }
+}
+
+namespace {
+bool EntryIsContextSensitive(
+ std::unique_ptr<cmCompiledGeneratorExpression> const& cge)
+{
+ return cge->GetHadContextSensitiveCondition();
+}
+}
+
+std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories(
+ cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* te)
+{
+ std::vector<std::string> 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("\"$<$<CONFIG:", config, ">:", dest, ">\""));
+ } else {
+ resultVector.emplace_back(cmStrCat('"', dest, '"'));
+ break;
+ }
+ }
+
+ return cmJoin(resultVector, " ");
+}
+
+std::string cmExportInstallCMakeConfigGenerator::GetFileSetFiles(
+ cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* te)
+{
+ std::vector<std::string> 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<std::string, std::vector<std::string>> 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("\"$<$<CONFIG:", config, ">:", escapedFile, ">\""));
+ } else {
+ resultVector.emplace_back(cmStrCat('"', escapedFile, '"'));
+ }
+ }
+ }
+
+ if (!(contextSensitive && configs.size() != 1)) {
+ break;
+ }
+ }
+
+ return cmJoin(resultVector, " ");
+}
+
+std::string cmExportInstallCMakeConfigGenerator::GetCxxModulesDirectory() const
+{
+ return IEGen->GetCxxModuleDirectory();
+}
+
+void cmExportInstallCMakeConfigGenerator::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 */
+}
+
+bool cmExportInstallCMakeConfigGenerator::
+ GenerateImportCxxModuleConfigTargetInclusion(std::string const& name,
+ std::string const& config)
+{
+ 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()) {
+ 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";
+ }
+
+ return true;
+}
diff --git a/Source/cmExportInstallCMakeConfigGenerator.h b/Source/cmExportInstallCMakeConfigGenerator.h
new file mode 100644
index 0000000..2ef9af0
--- /dev/null
+++ b/Source/cmExportInstallCMakeConfigGenerator.h
@@ -0,0 +1,74 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+
+#include "cmExportCMakeConfigGenerator.h"
+#include "cmExportInstallFileGenerator.h"
+
+class cmFileSet;
+class cmGeneratorTarget;
+class cmInstallExportGenerator;
+class cmTargetExport;
+
+/** \class cmExportInstallCMakeConfigGenerator
+ * \brief Generate files exporting targets from an install tree.
+ *
+ * cmExportInstallCMakeConfigGenerator generates files exporting targets from
+ * 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
+ * installed.
+ *
+ * This is used to implement the INSTALL(EXPORT) command.
+ */
+class cmExportInstallCMakeConfigGenerator
+ : public cmExportCMakeConfigGenerator
+ , public cmExportInstallFileGenerator
+{
+public:
+ /** Construct with the export installer that will install the
+ files. */
+ cmExportInstallCMakeConfigGenerator(cmInstallExportGenerator* iegen);
+
+ /** Compute the globbing expression used to load per-config import
+ files from the main file. */
+ 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;
+
+ /** 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);
+
+ std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
+ cmTargetExport const* te) override;
+ std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
+ 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&);
+};
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index f5f22ef..8738938 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -3,29 +3,21 @@
#include "cmExportInstallFileGenerator.h"
#include <algorithm>
+#include <cassert>
+#include <cstddef>
#include <memory>
+#include <set>
#include <sstream>
-#include <utility>
-
-#include <cm/string_view>
-#include <cmext/string_view>
#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,373 +30,75 @@ 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<std::string>& importedLocations)
{
- std::vector<cmTargetExport*> allTargets;
- {
- std::string expectedTargets;
- std::string sep;
- for (std::unique_ptr<cmTargetExport> const& te :
- this->IEGen->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->IEGen->GetExportSet()->GetName()
- << "\" ...) "
- << "includes target \"" << te->Target->GetName()
- << "\" more than once in the export set.";
- cmSystemTools::Error(e.str());
- return false;
- }
- }
-
- this->GenerateExpectedTargetsCode(os, expectedTargets);
- }
-
- // 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;
- }
-
- const bool 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->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);
+
+ // 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);
+
+ // 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);
}
-
- this->LoadConfigFiles(os);
-
- bool result = true;
-
- std::string cxx_modules_name = this->IEGen->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)
+std::string cmExportInstallFileGenerator::GetImportXcFrameworkLocation(
+ std::string const& config, cmTargetExport const* targetExport) const
{
- // 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);
+ 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);
}
- os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n"
- << " set(_IMPORT_PREFIX \"\")\n"
- << "endif()\n"
- << "\n";
}
-}
-void cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream& os)
-{
- /* 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(
- const std::string& 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, const std::string& config, std::string const& suffix)
-{
- // Add each target in the set to the export.
- for (std::unique_ptr<cmTargetExport> const& te :
- this->IEGen->GetExportSet()->GetTargetExports()) {
- // Collect import properties for this target.
- if (this->GetExportTargetType(te.get()) ==
- cmStateEnums::INTERFACE_LIBRARY) {
- continue;
- }
-
- ImportPropertyMap properties;
- std::set<std::string> 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);
- }
- }
+ return importedXcFrameworkLocation;
}
void cmExportInstallFileGenerator::SetImportLocationProperty(
- const std::string& config, std::string const& suffix,
+ std::string const& config, std::string const& suffix,
cmInstallTargetGenerator* itgen, ImportPropertyMap& properties,
std::set<std::string>& importedLocations)
{
@@ -501,11 +195,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)
{
- const std::string name = dependee->GetName();
+ std::string const& name = dependee->GetName();
cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
auto exportInfo = this->FindNamespaces(gg, name);
std::vector<std::string> const& exportFiles = exportInfo.first;
@@ -524,14 +223,14 @@ void cmExportInstallFileGenerator::HandleMissingTarget(
std::pair<std::vector<std::string>, std::string>
cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
- const std::string& name)
+ std::string const& name) const
{
std::vector<std::string> exportFiles;
std::string ns;
- const cmExportSetMap& exportSets = gg->GetExportSets();
+ cmExportSetMap const& exportSets = gg->GetExportSets();
for (auto const& expIt : exportSets) {
- const cmExportSet& exportSet = expIt.second;
+ cmExportSet const& exportSet = expIt.second;
bool containsTarget = false;
for (auto const& target : exportSet.GetTargetExports()) {
@@ -556,11 +255,11 @@ cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
- std::vector<std::string> const& exportFiles)
+ std::vector<std::string> const& exportFiles) const
{
std::ostringstream e;
- e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
- << "\" ...) "
+ e << "install(" << this->IEGen->InstallSubcommand() << " \""
+ << this->GetExportName() << "\" ...) "
<< "includes target \"" << depender->GetName()
<< "\" which requires target \"" << dependee->GetName() << "\" ";
if (exportFiles.empty()) {
@@ -573,220 +272,371 @@ 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(
- cmGeneratorTarget const* target, const std::string& config)
+ 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}");
+ auto const& prefix = this->GetInstallPrefix();
+ install_name_dir = target->GetInstallNameDirForInstallTree(config, prefix);
}
return install_name_dir;
}
-namespace {
-bool EntryIsContextSensitive(
- const std::unique_ptr<cmCompiledGeneratorExpression>& cge)
+std::string cmExportInstallFileGenerator::GetCxxModuleFile() const
{
- return cge->GetHadContextSensitiveCondition();
-}
+ return this->GetCxxModuleFile(this->GetExportSet()->GetName());
}
-std::string cmExportInstallFileGenerator::GetFileSetDirectories(
- cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+bool cmExportInstallFileGenerator::CollectExports(
+ std::function<void(cmTargetExport const*)> const& visitor)
{
- std::vector<std::string> 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 pred = [&](std::unique_ptr<cmTargetExport> const& te) -> bool {
+ if (te->NamelinkOnly) {
+ return true;
}
-
- 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 (this->ExportedTargets.insert(te->Target).second) {
+ visitor(te.get());
+ return true;
}
- if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
- resultVector.push_back(
- cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
- } else {
- resultVector.emplace_back(cmStrCat('"', dest, '"'));
- break;
- }
- }
+ this->ComplainAboutDuplicateTarget(te->Target->GetName());
+ return false;
+ };
- return cmJoin(resultVector, " ");
+ auto const& targets = this->GetExportSet()->GetTargetExports();
+ return std::all_of(targets.begin(), targets.end(), pred);
}
-std::string cmExportInstallFileGenerator::GetFileSetFiles(
- cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+bool cmExportInstallFileGenerator::PopulateInterfaceProperties(
+ cmTargetExport const* targetExport, ImportPropertyMap& properties)
{
- std::vector<std::string> resultVector;
+ 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);
+}
- auto configs =
- gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+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();
- auto fileEntries = fileSet->CompileFileEntries();
- auto directoryEntries = fileSet->CompileDirectoryEntries();
+ std::vector<std::string> parts;
+ cmGeneratorExpression::Split(prepro, parts);
- cmGeneratorExpression destGe(*gte->Makefile->GetCMakeInstance());
- auto destCge =
- destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
+ bool const inSourceBuild = topSourceDir == topBinaryDir;
- for (auto const& config : configs) {
- auto directories = fileSet->EvaluateDirectoryEntries(
- directoryEntries, gte->LocalGenerator, config, gte);
+ bool hadFatalError = false;
- std::map<std::string, std::vector<std::string>> files;
- for (auto const& entry : fileEntries) {
- fileSet->EvaluateFileEntry(directories, files, entry,
- gte->LocalGenerator, config, gte);
+ for (std::string const& li : parts) {
+ size_t genexPos = cmGeneratorExpression::Find(li);
+ if (genexPos == 0) {
+ continue;
}
- 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);
+ if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) {
+ continue;
}
-
- 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{};
+ 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;
+ }
}
-
- 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("\"$<$<CONFIG:", config, ">:", escapedFile, ">\""));
- } else {
- resultVector.emplace_back(cmStrCat('"', escapedFile, '"'));
+ 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 (!(contextSensitive && configs.size() != 1)) {
- break;
+ 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 cmJoin(resultVector, " ");
+ return !hadFatalError;
+}
}
-std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const
+void cmExportInstallFileGenerator::PopulateSourcesInterface(
+ cmGeneratorTarget const* gt,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties)
{
- return IEGen->GetCxxModuleDirectory();
+ 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::GenerateCxxModuleConfigInformation(
- std::string const& name, std::ostream& os) const
+void cmExportInstallFileGenerator::PopulateIncludeDirectoriesInterface(
+ cmGeneratorTarget const* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, cmTargetExport const& te,
+ std::string& includesDestinationDirs)
{
- // 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 */
+ 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<cmCompiledGeneratorExpression> 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;
+ }
}
-bool cmExportInstallFileGenerator::
- GenerateImportCxxModuleConfigTargetInclusion(std::string const& name,
- std::string const& config)
+void cmExportInstallFileGenerator::PopulateLinkDependsInterface(
+ cmGeneratorTarget const* gt,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties)
{
- auto cxx_modules_dirname = this->GetCxxModulesDirectory();
- if (cxx_modules_dirname.empty()) {
- return true;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ char const* const propName = "INTERFACE_LINK_DEPENDS";
+ cmValue input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
}
- std::string filename_config = config;
- if (filename_config.empty()) {
- filename_config = "noconfig";
+ if (input->empty()) {
+ properties[propName].clear();
+ return;
}
- std::string const dest =
- cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/');
- std::string fileName =
- cmStrCat(dest, "cxx-modules-", name, '-', filename_config, ".cmake");
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt);
- 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;
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
}
- os.SetCopyIfDifferent(true);
+}
- // Record this per-config import file.
- this->ConfigCxxModuleFiles[config] = fileName;
+void cmExportInstallFileGenerator::PopulateLinkDirectoriesInterface(
+ cmGeneratorTarget const* gt,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties)
+{
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
- 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()) {
- continue;
- }
+ char const* const propName = "INTERFACE_LINK_DIRECTORIES";
+ cmValue input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
- 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 (input->empty()) {
+ properties[propName].clear();
+ return;
}
- return true;
+ 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 7a72584..24cda9d 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -4,19 +4,21 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <iosfwd>
+#include <functional>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
+#include <cm/string_view>
+
#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
@@ -51,6 +45,9 @@ public:
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. */
@@ -70,65 +67,73 @@ 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, const std::string& 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<std::string> const& exportFiles);
+ void ComplainAboutMissingTarget(
+ cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
+ std::vector<std::string> const& exportFiles) const;
- std::pair<std::vector<std::string>, std::string> FindNamespaces(
- cmGlobalGenerator* gg, const std::string& name);
-
- /** Generate the relative import prefix. */
- virtual void GenerateImportPrefix(std::ostream&);
+ void ComplainAboutDuplicateTarget(
+ std::string const& targetName) const override;
- /** Generate the relative import prefix. */
- virtual void LoadConfigFiles(std::ostream&);
-
- virtual void CleanupTemporaryVariables(std::ostream&);
+ std::pair<std::vector<std::string>, std::string> FindNamespaces(
+ cmGlobalGenerator* gg, std::string const& name) const;
- /** Generate a per-configuration file for the targets. */
- virtual bool GenerateImportFileConfig(const std::string& config);
+ void ReportError(std::string const& errorMessage) const override;
/** Fill in properties indicating installed file locations. */
- void SetImportLocationProperty(const std::string& config,
+ void SetImportLocationProperty(std::string const& config,
std::string const& suffix,
cmInstallTargetGenerator* itgen,
ImportPropertyMap& properties,
std::set<std::string>& importedLocations);
std::string InstallNameDir(cmGeneratorTarget const* target,
- const std::string& config) override;
+ 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<void(cmTargetExport const*)> 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<std::string>& importedLocations);
+
cmInstallExportGenerator* IEGen;
// The import file generated for each configuration.
@@ -137,4 +142,29 @@ protected:
std::map<std::string, std::string> ConfigCxxModuleFiles;
// The C++ module property target files generated for each configuration.
std::map<std::string, std::vector<std::string>> 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 7ce5cd9..021e071 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -19,19 +19,26 @@
#include "cmOutputConverter.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmValue.h"
class cmTargetExport;
cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator(
- cmGlobalGenerator* gg, const std::vector<std::string>& targets,
+ cmGlobalGenerator* gg, std::vector<std::string> const& targets,
cmMakefile* mf, std::set<std::string> const& langs)
: Languages(langs.begin(), langs.end())
{
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<cmGeneratorTarget const*> emitted;
@@ -61,7 +68,7 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
}
std::string cmExportTryCompileFileGenerator::FindTargets(
- const std::string& propName, cmGeneratorTarget const* tgt,
+ std::string const& propName, cmGeneratorTarget const* tgt,
std::string const& language, std::set<cmGeneratorTarget const*>& emitted)
{
cmValue prop = tgt->GetProperty(propName);
@@ -94,7 +101,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
std::string result = cge->Evaluate(tgt->GetLocalGenerator(), this->Config,
&gDummyHead, &dagChecker, tgt, language);
- const std::set<cmGeneratorTarget const*>& allTargets =
+ std::set<cmGeneratorTarget const*> const& allTargets =
cge->GetAllTargetsSeen();
for (cmGeneratorTarget const* target : allTargets) {
if (emitted.insert(target).second) {
@@ -105,7 +112,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
}
void cmExportTryCompileFileGenerator::PopulateProperties(
- const cmGeneratorTarget* target, ImportPropertyMap& properties,
+ cmGeneratorTarget const* target, ImportPropertyMap& properties,
std::set<cmGeneratorTarget const*>& emitted)
{
// Look through all non-special properties.
@@ -140,7 +147,7 @@ void cmExportTryCompileFileGenerator::PopulateProperties(
}
std::string cmExportTryCompileFileGenerator::InstallNameDir(
- cmGeneratorTarget const* target, const std::string& config)
+ cmGeneratorTarget const* target, std::string const& config)
{
std::string install_name_dir;
@@ -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 4c7d287..4b290e6 100644
--- a/Source/cmExportTryCompileFileGenerator.h
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -9,7 +9,7 @@
#include <string>
#include <vector>
-#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,
@@ -26,13 +26,17 @@ public:
std::set<std::string> const& langs);
/** Set the list of targets to export. */
- void SetConfig(const std::string& config) { this->Config = config; }
+ void SetConfig(std::string const& config) { this->Config = config; }
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&, const std::string&,
+ void GenerateImportTargetsConfig(std::ostream&, std::string const&,
std::string const&) override
{
}
@@ -43,17 +47,17 @@ protected:
void PopulateProperties(cmGeneratorTarget const* target,
ImportPropertyMap& properties,
- std::set<const cmGeneratorTarget*>& emitted);
+ std::set<cmGeneratorTarget const*>& emitted);
std::string InstallNameDir(cmGeneratorTarget const* target,
- const std::string& config) override;
+ std::string const& config) override;
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&,
@@ -62,10 +66,10 @@ protected:
}
private:
- std::string FindTargets(const std::string& prop,
- const cmGeneratorTarget* tgt,
+ std::string FindTargets(std::string const& prop,
+ cmGeneratorTarget const* tgt,
std::string const& language,
- std::set<const cmGeneratorTarget*>& emitted);
+ std::set<cmGeneratorTarget const*>& emitted);
std::vector<cmGeneratorTarget const*> Exports;
std::string Config;
diff --git a/Source/cmInstallAndroidMKExportGenerator.cxx b/Source/cmInstallAndroidMKExportGenerator.cxx
new file mode 100644
index 0000000..b038ac1
--- /dev/null
+++ b/Source/cmInstallAndroidMKExportGenerator.cxx
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallAndroidMKExportGenerator.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmExportInstallAndroidMKGenerator.h"
+#include "cmExportInstallFileGenerator.h"
+#include "cmListFileCache.h"
+
+class cmExportSet;
+
+cmInstallAndroidMKExportGenerator::cmInstallAndroidMKExportGenerator(
+ cmExportSet* exportSet, std::string destination, std::string filePermissions,
+ std::vector<std::string> const& configurations, std::string component,
+ MessageLevel message, bool excludeFromAll, std::string filename,
+ 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))
+{
+ this->EFGen = cm::make_unique<cmExportInstallAndroidMKGenerator>(this);
+}
+
+cmInstallAndroidMKExportGenerator::~cmInstallAndroidMKExportGenerator() =
+ default;
diff --git a/Source/cmInstallAndroidMKExportGenerator.h b/Source/cmInstallAndroidMKExportGenerator.h
new file mode 100644
index 0000000..4ee80d4
--- /dev/null
+++ b/Source/cmInstallAndroidMKExportGenerator.h
@@ -0,0 +1,36 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmInstallExportGenerator.h"
+
+class cmExportSet;
+class cmListFileBacktrace;
+
+/** \class cmInstallAndroidMKExportGenerator
+ * \brief Generate rules for creating Android .mk export files.
+ */
+class cmInstallAndroidMKExportGenerator : public cmInstallExportGenerator
+{
+public:
+ cmInstallAndroidMKExportGenerator(
+ cmExportSet* exportSet, std::string destination,
+ std::string filePermissions,
+ std::vector<std::string> const& configurations, std::string component,
+ MessageLevel message, bool excludeFromAll, std::string filename,
+ std::string targetNamespace, cmListFileBacktrace backtrace);
+ cmInstallAndroidMKExportGenerator(cmInstallAndroidMKExportGenerator const&) =
+ delete;
+ ~cmInstallAndroidMKExportGenerator() override;
+
+ cmInstallAndroidMKExportGenerator& operator=(
+ cmInstallAndroidMKExportGenerator const&) = delete;
+
+ char const* InstallSubcommand() const override
+ {
+ return "EXPORT_ANDROID_MK";
+ }
+};
diff --git a/Source/cmInstallCMakeConfigExportGenerator.cxx b/Source/cmInstallCMakeConfigExportGenerator.cxx
new file mode 100644
index 0000000..e247e5b
--- /dev/null
+++ b/Source/cmInstallCMakeConfigExportGenerator.cxx
@@ -0,0 +1,43 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallCMakeConfigExportGenerator.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmExportInstallCMakeConfigGenerator.h"
+#include "cmExportInstallFileGenerator.h"
+#include "cmListFileCache.h"
+
+class cmExportSet;
+
+cmInstallCMakeConfigExportGenerator::cmInstallCMakeConfigExportGenerator(
+ cmExportSet* exportSet, std::string destination, std::string filePermissions,
+ std::vector<std::string> const& configurations, std::string component,
+ MessageLevel message, bool excludeFromAll, std::string filename,
+ std::string targetNamespace, std::string cxxModulesDirectory, bool exportOld,
+ bool exportPackageDependencies, cmListFileBacktrace backtrace)
+ : cmInstallExportGenerator(
+ exportSet, std::move(destination), std::move(filePermissions),
+ configurations, std::move(component), message, excludeFromAll,
+ std::move(filename), std::move(targetNamespace),
+ std::move(cxxModulesDirectory), std::move(backtrace))
+ , ExportOld(exportOld)
+ , ExportPackageDependencies(exportPackageDependencies)
+{
+ this->EFGen = cm::make_unique<cmExportInstallCMakeConfigGenerator>(this);
+}
+
+cmInstallCMakeConfigExportGenerator::~cmInstallCMakeConfigExportGenerator() =
+ default;
+
+void cmInstallCMakeConfigExportGenerator::GenerateScript(std::ostream& os)
+{
+ auto* const efgen =
+ static_cast<cmExportInstallCMakeConfigGenerator*>(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
new file mode 100644
index 0000000..03296de
--- /dev/null
+++ b/Source/cmInstallCMakeConfigExportGenerator.h
@@ -0,0 +1,42 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallExportGenerator.h"
+
+class cmExportSet;
+class cmListFileBacktrace;
+
+/** \class cmInstallCMakeConfigExportGenerator
+ * \brief Generate rules for creating CMake export files.
+ */
+class cmInstallCMakeConfigExportGenerator : public cmInstallExportGenerator
+{
+public:
+ cmInstallCMakeConfigExportGenerator(
+ cmExportSet* exportSet, std::string destination,
+ std::string filePermissions,
+ std::vector<std::string> const& configurations, std::string component,
+ MessageLevel message, bool excludeFromAll, std::string filename,
+ std::string targetNamespace, std::string cxxModulesDirectory,
+ bool exportOld, bool exportPackageDependencies,
+ cmListFileBacktrace backtrace);
+ cmInstallCMakeConfigExportGenerator(
+ cmInstallCMakeConfigExportGenerator const&) = delete;
+ ~cmInstallCMakeConfigExportGenerator() override;
+
+ cmInstallCMakeConfigExportGenerator& operator=(
+ cmInstallCMakeConfigExportGenerator const&) = delete;
+
+ char const* InstallSubcommand() const override { return "EXPORT"; }
+
+protected:
+ void GenerateScript(std::ostream& os) override;
+
+ bool const ExportOld;
+ bool const ExportPackageDependencies;
+};
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 1567629..3160585 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -26,10 +26,11 @@
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
+#include "cmInstallAndroidMKExportGenerator.h"
+#include "cmInstallCMakeConfigExportGenerator.h"
#include "cmInstallCommandArguments.h"
#include "cmInstallCxxModuleBmiGenerator.h"
#include "cmInstallDirectoryGenerator.h"
-#include "cmInstallExportGenerator.h"
#include "cmInstallFileSetGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
@@ -2028,10 +2029,10 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
// Create the export install generator.
helper.Makefile->AddInstallGenerator(
- cm::make_unique<cmInstallExportGenerator>(
+ cm::make_unique<cmInstallAndroidMKExportGenerator>(
&exportSet, ica.GetDestination(), ica.GetPermissions(),
ica.GetConfigurations(), ica.GetComponent(), message,
- ica.GetExcludeFromAll(), fname, name_space, "", exportOld, true, false,
+ ica.GetExcludeFromAll(), std::move(fname), std::move(name_space),
helper.Makefile->GetBacktrace()));
return true;
@@ -2151,11 +2152,11 @@ bool HandleExportMode(std::vector<std::string> const& args,
// Create the export install generator.
helper.Makefile->AddInstallGenerator(
- cm::make_unique<cmInstallExportGenerator>(
+ cm::make_unique<cmInstallCMakeConfigExportGenerator>(
&exportSet, ica.GetDestination(), ica.GetPermissions(),
ica.GetConfigurations(), ica.GetComponent(), message,
- ica.GetExcludeFromAll(), fname, name_space, cxx_modules_directory,
- exportOld, false, exportPackageDependencies,
+ ica.GetExcludeFromAll(), std::move(fname), std::move(name_space),
+ std::move(cxx_modules_directory), exportOld, exportPackageDependencies,
helper.Makefile->GetBacktrace()));
return true;
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 2f3da3e..9828bf2 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -6,12 +6,7 @@
#include <sstream>
#include <utility>
-#include <cm/memory>
-
#include "cmCryptoHash.h"
-#ifndef CMAKE_BOOTSTRAP
-# include "cmExportInstallAndroidMKGenerator.h"
-#endif
#include "cmExportInstallFileGenerator.h"
#include "cmExportSet.h"
#include "cmInstallType.h"
@@ -22,29 +17,20 @@
#include "cmSystemTools.h"
cmInstallExportGenerator::cmInstallExportGenerator(
- cmExportSet* exportSet, std::string const& destination,
- std::string file_permissions, std::vector<std::string> const& configurations,
- std::string const& component, MessageLevel message, bool exclude_from_all,
- std::string filename, std::string name_space,
- std::string cxx_modules_directory, bool exportOld, bool android,
- bool exportPackageDependencies, cmListFileBacktrace backtrace)
- : cmInstallGenerator(destination, configurations, component, message,
- exclude_from_all, false, std::move(backtrace))
+ cmExportSet* exportSet, std::string destination, std::string filePermissions,
+ std::vector<std::string> const& configurations, std::string component,
+ MessageLevel message, bool excludeFromAll, std::string filename,
+ std::string targetNamespace, std::string cxxModulesDirectory,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator(std::move(destination), configurations,
+ std::move(component), message, excludeFromAll, false,
+ std::move(backtrace))
, ExportSet(exportSet)
- , FilePermissions(std::move(file_permissions))
+ , FilePermissions(std::move(filePermissions))
, FileName(std::move(filename))
- , Namespace(std::move(name_space))
- , CxxModulesDirectory(std::move(cxx_modules_directory))
- , ExportOld(exportOld)
- , ExportPackageDependencies(exportPackageDependencies)
+ , Namespace(std::move(targetNamespace))
+ , CxxModulesDirectory(std::move(cxxModulesDirectory))
{
- if (android) {
-#ifndef CMAKE_BOOTSTRAP
- this->EFGen = cm::make_unique<cmExportInstallAndroidMKGenerator>(this);
-#endif
- } else {
- this->EFGen = cm::make_unique<cmExportInstallFileGenerator>(this);
- }
exportSet->AddInstallation(this);
}
@@ -92,7 +78,7 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os)
// Skip empty sets.
if (this->ExportSet->GetTargetExports().empty()) {
std::ostringstream e;
- e << "INSTALL(EXPORT) given unknown export \""
+ e << "INSTALL(" << this->InstallSubcommand() << ") given unknown export \""
<< this->ExportSet->GetName() << "\"";
cmSystemTools::Error(e.str());
return;
@@ -108,7 +94,6 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os)
// Generate the import file for this export set.
this->EFGen->SetExportFile(this->MainImportFile.c_str());
this->EFGen->SetNamespace(this->Namespace);
- this->EFGen->SetExportOld(this->ExportOld);
if (this->ConfigurationTypes->empty()) {
if (!this->ConfigurationName.empty()) {
this->EFGen->AddConfiguration(this->ConfigurationName);
@@ -120,7 +105,6 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os)
this->EFGen->AddConfiguration(c);
}
}
- this->EFGen->SetExportPackageDependencies(this->ExportPackageDependencies);
this->EFGen->GenerateImportFile();
// Perform the main install script generation.
@@ -149,37 +133,37 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
// Now create a configuration-specific install rule for the C++ module import
// property file of each configuration.
- auto cxx_module_dest =
+ auto const cxxModuleDestination =
cmStrCat(this->Destination, '/', this->CxxModulesDirectory);
- std::string config_file_example;
- for (auto const& i : this->EFGen->GetConfigCxxModuleFiles()) {
- config_file_example = i.second;
- break;
- }
- if (!config_file_example.empty()) {
+ auto const cxxModuleInstallFilePath = this->EFGen->GetCxxModuleFile();
+ auto const configImportFilesGlob = this->EFGen->GetConfigImportFileGlob();
+ if (!cxxModuleInstallFilePath.empty() && !configImportFilesGlob.empty()) {
+ auto const cxxModuleFilename =
+ cmSystemTools::GetFilenameName(cxxModuleInstallFilePath);
+
// Remove old per-configuration export files if the main changes.
- std::string installedDir = cmStrCat(
- "$ENV{DESTDIR}", ConvertToAbsoluteDestination(cxx_module_dest), '/');
- std::string installedFile = cmStrCat(installedDir, "/cxx-modules-",
- this->ExportSet->GetName(), ".cmake");
- std::string toInstallFile =
- cmStrCat(cmSystemTools::GetFilenamePath(config_file_example),
- "/cxx-modules-", this->ExportSet->GetName(), ".cmake");
+ std::string installedDir =
+ cmStrCat("$ENV{DESTDIR}",
+ ConvertToAbsoluteDestination(cxxModuleDestination), '/');
+ std::string installedFile = cmStrCat(installedDir, cxxModuleFilename);
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 << " \"" << toInstallFile << "\")\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";
@@ -187,12 +171,11 @@ 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.
- files.push_back(toInstallFile);
- this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, files,
+ files.push_back(cxxModuleInstallFilePath);
+ this->AddInstallRule(os, cxxModuleDestination, cmInstallType_FILES, files,
false, this->FilePermissions.c_str(), nullptr,
nullptr, nullptr, indent);
files.clear();
@@ -201,7 +184,7 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
files.push_back(i.second);
std::string config_test = this->CreateConfigTest(i.first);
os << indent << "if(" << config_test << ")\n";
- this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, files,
+ this->AddInstallRule(os, cxxModuleDestination, cmInstallType_FILES, files,
false, this->FilePermissions.c_str(), nullptr,
nullptr, nullptr, indent.Next());
os << indent << "endif()\n";
@@ -210,9 +193,9 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
for (auto const& i : this->EFGen->GetConfigCxxModuleTargetFiles()) {
std::string config_test = this->CreateConfigTest(i.first);
os << indent << "if(" << config_test << ")\n";
- this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, i.second,
- false, this->FilePermissions.c_str(), nullptr,
- nullptr, nullptr, indent.Next());
+ this->AddInstallRule(os, cxxModuleDestination, cmInstallType_FILES,
+ i.second, false, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent.Next());
os << indent << "endif()\n";
files.clear();
}
@@ -221,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<std::string> files;
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index 5f92851..6100610 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -17,19 +17,18 @@ class cmListFileBacktrace;
class cmLocalGenerator;
/** \class cmInstallExportGenerator
- * \brief Generate rules for creating an export files.
+ * \brief Support class for generating rules for creating export files.
*/
class cmInstallExportGenerator : public cmInstallGenerator
{
public:
- cmInstallExportGenerator(cmExportSet* exportSet, std::string const& dest,
- std::string file_permissions,
- const std::vector<std::string>& configurations,
- std::string const& component, MessageLevel message,
- bool exclude_from_all, std::string filename,
- std::string name_space,
- std::string cxx_modules_directory, bool exportOld,
- bool android, bool exportPackageDependencies,
+ cmInstallExportGenerator(cmExportSet* exportSet, std::string destination,
+ std::string filePermissions,
+ std::vector<std::string> const& configurations,
+ std::string component, MessageLevel message,
+ bool excludeFromAll, std::string filename,
+ std::string targetNamespace,
+ std::string cxxModulesDirectory,
cmListFileBacktrace backtrace);
cmInstallExportGenerator(const cmInstallExportGenerator&) = delete;
~cmInstallExportGenerator() override;
@@ -37,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;
@@ -60,8 +61,6 @@ protected:
void GenerateScript(std::ostream& os) override;
void GenerateScriptConfigs(std::ostream& os, Indent indent) override;
void GenerateScriptActions(std::ostream& os, Indent indent) override;
- void GenerateImportFile(cmExportSet const* exportSet);
- void GenerateImportFile(const char* config, cmExportSet const* exportSet);
std::string TempDirCalculate() const;
void ComputeTempDir();
@@ -70,8 +69,6 @@ protected:
std::string const FileName;
std::string const Namespace;
std::string const CxxModulesDirectory;
- bool const ExportOld;
- bool const ExportPackageDependencies;
cmLocalGenerator* LocalGenerator = nullptr;
std::string TempDir;
diff --git a/bootstrap b/bootstrap
index 6a3eef3..96d331f 100755
--- a/bootstrap
+++ b/bootstrap
@@ -345,8 +345,11 @@ CMAKE_CXX_SOURCES="\
cmExecuteProcessCommand \
cmExpandedCommandArgument \
cmExperimental \
+ cmExportBuildCMakeConfigGenerator \
cmExportBuildFileGenerator \
+ cmExportCMakeConfigGenerator \
cmExportFileGenerator \
+ cmExportInstallCMakeConfigGenerator \
cmExportInstallFileGenerator \
cmExportSet \
cmExportTryCompileFileGenerator \
@@ -408,6 +411,7 @@ CMAKE_CXX_SOURCES="\
cmIncludeGuardCommand \
cmIncludeDirectoryCommand \
cmIncludeRegularExpressionCommand \
+ cmInstallCMakeConfigExportGenerator \
cmInstallCommand \
cmInstallCommandArguments \
cmInstallCxxModuleBmiGenerator \