Merge topic 'curl-tls-verify'
[kiteware-cmake.git] / Source / cmDyndepCollation.cxx
blob1c05f25fe00d699bf8fceca89735f811b542c0fc
1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmDyndepCollation.h"
6 #include <algorithm>
7 #include <map>
8 #include <ostream>
9 #include <set>
10 #include <utility>
11 #include <vector>
13 #include <cm/memory>
14 #include <cm/string_view>
15 #include <cmext/string_view>
17 #include <cm3p/json/value.h>
19 #include "cmBuildDatabase.h"
20 #include "cmExportBuildFileGenerator.h"
21 #include "cmExportSet.h"
22 #include "cmFileSet.h"
23 #include "cmGeneratedFileStream.h"
24 #include "cmGeneratorExpression.h" // IWYU pragma: keep
25 #include "cmGeneratorTarget.h"
26 #include "cmGlobalGenerator.h"
27 #include "cmInstallCxxModuleBmiGenerator.h"
28 #include "cmInstallExportGenerator.h"
29 #include "cmInstallFileSetGenerator.h"
30 #include "cmInstallGenerator.h"
31 #include "cmMakefile.h"
32 #include "cmMessageType.h"
33 #include "cmOutputConverter.h"
34 #include "cmScanDepFormat.h"
35 #include "cmSourceFile.h"
36 #include "cmStringAlgorithms.h"
37 #include "cmSystemTools.h"
38 #include "cmTarget.h"
39 #include "cmTargetExport.h"
41 namespace {
43 struct TdiSourceInfo
45 Json::Value Sources;
46 Json::Value CxxModules;
49 TdiSourceInfo CollationInformationSources(cmGeneratorTarget const* gt,
50 std::string const& config,
51 cmDyndepGeneratorCallbacks const& cb)
53 TdiSourceInfo info;
54 cmTarget const* tgt = gt->Target;
55 auto all_file_sets = tgt->GetAllFileSetNames();
56 Json::Value& tdi_sources = info.Sources = Json::objectValue;
57 Json::Value& tdi_cxx_module_info = info.CxxModules = Json::objectValue;
59 enum class CompileType
61 ObjectAndBmi,
62 BmiOnly,
64 std::map<std::string, std::pair<cmSourceFile const*, CompileType>> sf_map;
66 auto fill_sf_map = [gt, tgt, &sf_map](cmSourceFile const* sf,
67 CompileType type) {
68 auto full_path = sf->GetFullPath();
69 if (full_path.empty()) {
70 gt->Makefile->IssueMessage(
71 MessageType::INTERNAL_ERROR,
72 cmStrCat("Target \"", tgt->GetName(),
73 "\" has a full path-less source file."));
74 return;
76 sf_map[full_path] = std::make_pair(sf, type);
79 std::vector<cmSourceFile const*> objectSources;
80 gt->GetObjectSources(objectSources, config);
81 for (auto const* sf : objectSources) {
82 fill_sf_map(sf, CompileType::ObjectAndBmi);
85 std::vector<cmSourceFile const*> cxxModuleSources;
86 gt->GetCxxModuleSources(cxxModuleSources, config);
87 for (auto const* sf : cxxModuleSources) {
88 fill_sf_map(sf, CompileType::BmiOnly);
92 for (auto const& file_set_name : all_file_sets) {
93 auto const* file_set = tgt->GetFileSet(file_set_name);
94 if (!file_set) {
95 gt->Makefile->IssueMessage(MessageType::INTERNAL_ERROR,
96 cmStrCat("Target \"", tgt->GetName(),
97 "\" is tracked to have file set \"",
98 file_set_name,
99 "\", but it was not found."));
100 continue;
102 auto fs_type = file_set->GetType();
103 // We only care about C++ module sources here.
104 if (fs_type != "CXX_MODULES"_s) {
105 continue;
108 auto fileEntries = file_set->CompileFileEntries();
109 auto directoryEntries = file_set->CompileDirectoryEntries();
111 auto directories = file_set->EvaluateDirectoryEntries(
112 directoryEntries, gt->LocalGenerator, config, gt);
113 std::map<std::string, std::vector<std::string>> files_per_dirs;
114 for (auto const& entry : fileEntries) {
115 file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
116 gt->LocalGenerator, config, gt);
119 Json::Value fs_dest = Json::nullValue;
120 for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
121 if (auto const* fsg =
122 dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
123 if (fsg->GetTarget() == gt && fsg->GetFileSet() == file_set) {
124 fs_dest = fsg->GetDestination(config);
125 continue;
130 for (auto const& files_per_dir : files_per_dirs) {
131 for (auto const& file : files_per_dir.second) {
132 auto const full_file = cmSystemTools::CollapseFullPath(file);
133 auto lookup = sf_map.find(full_file);
134 if (lookup == sf_map.end()) {
135 gt->Makefile->IssueMessage(
136 MessageType::FATAL_ERROR,
137 cmStrCat("Target \"", tgt->GetName(), "\" has source file\n ",
138 file,
139 "\nin a \"FILE_SET TYPE CXX_MODULES\" but it is not "
140 "scheduled for compilation."));
141 continue;
144 auto const* sf = lookup->second.first;
145 CompileType const ct = lookup->second.second;
147 sf_map.erase(lookup);
149 if (!sf) {
150 gt->Makefile->IssueMessage(
151 MessageType::INTERNAL_ERROR,
152 cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
153 file, "\" which has not been tracked properly."));
154 continue;
157 auto obj_path = ct == CompileType::ObjectAndBmi
158 ? cb.ObjectFilePath(sf, config)
159 : cb.BmiFilePath(sf, config);
160 Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
161 Json::objectValue;
163 tdi_module_info["source"] = full_file;
164 tdi_module_info["bmi-only"] = ct == CompileType::BmiOnly;
165 tdi_module_info["relative-directory"] = files_per_dir.first;
166 tdi_module_info["name"] = file_set->GetName();
167 tdi_module_info["type"] = file_set->GetType();
168 tdi_module_info["visibility"] =
169 std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
170 tdi_module_info["destination"] = fs_dest;
175 for (auto const& sf_entry : sf_map) {
176 CompileType const ct = sf_entry.second.second;
177 if (ct == CompileType::BmiOnly) {
178 continue;
181 auto const* sf = sf_entry.second.first;
182 if (!gt->NeedDyndepForSource(sf->GetLanguage(), config, sf)) {
183 continue;
186 auto full_file = cmSystemTools::CollapseFullPath(sf->GetFullPath());
187 auto obj_path = cb.ObjectFilePath(sf, config);
188 Json::Value& tdi_source_info = tdi_sources[obj_path] = Json::objectValue;
190 tdi_source_info["source"] = full_file;
191 tdi_source_info["language"] = sf->GetLanguage();
194 return info;
197 Json::Value CollationInformationDatabaseInfo(cmGeneratorTarget const* gt,
198 std::string const& config)
200 Json::Value db_info;
202 auto db_path = gt->BuildDatabasePath("CXX", config);
203 if (!db_path.empty()) {
204 db_info["template-path"] = cmStrCat(db_path, ".in");
205 db_info["output"] = db_path;
208 return db_info;
211 Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt,
212 std::string const& config)
214 cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
215 for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
216 if (auto const* bmig =
217 dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
218 if (bmig->GetTarget() == gt) {
219 bmi_gen = bmig;
220 continue;
224 if (bmi_gen) {
225 Json::Value tdi_bmi_info = Json::objectValue;
227 tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
228 tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
229 const char* msg_level = "";
230 switch (bmi_gen->GetMessageLevel()) {
231 case cmInstallGenerator::MessageDefault:
232 break;
233 case cmInstallGenerator::MessageAlways:
234 msg_level = "MESSAGE_ALWAYS";
235 break;
236 case cmInstallGenerator::MessageLazy:
237 msg_level = "MESSAGE_LAZY";
238 break;
239 case cmInstallGenerator::MessageNever:
240 msg_level = "MESSAGE_NEVER";
241 break;
243 tdi_bmi_info["message-level"] = msg_level;
244 tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
246 return tdi_bmi_info;
248 return Json::nullValue;
251 Json::Value CollationInformationExports(cmGeneratorTarget const* gt)
253 Json::Value tdi_exports = Json::arrayValue;
254 std::string export_name = gt->GetExportName();
255 std::string fs_export_name = gt->GetFilesystemExportName();
257 auto const& all_install_exports = gt->GetGlobalGenerator()->GetExportSets();
258 for (auto const& exp : all_install_exports) {
259 // Ignore exports sets which are not for this target.
260 auto const& targets = exp.second.GetTargetExports();
261 auto tgt_export =
262 std::find_if(targets.begin(), targets.end(),
263 [gt](std::unique_ptr<cmTargetExport> const& te) {
264 return te->Target == gt;
266 if (tgt_export == targets.end()) {
267 continue;
270 auto const* installs = exp.second.GetInstallations();
271 for (auto const* install : *installs) {
272 Json::Value tdi_export_info = Json::objectValue;
274 auto const& ns = install->GetNamespace();
275 auto const& dest = install->GetDestination();
276 auto const& cxxm_dir = install->GetCxxModuleDirectory();
277 auto const& export_prefix = install->GetTempDir();
279 tdi_export_info["namespace"] = ns;
280 tdi_export_info["export-name"] = export_name;
281 tdi_export_info["filesystem-export-name"] = fs_export_name;
282 tdi_export_info["destination"] = dest;
283 tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
284 tdi_export_info["export-prefix"] = export_prefix;
285 tdi_export_info["install"] = true;
287 tdi_exports.append(tdi_export_info);
291 auto const& all_build_exports =
292 gt->GetGlobalGenerator()->GetBuildExportSets();
293 for (auto const& exp_entry : all_build_exports) {
294 auto const* exp = exp_entry.second;
295 std::vector<cmExportBuildFileGenerator::TargetExport> targets;
296 exp->GetTargets(targets);
298 // Ignore exports sets which are not for this target.
299 auto const& name = gt->GetName();
300 bool has_current_target =
301 std::any_of(targets.begin(), targets.end(),
302 [name](cmExportBuildFileGenerator::TargetExport const& te) {
303 return te.Name == name;
305 if (!has_current_target) {
306 continue;
309 Json::Value tdi_export_info = Json::objectValue;
311 auto const& ns = exp->GetNamespace();
312 auto const& main_fn = exp->GetMainExportFileName();
313 auto const& cxxm_dir = exp->GetCxxModuleDirectory();
314 auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
315 auto const& export_prefix =
316 cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
318 tdi_export_info["namespace"] = ns;
319 tdi_export_info["export-name"] = export_name;
320 tdi_export_info["filesystem-export-name"] = fs_export_name;
321 tdi_export_info["destination"] = dest;
322 tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
323 tdi_export_info["export-prefix"] = export_prefix;
324 tdi_export_info["install"] = false;
326 tdi_exports.append(tdi_export_info);
329 return tdi_exports;
333 void cmDyndepCollation::AddCollationInformation(
334 Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config,
335 cmDyndepGeneratorCallbacks const& cb)
337 auto sourcesInfo = CollationInformationSources(gt, config, cb);
338 tdi["sources"] = sourcesInfo.Sources;
339 tdi["cxx-modules"] = sourcesInfo.CxxModules;
340 tdi["database-info"] = CollationInformationDatabaseInfo(gt, config);
341 tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config);
342 tdi["exports"] = CollationInformationExports(gt);
343 tdi["config"] = config;
346 struct SourceInfo
348 std::string SourcePath;
349 std::string Language;
352 struct CxxModuleFileSet
354 std::string Name;
355 bool BmiOnly = false;
356 std::string RelativeDirectory;
357 std::string SourcePath;
358 std::string Type;
359 cmFileSetVisibility Visibility = cmFileSetVisibility::Private;
360 cm::optional<std::string> Destination;
363 struct CxxModuleDatabaseInfo
365 std::string TemplatePath;
366 std::string Output;
369 struct CxxModuleBmiInstall
371 std::string Component;
372 std::string Destination;
373 bool ExcludeFromAll;
374 bool Optional;
375 std::string Permissions;
376 std::string MessageLevel;
377 std::string ScriptLocation;
380 struct CxxModuleExport
382 std::string Name;
383 std::string FilesystemName;
384 std::string Destination;
385 std::string Prefix;
386 std::string CxxModuleInfoDir;
387 std::string Namespace;
388 bool Install;
391 struct cmCxxModuleExportInfo
393 std::map<std::string, SourceInfo> ObjectToSource;
394 std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
395 cm::optional<CxxModuleDatabaseInfo> DatabaseInfo;
396 cm::optional<CxxModuleBmiInstall> BmiInstallation;
397 std::vector<CxxModuleExport> Exports;
398 std::string Config;
401 void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const
403 delete ei;
406 std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
407 cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
409 auto export_info =
410 std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>(
411 new cmCxxModuleExportInfo);
413 export_info->Config = tdi["config"].asString();
414 if (export_info->Config.empty()) {
415 export_info->Config = "noconfig";
417 Json::Value const& tdi_exports = tdi["exports"];
418 if (tdi_exports.isArray()) {
419 for (auto const& tdi_export : tdi_exports) {
420 CxxModuleExport exp;
421 exp.Install = tdi_export["install"].asBool();
422 exp.Name = tdi_export["export-name"].asString();
423 exp.FilesystemName = tdi_export["filesystem-export-name"].asString();
424 exp.Destination = tdi_export["destination"].asString();
425 exp.Prefix = tdi_export["export-prefix"].asString();
426 exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
427 exp.Namespace = tdi_export["namespace"].asString();
429 export_info->Exports.push_back(exp);
432 auto const& database_info = tdi["database-info"];
433 if (database_info.isObject()) {
434 CxxModuleDatabaseInfo db_info;
436 db_info.TemplatePath = database_info["template-path"].asString();
437 db_info.Output = database_info["output"].asString();
439 export_info->DatabaseInfo = db_info;
441 auto const& bmi_installation = tdi["bmi-installation"];
442 if (bmi_installation.isObject()) {
443 CxxModuleBmiInstall bmi_install;
445 bmi_install.Component = bmi_installation["component"].asString();
446 bmi_install.Destination = bmi_installation["destination"].asString();
447 bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
448 bmi_install.Optional = bmi_installation["optional"].asBool();
449 bmi_install.Permissions = bmi_installation["permissions"].asString();
450 bmi_install.MessageLevel = bmi_installation["message-level"].asString();
451 bmi_install.ScriptLocation =
452 bmi_installation["script-location"].asString();
454 export_info->BmiInstallation = bmi_install;
456 Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
457 if (tdi_cxx_modules.isObject()) {
458 for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
459 CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()];
460 auto const& tdi_cxx_module_info = *i;
461 fsi.Name = tdi_cxx_module_info["name"].asString();
462 fsi.BmiOnly = tdi_cxx_module_info["bmi-only"].asBool();
463 fsi.RelativeDirectory =
464 tdi_cxx_module_info["relative-directory"].asString();
465 if (!fsi.RelativeDirectory.empty() &&
466 fsi.RelativeDirectory.back() != '/') {
467 fsi.RelativeDirectory = cmStrCat(fsi.RelativeDirectory, '/');
469 fsi.SourcePath = tdi_cxx_module_info["source"].asString();
470 fsi.Type = tdi_cxx_module_info["type"].asString();
471 fsi.Visibility = cmFileSetVisibilityFromName(
472 tdi_cxx_module_info["visibility"].asString(), nullptr);
473 auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
474 if (tdi_fs_dest.isString()) {
475 fsi.Destination = tdi_fs_dest.asString();
479 Json::Value const& tdi_sources = tdi["sources"];
480 if (tdi_sources.isObject()) {
481 for (auto i = tdi_sources.begin(); i != tdi_sources.end(); ++i) {
482 SourceInfo& si = export_info->ObjectToSource[i.key().asString()];
483 auto const& tdi_source = *i;
484 si.SourcePath = tdi_source["source"].asString();
485 si.Language = tdi_source["language"].asString();
489 return export_info;
492 bool cmDyndepCollation::WriteDyndepMetadata(
493 std::string const& lang, std::vector<cmScanDepInfo> const& objects,
494 cmCxxModuleExportInfo const& export_info,
495 cmDyndepMetadataCallbacks const& cb)
497 // Only C++ supports any of the file-set or BMI installation considered
498 // below.
499 if (lang != "CXX"_s) {
500 return true;
503 bool result = true;
505 // Prepare the export information blocks.
506 std::string const config_upper =
507 cmSystemTools::UpperCase(export_info.Config);
508 std::vector<
509 std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>>
510 exports;
511 for (auto const& exp : export_info.Exports) {
512 std::unique_ptr<cmGeneratedFileStream> properties;
514 std::string const export_dir =
515 cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
516 std::string const property_file_path =
517 cmStrCat(export_dir, "target-", exp.FilesystemName, '-',
518 export_info.Config, ".cmake");
519 properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
521 // Set up the preamble.
522 *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
523 << "\"\n"
524 << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n';
526 exports.emplace_back(std::move(properties), &exp);
529 std::unique_ptr<cmBuildDatabase> module_database;
530 cmBuildDatabase::LookupTable build_database_lookup;
531 if (export_info.DatabaseInfo) {
532 module_database =
533 cmBuildDatabase::Load(export_info.DatabaseInfo->TemplatePath);
534 if (module_database) {
535 build_database_lookup = module_database->GenerateLookupTable();
536 } else {
537 cmSystemTools::Error(
538 cmStrCat("Failed to read the template build database ",
539 export_info.DatabaseInfo->TemplatePath));
540 result = false;
544 std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
545 if (export_info.BmiInstallation) {
546 bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
547 export_info.BmiInstallation->ScriptLocation);
550 auto cmEscape = [](cm::string_view str) {
551 return cmOutputConverter::EscapeForCMake(
552 str, cmOutputConverter::WrapQuotes::NoWrap);
554 auto install_destination =
555 [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
556 if (cmSystemTools::FileIsFullPath(dest)) {
557 return std::make_pair(true, cmEscape(dest));
559 return std::make_pair(false,
560 cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
563 // public/private requirement tracking.
564 std::set<std::string> private_modules;
565 std::map<std::string, std::set<std::string>> public_source_requires;
567 for (cmScanDepInfo const& object : objects) {
568 // Convert to forward slashes.
569 auto output_path = object.PrimaryOutput;
570 #ifdef _WIN32
571 cmSystemTools::ConvertToUnixSlashes(output_path);
572 #endif
574 auto source_info_itr = export_info.ObjectToSource.find(output_path);
576 // Update the module compilation database `requires` field if needed.
577 if (source_info_itr != export_info.ObjectToSource.end()) {
578 auto const& sourcePath = source_info_itr->second.SourcePath;
579 auto bdb_entry = build_database_lookup.find(sourcePath);
580 if (bdb_entry != build_database_lookup.end()) {
581 bdb_entry->second->Requires.clear();
582 for (auto const& req : object.Requires) {
583 bdb_entry->second->Requires.push_back(req.LogicalName);
585 } else if (export_info.DatabaseInfo) {
586 cmSystemTools::Error(
587 cmStrCat("Failed to find module database entry for ", sourcePath));
588 result = false;
592 // Find the fileset for this object.
593 auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
594 bool const has_provides = !object.Provides.empty();
595 if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
596 // If it provides anything, it should have type `CXX_MODULES`
597 // and be present.
598 if (has_provides) {
599 // Take the first module provided to provide context.
600 auto const& provides = object.Provides[0];
601 cmSystemTools::Error(
602 cmStrCat("Output ", object.PrimaryOutput, " provides the `",
603 provides.LogicalName,
604 "` module but it is not found in a `FILE_SET` of type "
605 "`CXX_MODULES`"));
606 result = false;
609 // This object file does not provide anything, so nothing more needs to
610 // be done.
611 continue;
614 auto const& file_set = fileset_info_itr->second;
616 // Update the module compilation database `provides` field if needed.
618 auto bdb_entry = build_database_lookup.find(file_set.SourcePath);
619 if (bdb_entry != build_database_lookup.end()) {
620 // Clear the provides mapping; we will re-initialize it here.
621 if (!object.Provides.empty()) {
622 bdb_entry->second->Provides.clear();
624 for (auto const& prov : object.Provides) {
625 auto bmiName = cb.ModuleFile(prov.LogicalName);
626 if (bmiName) {
627 bdb_entry->second->Provides[prov.LogicalName] = *bmiName;
628 } else {
629 cmSystemTools::Error(
630 cmStrCat("Failed to find BMI location for ", prov.LogicalName));
631 result = false;
634 } else if (export_info.DatabaseInfo) {
635 cmSystemTools::Error(cmStrCat(
636 "Failed to find module database entry for ", file_set.SourcePath));
637 result = false;
641 // Verify the fileset type for the object.
642 if (file_set.Type == "CXX_MODULES"_s) {
643 if (!has_provides) {
644 cmSystemTools::Error(
645 cmStrCat("Output ", object.PrimaryOutput,
646 " is of type `CXX_MODULES` but does not provide a module "
647 "interface unit or partition"));
648 result = false;
649 continue;
651 } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
652 // TODO.
653 } else {
654 if (has_provides) {
655 auto const& provides = object.Provides[0];
656 cmSystemTools::Error(cmStrCat(
657 "Source ", file_set.SourcePath, " provides the `",
658 provides.LogicalName, "` C++ module but is of type `", file_set.Type,
659 "` module but must be of type `CXX_MODULES`"));
660 result = false;
663 // Not a C++ module; ignore.
664 continue;
667 if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
668 // Nothing needs to be conveyed about non-`PUBLIC` modules.
669 for (auto const& p : object.Provides) {
670 private_modules.insert(p.LogicalName);
672 continue;
675 // The module is public. Record what it directly requires.
677 auto& reqs = public_source_requires[file_set.SourcePath];
678 for (auto const& r : object.Requires) {
679 reqs.insert(r.LogicalName);
683 // Write out properties and install rules for any exports.
684 for (auto const& p : object.Provides) {
685 bool bmi_dest_is_abs = false;
686 std::string bmi_destination;
687 if (export_info.BmiInstallation) {
688 auto dest =
689 install_destination(export_info.BmiInstallation->Destination);
690 bmi_dest_is_abs = dest.first;
691 bmi_destination = cmStrCat(dest.second, '/');
694 std::string install_bmi_path;
695 std::string build_bmi_path;
696 auto m = cb.ModuleFile(p.LogicalName);
697 if (m) {
698 install_bmi_path = cmStrCat(
699 bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m)));
700 build_bmi_path = cmEscape(*m);
703 for (auto const& exp : exports) {
704 std::string iface_source;
705 if (exp.second->Install && file_set.Destination) {
706 auto dest = install_destination(*file_set.Destination);
707 iface_source = cmStrCat(
708 dest.second, '/', cmEscape(file_set.RelativeDirectory),
709 cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
710 } else {
711 iface_source = cmEscape(file_set.SourcePath);
714 std::string bmi_path;
715 if (exp.second->Install && export_info.BmiInstallation) {
716 bmi_path = install_bmi_path;
717 } else if (!exp.second->Install) {
718 bmi_path = build_bmi_path;
721 if (iface_source.empty()) {
722 // No destination for the C++ module source; ignore this property
723 // value.
724 continue;
727 *exp.first << " \"" << cmEscape(p.LogicalName) << '='
728 << iface_source;
729 if (!bmi_path.empty()) {
730 *exp.first << ',' << bmi_path;
732 *exp.first << "\"\n";
735 if (bmi_install_script) {
736 auto const& bmi_install = *export_info.BmiInstallation;
738 *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
739 << cmEscape(bmi_install.Component) << '\"';
740 if (!bmi_install.ExcludeFromAll) {
741 *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
743 *bmi_install_script << ")\n";
744 *bmi_install_script << " file(INSTALL\n"
745 " DESTINATION \"";
746 if (!bmi_dest_is_abs) {
747 *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
749 *bmi_install_script << cmEscape(bmi_install.Destination)
750 << "\"\n"
751 " TYPE FILE\n";
752 if (bmi_install.Optional) {
753 *bmi_install_script << " OPTIONAL\n";
755 if (!bmi_install.MessageLevel.empty()) {
756 *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
758 if (!bmi_install.Permissions.empty()) {
759 *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
760 << "\n";
762 *bmi_install_script << " FILES \"" << *m << "\")\n";
763 if (bmi_dest_is_abs) {
764 *bmi_install_script
765 << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
766 " \""
767 << cmEscape(cmSystemTools::GetFilenameName(*m))
768 << "\")\n"
769 " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
770 " message(WARNING\n"
771 " \"ABSOLUTE path INSTALL DESTINATION : "
772 "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
773 " endif ()\n"
774 " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
775 " message(FATAL_ERROR\n"
776 " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
777 "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
778 " endif ()\n";
780 *bmi_install_script << "endif ()\n";
785 // Add trailing parenthesis for the `set_property` call.
786 for (auto const& exp : exports) {
787 *exp.first << ")\n";
790 // Check that public sources only require public modules.
791 for (auto const& pub_reqs : public_source_requires) {
792 for (auto const& req : pub_reqs.second) {
793 if (private_modules.count(req)) {
794 cmSystemTools::Error(cmStrCat(
795 "Public C++ module source `", pub_reqs.first, "` requires the `",
796 req, "` C++ module which is provided by a private source"));
797 result = false;
802 if (module_database) {
803 if (module_database->HasPlaceholderNames()) {
804 cmSystemTools::Error(
805 "Module compilation database still contains placeholders");
806 result = false;
807 } else {
808 module_database->Write(export_info.DatabaseInfo->Output);
812 return result;
815 bool cmDyndepCollation::IsObjectPrivate(
816 std::string const& object, cmCxxModuleExportInfo const& export_info)
818 #ifdef _WIN32
819 std::string output_path = object;
820 cmSystemTools::ConvertToUnixSlashes(output_path);
821 #else
822 std::string const& output_path = object;
823 #endif
824 auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
825 if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
826 return false;
828 auto const& file_set = fileset_info_itr->second;
829 return !cmFileSetVisibilityIsForInterface(file_set.Visibility);
832 bool cmDyndepCollation::IsBmiOnly(cmCxxModuleExportInfo const& exportInfo,
833 std::string const& object)
835 #ifdef _WIN32
836 auto object_path = object;
837 cmSystemTools::ConvertToUnixSlashes(object_path);
838 #else
839 auto const& object_path = object;
840 #endif
841 auto fs = exportInfo.ObjectToFileSet.find(object_path);
842 return (fs != exportInfo.ObjectToFileSet.end()) && fs->second.BmiOnly;