cmCMakePresetsGraphReadJSON.cxx 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  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 = 11;
  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 PresetUIntHelper(unsigned int& out, Json::Value const* value,
  337. cmJSONState* state)
  338. {
  339. static auto const helper = JSONHelperBuilder::UInt();
  340. return helper(out, value, state);
  341. }
  342. bool PresetOptionalUIntHelper(cm::optional<unsigned int>& out,
  343. Json::Value const* value, cmJSONState* state)
  344. {
  345. static auto const helper =
  346. JSONHelperBuilder::Optional<unsigned int>(PresetUIntHelper);
  347. return helper(out, value, state);
  348. }
  349. bool PresetVectorIntHelper(std::vector<int>& out, Json::Value const* value,
  350. cmJSONState* state)
  351. {
  352. static auto const helper = JSONHelperBuilder::Vector<int>(
  353. cmCMakePresetsErrors::INVALID_PRESET, PresetIntHelper);
  354. return helper(out, value, state);
  355. }
  356. cmJSONHelper<std::nullptr_t> VendorHelper(ErrorGenerator const& error)
  357. {
  358. return [error](std::nullptr_t& /*out*/, Json::Value const* value,
  359. cmJSONState* state) -> bool {
  360. if (!value) {
  361. return true;
  362. }
  363. if (!value->isObject()) {
  364. error(value, state);
  365. return false;
  366. }
  367. return true;
  368. };
  369. }
  370. bool PresetConditionHelper(
  371. std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
  372. Json::Value const* value, cmJSONState* state)
  373. {
  374. std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
  375. auto result = ConditionHelper(ptr, value, state);
  376. out = std::move(ptr);
  377. return result;
  378. }
  379. bool PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
  380. Json::Value const* value,
  381. cmJSONState* state)
  382. {
  383. out.clear();
  384. if (!value) {
  385. return true;
  386. }
  387. if (value->isString()) {
  388. out.push_back(value->asString());
  389. return true;
  390. }
  391. return PresetVectorStringHelper(out, value, state);
  392. }
  393. bool EnvironmentMapHelper(
  394. std::map<std::string, cm::optional<std::string>>& out,
  395. Json::Value const* value, cmJSONState* state)
  396. {
  397. static auto const helper = JSONHelperBuilder::Map<cm::optional<std::string>>(
  398. cmCMakePresetsErrors::INVALID_PRESET, EnvironmentHelper);
  399. return helper(out, value, state);
  400. }
  401. cmJSONHelper<std::nullptr_t> SchemaHelper()
  402. {
  403. return [](std::nullptr_t&, Json::Value const*, cmJSONState*) -> bool {
  404. return true;
  405. };
  406. }
  407. }
  408. bool cmCMakePresetsGraph::ReadJSONFile(std::string const& filename,
  409. RootType rootType,
  410. ReadReason readReason,
  411. std::vector<File*>& inProgressFiles,
  412. File*& file, std::string& errMsg)
  413. {
  414. bool result;
  415. for (auto const& f : this->Files) {
  416. if (cmSystemTools::SameFile(filename, f->Filename)) {
  417. file = f.get();
  418. auto fileIt =
  419. std::find(inProgressFiles.begin(), inProgressFiles.end(), file);
  420. if (fileIt != inProgressFiles.end()) {
  421. cmCMakePresetsErrors::CYCLIC_INCLUDE(filename, &this->parseState);
  422. return false;
  423. }
  424. return true;
  425. }
  426. }
  427. Json::Value root;
  428. this->parseState = cmJSONState(filename, &root);
  429. if (!this->parseState.errors.empty()) {
  430. return false;
  431. }
  432. int v = 0;
  433. if ((result = RootVersionHelper(v, &root, &parseState)) != true) {
  434. return result;
  435. }
  436. // Support for build and test presets added in version 2.
  437. if (v < 2) {
  438. if (root.isMember("buildPresets")) {
  439. cmCMakePresetsErrors::BUILD_TEST_PRESETS_UNSUPPORTED(
  440. &root["buildPresets"], &this->parseState);
  441. return false;
  442. }
  443. if (root.isMember("testPresets")) {
  444. cmCMakePresetsErrors::BUILD_TEST_PRESETS_UNSUPPORTED(
  445. &root["testPresets"], &this->parseState);
  446. return false;
  447. }
  448. }
  449. // Support for package presets added in version 6.
  450. if (v < 6 && root.isMember("packagePresets")) {
  451. cmCMakePresetsErrors::PACKAGE_PRESETS_UNSUPPORTED(&root["packagePresets"],
  452. &this->parseState);
  453. return false;
  454. }
  455. // Support for workflow presets added in version 6.
  456. if (v < 6 && root.isMember("workflowPresets")) {
  457. cmCMakePresetsErrors::WORKFLOW_PRESETS_UNSUPPORTED(
  458. &root["workflowPresets"], &this->parseState);
  459. return false;
  460. }
  461. // Support for include added in version 4.
  462. if (v < 4 && root.isMember("include")) {
  463. cmCMakePresetsErrors::INCLUDE_UNSUPPORTED(&root["include"],
  464. &this->parseState);
  465. return false;
  466. }
  467. // Support for $schema added in version 8.
  468. if (v < 8 && root.isMember("$schema")) {
  469. cmCMakePresetsErrors::SCHEMA_UNSUPPORTED(&this->parseState);
  470. return false;
  471. }
  472. // Support for $comment added in version 10.
  473. this->parseState.allowComments = (v >= 10);
  474. RootPresets presets;
  475. if ((result = RootPresetsHelper(presets, &root, &parseState)) != true) {
  476. return result;
  477. }
  478. unsigned int currentMajor = cmVersion::GetMajorVersion();
  479. unsigned int currentMinor = cmVersion::GetMinorVersion();
  480. unsigned int currentPatch = cmVersion::GetPatchVersion();
  481. auto const& required = presets.CMakeMinimumRequired;
  482. if (required.Major > currentMajor) {
  483. ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
  484. "major", currentMajor, required.Major);
  485. error(&root["cmakeMinimumRequired"]["major"], &this->parseState);
  486. return false;
  487. }
  488. if (required.Major == currentMajor) {
  489. if (required.Minor > currentMinor) {
  490. ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
  491. "minor", currentMinor, required.Minor);
  492. error(&root["cmakeMinimumRequired"]["minor"], &this->parseState);
  493. return false;
  494. }
  495. if (required.Minor == currentMinor && required.Patch > currentPatch) {
  496. ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
  497. "patch", currentPatch, required.Patch);
  498. error(&root["cmakeMinimumRequired"]["patch"], &this->parseState);
  499. return false;
  500. }
  501. }
  502. auto filePtr = cm::make_unique<File>();
  503. file = filePtr.get();
  504. this->Files.emplace_back(std::move(filePtr));
  505. inProgressFiles.emplace_back(file);
  506. file->Filename = filename;
  507. file->Version = v;
  508. file->ReachableFiles.insert(file);
  509. for (auto& preset : presets.ConfigurePresets) {
  510. preset.OriginFile = file;
  511. if (preset.Name.empty()) {
  512. // No error, already handled by PresetNameHelper
  513. return false;
  514. }
  515. PresetPair<ConfigurePreset> presetPair;
  516. presetPair.Unexpanded = preset;
  517. presetPair.Expanded = cm::nullopt;
  518. if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) {
  519. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  520. return false;
  521. }
  522. // Support for installDir presets added in version 3.
  523. if (v < 3 && !preset.InstallDir.empty()) {
  524. cmCMakePresetsErrors::INSTALL_PREFIX_UNSUPPORTED(&root["installDir"],
  525. &this->parseState);
  526. return false;
  527. }
  528. // Support for conditions added in version 3.
  529. if (v < 3 && preset.ConditionEvaluator) {
  530. cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
  531. return false;
  532. }
  533. // Support for toolchainFile presets added in version 3.
  534. if (v < 3 && !preset.ToolchainFile.empty()) {
  535. cmCMakePresetsErrors::TOOLCHAIN_FILE_UNSUPPORTED(&this->parseState);
  536. return false;
  537. }
  538. // Support for trace presets added in version 7.
  539. if (v < 7 &&
  540. (preset.TraceMode.has_value() || preset.TraceFormat.has_value() ||
  541. !preset.TraceRedirect.empty() || !preset.TraceSource.empty())) {
  542. cmCMakePresetsErrors::TRACE_UNSUPPORTED(&this->parseState);
  543. return false;
  544. }
  545. // Support for graphviz argument added in version 10.
  546. if (v < 10 && !preset.GraphVizFile.empty()) {
  547. cmCMakePresetsErrors::GRAPHVIZ_FILE_UNSUPPORTED(&this->parseState);
  548. return false;
  549. }
  550. this->ConfigurePresetOrder.push_back(preset.Name);
  551. }
  552. for (auto& preset : presets.BuildPresets) {
  553. preset.OriginFile = file;
  554. if (preset.Name.empty()) {
  555. // No error, already handled by PresetNameHelper
  556. return false;
  557. }
  558. PresetPair<BuildPreset> presetPair;
  559. presetPair.Unexpanded = preset;
  560. presetPair.Expanded = cm::nullopt;
  561. if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
  562. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  563. return false;
  564. }
  565. // Support for conditions added in version 3.
  566. if (v < 3 && preset.ConditionEvaluator) {
  567. cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
  568. return false;
  569. }
  570. this->BuildPresetOrder.push_back(preset.Name);
  571. }
  572. for (auto& preset : presets.TestPresets) {
  573. preset.OriginFile = file;
  574. if (preset.Name.empty()) {
  575. // No error, already handled by PresetNameHelper
  576. return false;
  577. }
  578. PresetPair<TestPreset> presetPair;
  579. presetPair.Unexpanded = preset;
  580. presetPair.Expanded = cm::nullopt;
  581. if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
  582. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  583. return false;
  584. }
  585. // Support for conditions added in version 3.
  586. if (v < 3 && preset.ConditionEvaluator) {
  587. cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
  588. return false;
  589. }
  590. // Support for TestOutputTruncation added in version 5.
  591. if (v < 5 && preset.Output && preset.Output->TestOutputTruncation) {
  592. cmCMakePresetsErrors::TEST_OUTPUT_TRUNCATION_UNSUPPORTED(
  593. &this->parseState);
  594. return false;
  595. }
  596. // Support for outputJUnitFile added in version 6.
  597. if (v < 6 && preset.Output && !preset.Output->OutputJUnitFile.empty()) {
  598. cmCMakePresetsErrors::CTEST_JUNIT_UNSUPPORTED(&this->parseState);
  599. return false;
  600. }
  601. // Support for processor-count-based jobs added in version 11.
  602. if (v < 11 && preset.Execution && preset.Execution->Jobs.has_value() &&
  603. !preset.Execution->Jobs->has_value()) {
  604. cmCMakePresetsErrors::JOBS_PROC_UNSUPPORTED(&this->parseState);
  605. return false;
  606. }
  607. this->TestPresetOrder.push_back(preset.Name);
  608. }
  609. for (auto& preset : presets.PackagePresets) {
  610. preset.OriginFile = file;
  611. if (preset.Name.empty()) {
  612. // No error, already handled by PresetNameHelper
  613. return false;
  614. }
  615. PresetPair<PackagePreset> presetPair;
  616. presetPair.Unexpanded = preset;
  617. presetPair.Expanded = cm::nullopt;
  618. if (!this->PackagePresets.emplace(preset.Name, presetPair).second) {
  619. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  620. return false;
  621. }
  622. // Support for conditions added in version 3, but this requires version 5
  623. // already, so no action needed.
  624. this->PackagePresetOrder.push_back(preset.Name);
  625. }
  626. for (auto& preset : presets.WorkflowPresets) {
  627. preset.OriginFile = file;
  628. if (preset.Name.empty()) {
  629. // No error, already handled by PresetNameHelper
  630. return false;
  631. }
  632. PresetPair<WorkflowPreset> presetPair;
  633. presetPair.Unexpanded = preset;
  634. presetPair.Expanded = cm::nullopt;
  635. if (!this->WorkflowPresets.emplace(preset.Name, presetPair).second) {
  636. cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
  637. return false;
  638. }
  639. // Support for conditions added in version 3, but this requires version 6
  640. // already, so no action needed.
  641. this->WorkflowPresetOrder.push_back(preset.Name);
  642. }
  643. auto const includeFile = [this, &inProgressFiles,
  644. file](std::string const& include,
  645. RootType rootType2, ReadReason readReason2,
  646. std::string& FailureMessage) -> bool {
  647. bool r;
  648. File* includedFile;
  649. if ((r =
  650. this->ReadJSONFile(include, rootType2, readReason2, inProgressFiles,
  651. includedFile, FailureMessage)) != true) {
  652. return r;
  653. }
  654. file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
  655. includedFile->ReachableFiles.end());
  656. return true;
  657. };
  658. MacroExpanderVector macroExpanders{};
  659. if (v >= 9) {
  660. macroExpanders.push_back(
  661. cm::make_unique<BaseMacroExpander>(*this, filename));
  662. }
  663. macroExpanders.push_back(cm::make_unique<EnvironmentMacroExpander>());
  664. for (Json::ArrayIndex i = 0; i < presets.Include.size(); ++i) {
  665. auto include = presets.Include[i];
  666. // Support for macro expansion in includes added in version 7
  667. if (v >= 7) {
  668. if (ExpandMacros(include, macroExpanders, v) != ExpandMacroResult::Ok) {
  669. cmCMakePresetsErrors::INVALID_INCLUDE(&root["include"][i],
  670. &this->parseState);
  671. return false;
  672. }
  673. }
  674. if (!cmSystemTools::FileIsFullPath(include)) {
  675. auto directory = cmSystemTools::GetFilenamePath(filename);
  676. include = cmStrCat(directory, '/', include);
  677. }
  678. if ((result = includeFile(include, rootType, ReadReason::Included,
  679. errMsg)) != true) {
  680. return result;
  681. }
  682. }
  683. if (rootType == RootType::User && readReason == ReadReason::Root) {
  684. auto cmakePresetsFilename = GetFilename(this->SourceDir);
  685. if (cmSystemTools::FileExists(cmakePresetsFilename)) {
  686. if ((result = includeFile(cmakePresetsFilename, RootType::Project,
  687. ReadReason::Root, errMsg)) != true) {
  688. return result;
  689. }
  690. }
  691. }
  692. inProgressFiles.pop_back();
  693. return true;
  694. }