cmDyndepCollation.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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 "cmDyndepCollation.h"
  4. #include <algorithm>
  5. #include <map>
  6. #include <ostream>
  7. #include <set>
  8. #include <utility>
  9. #include <vector>
  10. #include <cm/memory>
  11. #include <cm/string_view>
  12. #include <cmext/string_view>
  13. #include <cm3p/json/value.h>
  14. #include "cmExportBuildFileGenerator.h"
  15. #include "cmExportSet.h"
  16. #include "cmFileSet.h"
  17. #include "cmGeneratedFileStream.h"
  18. #include "cmGeneratorExpression.h" // IWYU pragma: keep
  19. #include "cmGeneratorTarget.h"
  20. #include "cmGlobalGenerator.h"
  21. #include "cmInstallCxxModuleBmiGenerator.h"
  22. #include "cmInstallExportGenerator.h"
  23. #include "cmInstallFileSetGenerator.h"
  24. #include "cmInstallGenerator.h"
  25. #include "cmMakefile.h"
  26. #include "cmMessageType.h"
  27. #include "cmOutputConverter.h"
  28. #include "cmScanDepFormat.h"
  29. #include "cmSourceFile.h"
  30. #include "cmStringAlgorithms.h"
  31. #include "cmSystemTools.h"
  32. #include "cmTarget.h"
  33. #include "cmTargetExport.h"
  34. namespace {
  35. Json::Value CollationInformationCxxModules(
  36. cmGeneratorTarget const* gt, std::string const& config,
  37. cmDyndepGeneratorCallbacks const& cb)
  38. {
  39. cmTarget const* tgt = gt->Target;
  40. auto all_file_sets = tgt->GetAllFileSetNames();
  41. Json::Value tdi_cxx_module_info = Json::objectValue;
  42. for (auto const& file_set_name : all_file_sets) {
  43. auto const* file_set = tgt->GetFileSet(file_set_name);
  44. if (!file_set) {
  45. gt->Makefile->IssueMessage(MessageType::INTERNAL_ERROR,
  46. cmStrCat("Target \"", tgt->GetName(),
  47. "\" is tracked to have file set \"",
  48. file_set_name,
  49. "\", but it was not found."));
  50. continue;
  51. }
  52. auto fs_type = file_set->GetType();
  53. // We only care about C++ module sources here.
  54. if (fs_type != "CXX_MODULES"_s) {
  55. continue;
  56. }
  57. auto fileEntries = file_set->CompileFileEntries();
  58. auto directoryEntries = file_set->CompileDirectoryEntries();
  59. auto directories = file_set->EvaluateDirectoryEntries(
  60. directoryEntries, gt->LocalGenerator, config, gt);
  61. std::map<std::string, std::vector<std::string>> files_per_dirs;
  62. for (auto const& entry : fileEntries) {
  63. file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
  64. gt->LocalGenerator, config, gt);
  65. }
  66. enum class CompileType
  67. {
  68. ObjectAndBmi,
  69. BmiOnly,
  70. };
  71. std::map<std::string, std::pair<cmSourceFile const*, CompileType>> sf_map;
  72. {
  73. auto fill_sf_map = [gt, tgt, &sf_map](cmSourceFile const* sf,
  74. CompileType type) {
  75. auto full_path = sf->GetFullPath();
  76. if (full_path.empty()) {
  77. gt->Makefile->IssueMessage(
  78. MessageType::INTERNAL_ERROR,
  79. cmStrCat("Target \"", tgt->GetName(),
  80. "\" has a full path-less source file."));
  81. return;
  82. }
  83. sf_map[full_path] = std::make_pair(sf, type);
  84. };
  85. std::vector<cmSourceFile const*> objectSources;
  86. gt->GetObjectSources(objectSources, config);
  87. for (auto const* sf : objectSources) {
  88. fill_sf_map(sf, CompileType::ObjectAndBmi);
  89. }
  90. std::vector<cmSourceFile const*> cxxModuleSources;
  91. gt->GetCxxModuleSources(cxxModuleSources, config);
  92. for (auto const* sf : cxxModuleSources) {
  93. fill_sf_map(sf, CompileType::BmiOnly);
  94. }
  95. }
  96. Json::Value fs_dest = Json::nullValue;
  97. for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
  98. if (auto const* fsg =
  99. dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
  100. if (fsg->GetTarget() == gt && fsg->GetFileSet() == file_set) {
  101. fs_dest = fsg->GetDestination(config);
  102. continue;
  103. }
  104. }
  105. }
  106. for (auto const& files_per_dir : files_per_dirs) {
  107. for (auto const& file : files_per_dir.second) {
  108. auto lookup = sf_map.find(file);
  109. if (lookup == sf_map.end()) {
  110. gt->Makefile->IssueMessage(
  111. MessageType::INTERNAL_ERROR,
  112. cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
  113. file,
  114. R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
  115. continue;
  116. }
  117. auto const* sf = lookup->second.first;
  118. CompileType const ct = lookup->second.second;
  119. if (!sf) {
  120. gt->Makefile->IssueMessage(
  121. MessageType::INTERNAL_ERROR,
  122. cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
  123. file, "\" which has not been tracked properly."));
  124. continue;
  125. }
  126. auto obj_path = ct == CompileType::ObjectAndBmi
  127. ? cb.ObjectFilePath(sf, config)
  128. : cb.BmiFilePath(sf, config);
  129. Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
  130. Json::objectValue;
  131. tdi_module_info["source"] = file;
  132. tdi_module_info["bmi-only"] = ct == CompileType::BmiOnly;
  133. tdi_module_info["relative-directory"] = files_per_dir.first;
  134. tdi_module_info["name"] = file_set->GetName();
  135. tdi_module_info["type"] = file_set->GetType();
  136. tdi_module_info["visibility"] =
  137. std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
  138. tdi_module_info["destination"] = fs_dest;
  139. }
  140. }
  141. }
  142. return tdi_cxx_module_info;
  143. }
  144. Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt,
  145. std::string const& config)
  146. {
  147. cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
  148. for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
  149. if (auto const* bmig =
  150. dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
  151. if (bmig->GetTarget() == gt) {
  152. bmi_gen = bmig;
  153. continue;
  154. }
  155. }
  156. }
  157. if (bmi_gen) {
  158. Json::Value tdi_bmi_info = Json::objectValue;
  159. tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
  160. tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
  161. const char* msg_level = "";
  162. switch (bmi_gen->GetMessageLevel()) {
  163. case cmInstallGenerator::MessageDefault:
  164. break;
  165. case cmInstallGenerator::MessageAlways:
  166. msg_level = "MESSAGE_ALWAYS";
  167. break;
  168. case cmInstallGenerator::MessageLazy:
  169. msg_level = "MESSAGE_LAZY";
  170. break;
  171. case cmInstallGenerator::MessageNever:
  172. msg_level = "MESSAGE_NEVER";
  173. break;
  174. }
  175. tdi_bmi_info["message-level"] = msg_level;
  176. tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
  177. return tdi_bmi_info;
  178. }
  179. return Json::nullValue;
  180. }
  181. Json::Value CollationInformationExports(cmGeneratorTarget const* gt)
  182. {
  183. Json::Value tdi_exports = Json::arrayValue;
  184. std::string export_name = gt->GetExportName();
  185. auto const& all_install_exports = gt->GetGlobalGenerator()->GetExportSets();
  186. for (auto const& exp : all_install_exports) {
  187. // Ignore exports sets which are not for this target.
  188. auto const& targets = exp.second.GetTargetExports();
  189. auto tgt_export =
  190. std::find_if(targets.begin(), targets.end(),
  191. [gt](std::unique_ptr<cmTargetExport> const& te) {
  192. return te->Target == gt;
  193. });
  194. if (tgt_export == targets.end()) {
  195. continue;
  196. }
  197. auto const* installs = exp.second.GetInstallations();
  198. for (auto const* install : *installs) {
  199. Json::Value tdi_export_info = Json::objectValue;
  200. auto const& ns = install->GetNamespace();
  201. auto const& dest = install->GetDestination();
  202. auto const& cxxm_dir = install->GetCxxModuleDirectory();
  203. auto const& export_prefix = install->GetTempDir();
  204. tdi_export_info["namespace"] = ns;
  205. tdi_export_info["export-name"] = export_name;
  206. tdi_export_info["destination"] = dest;
  207. tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
  208. tdi_export_info["export-prefix"] = export_prefix;
  209. tdi_export_info["install"] = true;
  210. tdi_exports.append(tdi_export_info);
  211. }
  212. }
  213. auto const& all_build_exports = gt->Makefile->GetExportBuildFileGenerators();
  214. for (auto const& exp : all_build_exports) {
  215. std::vector<std::string> targets;
  216. exp->GetTargets(targets);
  217. // Ignore exports sets which are not for this target.
  218. auto const& name = gt->GetName();
  219. bool has_current_target =
  220. std::any_of(targets.begin(), targets.end(),
  221. [name](std::string const& tname) { return tname == name; });
  222. if (!has_current_target) {
  223. continue;
  224. }
  225. Json::Value tdi_export_info = Json::objectValue;
  226. auto const& ns = exp->GetNamespace();
  227. auto const& main_fn = exp->GetMainExportFileName();
  228. auto const& cxxm_dir = exp->GetCxxModuleDirectory();
  229. auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
  230. auto const& export_prefix =
  231. cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
  232. tdi_export_info["namespace"] = ns;
  233. tdi_export_info["export-name"] = export_name;
  234. tdi_export_info["destination"] = dest;
  235. tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
  236. tdi_export_info["export-prefix"] = export_prefix;
  237. tdi_export_info["install"] = false;
  238. tdi_exports.append(tdi_export_info);
  239. }
  240. return tdi_exports;
  241. }
  242. }
  243. void cmDyndepCollation::AddCollationInformation(
  244. Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config,
  245. cmDyndepGeneratorCallbacks const& cb)
  246. {
  247. tdi["cxx-modules"] = CollationInformationCxxModules(gt, config, cb);
  248. tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config);
  249. tdi["exports"] = CollationInformationExports(gt);
  250. tdi["config"] = config;
  251. }
  252. struct CxxModuleFileSet
  253. {
  254. std::string Name;
  255. bool BmiOnly = false;
  256. std::string RelativeDirectory;
  257. std::string SourcePath;
  258. std::string Type;
  259. cmFileSetVisibility Visibility = cmFileSetVisibility::Private;
  260. cm::optional<std::string> Destination;
  261. };
  262. struct CxxModuleBmiInstall
  263. {
  264. std::string Component;
  265. std::string Destination;
  266. bool ExcludeFromAll;
  267. bool Optional;
  268. std::string Permissions;
  269. std::string MessageLevel;
  270. std::string ScriptLocation;
  271. };
  272. struct CxxModuleExport
  273. {
  274. std::string Name;
  275. std::string Destination;
  276. std::string Prefix;
  277. std::string CxxModuleInfoDir;
  278. std::string Namespace;
  279. bool Install;
  280. };
  281. struct cmCxxModuleExportInfo
  282. {
  283. std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
  284. cm::optional<CxxModuleBmiInstall> BmiInstallation;
  285. std::vector<CxxModuleExport> Exports;
  286. std::string Config;
  287. };
  288. void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const
  289. {
  290. delete ei;
  291. }
  292. std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
  293. cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
  294. {
  295. auto export_info =
  296. std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>(
  297. new cmCxxModuleExportInfo);
  298. export_info->Config = tdi["config"].asString();
  299. if (export_info->Config.empty()) {
  300. export_info->Config = "noconfig";
  301. }
  302. Json::Value const& tdi_exports = tdi["exports"];
  303. if (tdi_exports.isArray()) {
  304. for (auto const& tdi_export : tdi_exports) {
  305. CxxModuleExport exp;
  306. exp.Install = tdi_export["install"].asBool();
  307. exp.Name = tdi_export["export-name"].asString();
  308. exp.Destination = tdi_export["destination"].asString();
  309. exp.Prefix = tdi_export["export-prefix"].asString();
  310. exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
  311. exp.Namespace = tdi_export["namespace"].asString();
  312. export_info->Exports.push_back(exp);
  313. }
  314. }
  315. auto const& bmi_installation = tdi["bmi-installation"];
  316. if (bmi_installation.isObject()) {
  317. CxxModuleBmiInstall bmi_install;
  318. bmi_install.Component = bmi_installation["component"].asString();
  319. bmi_install.Destination = bmi_installation["destination"].asString();
  320. bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
  321. bmi_install.Optional = bmi_installation["optional"].asBool();
  322. bmi_install.Permissions = bmi_installation["permissions"].asString();
  323. bmi_install.MessageLevel = bmi_installation["message-level"].asString();
  324. bmi_install.ScriptLocation =
  325. bmi_installation["script-location"].asString();
  326. export_info->BmiInstallation = bmi_install;
  327. }
  328. Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
  329. if (tdi_cxx_modules.isObject()) {
  330. for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
  331. CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()];
  332. auto const& tdi_cxx_module_info = *i;
  333. fsi.Name = tdi_cxx_module_info["name"].asString();
  334. fsi.BmiOnly = tdi_cxx_module_info["bmi-only"].asBool();
  335. fsi.RelativeDirectory =
  336. tdi_cxx_module_info["relative-directory"].asString();
  337. if (!fsi.RelativeDirectory.empty() &&
  338. fsi.RelativeDirectory.back() != '/') {
  339. fsi.RelativeDirectory = cmStrCat(fsi.RelativeDirectory, '/');
  340. }
  341. fsi.SourcePath = tdi_cxx_module_info["source"].asString();
  342. fsi.Type = tdi_cxx_module_info["type"].asString();
  343. fsi.Visibility = cmFileSetVisibilityFromName(
  344. tdi_cxx_module_info["visibility"].asString(), nullptr);
  345. auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
  346. if (tdi_fs_dest.isString()) {
  347. fsi.Destination = tdi_fs_dest.asString();
  348. }
  349. }
  350. }
  351. return export_info;
  352. }
  353. bool cmDyndepCollation::WriteDyndepMetadata(
  354. std::string const& lang, std::vector<cmScanDepInfo> const& objects,
  355. cmCxxModuleExportInfo const& export_info,
  356. cmDyndepMetadataCallbacks const& cb)
  357. {
  358. // Only C++ supports any of the file-set or BMI installation considered
  359. // below.
  360. if (lang != "CXX"_s) {
  361. return true;
  362. }
  363. bool result = true;
  364. // Prepare the export information blocks.
  365. std::string const config_upper =
  366. cmSystemTools::UpperCase(export_info.Config);
  367. std::vector<
  368. std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>>
  369. exports;
  370. for (auto const& exp : export_info.Exports) {
  371. std::unique_ptr<cmGeneratedFileStream> properties;
  372. std::string const export_dir =
  373. cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
  374. std::string const property_file_path = cmStrCat(
  375. export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
  376. properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
  377. // Set up the preamble.
  378. *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
  379. << "\"\n"
  380. << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n';
  381. exports.emplace_back(std::move(properties), &exp);
  382. }
  383. std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
  384. if (export_info.BmiInstallation) {
  385. bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
  386. export_info.BmiInstallation->ScriptLocation);
  387. }
  388. auto cmEscape = [](cm::string_view str) {
  389. return cmOutputConverter::EscapeForCMake(
  390. str, cmOutputConverter::WrapQuotes::NoWrap);
  391. };
  392. auto install_destination =
  393. [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
  394. if (cmSystemTools::FileIsFullPath(dest)) {
  395. return std::make_pair(true, cmEscape(dest));
  396. }
  397. return std::make_pair(false,
  398. cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
  399. };
  400. // public/private requirement tracking.
  401. std::set<std::string> private_modules;
  402. std::map<std::string, std::set<std::string>> public_source_requires;
  403. for (cmScanDepInfo const& object : objects) {
  404. // Convert to forward slashes.
  405. auto output_path = object.PrimaryOutput;
  406. #ifdef _WIN32
  407. cmSystemTools::ConvertToUnixSlashes(output_path);
  408. #endif
  409. // Find the fileset for this object.
  410. auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
  411. bool const has_provides = !object.Provides.empty();
  412. if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
  413. // If it provides anything, it should have type `CXX_MODULES`
  414. // and be present.
  415. if (has_provides) {
  416. // Take the first module provided to provide context.
  417. auto const& provides = object.Provides[0];
  418. cmSystemTools::Error(
  419. cmStrCat("Output ", object.PrimaryOutput, " provides the `",
  420. provides.LogicalName,
  421. "` module but it is not found in a `FILE_SET` of type "
  422. "`CXX_MODULES`"));
  423. result = false;
  424. }
  425. // This object file does not provide anything, so nothing more needs to
  426. // be done.
  427. continue;
  428. }
  429. auto const& file_set = fileset_info_itr->second;
  430. // Verify the fileset type for the object.
  431. if (file_set.Type == "CXX_MODULES"_s) {
  432. if (!has_provides) {
  433. cmSystemTools::Error(
  434. cmStrCat("Output ", object.PrimaryOutput,
  435. " is of type `CXX_MODULES` but does not provide a module"));
  436. result = false;
  437. continue;
  438. }
  439. } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
  440. // TODO.
  441. } else {
  442. if (has_provides) {
  443. auto const& provides = object.Provides[0];
  444. cmSystemTools::Error(cmStrCat(
  445. "Source ", file_set.SourcePath, " provides the `",
  446. provides.LogicalName, "` C++ module but is of type `", file_set.Type,
  447. "` module but must be of type `CXX_MODULES`"));
  448. result = false;
  449. }
  450. // Not a C++ module; ignore.
  451. continue;
  452. }
  453. if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
  454. // Nothing needs to be conveyed about non-`PUBLIC` modules.
  455. for (auto const& p : object.Provides) {
  456. private_modules.insert(p.LogicalName);
  457. }
  458. continue;
  459. }
  460. // The module is public. Record what it directly requires.
  461. {
  462. auto& reqs = public_source_requires[file_set.SourcePath];
  463. for (auto const& r : object.Requires) {
  464. reqs.insert(r.LogicalName);
  465. }
  466. }
  467. // Write out properties and install rules for any exports.
  468. for (auto const& p : object.Provides) {
  469. bool bmi_dest_is_abs = false;
  470. std::string bmi_destination;
  471. if (export_info.BmiInstallation) {
  472. auto dest =
  473. install_destination(export_info.BmiInstallation->Destination);
  474. bmi_dest_is_abs = dest.first;
  475. bmi_destination = cmStrCat(dest.second, '/');
  476. }
  477. std::string install_bmi_path;
  478. std::string build_bmi_path;
  479. auto m = cb.ModuleFile(p.LogicalName);
  480. if (m) {
  481. install_bmi_path = cmStrCat(
  482. bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m)));
  483. build_bmi_path = cmEscape(*m);
  484. }
  485. for (auto const& exp : exports) {
  486. std::string iface_source;
  487. if (exp.second->Install && file_set.Destination) {
  488. auto dest = install_destination(*file_set.Destination);
  489. iface_source = cmStrCat(
  490. dest.second, '/', cmEscape(file_set.RelativeDirectory),
  491. cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
  492. } else {
  493. iface_source = cmEscape(file_set.SourcePath);
  494. }
  495. std::string bmi_path;
  496. if (exp.second->Install && export_info.BmiInstallation) {
  497. bmi_path = install_bmi_path;
  498. } else if (!exp.second->Install) {
  499. bmi_path = build_bmi_path;
  500. }
  501. if (iface_source.empty()) {
  502. // No destination for the C++ module source; ignore this property
  503. // value.
  504. continue;
  505. }
  506. *exp.first << " \"" << cmEscape(p.LogicalName) << '='
  507. << iface_source;
  508. if (!bmi_path.empty()) {
  509. *exp.first << ',' << bmi_path;
  510. }
  511. *exp.first << "\"\n";
  512. }
  513. if (bmi_install_script) {
  514. auto const& bmi_install = *export_info.BmiInstallation;
  515. *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
  516. << cmEscape(bmi_install.Component) << '\"';
  517. if (!bmi_install.ExcludeFromAll) {
  518. *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
  519. }
  520. *bmi_install_script << ")\n";
  521. *bmi_install_script << " file(INSTALL\n"
  522. " DESTINATION \"";
  523. if (!bmi_dest_is_abs) {
  524. *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
  525. }
  526. *bmi_install_script << cmEscape(bmi_install.Destination)
  527. << "\"\n"
  528. " TYPE FILE\n";
  529. if (bmi_install.Optional) {
  530. *bmi_install_script << " OPTIONAL\n";
  531. }
  532. if (!bmi_install.MessageLevel.empty()) {
  533. *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
  534. }
  535. if (!bmi_install.Permissions.empty()) {
  536. *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
  537. << "\n";
  538. }
  539. *bmi_install_script << " FILES \"" << *m << "\")\n";
  540. if (bmi_dest_is_abs) {
  541. *bmi_install_script
  542. << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
  543. " \""
  544. << cmEscape(cmSystemTools::GetFilenameName(*m))
  545. << "\")\n"
  546. " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
  547. " message(WARNING\n"
  548. " \"ABSOLUTE path INSTALL DESTINATION : "
  549. "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
  550. " endif ()\n"
  551. " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
  552. " message(FATAL_ERROR\n"
  553. " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
  554. "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
  555. " endif ()\n";
  556. }
  557. *bmi_install_script << "endif ()\n";
  558. }
  559. }
  560. }
  561. // Add trailing parenthesis for the `set_property` call.
  562. for (auto const& exp : exports) {
  563. *exp.first << ")\n";
  564. }
  565. // Check that public sources only require public modules.
  566. for (auto const& pub_reqs : public_source_requires) {
  567. for (auto const& req : pub_reqs.second) {
  568. if (private_modules.count(req)) {
  569. cmSystemTools::Error(cmStrCat(
  570. "Public C++ module source `", pub_reqs.first, "` requires the `",
  571. req, "` C++ module which is provided by a private source"));
  572. result = false;
  573. }
  574. }
  575. }
  576. return result;
  577. }
  578. bool cmDyndepCollation::IsObjectPrivate(
  579. std::string const& object, cmCxxModuleExportInfo const& export_info)
  580. {
  581. #ifdef _WIN32
  582. std::string output_path = object;
  583. cmSystemTools::ConvertToUnixSlashes(output_path);
  584. #else
  585. std::string const& output_path = object;
  586. #endif
  587. auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
  588. if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
  589. return false;
  590. }
  591. auto const& file_set = fileset_info_itr->second;
  592. return !cmFileSetVisibilityIsForInterface(file_set.Visibility);
  593. }
  594. bool cmDyndepCollation::IsBmiOnly(cmCxxModuleExportInfo const& exportInfo,
  595. std::string const& object)
  596. {
  597. #ifdef _WIN32
  598. auto object_path = object;
  599. cmSystemTools::ConvertToUnixSlashes(object_path);
  600. #else
  601. auto const& object_path = object;
  602. #endif
  603. auto fs = exportInfo.ObjectToFileSet.find(object_path);
  604. return (fs != exportInfo.ObjectToFileSet.end()) && fs->second.BmiOnly;
  605. }