cmDyndepCollation.cxx 23 KB

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