cmake/Source/cmExportInstallFileGenerator.cxx

767 lines
27 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportInstallFileGenerator.h"
2022-03-29 21:10:50 +02:00
#include <algorithm>
2020-02-01 23:06:01 +01:00
#include <memory>
#include <sstream>
#include <utility>
2022-11-16 20:14:03 +01:00
#include <cm/string_view>
#include <cmext/string_view>
2013-03-16 19:13:01 +02:00
#include "cmExportSet.h"
2022-03-29 21:10:50 +02:00
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
2016-10-30 18:24:19 +01:00
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
2013-03-16 19:13:01 +02:00
#include "cmGlobalGenerator.h"
#include "cmInstallExportGenerator.h"
2022-03-29 21:10:50 +02:00
#include "cmInstallFileSetGenerator.h"
#include "cmInstallTargetGenerator.h"
2016-07-09 11:21:54 +02:00
#include "cmLocalGenerator.h"
2016-10-30 18:24:19 +01:00
#include "cmMakefile.h"
2022-11-16 20:14:03 +01:00
#include "cmMessageType.h"
2022-03-29 21:10:50 +02:00
#include "cmOutputConverter.h"
2016-10-30 18:24:19 +01:00
#include "cmPolicies.h"
2017-04-14 19:02:05 +02:00
#include "cmStateTypes.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2016-10-30 18:24:19 +01:00
#include "cmSystemTools.h"
#include "cmTarget.h"
2013-03-16 19:13:01 +02:00
#include "cmTargetExport.h"
2021-11-20 13:41:27 +01:00
#include "cmValue.h"
2016-07-09 11:21:54 +02:00
cmExportInstallFileGenerator::cmExportInstallFileGenerator(
cmInstallExportGenerator* iegen)
: IEGen(iegen)
{
}
std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
{
2020-02-01 23:06:01 +01:00
std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt);
return glob;
}
bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
{
2013-11-03 12:27:13 +02:00
std::vector<cmTargetExport*> allTargets;
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
std::string expectedTargets;
std::string sep;
2020-02-01 23:06:01 +01:00
for (std::unique_ptr<cmTargetExport> const& te :
this->IEGen->GetExportSet()->GetTargetExports()) {
2021-09-14 00:13:48 +02:00
if (te->NamelinkOnly) {
continue;
}
2018-01-26 17:06:56 +01:00
expectedTargets += sep + this->Namespace + te->Target->GetExportName();
2016-07-09 11:21:54 +02:00
sep = " ";
if (this->ExportedTargets.insert(te->Target).second) {
2020-02-01 23:06:01 +01:00
allTargets.push_back(te.get());
2016-07-09 11:21:54 +02:00
} else {
std::ostringstream e;
e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
<< "\" ...) "
<< "includes target \"" << te->Target->GetName()
<< "\" more than once in the export set.";
2019-11-11 23:01:05 +01:00
cmSystemTools::Error(e.str());
2016-07-09 11:21:54 +02:00
return false;
}
}
2016-07-09 11:21:54 +02:00
this->GenerateExpectedTargetsCode(os, expectedTargets);
2013-03-16 19:13:01 +02:00
}
2016-10-30 18:24:19 +01:00
// Compute the relative import prefix for the file
this->GenerateImportPrefix(os);
2013-03-16 19:13:01 +02:00
2013-11-03 12:27:13 +02:00
bool require2_8_12 = false;
2014-08-03 19:52:23 +02:00
bool require3_0_0 = false;
2015-08-17 11:37:30 +02:00
bool require3_1_0 = false;
2014-08-03 19:52:23 +02:00
bool requiresConfigFiles = false;
2013-03-16 19:13:01 +02:00
// Create all the imported targets.
2018-01-26 17:06:56 +01:00
for (cmTargetExport* te : allTargets) {
cmGeneratorTarget* gt = te->Target;
2018-08-09 18:06:22 +02:00
cmStateEnums::TargetType targetType = this->GetExportTargetType(te);
2014-08-03 19:52:23 +02:00
2016-07-09 11:21:54 +02:00
requiresConfigFiles =
2018-08-09 18:06:22 +02:00
requiresConfigFiles || targetType != cmStateEnums::INTERFACE_LIBRARY;
2014-08-03 19:52:23 +02:00
2018-08-09 18:06:22 +02:00
this->GenerateImportTargetCode(os, gt, targetType);
2013-03-16 19:13:01 +02:00
ImportPropertyMap properties;
2016-07-09 11:21:54 +02:00
this->PopulateIncludeDirectoriesInterface(
2022-08-04 22:12:04 +02:00
gt, cmGeneratorExpression::InstallInterface, properties, *te);
2021-11-20 13:41:27 +01:00
this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2020-02-01 23:06:01 +01:00
this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2023-07-02 19:51:09 +02:00
this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt,
cmGeneratorExpression::InstallInterface,
properties);
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2018-10-28 12:09:07 +01:00
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
properties);
2018-10-28 12:09:07 +01:00
this->PopulateLinkDirectoriesInterface(
2022-08-04 22:12:04 +02:00
gt, cmGeneratorExpression::InstallInterface, properties);
2018-10-28 12:09:07 +01:00
this->PopulateLinkDependsInterface(
2022-08-04 22:12:04 +02:00
gt, cmGeneratorExpression::InstallInterface, properties);
2013-11-03 12:27:13 +02:00
2018-08-09 18:06:22 +02:00
std::string errorMessage;
if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
2019-11-11 23:01:05 +01:00
cmSystemTools::Error(errorMessage);
2018-08-09 18:06:22 +02:00
return false;
}
2013-11-03 12:27:13 +02:00
const bool newCMP0022Behavior =
2016-07-09 11:21:54 +02:00
gt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
gt->GetPolicyStatusCMP0022() != cmPolicies::OLD;
if (newCMP0022Behavior) {
if (this->PopulateInterfaceLinkLibrariesProperty(
2022-08-04 22:12:04 +02:00
gt, cmGeneratorExpression::InstallInterface, properties) &&
2016-07-09 11:21:54 +02:00
!this->ExportOld) {
2013-11-03 12:27:13 +02:00
require2_8_12 = true;
}
2016-07-09 11:21:54 +02:00
}
2018-08-09 18:06:22 +02:00
if (targetType == cmStateEnums::INTERFACE_LIBRARY) {
2014-08-03 19:52:23 +02:00
require3_0_0 = true;
2016-07-09 11:21:54 +02:00
}
if (gt->GetProperty("INTERFACE_SOURCES")) {
2015-08-17 11:37:30 +02:00
// We can only generate INTERFACE_SOURCES in CMake 3.3, but CMake 3.1
// can consume them.
require3_1_0 = true;
2016-07-09 11:21:54 +02:00
}
2015-08-17 11:37:30 +02:00
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt,
properties);
2015-11-17 17:22:37 +01:00
2016-03-13 13:35:51 +01:00
this->PopulateCompatibleInterfaceProperties(gt, properties);
2013-03-16 19:13:01 +02:00
2016-03-13 13:35:51 +01:00
this->GenerateInterfaceProperties(gt, os, properties);
2022-03-29 21:10:50 +02:00
this->GenerateTargetFileSets(gt, os, te);
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
if (require3_1_0) {
2015-08-17 11:37:30 +02:00
this->GenerateRequiredCMakeVersion(os, "3.1.0");
2016-07-09 11:21:54 +02:00
} else if (require3_0_0) {
2014-08-03 19:52:23 +02:00
this->GenerateRequiredCMakeVersion(os, "3.0.0");
2016-07-09 11:21:54 +02:00
} else if (require2_8_12) {
2013-11-03 12:27:13 +02:00
this->GenerateRequiredCMakeVersion(os, "2.8.12");
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2016-10-30 18:24:19 +01:00
this->LoadConfigFiles(os);
2022-11-16 20:14:03 +01:00
bool result = true;
this->GenerateCxxModuleInformation(os);
if (requiresConfigFiles) {
for (std::string const& c : this->Configurations) {
if (!this->GenerateImportCxxModuleConfigTargetInclusion(c)) {
result = false;
}
}
}
2016-10-30 18:24:19 +01:00
this->CleanupTemporaryVariables(os);
2013-03-16 19:13:01 +02:00
this->GenerateImportedFileCheckLoop(os);
2014-08-03 19:52:23 +02:00
// Generate an import file for each configuration.
// Don't do this if we only export INTERFACE_LIBRARY targets.
2016-07-09 11:21:54 +02:00
if (requiresConfigFiles) {
2018-01-26 17:06:56 +01:00
for (std::string const& c : this->Configurations) {
2022-08-04 22:12:04 +02:00
if (!this->GenerateImportFileConfig(c)) {
2014-08-03 19:52:23 +02:00
result = false;
}
}
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2022-08-04 22:12:04 +02:00
this->GenerateMissingTargetsCheckCode(os);
2013-03-16 19:13:01 +02:00
return result;
}
2016-10-30 18:24:19 +01:00
void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream& os)
{
// Set an _IMPORT_PREFIX variable for import location properties
// to reference if they are relative to the install prefix.
std::string installPrefix =
this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
"CMAKE_INSTALL_PREFIX");
std::string const& expDest = this->IEGen->GetDestination();
if (cmSystemTools::FileIsFullPath(expDest)) {
// The export file is being installed to an absolute path so the
// package is not relocatable. Use the configured install prefix.
/* clang-format off */
os <<
"# The installation prefix configured by this project.\n"
"set(_IMPORT_PREFIX \"" << installPrefix << "\")\n"
"\n";
/* clang-format on */
} else {
// Add code to compute the installation prefix relative to the
// import file location.
std::string absDest = installPrefix + "/" + expDest;
std::string absDestS = absDest + "/";
os << "# Compute the installation prefix relative to this file.\n"
<< "get_filename_component(_IMPORT_PREFIX"
<< " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
2018-04-23 21:13:27 +02:00
if (cmHasLiteralPrefix(absDestS, "/lib/") ||
cmHasLiteralPrefix(absDestS, "/lib64/") ||
cmHasLiteralPrefix(absDestS, "/libx32/") ||
cmHasLiteralPrefix(absDestS, "/usr/lib/") ||
cmHasLiteralPrefix(absDestS, "/usr/lib64/") ||
cmHasLiteralPrefix(absDestS, "/usr/libx32/")) {
2016-10-30 18:24:19 +01:00
// 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 cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream& os)
{
/* clang-format off */
os << "# Cleanup temporary variables.\n"
<< "set(_IMPORT_PREFIX)\n"
<< "\n";
/* clang-format on */
}
void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream& os)
{
// Now load per-configuration properties for them.
/* clang-format off */
os << "# Load information for each installed configuration.\n"
2022-08-04 22:12:04 +02:00
<< "file(GLOB _cmake_config_files \"${CMAKE_CURRENT_LIST_DIR}/"
2016-10-30 18:24:19 +01:00
<< this->GetConfigImportFileGlob() << "\")\n"
2022-08-04 22:12:04 +02:00
<< "foreach(_cmake_config_file IN LISTS _cmake_config_files)\n"
<< " include(\"${_cmake_config_file}\")\n"
2016-10-30 18:24:19 +01:00
<< "endforeach()\n"
2022-08-04 22:12:04 +02:00
<< "unset(_cmake_config_file)\n"
<< "unset(_cmake_config_files)\n"
2016-10-30 18:24:19 +01:00
<< "\n";
/* clang-format on */
}
2016-07-09 11:21:54 +02:00
void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input)
2013-03-16 19:13:01 +02:00
{
2020-08-30 11:54:41 +02:00
cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}");
2013-03-16 19:13:01 +02:00
}
2016-07-09 11:21:54 +02:00
bool cmExportInstallFileGenerator::GenerateImportFileConfig(
2022-08-04 22:12:04 +02:00
const std::string& config)
{
// Skip configurations not enabled for this export.
2016-07-09 11:21:54 +02:00
if (!this->IEGen->InstallsForConfig(config)) {
return true;
2016-07-09 11:21:54 +02:00
}
// Construct the name of the file to generate.
2020-02-01 23:06:01 +01:00
std::string fileName = cmStrCat(this->FileDir, '/', this->FileBase, '-');
2016-07-09 11:21:54 +02:00
if (!config.empty()) {
fileName += cmSystemTools::LowerCase(config);
2016-07-09 11:21:54 +02:00
} else {
fileName += "noconfig";
2016-07-09 11:21:54 +02:00
}
fileName += this->FileExt;
// Open the output file to generate it.
2018-10-28 12:09:07 +01:00
cmGeneratedFileStream exportFileStream(fileName, true);
2016-07-09 11:21:54 +02:00
if (!exportFileStream) {
std::string se = cmSystemTools::GetLastSystemError();
2015-04-27 22:25:09 +02:00
std::ostringstream e;
2016-07-09 11:21:54 +02:00
e << "cannot write to file \"" << fileName << "\": " << se;
2019-11-11 23:01:05 +01:00
cmSystemTools::Error(e.str());
return false;
2016-07-09 11:21:54 +02:00
}
2021-09-14 00:13:48 +02:00
exportFileStream.SetCopyIfDifferent(true);
std::ostream& os = exportFileStream;
// Start with the import file header.
this->GenerateImportHeaderCode(os, config);
// Generate the per-config target information.
2022-08-04 22:12:04 +02:00
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;
}
2016-07-09 11:21:54 +02:00
void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
2022-08-04 22:12:04 +02:00
std::ostream& os, const std::string& config, std::string const& suffix)
{
// Add each target in the set to the export.
2020-02-01 23:06:01 +01:00
for (std::unique_ptr<cmTargetExport> const& te :
this->IEGen->GetExportSet()->GetTargetExports()) {
// Collect import properties for this target.
2020-02-01 23:06:01 +01:00
if (this->GetExportTargetType(te.get()) ==
cmStateEnums::INTERFACE_LIBRARY) {
2014-08-03 19:52:23 +02:00
continue;
2016-07-09 11:21:54 +02:00
}
2014-08-03 19:52:23 +02:00
ImportPropertyMap properties;
2012-02-18 12:40:36 +02:00
std::set<std::string> importedLocations;
2014-08-03 19:52:23 +02:00
2012-02-18 12:40:36 +02:00
this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
properties, importedLocations);
2016-07-09 11:21:54 +02:00
this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
properties, importedLocations);
2017-07-20 19:35:53 +02:00
this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator,
properties, importedLocations);
2012-02-18 12:40:36 +02:00
this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
properties, importedLocations);
// If any file location was set for the target add it to the
// import file.
2016-07-09 11:21:54 +02:00
if (!properties.empty()) {
// Get the rest of the target details.
2016-07-09 11:21:54 +02:00
cmGeneratorTarget* gtgt = te->Target;
2022-08-04 22:12:04 +02:00
this->SetImportDetailProperties(config, suffix, gtgt, properties);
2013-03-16 19:13:01 +02:00
this->SetImportLinkInterface(config, suffix,
cmGeneratorExpression::InstallInterface,
2022-08-04 22:12:04 +02:00
gtgt, properties);
2018-08-09 18:06:22 +02:00
// 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.
2016-03-13 13:35:51 +01:00
this->GenerateImportPropertyCode(os, config, gtgt, properties);
this->GenerateImportedFileChecksCode(os, gtgt, properties,
2012-02-18 12:40:36 +02:00
importedLocations);
}
2016-07-09 11:21:54 +02:00
}
}
2016-07-09 11:21:54 +02:00
void cmExportInstallFileGenerator::SetImportLocationProperty(
const std::string& config, std::string const& suffix,
cmInstallTargetGenerator* itgen, ImportPropertyMap& properties,
std::set<std::string>& importedLocations)
{
// Skip rules that do not match this configuration.
2016-07-09 11:21:54 +02:00
if (!(itgen && itgen->InstallsForConfig(config))) {
return;
2016-07-09 11:21:54 +02:00
}
// Get the target to be installed.
2016-03-13 13:35:51 +01:00
cmGeneratorTarget* target = itgen->GetTarget();
// Construct the installed location of the target.
2015-08-17 11:37:30 +02:00
std::string dest = itgen->GetDestination(config);
std::string value;
2018-04-23 21:13:27 +02:00
if (!cmSystemTools::FileIsFullPath(dest)) {
// The target is installed relative to the installation prefix.
2015-04-27 22:25:09 +02:00
value = "${_IMPORT_PREFIX}/";
2016-07-09 11:21:54 +02:00
}
value += dest;
value += "/";
2016-07-09 11:21:54 +02:00
if (itgen->IsImportLibrary()) {
// Construct the property name.
2020-02-01 23:06:01 +01:00
std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
// Append the installed file name.
2019-11-11 23:01:05 +01:00
value += cmInstallTargetGenerator::GetInstallFilename(
2023-07-02 19:51:09 +02:00
target, config, cmInstallTargetGenerator::NameImplibReal);
// Store the property.
properties[prop] = value;
2012-02-18 12:40:36 +02:00
importedLocations.insert(prop);
2017-07-20 19:35:53 +02:00
} else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
// Construct the property name.
2020-02-01 23:06:01 +01:00
std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);
2017-07-20 19:35:53 +02:00
// Compute all the object files inside this target and setup
// IMPORTED_OBJECTS as a list of object files
std::vector<std::string> objects;
itgen->GetInstallObjectNames(config, objects);
2018-01-26 17:06:56 +01:00
for (std::string& obj : objects) {
2020-02-01 23:06:01 +01:00
obj = cmStrCat(value, obj);
2017-07-20 19:35:53 +02:00
}
// Store the property.
properties[prop] = cmJoin(objects, ";");
importedLocations.insert(prop);
2016-07-09 11:21:54 +02:00
} else {
2023-07-02 19:51:09 +02:00
if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) {
// store as well IMPLIB value
auto importProp = cmStrCat("IMPORTED_IMPLIB", suffix);
auto importValue =
cmStrCat(value,
cmInstallTargetGenerator::GetInstallFilename(
target, config, cmInstallTargetGenerator::NameImplibReal));
// Store the property.
properties[importProp] = importValue;
importedLocations.insert(importProp);
}
// Construct the property name.
2020-02-01 23:06:01 +01:00
std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
// Append the installed file name.
2016-07-09 11:21:54 +02:00
if (target->IsAppBundleOnApple()) {
2019-11-11 23:01:05 +01:00
value += cmInstallTargetGenerator::GetInstallFilename(target, config);
2022-11-16 20:14:03 +01:00
value += ".app/";
if (!target->Makefile->PlatformIsAppleEmbedded()) {
value += "Contents/MacOS/";
}
2019-11-11 23:01:05 +01:00
value += cmInstallTargetGenerator::GetInstallFilename(target, config);
2016-07-09 11:21:54 +02:00
} else {
2019-11-11 23:01:05 +01:00
value += cmInstallTargetGenerator::GetInstallFilename(
target, config, cmInstallTargetGenerator::NameReal);
2016-07-09 11:21:54 +02:00
}
// Store the property.
properties[prop] = value;
2012-02-18 12:40:36 +02:00
importedLocations.insert(prop);
2016-07-09 11:21:54 +02:00
}
}
2018-08-09 18:06:22 +02:00
cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType(
cmTargetExport const* targetExport) const
{
cmStateEnums::TargetType targetType = targetExport->Target->GetType();
// An OBJECT library installed with no OBJECTS DESTINATION
// is transformed to an INTERFACE library.
if (targetType == cmStateEnums::OBJECT_LIBRARY &&
targetExport->ObjectsGenerator == nullptr) {
targetType = cmStateEnums::INTERFACE_LIBRARY;
}
return targetType;
}
2016-07-09 11:21:54 +02:00
void cmExportInstallFileGenerator::HandleMissingTarget(
2022-08-04 22:12:04 +02:00
std::string& link_libs, cmGeneratorTarget const* depender,
cmGeneratorTarget* dependee)
2013-03-16 19:13:01 +02:00
{
2013-11-03 12:27:13 +02:00
const std::string name = dependee->GetName();
2016-03-13 13:35:51 +01:00
cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
2020-02-01 23:06:01 +01:00
auto exportInfo = this->FindNamespaces(gg, name);
std::vector<std::string> const& exportFiles = exportInfo.first;
if (exportFiles.size() == 1) {
std::string missingTarget = exportInfo.second;
2013-11-03 12:27:13 +02:00
missingTarget += dependee->GetExportName();
2013-03-16 19:13:01 +02:00
link_libs += missingTarget;
2022-08-04 22:12:04 +02:00
this->MissingTargets.emplace_back(std::move(missingTarget));
2016-07-09 11:21:54 +02:00
} else {
2014-08-03 19:52:23 +02:00
// All exported targets should be known here and should be unique.
// This is probably user-error.
2020-02-01 23:06:01 +01:00
this->ComplainAboutMissingTarget(depender, dependee, exportFiles);
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
}
2020-02-01 23:06:01 +01:00
std::pair<std::vector<std::string>, std::string>
cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
const std::string& name)
2013-03-16 19:13:01 +02:00
{
2020-02-01 23:06:01 +01:00
std::vector<std::string> exportFiles;
std::string ns;
2013-03-16 19:13:01 +02:00
const cmExportSetMap& exportSets = gg->GetExportSets();
2018-01-26 17:06:56 +01:00
for (auto const& expIt : exportSets) {
2020-02-01 23:06:01 +01:00
const cmExportSet& exportSet = expIt.second;
2013-03-16 19:13:01 +02:00
bool containsTarget = false;
2020-02-01 23:06:01 +01:00
for (auto const& target : exportSet.GetTargetExports()) {
2018-01-26 17:06:56 +01:00
if (name == target->TargetName) {
2013-03-16 19:13:01 +02:00
containsTarget = true;
break;
}
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
if (containsTarget) {
2013-03-16 19:13:01 +02:00
std::vector<cmInstallExportGenerator const*> const* installs =
2020-02-01 23:06:01 +01:00
exportSet.GetInstallations();
2018-01-26 17:06:56 +01:00
for (cmInstallExportGenerator const* install : *installs) {
2020-02-01 23:06:01 +01:00
exportFiles.push_back(install->GetDestinationFile());
ns = install->GetNamespace();
2013-03-16 19:13:01 +02:00
}
}
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2020-02-01 23:06:01 +01:00
return { exportFiles, ns };
2013-03-16 19:13:01 +02:00
}
2016-07-09 11:21:54 +02:00
void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
2021-11-20 13:41:27 +01:00
cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
2020-02-01 23:06:01 +01:00
std::vector<std::string> const& exportFiles)
{
2015-04-27 22:25:09 +02:00
std::ostringstream e;
2016-07-09 11:21:54 +02:00
e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
2013-03-16 19:13:01 +02:00
<< "\" ...) "
<< "includes target \"" << depender->GetName()
2013-03-16 19:13:01 +02:00
<< "\" which requires target \"" << dependee->GetName() << "\" ";
2020-02-01 23:06:01 +01:00
if (exportFiles.empty()) {
e << "that is not in any export set.";
2016-07-09 11:21:54 +02:00
} else {
2020-02-01 23:06:01 +01:00
e << "that is not in this export set, but in multiple other export sets: "
<< cmJoin(exportFiles, ", ") << ".\n";
e << "An exported target cannot depend upon another target which is "
"exported multiple times. Consider consolidating the exports of the "
"\""
<< dependee->GetName() << "\" target to a single export.";
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
cmSystemTools::Error(e.str());
}
2013-11-03 12:27:13 +02:00
2016-07-09 11:21:54 +02:00
std::string cmExportInstallFileGenerator::InstallNameDir(
2021-11-20 13:41:27 +01:00
cmGeneratorTarget const* target, const std::string& config)
2013-11-03 12:27:13 +02:00
{
std::string install_name_dir;
2015-11-17 17:22:37 +01:00
cmMakefile* mf = target->Target->GetMakefile();
2016-07-09 11:21:54 +02:00
if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2020-08-30 11:54:41 +02:00
install_name_dir =
target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}");
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
return install_name_dir;
}
2022-03-29 21:10:50 +02:00
namespace {
bool EntryIsContextSensitive(
const std::unique_ptr<cmCompiledGeneratorExpression>& cge)
{
return cge->GetHadContextSensitiveCondition();
}
}
std::string cmExportInstallFileGenerator::GetFileSetDirectories(
cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
{
std::vector<std::string> resultVector;
auto configs =
gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2023-05-23 16:38:00 +02:00
cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
2022-03-29 21:10:50 +02:00
auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
for (auto const& config : configs) {
auto dest = cmStrCat("${_IMPORT_PREFIX}/",
cmOutputConverter::EscapeForCMake(
cge->Evaluate(gte->LocalGenerator, config, gte),
cmOutputConverter::WrapQuotes::NoWrap));
2022-11-16 20:14:03 +01:00
auto const& type = fileSet->GetType();
// C++ modules do not support interface file sets which are dependent upon
// the configuration.
2023-07-02 19:51:09 +02:00
if (cge->GetHadContextSensitiveCondition() && type == "CXX_MODULES"_s) {
2022-11-16 20:14:03 +01:00
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{};
}
2022-03-29 21:10:50 +02:00
if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
resultVector.push_back(
cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
} else {
resultVector.push_back(cmStrCat('"', dest, '"'));
break;
}
}
return cmJoin(resultVector, " ");
}
std::string cmExportInstallFileGenerator::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();
2023-05-23 16:38:00 +02:00
cmGeneratorExpression destGe(*gte->Makefile->GetCMakeInstance());
2022-03-29 21:10:50 +02:00
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 dest = cmStrCat("${_IMPORT_PREFIX}/",
cmOutputConverter::EscapeForCMake(
destCge->Evaluate(gte->LocalGenerator, config, gte),
cmOutputConverter::WrapQuotes::NoWrap),
'/');
bool const contextSensitive = destCge->GetHadContextSensitiveCondition() ||
std::any_of(directoryEntries.begin(), directoryEntries.end(),
EntryIsContextSensitive) ||
std::any_of(fileEntries.begin(), fileEntries.end(),
EntryIsContextSensitive);
2022-11-16 20:14:03 +01:00
auto const& type = fileSet->GetType();
// C++ modules do not support interface file sets which are dependent upon
// the configuration.
2023-07-02 19:51:09 +02:00
if (contextSensitive && type == "CXX_MODULES"_s) {
2022-11-16 20:14:03 +01:00
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{};
}
2022-03-29 21:10:50 +02:00
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.push_back(cmStrCat('"', escapedFile, '"'));
}
}
}
if (!(contextSensitive && configs.size() != 1)) {
break;
}
}
return cmJoin(resultVector, " ");
}
2022-11-16 20:14:03 +01:00
std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const
{
return IEGen->GetCxxModuleDirectory();
}
void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
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-*.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 cmExportInstallFileGenerator::
GenerateImportCxxModuleConfigTargetInclusion(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-", 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) {
2023-07-02 19:51:09 +02:00
// Only targets with C++ module sources will have a
// collator-generated install script.
if (!tgt->HaveCxx20ModuleSources()) {
continue;
}
2022-11-16 20:14:03 +01:00
auto prop_filename = cmStrCat("target-", tgt->GetExportName(), '-',
filename_config, ".cmake");
prop_files.emplace_back(cmStrCat(dest, prop_filename));
os << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << prop_filename << "\")\n";
}
return true;
}