cmPackageInfoReader.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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 "cmPackageInfoReader.h"
  4. #include <initializer_list>
  5. #include <limits>
  6. #include <unordered_map>
  7. #include <utility>
  8. #include <cmext/string_view>
  9. #include <cm3p/json/reader.h>
  10. #include <cm3p/json/value.h>
  11. #include <cm3p/json/version.h>
  12. #include "cmsys/FStream.hxx"
  13. #include "cmsys/RegularExpression.hxx"
  14. #include "cmExecutionStatus.h"
  15. #include "cmListFileCache.h"
  16. #include "cmMakefile.h"
  17. #include "cmMessageType.h"
  18. #include "cmStringAlgorithms.h"
  19. #include "cmSystemTools.h"
  20. #include "cmTarget.h"
  21. namespace {
  22. // Map of CPS language names to CMake language name. Case insensitivity is
  23. // achieved by converting the CPS value to lower case, so keys in this map must
  24. // be lower case.
  25. std::unordered_map<std::string, std::string> Languages = {
  26. // clang-format off
  27. { "c", "C" },
  28. { "c++", "CXX" },
  29. { "cpp", "CXX" },
  30. { "cxx", "CXX" },
  31. { "objc", "OBJC" },
  32. { "objc++", "OBJCXX" },
  33. { "objcpp", "OBJCXX" },
  34. { "objcxx", "OBJCXX" },
  35. { "swift", "swift" },
  36. { "hip", "HIP" },
  37. { "cuda", "CUDA" },
  38. { "ispc", "ISPC" },
  39. { "c#", "CSharp" },
  40. { "csharp", "CSharp" },
  41. { "fortran", "Fortran" },
  42. // clang-format on
  43. };
  44. enum LanguageGlobOption
  45. {
  46. DisallowGlob,
  47. AllowGlob,
  48. };
  49. cm::string_view MapLanguage(cm::string_view lang,
  50. LanguageGlobOption glob = AllowGlob)
  51. {
  52. if (glob == AllowGlob && lang == "*"_s) {
  53. return "*"_s;
  54. }
  55. auto const li = Languages.find(cmSystemTools::LowerCase(lang));
  56. if (li != Languages.end()) {
  57. return li->second;
  58. }
  59. return {};
  60. }
  61. std::string GetRealPath(std::string const& path)
  62. {
  63. return cmSystemTools::GetRealPath(path);
  64. }
  65. std::string GetRealDir(std::string const& path)
  66. {
  67. return cmSystemTools::GetFilenamePath(cmSystemTools::GetRealPath(path));
  68. }
  69. Json::Value ReadJson(std::string const& fileName)
  70. {
  71. // Open the specified file.
  72. cmsys::ifstream file(fileName.c_str(), std::ios::in | std::ios::binary);
  73. if (!file) {
  74. #if JSONCPP_VERSION_HEXA < 0x01070300
  75. return Json::Value::null;
  76. #else
  77. return Json::Value::nullSingleton();
  78. #endif
  79. }
  80. // Read file content and translate JSON.
  81. Json::Value data;
  82. Json::CharReaderBuilder builder;
  83. builder["collectComments"] = false;
  84. if (!Json::parseFromStream(builder, file, &data, nullptr)) {
  85. #if JSONCPP_VERSION_HEXA < 0x01070300
  86. return Json::Value::null;
  87. #else
  88. return Json::Value::nullSingleton();
  89. #endif
  90. }
  91. return data;
  92. }
  93. bool CheckSchemaVersion(Json::Value const& data)
  94. {
  95. std::string const& version = data["cps_version"].asString();
  96. // Check that a valid version is specified.
  97. if (version.empty()) {
  98. return false;
  99. }
  100. // Check that we understand this version.
  101. return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
  102. version, "0.13") &&
  103. cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, version, "1");
  104. // TODO Eventually this probably needs to return the version tuple, and
  105. // should share code with cmPackageInfoReader::ParseVersion.
  106. }
  107. bool ComparePathSuffix(std::string const& path, std::string const& suffix)
  108. {
  109. std::string const& tail = path.substr(path.size() - suffix.size());
  110. return cmSystemTools::ComparePath(tail, suffix);
  111. }
  112. std::string DeterminePrefix(std::string const& filepath,
  113. Json::Value const& data)
  114. {
  115. // First check if an absolute prefix was supplied.
  116. std::string prefix = data["prefix"].asString();
  117. if (!prefix.empty()) {
  118. // Ensure that the specified prefix is valid.
  119. if (cmsys::SystemTools::FileIsFullPath(prefix) &&
  120. cmsys::SystemTools::FileIsDirectory(prefix)) {
  121. cmSystemTools::ConvertToUnixSlashes(prefix);
  122. return prefix;
  123. }
  124. // The specified absolute prefix is not valid.
  125. return {};
  126. }
  127. // Get and validate prefix-relative path.
  128. std::string relPath = data["cps_path"].asString();
  129. cmSystemTools::ConvertToUnixSlashes(relPath);
  130. if (relPath.empty() || !cmHasLiteralPrefix(relPath, "@prefix@/")) {
  131. // The relative prefix is not valid.
  132. return {};
  133. }
  134. relPath = relPath.substr(8);
  135. // Get directory portion of the absolute path.
  136. std::string const& absPath = cmSystemTools::GetFilenamePath(filepath);
  137. if (ComparePathSuffix(absPath, relPath)) {
  138. return absPath.substr(0, absPath.size() - relPath.size());
  139. }
  140. for (auto* const f : { GetRealPath, GetRealDir }) {
  141. std::string const& tmpPath = (*f)(absPath);
  142. if (!cmSystemTools::ComparePath(tmpPath, absPath) &&
  143. ComparePathSuffix(tmpPath, relPath)) {
  144. return tmpPath.substr(0, tmpPath.size() - relPath.size());
  145. }
  146. }
  147. return {};
  148. }
  149. // Extract key name from value iterator as string_view.
  150. cm::string_view IterKey(Json::Value::const_iterator const& iter)
  151. {
  152. char const* end;
  153. char const* const start = iter.memberName(&end);
  154. return { start, static_cast<std::string::size_type>(end - start) };
  155. }
  156. // Get list-of-strings value from object.
  157. std::vector<std::string> ReadList(Json::Value const& arr)
  158. {
  159. std::vector<std::string> result;
  160. if (arr.isArray()) {
  161. for (Json::Value const& val : arr) {
  162. if (val.isString()) {
  163. result.push_back(val.asString());
  164. }
  165. }
  166. }
  167. return result;
  168. }
  169. std::vector<std::string> ReadList(Json::Value const& data, char const* key)
  170. {
  171. return ReadList(data[key]);
  172. }
  173. std::string NormalizeTargetName(std::string const& name,
  174. std::string const& context)
  175. {
  176. if (cmHasLiteralPrefix(name, ":")) {
  177. return cmStrCat(context, name);
  178. }
  179. std::string::size_type const n = name.find_first_of(':');
  180. if (n != std::string::npos) {
  181. cm::string_view v{ name };
  182. return cmStrCat(v.substr(0, n), ':', v.substr(n));
  183. }
  184. return name;
  185. }
  186. void AppendProperty(cmMakefile* makefile, cmTarget* target,
  187. cm::string_view property, cm::string_view configuration,
  188. std::string const& value)
  189. {
  190. std::string fullprop;
  191. if (configuration.empty()) {
  192. fullprop = cmStrCat("INTERFACE_"_s, property);
  193. } else {
  194. fullprop = cmStrCat("INTERFACE_"_s, property, '_',
  195. cmSystemTools::UpperCase(configuration));
  196. }
  197. target->AppendProperty(fullprop, value, makefile->GetBacktrace());
  198. }
  199. template <typename Transform>
  200. void AppendLanguageProperties(cmMakefile* makefile, cmTarget* target,
  201. cm::string_view property,
  202. cm::string_view configuration,
  203. Json::Value const& data, char const* key,
  204. Transform transform)
  205. {
  206. Json::Value const& value = data[key];
  207. if (value.isArray()) {
  208. for (std::string v : ReadList(value)) {
  209. AppendProperty(makefile, target, property, configuration,
  210. transform(std::move(v)));
  211. }
  212. } else if (value.isObject()) {
  213. for (auto vi = value.begin(), ve = value.end(); vi != ve; ++vi) {
  214. cm::string_view const originalLang = IterKey(vi);
  215. cm::string_view const lang = MapLanguage(originalLang);
  216. if (lang.empty()) {
  217. makefile->IssueMessage(MessageType::WARNING,
  218. cmStrCat(R"(ignoring unknown language ")"_s,
  219. originalLang, R"(" in )"_s, key,
  220. " for "_s, target->GetName()));
  221. continue;
  222. }
  223. if (lang == "*"_s) {
  224. for (std::string v : ReadList(*vi)) {
  225. AppendProperty(makefile, target, property, configuration,
  226. transform(std::move(v)));
  227. }
  228. } else {
  229. for (std::string v : ReadList(*vi)) {
  230. v = cmStrCat("$<$<COMPILE_LANGUAGE:"_s, lang, ">:"_s,
  231. transform(std::move(v)), '>');
  232. AppendProperty(makefile, target, property, configuration, v);
  233. }
  234. }
  235. }
  236. }
  237. }
  238. void AddCompileFeature(cmMakefile* makefile, cmTarget* target,
  239. cm::string_view configuration, std::string const& value)
  240. {
  241. auto reLanguageLevel = []() -> cmsys::RegularExpression {
  242. static cmsys::RegularExpression re{ "^[Cc]([+][+])?([0-9][0-9])$" };
  243. return re;
  244. }();
  245. if (reLanguageLevel.find(value)) {
  246. std::string::size_type const n = reLanguageLevel.end() - 2;
  247. cm::string_view const featurePrefix = (n == 3 ? "cxx_std_"_s : "c_std_"_s);
  248. if (configuration.empty()) {
  249. AppendProperty(makefile, target, "COMPILE_FEATURES"_s, {},
  250. cmStrCat(featurePrefix, value.substr(n)));
  251. } else {
  252. std::string const& feature =
  253. cmStrCat("$<$<CONFIG:"_s, configuration, ">:"_s, featurePrefix,
  254. value.substr(n), '>');
  255. AppendProperty(makefile, target, "COMPILE_FEATURES"_s, {}, feature);
  256. }
  257. } else if (cmStrCaseEq(value, "gnu"_s)) {
  258. // Not implemented in CMake at this time
  259. } else if (cmStrCaseEq(value, "threads"_s)) {
  260. AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration,
  261. "Threads::Threads");
  262. }
  263. }
  264. void AddLinkFeature(cmMakefile* makefile, cmTarget* target,
  265. cm::string_view configuration, std::string const& value)
  266. {
  267. if (cmStrCaseEq(value, "thread"_s)) {
  268. AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration,
  269. "Threads::Threads");
  270. }
  271. }
  272. std::string BuildDefinition(std::string const& name, Json::Value const& value)
  273. {
  274. if (!value.isNull() && value.isConvertibleTo(Json::stringValue)) {
  275. return cmStrCat(name, '=', value.asString());
  276. }
  277. return name;
  278. }
  279. void AddDefinition(cmMakefile* makefile, cmTarget* target,
  280. cm::string_view configuration,
  281. std::string const& definition)
  282. {
  283. AppendProperty(makefile, target, "COMPILE_DEFINITIONS"_s, configuration,
  284. definition);
  285. }
  286. using DefinitionLanguageMap = std::map<cm::string_view, Json::Value>;
  287. using DefinitionsMap = std::map<std::string, DefinitionLanguageMap>;
  288. void AddDefinitions(cmMakefile* makefile, cmTarget* target,
  289. cm::string_view configuration,
  290. DefinitionsMap const& definitions)
  291. {
  292. for (auto const& di : definitions) {
  293. auto const& g = di.second.find("*"_s);
  294. if (g != di.second.end()) {
  295. std::string const& def = BuildDefinition(di.first, g->second);
  296. if (di.second.size() == 1) {
  297. // Only the non-language-specific definition exists.
  298. AddDefinition(makefile, target, configuration, def);
  299. continue;
  300. }
  301. // Create a genex to apply this definition to all languages except
  302. // those that override it.
  303. std::vector<cm::string_view> excludedLanguages;
  304. for (auto const& li : di.second) {
  305. if (li.first != "*"_s) {
  306. excludedLanguages.emplace_back(li.first);
  307. }
  308. }
  309. AddDefinition(makefile, target, configuration,
  310. cmStrCat("$<$<NOT:$<COMPILE_LANGUAGE:"_s,
  311. cmJoin(excludedLanguages, ","_s), ">>:"_s, def,
  312. '>'));
  313. }
  314. // Add language-specific definitions.
  315. for (auto const& li : di.second) {
  316. if (li.first != "*"_s) {
  317. AddDefinition(makefile, target, configuration,
  318. cmStrCat("$<$<COMPILE_LANGUAGE:"_s, li.first, ">:"_s,
  319. BuildDefinition(di.first, li.second), '>'));
  320. }
  321. }
  322. }
  323. }
  324. } // namespace
  325. std::unique_ptr<cmPackageInfoReader> cmPackageInfoReader::Read(
  326. std::string const& path, cmPackageInfoReader const* parent)
  327. {
  328. // Read file and perform some basic validation:
  329. // - the input is valid JSON
  330. // - the input is a JSON object
  331. // - the input has a "cps_version" that we (in theory) know how to parse
  332. Json::Value data = ReadJson(path);
  333. if (!data.isObject() || (!parent && !CheckSchemaVersion(data))) {
  334. return nullptr;
  335. }
  336. // - the input has a "name" attribute that is a non-empty string
  337. Json::Value const& name = data["name"];
  338. if (!name.isString() || name.empty()) {
  339. return nullptr;
  340. }
  341. // - the input has a "components" attribute that is a JSON object
  342. if (!data["components"].isObject()) {
  343. return nullptr;
  344. }
  345. std::string prefix = (parent ? parent->Prefix : DeterminePrefix(path, data));
  346. if (prefix.empty()) {
  347. return nullptr;
  348. }
  349. // Seems sane enough to hand back to the caller.
  350. std::unique_ptr<cmPackageInfoReader> reader{ new cmPackageInfoReader };
  351. reader->Data = std::move(data);
  352. reader->Prefix = std::move(prefix);
  353. reader->Path = path;
  354. // Determine other information we need to know immediately, or (if this is
  355. // a supplemental reader) copy from the parent.
  356. if (parent) {
  357. reader->ComponentTargets = parent->ComponentTargets;
  358. reader->DefaultConfigurations = parent->DefaultConfigurations;
  359. } else {
  360. reader->DefaultConfigurations = ReadList(reader->Data, "configurations");
  361. }
  362. return reader;
  363. }
  364. std::string cmPackageInfoReader::GetName() const
  365. {
  366. return this->Data["name"].asString();
  367. }
  368. cm::optional<std::string> cmPackageInfoReader::GetVersion() const
  369. {
  370. Json::Value const& version = this->Data["version"];
  371. if (version.isString()) {
  372. return version.asString();
  373. }
  374. return cm::nullopt;
  375. }
  376. std::vector<unsigned> cmPackageInfoReader::ParseVersion() const
  377. {
  378. // Check that we have a version.
  379. cm::optional<std::string> const& version = this->GetVersion();
  380. if (!version) {
  381. return {};
  382. }
  383. std::vector<unsigned> result;
  384. cm::string_view remnant{ *version };
  385. // Check if we know how to parse the version.
  386. Json::Value const& schema = this->Data["version_schema"];
  387. if (schema.isNull() || cmStrCaseEq(schema.asString(), "simple"_s)) {
  388. // Keep going until we run out of parts.
  389. while (!remnant.empty()) {
  390. std::string::size_type n = remnant.find('.');
  391. cm::string_view part = remnant.substr(0, n);
  392. if (n == std::string::npos) {
  393. remnant = {};
  394. } else {
  395. remnant = remnant.substr(n + 1);
  396. }
  397. unsigned long const value = std::stoul(std::string{ part }, &n);
  398. if (n == 0 || value > std::numeric_limits<unsigned>::max()) {
  399. // The part was not a valid number or is too big.
  400. return {};
  401. }
  402. result.push_back(static_cast<unsigned>(value));
  403. }
  404. }
  405. return result;
  406. }
  407. std::vector<cmPackageRequirement> cmPackageInfoReader::GetRequirements() const
  408. {
  409. std::vector<cmPackageRequirement> requirements;
  410. auto const& requirementObjects = this->Data["requires"];
  411. for (auto ri = requirementObjects.begin(), re = requirementObjects.end();
  412. ri != re; ++ri) {
  413. cmPackageRequirement r{ ri.name(), (*ri)["version"].asString(),
  414. ReadList(*ri, "components"),
  415. ReadList(*ri, "hints") };
  416. requirements.emplace_back(std::move(r));
  417. }
  418. return requirements;
  419. }
  420. std::vector<std::string> cmPackageInfoReader::GetComponentNames() const
  421. {
  422. std::vector<std::string> componentNames;
  423. Json::Value const& components = this->Data["components"];
  424. for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
  425. componentNames.emplace_back(ci.name());
  426. }
  427. return componentNames;
  428. }
  429. std::string cmPackageInfoReader::ResolvePath(std::string path) const
  430. {
  431. cmSystemTools::ConvertToUnixSlashes(path);
  432. if (cmHasPrefix(path, "@prefix@"_s)) {
  433. return cmStrCat(this->Prefix, path.substr(8));
  434. }
  435. if (!cmSystemTools::FileIsFullPath(path)) {
  436. return cmStrCat(cmSystemTools::GetFilenamePath(this->Path), '/', path);
  437. }
  438. return path;
  439. }
  440. void cmPackageInfoReader::SetOptionalProperty(cmTarget* target,
  441. cm::string_view property,
  442. cm::string_view configuration,
  443. Json::Value const& value) const
  444. {
  445. if (!value.isNull()) {
  446. std::string fullprop;
  447. if (configuration.empty()) {
  448. fullprop = cmStrCat("IMPORTED_"_s, property);
  449. } else {
  450. fullprop = cmStrCat("IMPORTED_"_s, property, '_',
  451. cmSystemTools::UpperCase(configuration));
  452. }
  453. target->SetProperty(fullprop, this->ResolvePath(value.asString()));
  454. }
  455. }
  456. void cmPackageInfoReader::SetTargetProperties(
  457. cmMakefile* makefile, cmTarget* target, Json::Value const& data,
  458. std::string const& package, cm::string_view configuration) const
  459. {
  460. // Add configuration (if applicable).
  461. if (!configuration.empty()) {
  462. target->AppendProperty("IMPORTED_CONFIGURATIONS",
  463. cmSystemTools::UpperCase(configuration),
  464. makefile->GetBacktrace());
  465. }
  466. // Add compile and link features.
  467. for (std::string const& def : ReadList(data, "compile_features")) {
  468. AddCompileFeature(makefile, target, configuration, def);
  469. }
  470. for (std::string const& def : ReadList(data, "link_features")) {
  471. AddLinkFeature(makefile, target, configuration, def);
  472. }
  473. // Add compile definitions.
  474. Json::Value const& defs = data["definitions"];
  475. DefinitionsMap definitionsMap;
  476. for (auto ldi = defs.begin(), lde = defs.end(); ldi != lde; ++ldi) {
  477. cm::string_view const originalLang = IterKey(ldi);
  478. cm::string_view const lang = MapLanguage(originalLang);
  479. if (lang.empty()) {
  480. makefile->IssueMessage(
  481. MessageType::WARNING,
  482. cmStrCat(R"(ignoring unknown language ")"_s, originalLang,
  483. R"(" in definitions for )"_s, target->GetName()));
  484. continue;
  485. }
  486. for (auto di = ldi->begin(), de = ldi->end(); di != de; ++di) {
  487. definitionsMap[di.name()].emplace(lang, *di);
  488. }
  489. }
  490. AddDefinitions(makefile, target, configuration, definitionsMap);
  491. // Add include directories.
  492. AppendLanguageProperties(makefile, target, "INCLUDE_DIRECTORIES"_s,
  493. configuration, data, "includes",
  494. [this](std::string p) -> std::string {
  495. return this->ResolvePath(std::move(p));
  496. });
  497. // Add link name/location(s).
  498. this->SetOptionalProperty(target, "LOCATION"_s, configuration,
  499. data["location"]);
  500. this->SetOptionalProperty(target, "IMPLIB"_s, configuration,
  501. data["link_location"]);
  502. this->SetOptionalProperty(target, "SONAME"_s, configuration,
  503. data["link_name"]);
  504. // Add link languages.
  505. for (std::string const& originalLang : ReadList(data, "link_languages")) {
  506. cm::string_view const lang = MapLanguage(originalLang, DisallowGlob);
  507. if (!lang.empty()) {
  508. AppendProperty(makefile, target, "LINK_LANGUAGES"_s, configuration,
  509. std::string{ lang });
  510. }
  511. }
  512. // Add transitive dependencies.
  513. for (std::string const& dep : ReadList(data, "requires")) {
  514. AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration,
  515. NormalizeTargetName(dep, package));
  516. }
  517. for (std::string const& dep : ReadList(data, "link_requires")) {
  518. std::string const& lib =
  519. cmStrCat("$<LINK_ONLY:"_s, NormalizeTargetName(dep, package), '>');
  520. AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration, lib);
  521. }
  522. }
  523. cmTarget* cmPackageInfoReader::AddLibraryComponent(
  524. cmMakefile* makefile, cmStateEnums::TargetType type, std::string const& name,
  525. Json::Value const& data, std::string const& package) const
  526. {
  527. // Create the imported target.
  528. cmTarget* const target = makefile->AddImportedTarget(name, type, false);
  529. // Set target properties.
  530. this->SetTargetProperties(makefile, target, data, package, {});
  531. auto const& cfgData = data["configurations"];
  532. for (auto ci = cfgData.begin(), ce = cfgData.end(); ci != ce; ++ci) {
  533. this->SetTargetProperties(makefile, target, *ci, package, IterKey(ci));
  534. }
  535. // Set default configurations.
  536. if (!this->DefaultConfigurations.empty()) {
  537. target->SetProperty("IMPORTED_CONFIGURATIONS",
  538. cmJoin(this->DefaultConfigurations, ";"_s));
  539. }
  540. return target;
  541. }
  542. bool cmPackageInfoReader::ImportTargets(cmMakefile* makefile,
  543. cmExecutionStatus& status)
  544. {
  545. std::string const& package = this->GetName();
  546. // Read components.
  547. Json::Value const& components = this->Data["components"];
  548. for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
  549. cm::string_view const& name = IterKey(ci);
  550. std::string const& type =
  551. cmSystemTools::LowerCase((*ci)["type"].asString());
  552. // Get and validate full target name.
  553. std::string const& fullName = cmStrCat(package, "::"_s, name);
  554. {
  555. std::string msg;
  556. if (!makefile->EnforceUniqueName(fullName, msg)) {
  557. status.SetError(msg);
  558. return false;
  559. }
  560. }
  561. cmTarget* target = nullptr;
  562. if (type == "symbolic"_s) {
  563. // TODO
  564. } else if (type == "dylib"_s) {
  565. target = this->AddLibraryComponent(
  566. makefile, cmStateEnums::SHARED_LIBRARY, fullName, *ci, package);
  567. } else if (type == "module"_s) {
  568. target = this->AddLibraryComponent(
  569. makefile, cmStateEnums::MODULE_LIBRARY, fullName, *ci, package);
  570. } else if (type == "archive"_s) {
  571. target = this->AddLibraryComponent(
  572. makefile, cmStateEnums::STATIC_LIBRARY, fullName, *ci, package);
  573. } else if (type == "interface"_s) {
  574. target = this->AddLibraryComponent(
  575. makefile, cmStateEnums::INTERFACE_LIBRARY, fullName, *ci, package);
  576. } else {
  577. makefile->IssueMessage(MessageType::WARNING,
  578. cmStrCat(R"(component ")"_s, fullName,
  579. R"(" has unknown type ")"_s, type,
  580. R"(" and was not imported)"_s));
  581. }
  582. if (target) {
  583. this->ComponentTargets.emplace(std::string{ name }, target);
  584. }
  585. }
  586. // Read default components.
  587. std::vector<std::string> const& defaultComponents =
  588. ReadList(this->Data, "default_components");
  589. if (!defaultComponents.empty()) {
  590. std::string msg;
  591. if (!makefile->EnforceUniqueName(package, msg)) {
  592. status.SetError(msg);
  593. return false;
  594. }
  595. cmTarget* const target = makefile->AddImportedTarget(
  596. package, cmStateEnums::INTERFACE_LIBRARY, false);
  597. for (std::string const& name : defaultComponents) {
  598. std::string const& fullName = cmStrCat(package, "::"_s, name);
  599. AppendProperty(makefile, target, "LINK_LIBRARIES"_s, {}, fullName);
  600. }
  601. }
  602. return true;
  603. }
  604. bool cmPackageInfoReader::ImportTargetConfigurations(
  605. cmMakefile* makefile, cmExecutionStatus& status) const
  606. {
  607. std::string const& configuration = this->Data["configuration"].asString();
  608. if (configuration.empty()) {
  609. makefile->IssueMessage(MessageType::WARNING,
  610. cmStrCat("supplemental file "_s, this->Path,
  611. " does not specify a configuration"_s));
  612. return true;
  613. }
  614. std::string const& package = this->GetName();
  615. Json::Value const& components = this->Data["components"];
  616. for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
  617. // Get component name and look up target.
  618. cm::string_view const& name = IterKey(ci);
  619. auto const& ti = this->ComponentTargets.find(std::string{ name });
  620. if (ti == this->ComponentTargets.end()) {
  621. status.SetError(cmStrCat("component "_s, name, " was not found"_s));
  622. return false;
  623. }
  624. // Read supplemental data for component.
  625. this->SetTargetProperties(makefile, ti->second, *ci, package,
  626. configuration);
  627. }
  628. return true;
  629. }