Merge topic 'export-refactor-for-cps'

ff24058e46 export: Use std::all_of to collect exports
20fa4ce8d8 export: Factor out CMake-specific export generation (2/2)
6c66340a64 export: Fix const placement
1bceab3520 export: Factor out CMake-specific export generation (*/2)
a6cc595772 export: Factor out CMake-specific export generation (1/2)
0352376e44 export: Immediately report actual version required

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !9646
This commit is contained in:
Brad King
2024-07-25 15:16:41 +00:00
committed by Kitware Robot
30 changed files with 3194 additions and 2550 deletions

View File

@@ -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

View File

@@ -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";
}

View File

@@ -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
{
}
};

View File

@@ -2,45 +2,58 @@
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()
cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator() = default;
bool cmExportBuildAndroidMKGenerator::GenerateMainFile(std::ostream& os)
{
this->LG = nullptr;
this->ExportSet = nullptr;
if (!this->CollectExports([&](cmGeneratorTarget const*) {})) {
return false;
}
// Create all the imported targets.
for (auto const& exp : this->Exports) {
cmGeneratorTarget* gte = exp.Target;
this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte));
gte->Target->AppendBuildInterfaceIncludes();
ImportPropertyMap properties;
if (!this->PopulateInterfaceProperties(gte, properties)) {
return false;
}
bool const newCMP0022Behavior =
gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;
if (newCMP0022Behavior) {
this->PopulateInterfaceLinkLibrariesProperty(
gte, cmGeneratorExpression::BuildInterface, properties);
}
this->GenerateInterfaceProperties(gte, os, properties);
}
return true;
}
void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
std::ostream& os, const std::string&)
std::ostream& os, std::string const&)
{
os << "LOCAL_PATH := $(call my-dir)\n\n";
}
void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
{
}
void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode(
std::ostream&, const std::string&)
{
}
void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
std::ostream& os, cmGeneratorTarget const* target,
cmStateEnums::TargetType /*targetType*/)
@@ -55,143 +68,3 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
os << path << "\n";
}
void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode(
std::ostream&, 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";
}

View File

@@ -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 {}; }
};

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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)
bool cmExportBuildFileGenerator::PopulateInterfaceProperties(
cmGeneratorTarget const* target, ImportPropertyMap& properties)
{
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*/)
{
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);
}

View File

@@ -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
{

View File

@@ -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;
}
}

View File

@@ -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;
};

View File

@@ -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 =

File diff suppressed because it is too large Load Diff

View File

@@ -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);
void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
cmTargetExport* te = nullptr);
void GenerateCxxModuleInformation(std::string const& name, std::ostream& os);
virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
cmFileSet* fileSet,
cmTargetExport* te) = 0;
virtual std::string GetFileSetFiles(cmGeneratorTarget* gte,
cmFileSet* fileSet,
cmTargetExport* te) = 0;
virtual cmExportSet* GetExportSet() const { return nullptr; }
void SetRequiredCMakeVersion(unsigned int major, unsigned int minor,
unsigned int patch);
virtual void ReplaceInstallPrefix(std::string& input) const;
virtual std::string InstallNameDir(cmGeneratorTarget const* target,
std::string const& config) = 0;
/** Get the temporary location of the config-agnostic C++ module file. */
virtual std::string GetCxxModuleFile(std::string const& name) const = 0;
virtual std::string GetCxxModulesDirectory() const = 0;
virtual void GenerateCxxModuleConfigInformation(std::string const&,
std::ostream& os) const = 0;
bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target,
cmLocalGenerator const* lg);
// The namespace in which the exports are placed in the generated file.
std::string Namespace;
bool ExportOld;
// The set of configurations to export.
std::vector<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;
virtual std::string GetCxxModulesDirectory() const = 0;
virtual void GenerateCxxModuleConfigInformation(std::string const&,
std::ostream& os) const = 0;
};
extern template void cmExportFileGenerator::SetImportLinkProperty<std::string>(
std::string const&, cmGeneratorTarget const*, std::string const&,
std::vector<std::string> const&, ImportPropertyMap& properties,
ImportLinkPropertyTargetNames);
extern template void cmExportFileGenerator::SetImportLinkProperty<cmLinkItem>(
std::string const&, cmGeneratorTarget const*, std::string const&,
std::vector<cmLinkItem> const&, ImportPropertyMap& properties,
ImportLinkPropertyTargetNames);

View File

@@ -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;
}

View File

@@ -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 {}; }
};

View File

@@ -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;
}

View File

@@ -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&);
};

File diff suppressed because it is too large Load Diff

View File

@@ -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;
void ComplainAboutDuplicateTarget(
std::string const& targetName) const override;
std::pair<std::vector<std::string>, std::string> FindNamespaces(
cmGlobalGenerator* gg, const std::string& name);
cmGlobalGenerator* gg, std::string const& name) const;
/** Generate the relative import prefix. */
virtual void GenerateImportPrefix(std::ostream&);
/** Generate the relative import prefix. */
virtual void LoadConfigFiles(std::ostream&);
virtual void CleanupTemporaryVariables(std::ostream&);
/** Generate a per-configuration file for the targets. */
virtual bool GenerateImportFileConfig(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);
};

View File

@@ -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()));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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";
}
};

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 \