cmDyndepCollation.cxx 22 KB

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