1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmExportInstallFileGenerator.h"
10 #include <cm/string_view>
11 #include <cmext/string_view>
13 #include "cmExportSet.h"
14 #include "cmFileSet.h"
15 #include "cmGeneratedFileStream.h"
16 #include "cmGeneratorExpression.h"
17 #include "cmGeneratorTarget.h"
18 #include "cmGlobalGenerator.h"
19 #include "cmInstallExportGenerator.h"
20 #include "cmInstallFileSetGenerator.h"
21 #include "cmInstallTargetGenerator.h"
23 #include "cmLocalGenerator.h"
24 #include "cmMakefile.h"
25 #include "cmMessageType.h"
26 #include "cmOutputConverter.h"
27 #include "cmPolicies.h"
28 #include "cmStateTypes.h"
29 #include "cmStringAlgorithms.h"
30 #include "cmSystemTools.h"
32 #include "cmTargetExport.h"
35 cmExportInstallFileGenerator::cmExportInstallFileGenerator(
36 cmInstallExportGenerator
* iegen
)
41 std::string
cmExportInstallFileGenerator::GetConfigImportFileGlob()
43 std::string glob
= cmStrCat(this->FileBase
, "-*", this->FileExt
);
47 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream
& os
)
49 std::vector
<cmTargetExport
*> allTargets
;
51 std::string expectedTargets
;
53 for (std::unique_ptr
<cmTargetExport
> const& te
:
54 this->IEGen
->GetExportSet()->GetTargetExports()) {
55 if (te
->NamelinkOnly
) {
58 expectedTargets
+= sep
+ this->Namespace
+ te
->Target
->GetExportName();
60 if (this->ExportedTargets
.insert(te
->Target
).second
) {
61 allTargets
.push_back(te
.get());
64 e
<< "install(EXPORT \"" << this->IEGen
->GetExportSet()->GetName()
66 << "includes target \"" << te
->Target
->GetName()
67 << "\" more than once in the export set.";
68 cmSystemTools::Error(e
.str());
73 this->GenerateExpectedTargetsCode(os
, expectedTargets
);
76 // Compute the relative import prefix for the file
77 this->GenerateImportPrefix(os
);
79 bool requiresConfigFiles
= false;
80 // Create all the imported targets.
81 for (cmTargetExport
* te
: allTargets
) {
82 cmGeneratorTarget
* gt
= te
->Target
;
83 cmStateEnums::TargetType targetType
= this->GetExportTargetType(te
);
86 requiresConfigFiles
|| targetType
!= cmStateEnums::INTERFACE_LIBRARY
;
88 this->GenerateImportTargetCode(os
, gt
, targetType
);
90 ImportPropertyMap properties
;
92 std::string includesDestinationDirs
;
93 this->PopulateIncludeDirectoriesInterface(
94 gt
, cmGeneratorExpression::InstallInterface
, properties
, *te
,
95 includesDestinationDirs
);
96 this->PopulateSourcesInterface(gt
, cmGeneratorExpression::InstallInterface
,
98 this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt
,
99 cmGeneratorExpression::InstallInterface
,
101 this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt
,
102 cmGeneratorExpression::InstallInterface
,
104 this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt
,
105 cmGeneratorExpression::InstallInterface
,
107 this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt
,
108 cmGeneratorExpression::InstallInterface
,
110 this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt
,
111 cmGeneratorExpression::InstallInterface
,
113 this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt
,
114 cmGeneratorExpression::InstallInterface
,
116 this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt
,
117 cmGeneratorExpression::InstallInterface
,
119 this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt
,
120 cmGeneratorExpression::InstallInterface
,
122 this->PopulateLinkDirectoriesInterface(
123 gt
, cmGeneratorExpression::InstallInterface
, properties
);
124 this->PopulateLinkDependsInterface(
125 gt
, cmGeneratorExpression::InstallInterface
, properties
);
127 std::string errorMessage
;
128 if (!this->PopulateCxxModuleExportProperties(
129 gt
, properties
, cmGeneratorExpression::InstallInterface
,
130 includesDestinationDirs
, errorMessage
)) {
131 cmSystemTools::Error(errorMessage
);
135 if (!this->PopulateExportProperties(gt
, properties
, errorMessage
)) {
136 cmSystemTools::Error(errorMessage
);
140 const bool newCMP0022Behavior
=
141 gt
->GetPolicyStatusCMP0022() != cmPolicies::WARN
&&
142 gt
->GetPolicyStatusCMP0022() != cmPolicies::OLD
;
143 if (newCMP0022Behavior
) {
144 if (this->PopulateInterfaceLinkLibrariesProperty(
145 gt
, cmGeneratorExpression::InstallInterface
, properties
) &&
147 this->SetRequiredCMakeVersion(2, 8, 12);
150 if (targetType
== cmStateEnums::INTERFACE_LIBRARY
) {
151 this->SetRequiredCMakeVersion(3, 0, 0);
153 if (gt
->GetProperty("INTERFACE_SOURCES")) {
154 // We can only generate INTERFACE_SOURCES in CMake 3.3, but CMake 3.1
156 this->SetRequiredCMakeVersion(3, 1, 0);
159 this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt
,
162 this->PopulateCompatibleInterfaceProperties(gt
, properties
);
163 this->PopulateCustomTransitiveInterfaceProperties(
164 gt
, cmGeneratorExpression::InstallInterface
, properties
);
166 this->GenerateInterfaceProperties(gt
, os
, properties
);
168 this->GenerateTargetFileSets(gt
, os
, te
);
171 this->LoadConfigFiles(os
);
175 std::string cxx_modules_name
= this->IEGen
->GetExportSet()->GetName();
176 this->GenerateCxxModuleInformation(cxx_modules_name
, os
);
177 if (requiresConfigFiles
) {
178 for (std::string
const& c
: this->Configurations
) {
179 if (!this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name
,
186 this->CleanupTemporaryVariables(os
);
187 this->GenerateImportedFileCheckLoop(os
);
189 // Generate an import file for each configuration.
190 // Don't do this if we only export INTERFACE_LIBRARY targets.
191 if (requiresConfigFiles
) {
192 for (std::string
const& c
: this->Configurations
) {
193 if (!this->GenerateImportFileConfig(c
)) {
199 this->GenerateMissingTargetsCheckCode(os
);
204 void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream
& os
)
206 // Set an _IMPORT_PREFIX variable for import location properties
207 // to reference if they are relative to the install prefix.
208 std::string installPrefix
=
209 this->IEGen
->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
210 "CMAKE_INSTALL_PREFIX");
211 std::string
const& expDest
= this->IEGen
->GetDestination();
212 if (cmSystemTools::FileIsFullPath(expDest
)) {
213 // The export file is being installed to an absolute path so the
214 // package is not relocatable. Use the configured install prefix.
215 /* clang-format off */
217 "# The installation prefix configured by this project.\n"
218 "set(_IMPORT_PREFIX \"" << installPrefix
<< "\")\n"
220 /* clang-format on */
222 // Add code to compute the installation prefix relative to the
223 // import file location.
224 std::string absDest
= installPrefix
+ "/" + expDest
;
225 std::string absDestS
= absDest
+ "/";
226 os
<< "# Compute the installation prefix relative to this file.\n"
227 << "get_filename_component(_IMPORT_PREFIX"
228 << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
229 if (cmHasLiteralPrefix(absDestS
, "/lib/") ||
230 cmHasLiteralPrefix(absDestS
, "/lib64/") ||
231 cmHasLiteralPrefix(absDestS
, "/libx32/") ||
232 cmHasLiteralPrefix(absDestS
, "/usr/lib/") ||
233 cmHasLiteralPrefix(absDestS
, "/usr/lib64/") ||
234 cmHasLiteralPrefix(absDestS
, "/usr/libx32/")) {
235 // Handle "/usr move" symlinks created by some Linux distros.
236 /* clang-format off */
238 "# Use original install prefix when loaded through a\n"
239 "# cross-prefix symbolic link such as /lib -> /usr/lib.\n"
240 "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n"
241 "get_filename_component(_realOrig \"" << absDest
<< "\" REALPATH)\n"
242 "if(_realCurr STREQUAL _realOrig)\n"
243 " set(_IMPORT_PREFIX \"" << absDest
<< "\")\n"
246 "unset(_realCurr)\n";
247 /* clang-format on */
249 std::string dest
= expDest
;
250 while (!dest
.empty()) {
251 os
<< "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" "
253 dest
= cmSystemTools::GetFilenamePath(dest
);
255 os
<< "if(_IMPORT_PREFIX STREQUAL \"/\")\n"
256 << " set(_IMPORT_PREFIX \"\")\n"
262 void cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream
& os
)
264 /* clang-format off */
265 os
<< "# Cleanup temporary variables.\n"
266 << "set(_IMPORT_PREFIX)\n"
268 /* clang-format on */
271 void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream
& os
)
273 // Now load per-configuration properties for them.
274 /* clang-format off */
275 os
<< "# Load information for each installed configuration.\n"
276 << "file(GLOB _cmake_config_files \"${CMAKE_CURRENT_LIST_DIR}/"
277 << this->GetConfigImportFileGlob() << "\")\n"
278 << "foreach(_cmake_config_file IN LISTS _cmake_config_files)\n"
279 << " include(\"${_cmake_config_file}\")\n"
281 << "unset(_cmake_config_file)\n"
282 << "unset(_cmake_config_files)\n"
284 /* clang-format on */
287 void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string
& input
)
289 cmGeneratorExpression::ReplaceInstallPrefix(input
, "${_IMPORT_PREFIX}");
292 bool cmExportInstallFileGenerator::GenerateImportFileConfig(
293 const std::string
& config
)
295 // Skip configurations not enabled for this export.
296 if (!this->IEGen
->InstallsForConfig(config
)) {
300 // Construct the name of the file to generate.
301 std::string fileName
= cmStrCat(this->FileDir
, '/', this->FileBase
, '-');
302 if (!config
.empty()) {
303 fileName
+= cmSystemTools::LowerCase(config
);
305 fileName
+= "noconfig";
307 fileName
+= this->FileExt
;
309 // Open the output file to generate it.
310 cmGeneratedFileStream
exportFileStream(fileName
, true);
311 if (!exportFileStream
) {
312 std::string se
= cmSystemTools::GetLastSystemError();
313 std::ostringstream e
;
314 e
<< "cannot write to file \"" << fileName
<< "\": " << se
;
315 cmSystemTools::Error(e
.str());
318 exportFileStream
.SetCopyIfDifferent(true);
319 std::ostream
& os
= exportFileStream
;
321 // Start with the import file header.
322 this->GenerateImportHeaderCode(os
, config
);
324 // Generate the per-config target information.
325 this->GenerateImportConfig(os
, config
);
327 // End with the import file footer.
328 this->GenerateImportFooterCode(os
);
330 // Record this per-config import file.
331 this->ConfigImportFiles
[config
] = fileName
;
336 void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
337 std::ostream
& os
, const std::string
& config
, std::string
const& suffix
)
339 // Add each target in the set to the export.
340 for (std::unique_ptr
<cmTargetExport
> const& te
:
341 this->IEGen
->GetExportSet()->GetTargetExports()) {
342 // Collect import properties for this target.
343 if (this->GetExportTargetType(te
.get()) ==
344 cmStateEnums::INTERFACE_LIBRARY
) {
348 ImportPropertyMap properties
;
349 std::set
<std::string
> importedLocations
;
351 this->SetImportLocationProperty(config
, suffix
, te
->ArchiveGenerator
,
352 properties
, importedLocations
);
353 this->SetImportLocationProperty(config
, suffix
, te
->LibraryGenerator
,
354 properties
, importedLocations
);
355 this->SetImportLocationProperty(config
, suffix
, te
->RuntimeGenerator
,
356 properties
, importedLocations
);
357 this->SetImportLocationProperty(config
, suffix
, te
->ObjectsGenerator
,
358 properties
, importedLocations
);
359 this->SetImportLocationProperty(config
, suffix
, te
->FrameworkGenerator
,
360 properties
, importedLocations
);
361 this->SetImportLocationProperty(config
, suffix
, te
->BundleGenerator
,
362 properties
, importedLocations
);
364 // If any file location was set for the target add it to the
366 if (!properties
.empty()) {
367 // Get the rest of the target details.
368 cmGeneratorTarget
* gtgt
= te
->Target
;
369 this->SetImportDetailProperties(config
, suffix
, gtgt
, properties
);
371 this->SetImportLinkInterface(config
, suffix
,
372 cmGeneratorExpression::InstallInterface
,
375 // TODO: PUBLIC_HEADER_LOCATION
376 // This should wait until the build feature propagation stuff
377 // is done. Then this can be a propagated include directory.
378 // this->GenerateImportProperty(config, te->HeaderGenerator,
381 // Generate code in the export file.
382 std::string importedXcFrameworkLocation
= te
->XcFrameworkLocation
;
383 if (!importedXcFrameworkLocation
.empty()) {
384 importedXcFrameworkLocation
= cmGeneratorExpression::Preprocess(
385 importedXcFrameworkLocation
,
386 cmGeneratorExpression::PreprocessContext::InstallInterface
, true);
387 importedXcFrameworkLocation
= cmGeneratorExpression::Evaluate(
388 importedXcFrameworkLocation
, te
->Target
->GetLocalGenerator(), config
,
389 te
->Target
, nullptr, te
->Target
);
390 if (!importedXcFrameworkLocation
.empty() &&
391 !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation
) &&
392 !cmHasLiteralPrefix(importedXcFrameworkLocation
,
393 "${_IMPORT_PREFIX}/")) {
394 importedXcFrameworkLocation
=
395 cmStrCat("${_IMPORT_PREFIX}/", importedXcFrameworkLocation
);
398 this->GenerateImportPropertyCode(os
, config
, suffix
, gtgt
, properties
,
399 importedXcFrameworkLocation
);
400 this->GenerateImportedFileChecksCode(
401 os
, gtgt
, properties
, importedLocations
, importedXcFrameworkLocation
);
406 void cmExportInstallFileGenerator::SetImportLocationProperty(
407 const std::string
& config
, std::string
const& suffix
,
408 cmInstallTargetGenerator
* itgen
, ImportPropertyMap
& properties
,
409 std::set
<std::string
>& importedLocations
)
411 // Skip rules that do not match this configuration.
412 if (!(itgen
&& itgen
->InstallsForConfig(config
))) {
416 // Get the target to be installed.
417 cmGeneratorTarget
* target
= itgen
->GetTarget();
419 // Construct the installed location of the target.
420 std::string dest
= itgen
->GetDestination(config
);
422 if (!cmSystemTools::FileIsFullPath(dest
)) {
423 // The target is installed relative to the installation prefix.
424 value
= "${_IMPORT_PREFIX}/";
429 if (itgen
->IsImportLibrary()) {
430 // Construct the property name.
431 std::string prop
= cmStrCat("IMPORTED_IMPLIB", suffix
);
433 // Append the installed file name.
434 value
+= cmInstallTargetGenerator::GetInstallFilename(
435 target
, config
, cmInstallTargetGenerator::NameImplibReal
);
437 // Store the property.
438 properties
[prop
] = value
;
439 importedLocations
.insert(prop
);
440 } else if (itgen
->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY
) {
441 // Construct the property name.
442 std::string prop
= cmStrCat("IMPORTED_OBJECTS", suffix
);
444 // Compute all the object files inside this target and setup
445 // IMPORTED_OBJECTS as a list of object files
446 std::vector
<std::string
> objects
;
447 itgen
->GetInstallObjectNames(config
, objects
);
448 for (std::string
& obj
: objects
) {
449 obj
= cmStrCat(value
, obj
);
452 // Store the property.
453 properties
[prop
] = cmList::to_string(objects
);
454 importedLocations
.insert(prop
);
456 if (target
->IsFrameworkOnApple() && target
->HasImportLibrary(config
)) {
457 // store as well IMPLIB value
458 auto importProp
= cmStrCat("IMPORTED_IMPLIB", suffix
);
461 cmInstallTargetGenerator::GetInstallFilename(
462 target
, config
, cmInstallTargetGenerator::NameImplibReal
));
464 // Store the property.
465 properties
[importProp
] = importValue
;
466 importedLocations
.insert(importProp
);
469 // Construct the property name.
470 std::string prop
= cmStrCat("IMPORTED_LOCATION", suffix
);
472 // Append the installed file name.
473 if (target
->IsAppBundleOnApple()) {
474 value
+= cmInstallTargetGenerator::GetInstallFilename(target
, config
);
476 if (!target
->Makefile
->PlatformIsAppleEmbedded()) {
477 value
+= "Contents/MacOS/";
479 value
+= cmInstallTargetGenerator::GetInstallFilename(target
, config
);
481 value
+= cmInstallTargetGenerator::GetInstallFilename(
482 target
, config
, cmInstallTargetGenerator::NameReal
);
485 // Store the property.
486 properties
[prop
] = value
;
487 importedLocations
.insert(prop
);
491 cmStateEnums::TargetType
cmExportInstallFileGenerator::GetExportTargetType(
492 cmTargetExport
const* targetExport
) const
494 cmStateEnums::TargetType targetType
= targetExport
->Target
->GetType();
495 // An OBJECT library installed with no OBJECTS DESTINATION
496 // is transformed to an INTERFACE library.
497 if (targetType
== cmStateEnums::OBJECT_LIBRARY
&&
498 targetExport
->ObjectsGenerator
== nullptr) {
499 targetType
= cmStateEnums::INTERFACE_LIBRARY
;
504 void cmExportInstallFileGenerator::HandleMissingTarget(
505 std::string
& link_libs
, cmGeneratorTarget
const* depender
,
506 cmGeneratorTarget
* dependee
)
508 const std::string name
= dependee
->GetName();
509 cmGlobalGenerator
* gg
= dependee
->GetLocalGenerator()->GetGlobalGenerator();
510 auto exportInfo
= this->FindNamespaces(gg
, name
);
511 std::vector
<std::string
> const& exportFiles
= exportInfo
.first
;
512 if (exportFiles
.size() == 1) {
513 std::string missingTarget
= exportInfo
.second
;
515 missingTarget
+= dependee
->GetExportName();
516 link_libs
+= missingTarget
;
517 this->MissingTargets
.emplace_back(std::move(missingTarget
));
519 // All exported targets should be known here and should be unique.
520 // This is probably user-error.
521 this->ComplainAboutMissingTarget(depender
, dependee
, exportFiles
);
525 std::pair
<std::vector
<std::string
>, std::string
>
526 cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator
* gg
,
527 const std::string
& name
)
529 std::vector
<std::string
> exportFiles
;
531 const cmExportSetMap
& exportSets
= gg
->GetExportSets();
533 for (auto const& expIt
: exportSets
) {
534 const cmExportSet
& exportSet
= expIt
.second
;
536 bool containsTarget
= false;
537 for (auto const& target
: exportSet
.GetTargetExports()) {
538 if (name
== target
->TargetName
) {
539 containsTarget
= true;
544 if (containsTarget
) {
545 std::vector
<cmInstallExportGenerator
const*> const* installs
=
546 exportSet
.GetInstallations();
547 for (cmInstallExportGenerator
const* install
: *installs
) {
548 exportFiles
.push_back(install
->GetDestinationFile());
549 ns
= install
->GetNamespace();
554 return { exportFiles
, ns
};
557 void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
558 cmGeneratorTarget
const* depender
, cmGeneratorTarget
const* dependee
,
559 std::vector
<std::string
> const& exportFiles
)
561 std::ostringstream e
;
562 e
<< "install(EXPORT \"" << this->IEGen
->GetExportSet()->GetName()
564 << "includes target \"" << depender
->GetName()
565 << "\" which requires target \"" << dependee
->GetName() << "\" ";
566 if (exportFiles
.empty()) {
567 e
<< "that is not in any export set.";
569 e
<< "that is not in this export set, but in multiple other export sets: "
570 << cmJoin(exportFiles
, ", ") << ".\n";
571 e
<< "An exported target cannot depend upon another target which is "
572 "exported multiple times. Consider consolidating the exports of the "
574 << dependee
->GetName() << "\" target to a single export.";
576 cmSystemTools::Error(e
.str());
579 std::string
cmExportInstallFileGenerator::InstallNameDir(
580 cmGeneratorTarget
const* target
, const std::string
& config
)
582 std::string install_name_dir
;
584 cmMakefile
* mf
= target
->Target
->GetMakefile();
585 if (mf
->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
587 target
->GetInstallNameDirForInstallTree(config
, "${_IMPORT_PREFIX}");
590 return install_name_dir
;
594 bool EntryIsContextSensitive(
595 const std::unique_ptr
<cmCompiledGeneratorExpression
>& cge
)
597 return cge
->GetHadContextSensitiveCondition();
601 std::string
cmExportInstallFileGenerator::GetFileSetDirectories(
602 cmGeneratorTarget
* gte
, cmFileSet
* fileSet
, cmTargetExport
* te
)
604 std::vector
<std::string
> resultVector
;
607 gte
->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
609 cmGeneratorExpression
ge(*gte
->Makefile
->GetCMakeInstance());
610 auto cge
= ge
.Parse(te
->FileSetGenerators
.at(fileSet
)->GetDestination());
612 for (auto const& config
: configs
) {
613 auto unescapedDest
= cge
->Evaluate(gte
->LocalGenerator
, config
, gte
);
614 auto dest
= cmOutputConverter::EscapeForCMake(
615 unescapedDest
, cmOutputConverter::WrapQuotes::NoWrap
);
616 if (!cmSystemTools::FileIsFullPath(unescapedDest
)) {
617 dest
= cmStrCat("${_IMPORT_PREFIX}/", dest
);
620 auto const& type
= fileSet
->GetType();
621 // C++ modules do not support interface file sets which are dependent upon
622 // the configuration.
623 if (cge
->GetHadContextSensitiveCondition() && type
== "CXX_MODULES"_s
) {
624 auto* mf
= this->IEGen
->GetLocalGenerator()->GetMakefile();
625 std::ostringstream e
;
626 e
<< "The \"" << gte
->GetName() << "\" target's interface file set \""
627 << fileSet
->GetName() << "\" of type \"" << type
628 << "\" contains context-sensitive base file entries which is not "
630 mf
->IssueMessage(MessageType::FATAL_ERROR
, e
.str());
631 return std::string
{};
634 if (cge
->GetHadContextSensitiveCondition() && configs
.size() != 1) {
635 resultVector
.push_back(
636 cmStrCat("\"$<$<CONFIG:", config
, ">:", dest
, ">\""));
638 resultVector
.emplace_back(cmStrCat('"', dest
, '"'));
643 return cmJoin(resultVector
, " ");
646 std::string
cmExportInstallFileGenerator::GetFileSetFiles(
647 cmGeneratorTarget
* gte
, cmFileSet
* fileSet
, cmTargetExport
* te
)
649 std::vector
<std::string
> resultVector
;
652 gte
->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
654 auto fileEntries
= fileSet
->CompileFileEntries();
655 auto directoryEntries
= fileSet
->CompileDirectoryEntries();
657 cmGeneratorExpression
destGe(*gte
->Makefile
->GetCMakeInstance());
659 destGe
.Parse(te
->FileSetGenerators
.at(fileSet
)->GetDestination());
661 for (auto const& config
: configs
) {
662 auto directories
= fileSet
->EvaluateDirectoryEntries(
663 directoryEntries
, gte
->LocalGenerator
, config
, gte
);
665 std::map
<std::string
, std::vector
<std::string
>> files
;
666 for (auto const& entry
: fileEntries
) {
667 fileSet
->EvaluateFileEntry(directories
, files
, entry
,
668 gte
->LocalGenerator
, config
, gte
);
670 auto unescapedDest
= destCge
->Evaluate(gte
->LocalGenerator
, config
, gte
);
672 cmStrCat(cmOutputConverter::EscapeForCMake(
673 unescapedDest
, cmOutputConverter::WrapQuotes::NoWrap
),
675 if (!cmSystemTools::FileIsFullPath(unescapedDest
)) {
676 dest
= cmStrCat("${_IMPORT_PREFIX}/", dest
);
679 bool const contextSensitive
= destCge
->GetHadContextSensitiveCondition() ||
680 std::any_of(directoryEntries
.begin(), directoryEntries
.end(),
681 EntryIsContextSensitive
) ||
682 std::any_of(fileEntries
.begin(), fileEntries
.end(),
683 EntryIsContextSensitive
);
685 auto const& type
= fileSet
->GetType();
686 // C++ modules do not support interface file sets which are dependent upon
687 // the configuration.
688 if (contextSensitive
&& type
== "CXX_MODULES"_s
) {
689 auto* mf
= this->IEGen
->GetLocalGenerator()->GetMakefile();
690 std::ostringstream e
;
691 e
<< "The \"" << gte
->GetName() << "\" target's interface file set \""
692 << fileSet
->GetName() << "\" of type \"" << type
693 << "\" contains context-sensitive base file entries which is not "
695 mf
->IssueMessage(MessageType::FATAL_ERROR
, e
.str());
696 return std::string
{};
699 for (auto const& it
: files
) {
700 auto prefix
= it
.first
.empty() ? "" : cmStrCat(it
.first
, '/');
701 for (auto const& filename
: it
.second
) {
703 cmStrCat(prefix
, cmSystemTools::GetFilenameName(filename
));
706 cmOutputConverter::EscapeForCMake(
707 relFile
, cmOutputConverter::WrapQuotes::NoWrap
));
708 if (contextSensitive
&& configs
.size() != 1) {
709 resultVector
.push_back(
710 cmStrCat("\"$<$<CONFIG:", config
, ">:", escapedFile
, ">\""));
712 resultVector
.emplace_back(cmStrCat('"', escapedFile
, '"'));
717 if (!(contextSensitive
&& configs
.size() != 1)) {
722 return cmJoin(resultVector
, " ");
725 std::string
cmExportInstallFileGenerator::GetCxxModulesDirectory() const
727 return IEGen
->GetCxxModuleDirectory();
730 void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
731 std::string
const& name
, std::ostream
& os
) const
733 // Now load per-configuration properties for them.
734 /* clang-format off */
735 os
<< "# Load information for each installed configuration.\n"
736 "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name
<< "-*.cmake\")\n"
737 "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n"
738 " include(\"${_cmake_cxx_module_include}\")\n"
740 "unset(_cmake_cxx_module_include)\n"
741 "unset(_cmake_cxx_module_includes)\n";
742 /* clang-format on */
745 bool cmExportInstallFileGenerator::
746 GenerateImportCxxModuleConfigTargetInclusion(std::string
const& name
,
747 std::string
const& config
)
749 auto cxx_modules_dirname
= this->GetCxxModulesDirectory();
750 if (cxx_modules_dirname
.empty()) {
754 std::string filename_config
= config
;
755 if (filename_config
.empty()) {
756 filename_config
= "noconfig";
759 std::string
const dest
=
760 cmStrCat(this->FileDir
, '/', cxx_modules_dirname
, '/');
761 std::string fileName
=
762 cmStrCat(dest
, "cxx-modules-", name
, '-', filename_config
, ".cmake");
764 cmGeneratedFileStream
os(fileName
, true);
766 std::string se
= cmSystemTools::GetLastSystemError();
767 std::ostringstream e
;
768 e
<< "cannot write to file \"" << fileName
<< "\": " << se
;
769 cmSystemTools::Error(e
.str());
772 os
.SetCopyIfDifferent(true);
774 // Record this per-config import file.
775 this->ConfigCxxModuleFiles
[config
] = fileName
;
777 auto& prop_files
= this->ConfigCxxModuleTargetFiles
[config
];
778 for (auto const* tgt
: this->ExportedTargets
) {
779 // Only targets with C++ module sources will have a
780 // collator-generated install script.
781 if (!tgt
->HaveCxx20ModuleSources()) {
785 auto prop_filename
= cmStrCat("target-", tgt
->GetFilesystemExportName(),
786 '-', filename_config
, ".cmake");
787 prop_files
.emplace_back(cmStrCat(dest
, prop_filename
));
788 os
<< "include(\"${CMAKE_CURRENT_LIST_DIR}/" << prop_filename
<< "\")\n";