cmCMakePresetsGraphReadJSON.cxx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <functional>
  6. #include <map>
  7. #include <string>
  8. #include <unordered_set>
  9. #include <utility>
  10. #include <vector>
  11. #include <cm/memory>
  12. #include <cm/optional>
  13. #include <cmext/string_view>
  14. #include <cm3p/json/value.h>
  15. #include "cmCMakePresetsErrors.h"
  16. #include "cmCMakePresetsGraph.h"
  17. #include "cmCMakePresetsGraphInternal.h"
  18. #include "cmJSONHelpers.h"
  19. #include "cmJSONState.h"
  20. #include "cmStringAlgorithms.h"
  21. #include "cmSystemTools.h"
  22. #include "cmVersion.h"
  23. namespace {
  24. using CacheVariable = cmCMakePresetsGraph::CacheVariable;
  25. using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
  26. using BuildPreset = cmCMakePresetsGraph::BuildPreset;
  27. using TestPreset = cmCMakePresetsGraph::TestPreset;
  28. using PackagePreset = cmCMakePresetsGraph::PackagePreset;
  29. using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset;
  30. using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
  31. using JSONHelperBuilder = cmJSONHelperBuilder;
  32. using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult;
  33. using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander;
  34. using MacroExpanderVector = cmCMakePresetsGraphInternal::MacroExpanderVector;
  35. using cmCMakePresetsGraphInternal::BaseMacroExpander;
  36. using cmCMakePresetsGraphInternal::ExpandMacros;
  37. constexpr int MIN_VERSION = 1;
  38. constexpr int MAX_VERSION = 10;
  39. struct CMakeVersion
  40. {
  41. unsigned int Major = 0;
  42. unsigned int Minor = 0;
  43. unsigned int Patch = 0;
  44. };
  45. struct RootPresets
  46. {
  47. CMakeVersion CMakeMinimumRequired;
  48. std::vector<ConfigurePreset> ConfigurePresets;
  49. std::vector<BuildPreset> BuildPresets;
  50. std::vector<TestPreset> TestPresets;
  51. std::vector<PackagePreset> PackagePresets;
  52. std::vector<WorkflowPreset> WorkflowPresets;
  53. std::vector<std::string> Include;
  54. };
  55. std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition(
  56. std::unique_ptr<cmCMakePresetsGraph::Condition> condition)
  57. {
  58. auto retval = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
  59. retval->SubCondition = std::move(condition);
  60. return retval;
  61. }
  62. auto const ConditionStringHelper = JSONHelperBuilder::String();
  63. auto const ConditionBoolHelper = JSONHelperBuilder::Bool();
  64. auto const ConditionStringListHelper = JSONHelperBuilder::Vector<std::string>(
  65. cmCMakePresetsErrors::INVALID_CONDITION, ConditionStringHelper);
  66. auto const ConstConditionHelper =
  67. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::ConstCondition>(
  68. cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
  69. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  70. .Bind("value"_s, &cmCMakePresetsGraphInternal::ConstCondition::Value,
  71. ConditionBoolHelper, true);
  72. auto const EqualsConditionHelper =
  73. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::EqualsCondition>(
  74. cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
  75. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  76. .Bind("lhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Lhs,
  77. ConditionStringHelper, true)
  78. .Bind("rhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Rhs,
  79. ConditionStringHelper, true);
  80. auto const InListConditionHelper =
  81. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::InListCondition>(
  82. cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
  83. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  84. .Bind("string"_s, &cmCMakePresetsGraphInternal::InListCondition::String,
  85. ConditionStringHelper, true)
  86. .Bind("list"_s, &cmCMakePresetsGraphInternal::InListCondition::List,
  87. ConditionStringListHelper, true);
  88. auto const MatchesConditionHelper =
  89. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::MatchesCondition>(
  90. cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
  91. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  92. .Bind("string"_s, &cmCMakePresetsGraphInternal::MatchesCondition::String,
  93. ConditionStringHelper, true)
  94. .Bind("regex"_s, &cmCMakePresetsGraphInternal::MatchesCondition::Regex,
  95. ConditionStringHelper, true);
  96. bool SubConditionHelper(std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
  97. Json::Value const* value, cmJSONState* state);
  98. auto const ListConditionVectorHelper =
  99. JSONHelperBuilder::Vector<std::unique_ptr<cmCMakePresetsGraph::Condition>>(
  100. cmCMakePresetsErrors::INVALID_CONDITION, SubConditionHelper);
  101. auto const AnyAllOfConditionHelper =
  102. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::AnyAllOfCondition>(
  103. cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
  104. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  105. .Bind("conditions"_s,
  106. &cmCMakePresetsGraphInternal::AnyAllOfCondition::Conditions,
  107. ListConditionVectorHelper);
  108. auto const NotConditionHelper =
  109. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::NotCondition>(
  110. cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
  111. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  112. .Bind("condition"_s,
  113. &cmCMakePresetsGraphInternal::NotCondition::SubCondition,
  114. SubConditionHelper);
  115. bool ConditionHelper(std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
  116. Json::Value const* value, cmJSONState* state)
  117. {
  118. if (!value) {
  119. out.reset();
  120. return true;
  121. }
  122. if (value->isBool()) {
  123. auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
  124. c->Value = value->asBool();
  125. out = std::move(c);
  126. return true;
  127. }
  128. if (value->isNull()) {
  129. out = cm::make_unique<cmCMakePresetsGraphInternal::NullCondition>();
  130. return true;
  131. }
  132. if (value->isObject()) {
  133. if (!value->isMember("type")) {
  134. cmCMakePresetsErrors::INVALID_CONDITION(value, state);
  135. return false;
  136. }
  137. if (!(*value)["type"].isString()) {
  138. cmCMakePresetsErrors::INVALID_CONDITION(value, state);
  139. return false;
  140. }
  141. auto type = (*value)["type"].asString();
  142. if (type == "const") {
  143. auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
  144. CHECK_OK(ConstConditionHelper(*c, value, state));
  145. out = std::move(c);
  146. return true;
  147. }
  148. if (type == "equals" || type == "notEquals") {
  149. auto c = cm::make_unique<cmCMakePresetsGraphInternal::EqualsCondition>();
  150. CHECK_OK(EqualsConditionHelper(*c, value, state));
  151. out = std::move(c);
  152. if (type == "notEquals") {
  153. out = InvertCondition(std::move(out));
  154. }
  155. return true;
  156. }
  157. if (type == "inList" || type == "notInList") {
  158. auto c = cm::make_unique<cmCMakePresetsGraphInternal::InListCondition>();
  159. CHECK_OK(InListConditionHelper(*c, value, state));
  160. out = std::move(c);
  161. if (type == "notInList") {
  162. out = InvertCondition(std::move(out));
  163. }
  164. return true;
  165. }
  166. if (type == "matches" || type == "notMatches") {
  167. auto c =
  168. cm::make_unique<cmCMakePresetsGraphInternal::MatchesCondition>();
  169. CHECK_OK(MatchesConditionHelper(*c, value, state));
  170. out = std::move(c);
  171. if (type == "notMatches") {
  172. out = InvertCondition(std::move(out));
  173. }
  174. return true;
  175. }
  176. if (type == "anyOf" || type == "allOf") {
  177. auto c =
  178. cm::make_unique<cmCMakePresetsGraphInternal::AnyAllOfCondition>();
  179. c->StopValue = (type == "anyOf");
  180. CHECK_OK(AnyAllOfConditionHelper(*c, value, state));
  181. out = std::move(c);
  182. return true;
  183. }
  184. if (type == "not") {
  185. auto c = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
  186. CHECK_OK(NotConditionHelper(*c, value, state));
  187. out = std::move(c);
  188. return true;
  189. }
  190. }
  191. cmCMakePresetsErrors::INVALID_CONDITION(value, state);
  192. return false;
  193. }
  194. bool SubConditionHelper(std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
  195. Json::Value const* value, cmJSONState* state)
  196. {
  197. std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
  198. auto result = ConditionHelper(ptr, value, state);
  199. if (ptr && ptr->IsNull()) {
  200. cmCMakePresetsErrors::INVALID_CONDITION(value, state);
  201. return false;
  202. }
  203. out = std::move(ptr);
  204. return result;
  205. }
  206. bool EnvironmentHelper(cm::optional<std::string>& out,
  207. Json::Value const* value, cmJSONState* state)
  208. {
  209. if (!value || value->isNull()) {
  210. out = cm::nullopt;
  211. return true;
  212. }
  213. if (value->isString()) {
  214. out = value->asString();
  215. return true;
  216. }
  217. cmCMakePresetsErrors::INVALID_PRESET(value, state);
  218. return false;
  219. }
  220. auto const VersionIntHelper =
  221. JSONHelperBuilder::Int(cmCMakePresetsErrors::INVALID_VERSION);
  222. auto const VersionHelper = JSONHelperBuilder::Required<int>(
  223. cmCMakePresetsErrors::NO_VERSION, VersionIntHelper);
  224. auto const VersionRangeHelper = JSONHelperBuilder::Checked<int>(
  225. cmCMakePresetsErrors::UNRECOGNIZED_VERSION_RANGE(MIN_VERSION, MAX_VERSION),
  226. VersionHelper,
  227. [](int const v) -> bool { return v >= MIN_VERSION && v <= MAX_VERSION; });
  228. auto const RootVersionHelper =
  229. JSONHelperBuilder::Object<int>(cmCMakePresetsErrors::INVALID_ROOT_OBJECT)
  230. .Bind("version"_s, VersionRangeHelper, false);
  231. auto const CMakeVersionUIntHelper =
  232. JSONHelperBuilder::UInt(cmCMakePresetsErrors::INVALID_VERSION);
  233. auto const CMakeVersionHelper =
  234. JSONHelperBuilder::Object<CMakeVersion>(JsonErrors::INVALID_NAMED_OBJECT_KEY,
  235. false)
  236. .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
  237. .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
  238. .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
  239. auto const IncludeHelper =
  240. JSONHelperBuilder::String(cmCMakePresetsErrors::INVALID_INCLUDE);
  241. auto const IncludeVectorHelper = JSONHelperBuilder::Vector<std::string>(
  242. cmCMakePresetsErrors::INVALID_INCLUDE, IncludeHelper);
  243. auto const RootPresetsHelper =
  244. JSONHelperBuilder::Object<RootPresets>(
  245. cmCMakePresetsErrors::INVALID_ROOT_OBJECT, false)
  246. .Bind<int>("version"_s, nullptr, VersionHelper)
  247. .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
  248. cmCMakePresetsGraphInternal::ConfigurePresetsHelper, false)
  249. .Bind("buildPresets"_s, &RootPresets::BuildPresets,
  250. cmCMakePresetsGraphInternal::BuildPresetsHelper, false)
  251. .Bind("testPresets"_s, &RootPresets::TestPresets,
  252. cmCMakePresetsGraphInternal::TestPresetsHelper, false)
  253. .Bind("packagePresets"_s, &RootPresets::PackagePresets,
  254. cmCMakePresetsGraphInternal::PackagePresetsHelper, false)
  255. .Bind("workflowPresets"_s, &RootPresets::WorkflowPresets,
  256. cmCMakePresetsGraphInternal::WorkflowPresetsHelper, false)
  257. .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
  258. CMakeVersionHelper, false)
  259. .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
  260. .Bind<std::nullptr_t>("vendor"_s, nullptr,
  261. cmCMakePresetsGraphInternal::VendorHelper(
  262. cmCMakePresetsErrors::INVALID_ROOT),
  263. false)
  264. .Bind<std::nullptr_t>("$schema"_s, nullptr,
  265. cmCMakePresetsGraphInternal::SchemaHelper(), false);
  266. class EnvironmentMacroExpander : public MacroExpander
  267. {
  268. public:
  269. ExpandMacroResult operator()(std::string const& macroNamespace,
  270. std::string const& macroName,
  271. std::string& macroOut,
  272. int /*version*/) const override
  273. {
  274. if (macroNamespace == "penv") {
  275. if (macroName.empty()) {
  276. return ExpandMacroResult::Error;
  277. }
  278. if (cm::optional<std::string> value =
  279. cmSystemTools::GetEnvVar(macroName)) {
  280. macroOut += *value;
  281. }
  282. return ExpandMacroResult::Ok;
  283. }
  284. return ExpandMacroResult::Ignore;
  285. }
  286. };
  287. }
  288. namespace cmCMakePresetsGraphInternal {
  289. bool PresetStringHelper(std::string& out, Json::Value const* value,
  290. cmJSONState* state)
  291. {
  292. static auto const helper = JSONHelperBuilder::String();
  293. return helper(out, value, state);
  294. }
  295. bool PresetNameHelper(std::string& out, Json::Value const* value,
  296. cmJSONState* state)
  297. {
  298. if (!value || !value->isString() || value->asString().empty()) {
  299. cmCMakePresetsErrors::INVALID_PRESET_NAME(value, state);
  300. return false;
  301. }
  302. out = value->asString();
  303. return true;
  304. }
  305. bool PresetVectorStringHelper(std::vector<std::string>& out,
  306. Json::Value const* value, cmJSONState* state)
  307. {
  308. static auto const helper = JSONHelperBuilder::Vector<std::string>(
  309. cmCMakePresetsErrors::INVALID_PRESET,
  310. cmCMakePresetsGraphInternal::PresetStringHelper);
  311. return helper(out, value, state);
  312. }
  313. bool PresetBoolHelper(bool& out, Json::Value const* value, cmJSONState* state)
  314. {
  315. static auto const helper = JSONHelperBuilder::Bool();
  316. return helper(out, value, state);
  317. }
  318. bool PresetOptionalBoolHelper(cm::optional<bool>& out,
  319. Json::Value const* value, cmJSONState* state)
  320. {
  321. static auto const helper =
  322. JSONHelperBuilder::Optional<bool>(PresetBoolHelper);
  323. return helper(out, value, state);
  324. }
  325. bool PresetIntHelper(int& out, Json::Value const* value, cmJSONState* state)
  326. {
  327. static auto const helper = JSONHelperBuilder::Int();
  328. return helper(out, value, state);
  329. }
  330. bool PresetOptionalIntHelper(cm::optional<int>& out, Json::Value const* value,
  331. cmJSONState* state)
  332. {
  333. static auto const helper = JSONHelperBuilder::Optional<int>(PresetIntHelper);
  334. return helper(out, value, state);
  335. }
  336. bool PresetVectorIntHelper(std::vector<int>& out, Json::Value const* value,
  337. cmJSONState* state)
  338. {
  339. static auto const helper = JSONHelperBuilder::Vector<int>(
  340. cmCMakePresetsErrors::INVALID_PRESET, PresetIntHelper);
  341. return helper(out, value, state);
  342. }
  343. cmJSONHelper<std::nullptr_t> VendorHelper(ErrorGenerator const& error)
  344. {
  345. return [error](std::nullptr_t& /*out*/, Json::Value const* value,
  346. cmJSONState* state) -> bool {
  347. if (!value) {
  348. return true;
  349. }
  350. if (!value->isObject()) {
  351. error(value, state);
  352. return false;
  353. }
  354. return true;
  355. };
  356. }
  357. bool PresetConditionHelper(
  358. std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
  359. Json::Value const* value, cmJSONState* state)
  360. {
  361. std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
  362. auto result = ConditionHelper(ptr, value, state);
  363. out = std::move(ptr);
  364. return result;
  365. }
  366. bool PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
  367. Json::Value const* value,
  368. cmJSONState* state)
  369. {
  370. out.clear();
  371. if (!value) {
  372. return true;
  373. }
  374. if (value->isString()) {
  375. out.push_back(value->asString());
  376. return true;
  377. }
  378. return PresetVectorStringHelper(out, value, state);
  379. }
  380. bool EnvironmentMapHelper(
  381. std::map<std::string, cm::optional<std::string>>& out,
  382. Json::Value const* value, cmJSONState* state)
  383. {
  384. static auto const helper = JSONHelperBuilder::Map<cm::optional<std::string>>(
  385. cmCMakePresetsErrors::INVALID_PRESET, EnvironmentHelper);
  386. return helper(out, value, state);
  387. }
  388. cmJSONHelper<std::nullptr_t> SchemaHelper()
  389. {
  390. return [](std::nullptr_t&, Json::Value const*, cmJSONState*) -> bool {
  391. return true;
  392. };
  393. }
  394. }
  395. bool cmCMakePresetsGraph::ReadJSONFile(std::string const& filename,
  396. RootType rootType,
  397. ReadReason readReason,
  398. std::vector<File*>& inProgressFiles,
  399. File*& file, std::string& errMsg)
  400. {
  401. bool result;
  402. for (auto const& f : this->Files) {
  403. if (cmSystemTools::SameFile(filename, f->Filename)) {
  404. file = f.get();
  405. auto fileIt =
  406. std::find(inProgressFiles.begin(), inProgressFiles.end(), file);
  407. if (fileIt != inProgressFiles.end()) {
  408. cmCMakePresetsErrors::CYCLIC_INCLUDE(filename, &this->parseState);
  409. return false;
  410. }
  411. return true;
  412. }
  413. }
  414. Json::Value root;
  415. this->parseState = cmJSONState(filename, &root);
  416. if (!this->parseState.errors.empty()) {
  417. return false;
  418. }
  419. int v = 0;
  420. if ((result = RootVersionHelper(v, &root, &parseState)) != true) {
  421. return result;
  422. }
  423. // Support for build and test presets added in version 2.
  424. if (v < 2) {
  425. if (root.isMember("buildPresets")) {
  426. cmCMakePresetsErrors::BUILD_TEST_PRESETS_UNSUPPORTED(
  427. &root["buildPresets"], &this->parseState);
  428. return false;
  429. }
  430. if (root.isMember("testPresets")) {
  431. cmCMakePresetsErrors::BUILD_TEST_PRESETS_UNSUPPORTED(
  432. &root["testPresets"], &this->parseState);
  433. return false;
  434. }
  435. }
  436. // Support for package presets added in version 6.
  437. if (v < 6 && root.isMember("packagePresets")) {
  438. cmCMakePresetsErrors::PACKAGE_PRESETS_UNSUPPORTED(&root["packagePresets"],
  439. &this->parseState);
  440. return false;
  441. }
  442. // Support for workflow presets added in version 6.
  443. if (v < 6 && root.isMember("workflowPresets")) {
  444. cmCMakePresetsErrors::WORKFLOW_PRESETS_UNSUPPORTED(
  445. &root["workflowPresets"], &this->parseState);
  446. return false;
  447. }
  448. // Support for include added in version 4.
  449. if (v < 4 && root.isMember("include")) {
  450. cmCMakePresetsErrors::INCLUDE_UNSUPPORTED(&root["include"],
  451. &this->parseState);
  452. return false;
  453. }
  454. // Support for $schema added in version 8.
  455. if (v < 8 && root.isMember("$schema")) {
  456. cmCMakePresetsErrors::SCHEMA_UNSUPPORTED(&this->parseState);
  457. return false;
  458. }
  459. // Support for $comment added in version 10.
  460. this->parseState.allowComments = (v >= 10);
  461. RootPresets presets;
  462. if ((result = RootPresetsHelper(presets, &root, &parseState)) != true) {
  463. return result;
  464. }
  465. unsigned int currentMajor = cmVersion::GetMajorVersion();
  466. unsigned int currentMinor = cmVersion::GetMinorVersion();
  467. unsigned int currentPatch = cmVersion::GetPatchVersion();
  468. auto const& required = presets.CMakeMinimumRequired;
  469. if (required.Major > currentMajor) {
  470. ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
  471. "major", currentMajor, required.Major);
  472. error(&root["cmakeMinimumRequired"]["major"], &this->parseState);
  473. return false;
  474. }
  475. if (required.Major == currentMajor) {
  476. if (required.Minor > currentMinor) {
  477. ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
  478. "minor", currentMinor, required.Minor);
  479. error(&root["cmakeMinimumRequired"]["minor"], &this->parseState);
  480. return false;
  481. }
  482. if (required.Minor == currentMinor && required.Patch > currentPatch) {
  483. ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
  484. "patch", currentPatch, required.Patch);
  485. error(&root["cmakeMinimumRequired"]["patch"], &this->parseState);
  486. return false;
  487. }
  488. }
  489. auto filePtr = cm::make_unique<File>();
  490. file = filePtr.get();
  491. this->Files.emplace_back(std::move(filePtr));
  492. inProgressFiles.emplace_back(file);
  493. file->Filename = filename;
  494. file->Version = v;
  495. file->ReachableFiles.insert(file);
  496. for (auto& preset : presets.ConfigurePresets) {
  497. preset.OriginFile = file;
  498. if (preset.Name.empty()) {
  499. // No error, already handled by PresetNameHelper
  500. return false;
  501. }
  502. PresetPair<ConfigurePreset> presetPair;
  503. presetPair.Unexpanded = preset;
  504. presetPair.Expanded = cm::nullopt;
  505. if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) {
  506. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  507. return false;
  508. }
  509. // Support for installDir presets added in version 3.
  510. if (v < 3 && !preset.InstallDir.empty()) {
  511. cmCMakePresetsErrors::INSTALL_PREFIX_UNSUPPORTED(&root["installDir"],
  512. &this->parseState);
  513. return false;
  514. }
  515. // Support for conditions added in version 3.
  516. if (v < 3 && preset.ConditionEvaluator) {
  517. cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
  518. return false;
  519. }
  520. // Support for toolchainFile presets added in version 3.
  521. if (v < 3 && !preset.ToolchainFile.empty()) {
  522. cmCMakePresetsErrors::TOOLCHAIN_FILE_UNSUPPORTED(&this->parseState);
  523. return false;
  524. }
  525. // Support for trace presets added in version 7.
  526. if (v < 7 &&
  527. (preset.TraceMode.has_value() || preset.TraceFormat.has_value() ||
  528. !preset.TraceRedirect.empty() || !preset.TraceSource.empty())) {
  529. cmCMakePresetsErrors::TRACE_UNSUPPORTED(&this->parseState);
  530. return false;
  531. }
  532. // Support for graphviz argument added in version 10.
  533. if (v < 10 && !preset.GraphVizFile.empty()) {
  534. cmCMakePresetsErrors::GRAPHVIZ_FILE_UNSUPPORTED(&this->parseState);
  535. return false;
  536. }
  537. this->ConfigurePresetOrder.push_back(preset.Name);
  538. }
  539. for (auto& preset : presets.BuildPresets) {
  540. preset.OriginFile = file;
  541. if (preset.Name.empty()) {
  542. // No error, already handled by PresetNameHelper
  543. return false;
  544. }
  545. PresetPair<BuildPreset> presetPair;
  546. presetPair.Unexpanded = preset;
  547. presetPair.Expanded = cm::nullopt;
  548. if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
  549. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  550. return false;
  551. }
  552. // Support for conditions added in version 3.
  553. if (v < 3 && preset.ConditionEvaluator) {
  554. cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
  555. return false;
  556. }
  557. this->BuildPresetOrder.push_back(preset.Name);
  558. }
  559. for (auto& preset : presets.TestPresets) {
  560. preset.OriginFile = file;
  561. if (preset.Name.empty()) {
  562. // No error, already handled by PresetNameHelper
  563. return false;
  564. }
  565. PresetPair<TestPreset> presetPair;
  566. presetPair.Unexpanded = preset;
  567. presetPair.Expanded = cm::nullopt;
  568. if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
  569. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  570. return false;
  571. }
  572. // Support for conditions added in version 3.
  573. if (v < 3 && preset.ConditionEvaluator) {
  574. cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
  575. return false;
  576. }
  577. // Support for TestOutputTruncation added in version 5.
  578. if (v < 5 && preset.Output && preset.Output->TestOutputTruncation) {
  579. cmCMakePresetsErrors::TEST_OUTPUT_TRUNCATION_UNSUPPORTED(
  580. &this->parseState);
  581. return false;
  582. }
  583. // Support for outputJUnitFile added in version 6.
  584. if (v < 6 && preset.Output && !preset.Output->OutputJUnitFile.empty()) {
  585. cmCMakePresetsErrors::CTEST_JUNIT_UNSUPPORTED(&this->parseState);
  586. return false;
  587. }
  588. this->TestPresetOrder.push_back(preset.Name);
  589. }
  590. for (auto& preset : presets.PackagePresets) {
  591. preset.OriginFile = file;
  592. if (preset.Name.empty()) {
  593. // No error, already handled by PresetNameHelper
  594. return false;
  595. }
  596. PresetPair<PackagePreset> presetPair;
  597. presetPair.Unexpanded = preset;
  598. presetPair.Expanded = cm::nullopt;
  599. if (!this->PackagePresets.emplace(preset.Name, presetPair).second) {
  600. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  601. return false;
  602. }
  603. // Support for conditions added in version 3, but this requires version 5
  604. // already, so no action needed.
  605. this->PackagePresetOrder.push_back(preset.Name);
  606. }
  607. for (auto& preset : presets.WorkflowPresets) {
  608. preset.OriginFile = file;
  609. if (preset.Name.empty()) {
  610. // No error, already handled by PresetNameHelper
  611. return false;
  612. }
  613. PresetPair<WorkflowPreset> presetPair;
  614. presetPair.Unexpanded = preset;
  615. presetPair.Expanded = cm::nullopt;
  616. if (!this->WorkflowPresets.emplace(preset.Name, presetPair).second) {
  617. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  618. return false;
  619. }
  620. // Support for conditions added in version 3, but this requires version 6
  621. // already, so no action needed.
  622. this->WorkflowPresetOrder.push_back(preset.Name);
  623. }
  624. auto const includeFile = [this, &inProgressFiles,
  625. file](std::string const& include,
  626. RootType rootType2, ReadReason readReason2,
  627. std::string& FailureMessage) -> bool {
  628. bool r;
  629. File* includedFile;
  630. if ((r =
  631. this->ReadJSONFile(include, rootType2, readReason2, inProgressFiles,
  632. includedFile, FailureMessage)) != true) {
  633. return r;
  634. }
  635. file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
  636. includedFile->ReachableFiles.end());
  637. return true;
  638. };
  639. MacroExpanderVector macroExpanders{};
  640. if (v >= 9) {
  641. macroExpanders.push_back(
  642. cm::make_unique<BaseMacroExpander>(*this, filename));
  643. }
  644. macroExpanders.push_back(cm::make_unique<EnvironmentMacroExpander>());
  645. for (Json::ArrayIndex i = 0; i < presets.Include.size(); ++i) {
  646. auto include = presets.Include[i];
  647. // Support for macro expansion in includes added in version 7
  648. if (v >= 7) {
  649. if (ExpandMacros(include, macroExpanders, v) != ExpandMacroResult::Ok) {
  650. cmCMakePresetsErrors::INVALID_INCLUDE(&root["include"][i],
  651. &this->parseState);
  652. return false;
  653. }
  654. }
  655. if (!cmSystemTools::FileIsFullPath(include)) {
  656. auto directory = cmSystemTools::GetFilenamePath(filename);
  657. include = cmStrCat(directory, '/', include);
  658. }
  659. if ((result = includeFile(include, rootType, ReadReason::Included,
  660. errMsg)) != true) {
  661. return result;
  662. }
  663. }
  664. if (rootType == RootType::User && readReason == ReadReason::Root) {
  665. auto cmakePresetsFilename = GetFilename(this->SourceDir);
  666. if (cmSystemTools::FileExists(cmakePresetsFilename)) {
  667. if ((result = includeFile(cmakePresetsFilename, RootType::Project,
  668. ReadReason::Root, errMsg)) != true) {
  669. return result;
  670. }
  671. }
  672. }
  673. inProgressFiles.pop_back();
  674. return true;
  675. }