cmCMakePresetsFile.cxx 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767
  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 "cmCMakePresetsFile.h"
  4. #include <algorithm>
  5. #include <cstdlib>
  6. #include <functional>
  7. #include <iostream>
  8. #include <iterator>
  9. #include <utility>
  10. #include <cm/string_view>
  11. #include <cmext/string_view>
  12. #include <cm3p/json/reader.h>
  13. #include <cm3p/json/value.h>
  14. #include "cmsys/FStream.hxx"
  15. #include "cmJSONHelpers.h"
  16. #include "cmStringAlgorithms.h"
  17. #include "cmSystemTools.h"
  18. #include "cmVersion.h"
  19. #define CHECK_OK(expr) \
  20. { \
  21. auto _result = expr; \
  22. if (_result != ReadFileResult::READ_OK) \
  23. return _result; \
  24. }
  25. #define CHECK_EXPAND(out, field, expanders, version) \
  26. { \
  27. switch (ExpandMacros(field, expanders, version)) { \
  28. case ExpandMacroResult::Error: \
  29. return false; \
  30. case ExpandMacroResult::Ignore: \
  31. out.reset(); \
  32. return true; \
  33. case ExpandMacroResult::Ok: \
  34. break; \
  35. } \
  36. }
  37. namespace {
  38. enum class CycleStatus
  39. {
  40. Unvisited,
  41. InProgress,
  42. Verified,
  43. };
  44. using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
  45. using CacheVariable = cmCMakePresetsFile::CacheVariable;
  46. using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
  47. using BuildPreset = cmCMakePresetsFile::BuildPreset;
  48. using TestPreset = cmCMakePresetsFile::TestPreset;
  49. using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
  50. constexpr int MIN_VERSION = 1;
  51. constexpr int MAX_VERSION = 3;
  52. struct CMakeVersion
  53. {
  54. unsigned int Major = 0;
  55. unsigned int Minor = 0;
  56. unsigned int Patch = 0;
  57. };
  58. struct RootPresets
  59. {
  60. CMakeVersion CMakeMinimumRequired;
  61. std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets;
  62. std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets;
  63. std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
  64. };
  65. cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
  66. {
  67. return [error](std::nullptr_t& /*out*/,
  68. const Json::Value* value) -> ReadFileResult {
  69. if (!value) {
  70. return ReadFileResult::READ_OK;
  71. }
  72. if (!value->isObject()) {
  73. return error;
  74. }
  75. return ReadFileResult::READ_OK;
  76. };
  77. }
  78. auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
  79. ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
  80. auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>(
  81. ReadFileResult::NO_VERSION, VersionIntHelper);
  82. auto const RootVersionHelper =
  83. cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK,
  84. ReadFileResult::INVALID_ROOT)
  85. .Bind("version"_s, VersionHelper, false);
  86. auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
  87. ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
  88. ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
  89. {
  90. if (!value) {
  91. out.clear();
  92. return ReadFileResult::READ_OK;
  93. }
  94. if (value->isBool()) {
  95. out = value->asBool() ? "TRUE" : "FALSE";
  96. return ReadFileResult::READ_OK;
  97. }
  98. return VariableStringHelper(out, value);
  99. }
  100. auto const VariableObjectHelper =
  101. cmJSONObjectHelper<CacheVariable, ReadFileResult>(
  102. ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
  103. .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
  104. .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
  105. ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
  106. const Json::Value* value)
  107. {
  108. if (value->isBool()) {
  109. out = CacheVariable{
  110. /*Type=*/"BOOL",
  111. /*Value=*/value->asBool() ? "TRUE" : "FALSE",
  112. };
  113. return ReadFileResult::READ_OK;
  114. }
  115. if (value->isString()) {
  116. out = CacheVariable{
  117. /*Type=*/"",
  118. /*Value=*/value->asString(),
  119. };
  120. return ReadFileResult::READ_OK;
  121. }
  122. if (value->isObject()) {
  123. out.emplace();
  124. return VariableObjectHelper(*out, value);
  125. }
  126. if (value->isNull()) {
  127. out = cm::nullopt;
  128. return ReadFileResult::READ_OK;
  129. }
  130. return ReadFileResult::INVALID_VARIABLE;
  131. }
  132. auto const VariablesHelper =
  133. cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
  134. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
  135. auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>(
  136. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
  137. ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
  138. const Json::Value* value)
  139. {
  140. if (!value || value->isNull()) {
  141. out = cm::nullopt;
  142. return ReadFileResult::READ_OK;
  143. }
  144. if (value->isString()) {
  145. out = value->asString();
  146. return ReadFileResult::READ_OK;
  147. }
  148. return ReadFileResult::INVALID_PRESET;
  149. }
  150. auto const EnvironmentMapHelper =
  151. cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
  152. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
  153. EnvironmentHelper);
  154. auto const PresetVectorStringHelper =
  155. cmJSONVectorHelper<std::string, ReadFileResult>(
  156. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
  157. PresetStringHelper);
  158. ReadFileResult PresetInheritsHelper(std::vector<std::string>& out,
  159. const Json::Value* value)
  160. {
  161. out.clear();
  162. if (!value) {
  163. return ReadFileResult::READ_OK;
  164. }
  165. if (value->isString()) {
  166. out.push_back(value->asString());
  167. return ReadFileResult::READ_OK;
  168. }
  169. return PresetVectorStringHelper(out, value);
  170. }
  171. auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>(
  172. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
  173. auto const PresetOptionalBoolHelper =
  174. cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
  175. PresetBoolHelper);
  176. auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
  177. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
  178. auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
  179. ReadFileResult::READ_OK, PresetIntHelper);
  180. auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
  181. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
  182. auto const PresetWarningsHelper =
  183. cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
  184. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  185. .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
  186. .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
  187. PresetOptionalBoolHelper, false)
  188. .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
  189. PresetOptionalBoolHelper, false)
  190. .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
  191. PresetOptionalBoolHelper, false)
  192. .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
  193. PresetOptionalBoolHelper, false);
  194. auto const PresetErrorsHelper =
  195. cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
  196. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  197. .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
  198. .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
  199. PresetOptionalBoolHelper, false);
  200. auto const PresetDebugHelper =
  201. cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
  202. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  203. .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
  204. false)
  205. .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
  206. PresetOptionalBoolHelper, false)
  207. .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
  208. false);
  209. ReadFileResult ArchToolsetStrategyHelper(
  210. cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
  211. {
  212. if (!value) {
  213. out = cm::nullopt;
  214. return ReadFileResult::READ_OK;
  215. }
  216. if (!value->isString()) {
  217. return ReadFileResult::INVALID_PRESET;
  218. }
  219. if (value->asString() == "set") {
  220. out = ArchToolsetStrategy::Set;
  221. return ReadFileResult::READ_OK;
  222. }
  223. if (value->asString() == "external") {
  224. out = ArchToolsetStrategy::External;
  225. return ReadFileResult::READ_OK;
  226. }
  227. return ReadFileResult::INVALID_PRESET;
  228. }
  229. std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
  230. ArchToolsetHelper(
  231. std::string ConfigurePreset::*valueField,
  232. cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
  233. {
  234. auto const objectHelper =
  235. cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
  236. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  237. .Bind("value", valueField, PresetStringHelper, false)
  238. .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
  239. return [valueField, strategyField, objectHelper](
  240. ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
  241. if (!value) {
  242. (out.*valueField).clear();
  243. out.*strategyField = cm::nullopt;
  244. return ReadFileResult::READ_OK;
  245. }
  246. if (value->isString()) {
  247. out.*valueField = value->asString();
  248. out.*strategyField = cm::nullopt;
  249. return ReadFileResult::READ_OK;
  250. }
  251. if (value->isObject()) {
  252. return objectHelper(out, value);
  253. }
  254. return ReadFileResult::INVALID_PRESET;
  255. };
  256. }
  257. auto const ArchitectureHelper = ArchToolsetHelper(
  258. &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
  259. auto const ToolsetHelper = ArchToolsetHelper(
  260. &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
  261. auto const ConfigurePresetHelper =
  262. cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
  263. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  264. .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
  265. .Bind("inherits"_s, &ConfigurePreset::Inherits, PresetInheritsHelper,
  266. false)
  267. .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
  268. .Bind<std::nullptr_t>("vendor"_s, nullptr,
  269. VendorHelper(ReadFileResult::INVALID_PRESET), false)
  270. .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
  271. false)
  272. .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
  273. false)
  274. .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
  275. false)
  276. .Bind("architecture"_s, ArchitectureHelper, false)
  277. .Bind("toolset"_s, ToolsetHelper, false)
  278. .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
  279. false)
  280. .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper,
  281. false)
  282. .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
  283. .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
  284. VariablesHelper, false)
  285. .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
  286. false)
  287. .Bind("warnings"_s, PresetWarningsHelper, false)
  288. .Bind("errors"_s, PresetErrorsHelper, false)
  289. .Bind("debug"_s, PresetDebugHelper, false);
  290. auto const BuildPresetHelper =
  291. cmJSONObjectHelper<BuildPreset, ReadFileResult>(
  292. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  293. .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
  294. .Bind("inherits"_s, &BuildPreset::Inherits, PresetInheritsHelper, false)
  295. .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
  296. .Bind<std::nullptr_t>("vendor"_s, nullptr,
  297. VendorHelper(ReadFileResult::INVALID_PRESET), false)
  298. .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
  299. false)
  300. .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
  301. false)
  302. .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
  303. false)
  304. .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
  305. PresetStringHelper, false)
  306. .Bind("inheritConfigureEnvironment"_s,
  307. &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
  308. false)
  309. .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
  310. .Bind("targets"_s, &BuildPreset::Targets, PresetVectorStringHelper, false)
  311. .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
  312. false)
  313. .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
  314. false)
  315. .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
  316. .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
  317. PresetVectorStringHelper, false);
  318. ReadFileResult TestPresetOutputVerbosityHelper(
  319. TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
  320. {
  321. if (!value) {
  322. out = TestPreset::OutputOptions::VerbosityEnum::Default;
  323. return ReadFileResult::READ_OK;
  324. }
  325. if (!value->isString()) {
  326. return ReadFileResult::INVALID_PRESET;
  327. }
  328. if (value->asString() == "default") {
  329. out = TestPreset::OutputOptions::VerbosityEnum::Default;
  330. return ReadFileResult::READ_OK;
  331. }
  332. if (value->asString() == "verbose") {
  333. out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
  334. return ReadFileResult::READ_OK;
  335. }
  336. if (value->asString() == "extra") {
  337. out = TestPreset::OutputOptions::VerbosityEnum::Extra;
  338. return ReadFileResult::READ_OK;
  339. }
  340. return ReadFileResult::INVALID_PRESET;
  341. }
  342. auto const TestPresetOptionalOutputVerbosityHelper =
  343. cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
  344. ReadFileResult>(ReadFileResult::READ_OK,
  345. TestPresetOutputVerbosityHelper);
  346. auto const TestPresetOptionalOutputHelper =
  347. cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
  348. ReadFileResult::READ_OK,
  349. cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
  350. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  351. .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
  352. PresetOptionalBoolHelper, false)
  353. .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
  354. TestPresetOptionalOutputVerbosityHelper, false)
  355. .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
  356. PresetOptionalBoolHelper, false)
  357. .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
  358. PresetOptionalBoolHelper, false)
  359. .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
  360. PresetOptionalBoolHelper, false)
  361. .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
  362. PresetStringHelper, false)
  363. .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
  364. PresetOptionalBoolHelper, false)
  365. .Bind("subprojectSummary"_s,
  366. &TestPreset::OutputOptions::SubprojectSummary,
  367. PresetOptionalBoolHelper, false)
  368. .Bind("maxPassedTestOutputSize"_s,
  369. &TestPreset::OutputOptions::MaxPassedTestOutputSize,
  370. PresetOptionalIntHelper, false)
  371. .Bind("maxFailedTestOutputSize"_s,
  372. &TestPreset::OutputOptions::MaxFailedTestOutputSize,
  373. PresetOptionalIntHelper, false)
  374. .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
  375. PresetOptionalIntHelper, false));
  376. auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
  377. cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
  378. ReadFileResult>(
  379. ReadFileResult::READ_OK,
  380. cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
  381. ReadFileResult>(ReadFileResult::READ_OK,
  382. ReadFileResult::INVALID_PRESET)
  383. .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
  384. PresetOptionalIntHelper, false)
  385. .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
  386. PresetOptionalIntHelper, false)
  387. .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
  388. PresetOptionalIntHelper, false)
  389. .Bind("specificTests"_s,
  390. &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
  391. PresetVectorIntHelper, false));
  392. ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
  393. cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
  394. const Json::Value* value)
  395. {
  396. if (!value) {
  397. out = cm::nullopt;
  398. return ReadFileResult::READ_OK;
  399. }
  400. if (value->isString()) {
  401. out.emplace();
  402. out->IndexFile = value->asString();
  403. return ReadFileResult::READ_OK;
  404. }
  405. if (value->isObject()) {
  406. return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
  407. }
  408. return ReadFileResult::INVALID_PRESET;
  409. }
  410. auto const TestPresetOptionalFilterIncludeHelper =
  411. cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
  412. ReadFileResult::READ_OK,
  413. cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
  414. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
  415. .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
  416. false)
  417. .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
  418. false)
  419. .Bind("index"_s, &TestPreset::IncludeOptions::Index,
  420. TestPresetOptionalFilterIncludeIndexHelper, false)
  421. .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
  422. PresetOptionalBoolHelper, false));
  423. auto const TestPresetOptionalFilterExcludeFixturesHelper =
  424. cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
  425. ReadFileResult>(
  426. ReadFileResult::READ_OK,
  427. cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
  428. ReadFileResult>(ReadFileResult::READ_OK,
  429. ReadFileResult::INVALID_PRESET)
  430. .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
  431. PresetStringHelper, false)
  432. .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
  433. PresetStringHelper, false)
  434. .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
  435. PresetStringHelper, false));
  436. auto const TestPresetOptionalFilterExcludeHelper =
  437. cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
  438. ReadFileResult::READ_OK,
  439. cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
  440. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
  441. .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
  442. false)
  443. .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
  444. false)
  445. .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
  446. TestPresetOptionalFilterExcludeFixturesHelper, false));
  447. ReadFileResult TestPresetExecutionShowOnlyHelper(
  448. TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
  449. {
  450. if (!value || !value->isString()) {
  451. return ReadFileResult::INVALID_PRESET;
  452. }
  453. if (value->asString() == "human") {
  454. out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
  455. return ReadFileResult::READ_OK;
  456. }
  457. if (value->asString() == "json-v1") {
  458. out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
  459. return ReadFileResult::READ_OK;
  460. }
  461. return ReadFileResult::INVALID_PRESET;
  462. }
  463. auto const TestPresetOptionalExecutionShowOnlyHelper =
  464. cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
  465. ReadFileResult>(ReadFileResult::READ_OK,
  466. TestPresetExecutionShowOnlyHelper);
  467. ReadFileResult TestPresetExecutionModeHelper(
  468. TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
  469. const Json::Value* value)
  470. {
  471. if (!value) {
  472. return ReadFileResult::READ_OK;
  473. }
  474. if (!value->isString()) {
  475. return ReadFileResult::INVALID_PRESET;
  476. }
  477. if (value->asString() == "until-fail") {
  478. out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
  479. return ReadFileResult::READ_OK;
  480. }
  481. if (value->asString() == "until-pass") {
  482. out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
  483. return ReadFileResult::READ_OK;
  484. }
  485. if (value->asString() == "after-timeout") {
  486. out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
  487. return ReadFileResult::READ_OK;
  488. }
  489. return ReadFileResult::INVALID_PRESET;
  490. }
  491. auto const TestPresetOptionalExecutionRepeatHelper =
  492. cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
  493. ReadFileResult>(
  494. ReadFileResult::READ_OK,
  495. cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
  496. ReadFileResult>(ReadFileResult::READ_OK,
  497. ReadFileResult::INVALID_PRESET)
  498. .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
  499. TestPresetExecutionModeHelper, true)
  500. .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
  501. PresetIntHelper, true));
  502. ReadFileResult TestPresetExecutionNoTestsActionHelper(
  503. TestPreset::ExecutionOptions::NoTestsActionEnum& out,
  504. const Json::Value* value)
  505. {
  506. if (!value) {
  507. out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
  508. return ReadFileResult::READ_OK;
  509. }
  510. if (!value->isString()) {
  511. return ReadFileResult::INVALID_PRESET;
  512. }
  513. if (value->asString() == "default") {
  514. out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
  515. return ReadFileResult::READ_OK;
  516. }
  517. if (value->asString() == "error") {
  518. out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
  519. return ReadFileResult::READ_OK;
  520. }
  521. if (value->asString() == "ignore") {
  522. out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
  523. return ReadFileResult::READ_OK;
  524. }
  525. return ReadFileResult::INVALID_PRESET;
  526. }
  527. auto const TestPresetOptionalExecutionNoTestsActionHelper =
  528. cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
  529. ReadFileResult>(ReadFileResult::READ_OK,
  530. TestPresetExecutionNoTestsActionHelper);
  531. auto const TestPresetExecutionHelper =
  532. cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
  533. ReadFileResult::READ_OK,
  534. cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
  535. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
  536. .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
  537. PresetOptionalBoolHelper, false)
  538. .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
  539. PresetOptionalBoolHelper, false)
  540. .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
  541. PresetOptionalIntHelper, false)
  542. .Bind("resourceSpecFile"_s,
  543. &TestPreset::ExecutionOptions::ResourceSpecFile,
  544. PresetStringHelper, false)
  545. .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
  546. PresetOptionalIntHelper, false)
  547. .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
  548. TestPresetOptionalExecutionShowOnlyHelper, false)
  549. .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
  550. TestPresetOptionalExecutionRepeatHelper, false)
  551. .Bind("interactiveDebugging"_s,
  552. &TestPreset::ExecutionOptions::InteractiveDebugging,
  553. PresetOptionalBoolHelper, false)
  554. .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
  555. PresetOptionalBoolHelper, false)
  556. .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
  557. PresetOptionalIntHelper, false)
  558. .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
  559. TestPresetOptionalExecutionNoTestsActionHelper, false));
  560. auto const TestPresetFilterHelper =
  561. cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
  562. ReadFileResult::READ_OK,
  563. cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
  564. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
  565. .Bind("include"_s, &TestPreset::FilterOptions::Include,
  566. TestPresetOptionalFilterIncludeHelper, false)
  567. .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
  568. TestPresetOptionalFilterExcludeHelper, false));
  569. auto const TestPresetHelper =
  570. cmJSONObjectHelper<TestPreset, ReadFileResult>(
  571. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
  572. .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
  573. .Bind("inherits"_s, &TestPreset::Inherits, PresetInheritsHelper, false)
  574. .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
  575. .Bind<std::nullptr_t>("vendor"_s, nullptr,
  576. VendorHelper(ReadFileResult::INVALID_PRESET), false)
  577. .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
  578. .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
  579. .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
  580. false)
  581. .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
  582. PresetStringHelper, false)
  583. .Bind("inheritConfigureEnvironment"_s,
  584. &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
  585. false)
  586. .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
  587. false)
  588. .Bind("overwriteConfigurationFile"_s,
  589. &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
  590. false)
  591. .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
  592. false)
  593. .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
  594. .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
  595. false);
  596. auto const ConfigurePresetsHelper =
  597. cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
  598. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
  599. ConfigurePresetHelper);
  600. auto const BuildPresetsHelper =
  601. cmJSONVectorHelper<BuildPreset, ReadFileResult>(
  602. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
  603. BuildPresetHelper);
  604. auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
  605. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
  606. auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
  607. ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
  608. auto const CMakeVersionHelper =
  609. cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
  610. ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
  611. .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
  612. .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
  613. .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
  614. auto const RootPresetsHelper =
  615. cmJSONObjectHelper<RootPresets, ReadFileResult>(
  616. ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
  617. .Bind<int>("version"_s, nullptr, VersionHelper)
  618. .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
  619. ConfigurePresetsHelper, false)
  620. .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
  621. false)
  622. .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
  623. .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
  624. CMakeVersionHelper, false)
  625. .Bind<std::nullptr_t>("vendor"_s, nullptr,
  626. VendorHelper(ReadFileResult::INVALID_ROOT), false);
  627. void InheritString(std::string& child, const std::string& parent)
  628. {
  629. if (child.empty()) {
  630. child = parent;
  631. }
  632. }
  633. template <typename T>
  634. void InheritOptionalValue(cm::optional<T>& child,
  635. const cm::optional<T>& parent)
  636. {
  637. if (!child) {
  638. child = parent;
  639. }
  640. }
  641. template <typename T>
  642. void InheritVector(std::vector<T>& child, const std::vector<T>& parent)
  643. {
  644. if (child.empty()) {
  645. child = parent;
  646. }
  647. }
  648. /**
  649. * Check preset inheritance for cycles (using a DAG check algorithm) while
  650. * also bubbling up fields through the inheritance hierarchy, then verify
  651. * that each preset has the required fields, either directly or through
  652. * inheritance.
  653. */
  654. template <class T>
  655. ReadFileResult VisitPreset(
  656. T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
  657. std::map<std::string, CycleStatus> cycleStatus)
  658. {
  659. switch (cycleStatus[preset.Name]) {
  660. case CycleStatus::InProgress:
  661. return ReadFileResult::CYCLIC_PRESET_INHERITANCE;
  662. case CycleStatus::Verified:
  663. return ReadFileResult::READ_OK;
  664. default:
  665. break;
  666. }
  667. cycleStatus[preset.Name] = CycleStatus::InProgress;
  668. if (preset.Environment.count("") != 0) {
  669. return ReadFileResult::INVALID_PRESET;
  670. }
  671. CHECK_OK(preset.VisitPresetBeforeInherit())
  672. for (auto const& i : preset.Inherits) {
  673. auto parent = presets.find(i);
  674. if (parent == presets.end()) {
  675. return ReadFileResult::INVALID_PRESET;
  676. }
  677. auto& parentPreset = parent->second.Unexpanded;
  678. if (!preset.User && parentPreset.User) {
  679. return ReadFileResult::USER_PRESET_INHERITANCE;
  680. }
  681. auto result = VisitPreset(parentPreset, presets, cycleStatus);
  682. if (result != ReadFileResult::READ_OK) {
  683. return result;
  684. }
  685. CHECK_OK(preset.VisitPresetInherit(parentPreset))
  686. for (auto const& v : parentPreset.Environment) {
  687. preset.Environment.insert(v);
  688. }
  689. }
  690. CHECK_OK(preset.VisitPresetAfterInherit())
  691. cycleStatus[preset.Name] = CycleStatus::Verified;
  692. return ReadFileResult::READ_OK;
  693. }
  694. template <class T>
  695. ReadFileResult ComputePresetInheritance(
  696. std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets)
  697. {
  698. std::map<std::string, CycleStatus> cycleStatus;
  699. for (auto const& it : presets) {
  700. cycleStatus[it.first] = CycleStatus::Unvisited;
  701. }
  702. for (auto& it : presets) {
  703. auto result = VisitPreset<T>(it.second.Unexpanded, presets, cycleStatus);
  704. if (result != ReadFileResult::READ_OK) {
  705. return result;
  706. }
  707. }
  708. return ReadFileResult::READ_OK;
  709. }
  710. constexpr const char* ValidPrefixes[] = {
  711. "",
  712. "env",
  713. "penv",
  714. "vendor",
  715. };
  716. bool PrefixesValidMacroNamespace(const std::string& str)
  717. {
  718. return std::any_of(
  719. std::begin(ValidPrefixes), std::end(ValidPrefixes),
  720. [&str](const char* prefix) -> bool { return cmHasPrefix(prefix, str); });
  721. }
  722. bool IsValidMacroNamespace(const std::string& str)
  723. {
  724. return std::any_of(
  725. std::begin(ValidPrefixes), std::end(ValidPrefixes),
  726. [&str](const char* prefix) -> bool { return str == prefix; });
  727. }
  728. enum class ExpandMacroResult
  729. {
  730. Ok,
  731. Ignore,
  732. Error,
  733. };
  734. using MacroExpander = std::function<ExpandMacroResult(
  735. const std::string&, const std::string&, std::string&, int version)>;
  736. ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
  737. const std::vector<MacroExpander>& macroExpanders,
  738. int version);
  739. ExpandMacroResult ExpandMacros(
  740. std::string& out, const std::vector<MacroExpander>& macroExpanders,
  741. int version);
  742. ExpandMacroResult ExpandMacro(std::string& out,
  743. const std::string& macroNamespace,
  744. const std::string& macroName,
  745. const std::vector<MacroExpander>& macroExpanders,
  746. int version);
  747. bool ExpandMacros(const cmCMakePresetsFile& file,
  748. const ConfigurePreset& preset,
  749. cm::optional<ConfigurePreset>& out,
  750. const std::vector<MacroExpander>& macroExpanders)
  751. {
  752. std::string binaryDir = preset.BinaryDir;
  753. CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset))
  754. if (!cmSystemTools::FileIsFullPath(binaryDir)) {
  755. binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
  756. }
  757. out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
  758. cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
  759. if (!preset.InstallDir.empty()) {
  760. std::string installDir = preset.InstallDir;
  761. CHECK_EXPAND(out, installDir, macroExpanders, file.GetVersion(preset))
  762. if (!cmSystemTools::FileIsFullPath(installDir)) {
  763. installDir = cmStrCat(file.SourceDir, '/', installDir);
  764. }
  765. out->InstallDir = cmSystemTools::CollapseFullPath(installDir);
  766. cmSystemTools::ConvertToUnixSlashes(out->InstallDir);
  767. }
  768. for (auto& variable : out->CacheVariables) {
  769. if (variable.second) {
  770. CHECK_EXPAND(out, variable.second->Value, macroExpanders,
  771. file.GetVersion(preset))
  772. }
  773. }
  774. return true;
  775. }
  776. bool ExpandMacros(const cmCMakePresetsFile& file, const BuildPreset& preset,
  777. cm::optional<BuildPreset>& out,
  778. const std::vector<MacroExpander>& macroExpanders)
  779. {
  780. for (auto& target : out->Targets) {
  781. CHECK_EXPAND(out, target, macroExpanders, file.GetVersion(preset))
  782. }
  783. for (auto& nativeToolOption : out->NativeToolOptions) {
  784. CHECK_EXPAND(out, nativeToolOption, macroExpanders,
  785. file.GetVersion(preset))
  786. }
  787. return true;
  788. }
  789. bool ExpandMacros(const cmCMakePresetsFile& file, const TestPreset& preset,
  790. cm::optional<TestPreset>& out,
  791. const std::vector<MacroExpander>& macroExpanders)
  792. {
  793. for (auto& overwrite : out->OverwriteConfigurationFile) {
  794. CHECK_EXPAND(out, overwrite, macroExpanders, file.GetVersion(preset));
  795. }
  796. if (out->Output) {
  797. CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders,
  798. file.GetVersion(preset))
  799. }
  800. if (out->Filter) {
  801. if (out->Filter->Include) {
  802. CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders,
  803. file.GetVersion(preset))
  804. CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders,
  805. file.GetVersion(preset))
  806. if (out->Filter->Include->Index) {
  807. CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile,
  808. macroExpanders, file.GetVersion(preset));
  809. }
  810. }
  811. if (out->Filter->Exclude) {
  812. CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders,
  813. file.GetVersion(preset))
  814. CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders,
  815. file.GetVersion(preset))
  816. if (out->Filter->Exclude->Fixtures) {
  817. CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders,
  818. file.GetVersion(preset))
  819. CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup,
  820. macroExpanders, file.GetVersion(preset))
  821. CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup,
  822. macroExpanders, file.GetVersion(preset))
  823. }
  824. }
  825. }
  826. if (out->Execution) {
  827. CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders,
  828. file.GetVersion(preset))
  829. }
  830. return true;
  831. }
  832. template <class T>
  833. bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
  834. cm::optional<T>& out)
  835. {
  836. out.emplace(preset);
  837. std::map<std::string, CycleStatus> envCycles;
  838. for (auto const& v : out->Environment) {
  839. envCycles[v.first] = CycleStatus::Unvisited;
  840. }
  841. std::vector<MacroExpander> macroExpanders;
  842. MacroExpander defaultMacroExpander =
  843. [&file, &preset](const std::string& macroNamespace,
  844. const std::string& macroName, std::string& macroOut,
  845. int version) -> ExpandMacroResult {
  846. if (macroNamespace.empty()) {
  847. if (macroName == "sourceDir") {
  848. macroOut += file.SourceDir;
  849. return ExpandMacroResult::Ok;
  850. }
  851. if (macroName == "sourceParentDir") {
  852. macroOut += cmSystemTools::GetParentDirectory(file.SourceDir);
  853. return ExpandMacroResult::Ok;
  854. }
  855. if (macroName == "sourceDirName") {
  856. macroOut += cmSystemTools::GetFilenameName(file.SourceDir);
  857. return ExpandMacroResult::Ok;
  858. }
  859. if (macroName == "presetName") {
  860. macroOut += preset.Name;
  861. return ExpandMacroResult::Ok;
  862. }
  863. if (macroName == "generator") {
  864. // Generator only makes sense if preset is not hidden.
  865. if (!preset.Hidden) {
  866. macroOut += file.GetGeneratorForPreset(preset.Name);
  867. }
  868. return ExpandMacroResult::Ok;
  869. }
  870. if (macroName == "dollar") {
  871. macroOut += '$';
  872. return ExpandMacroResult::Ok;
  873. }
  874. if (macroName == "hostSystemName") {
  875. if (version < 3) {
  876. return ExpandMacroResult::Error;
  877. }
  878. macroOut += cmSystemTools::GetSystemName();
  879. return ExpandMacroResult::Ok;
  880. }
  881. }
  882. return ExpandMacroResult::Ignore;
  883. };
  884. MacroExpander environmentMacroExpander =
  885. [&macroExpanders, &out, &envCycles](
  886. const std::string& macroNamespace, const std::string& macroName,
  887. std::string& result, int version) -> ExpandMacroResult {
  888. if (macroNamespace == "env" && !macroName.empty() && out) {
  889. auto v = out->Environment.find(macroName);
  890. if (v != out->Environment.end() && v->second) {
  891. auto e =
  892. VisitEnv(*v->second, envCycles[macroName], macroExpanders, version);
  893. if (e != ExpandMacroResult::Ok) {
  894. return e;
  895. }
  896. result += *v->second;
  897. return ExpandMacroResult::Ok;
  898. }
  899. }
  900. if (macroNamespace == "env" || macroNamespace == "penv") {
  901. if (macroName.empty()) {
  902. return ExpandMacroResult::Error;
  903. }
  904. const char* value = std::getenv(macroName.c_str());
  905. if (value) {
  906. result += value;
  907. }
  908. return ExpandMacroResult::Ok;
  909. }
  910. return ExpandMacroResult::Ignore;
  911. };
  912. macroExpanders.push_back(defaultMacroExpander);
  913. macroExpanders.push_back(environmentMacroExpander);
  914. for (auto& v : out->Environment) {
  915. if (v.second) {
  916. switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
  917. file.GetVersion(preset))) {
  918. case ExpandMacroResult::Error:
  919. return false;
  920. case ExpandMacroResult::Ignore:
  921. out.reset();
  922. return true;
  923. case ExpandMacroResult::Ok:
  924. break;
  925. }
  926. }
  927. }
  928. return ExpandMacros(file, preset, out, macroExpanders);
  929. }
  930. ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
  931. const std::vector<MacroExpander>& macroExpanders,
  932. int version)
  933. {
  934. if (status == CycleStatus::Verified) {
  935. return ExpandMacroResult::Ok;
  936. }
  937. if (status == CycleStatus::InProgress) {
  938. return ExpandMacroResult::Error;
  939. }
  940. status = CycleStatus::InProgress;
  941. auto e = ExpandMacros(value, macroExpanders, version);
  942. if (e != ExpandMacroResult::Ok) {
  943. return e;
  944. }
  945. status = CycleStatus::Verified;
  946. return ExpandMacroResult::Ok;
  947. }
  948. ExpandMacroResult ExpandMacros(
  949. std::string& out, const std::vector<MacroExpander>& macroExpanders,
  950. int version)
  951. {
  952. std::string result;
  953. std::string macroNamespace;
  954. std::string macroName;
  955. enum class State
  956. {
  957. Default,
  958. MacroNamespace,
  959. MacroName,
  960. } state = State::Default;
  961. for (auto c : out) {
  962. switch (state) {
  963. case State::Default:
  964. if (c == '$') {
  965. state = State::MacroNamespace;
  966. } else {
  967. result += c;
  968. }
  969. break;
  970. case State::MacroNamespace:
  971. if (c == '{') {
  972. if (IsValidMacroNamespace(macroNamespace)) {
  973. state = State::MacroName;
  974. } else {
  975. result += '$';
  976. result += macroNamespace;
  977. result += '{';
  978. macroNamespace.clear();
  979. state = State::Default;
  980. }
  981. } else {
  982. macroNamespace += c;
  983. if (!PrefixesValidMacroNamespace(macroNamespace)) {
  984. result += '$';
  985. result += macroNamespace;
  986. macroNamespace.clear();
  987. state = State::Default;
  988. }
  989. }
  990. break;
  991. case State::MacroName:
  992. if (c == '}') {
  993. auto e = ExpandMacro(result, macroNamespace, macroName,
  994. macroExpanders, version);
  995. if (e != ExpandMacroResult::Ok) {
  996. return e;
  997. }
  998. macroNamespace.clear();
  999. macroName.clear();
  1000. state = State::Default;
  1001. } else {
  1002. macroName += c;
  1003. }
  1004. break;
  1005. }
  1006. }
  1007. switch (state) {
  1008. case State::Default:
  1009. break;
  1010. case State::MacroNamespace:
  1011. result += '$';
  1012. result += macroNamespace;
  1013. break;
  1014. case State::MacroName:
  1015. return ExpandMacroResult::Error;
  1016. }
  1017. out = std::move(result);
  1018. return ExpandMacroResult::Ok;
  1019. }
  1020. ExpandMacroResult ExpandMacro(std::string& out,
  1021. const std::string& macroNamespace,
  1022. const std::string& macroName,
  1023. const std::vector<MacroExpander>& macroExpanders,
  1024. int version)
  1025. {
  1026. for (auto const& macroExpander : macroExpanders) {
  1027. auto result = macroExpander(macroNamespace, macroName, out, version);
  1028. if (result != ExpandMacroResult::Ignore) {
  1029. return result;
  1030. }
  1031. }
  1032. if (macroNamespace == "vendor") {
  1033. return ExpandMacroResult::Ignore;
  1034. }
  1035. return ExpandMacroResult::Error;
  1036. }
  1037. }
  1038. cmCMakePresetsFile::ReadFileResult
  1039. cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
  1040. const cmCMakePresetsFile::Preset& parentPreset)
  1041. {
  1042. auto& preset = *this;
  1043. const ConfigurePreset& parent =
  1044. static_cast<const ConfigurePreset&>(parentPreset);
  1045. InheritString(preset.Generator, parent.Generator);
  1046. InheritString(preset.Architecture, parent.Architecture);
  1047. InheritString(preset.Toolset, parent.Toolset);
  1048. if (!preset.ArchitectureStrategy) {
  1049. preset.ArchitectureStrategy = parent.ArchitectureStrategy;
  1050. }
  1051. if (!preset.ToolsetStrategy) {
  1052. preset.ToolsetStrategy = parent.ToolsetStrategy;
  1053. }
  1054. InheritString(preset.BinaryDir, parent.BinaryDir);
  1055. InheritString(preset.InstallDir, parent.InstallDir);
  1056. InheritOptionalValue(preset.WarnDev, parent.WarnDev);
  1057. InheritOptionalValue(preset.ErrorDev, parent.ErrorDev);
  1058. InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated);
  1059. InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated);
  1060. InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized);
  1061. InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli);
  1062. InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars);
  1063. for (auto const& v : parent.CacheVariables) {
  1064. preset.CacheVariables.insert(v);
  1065. }
  1066. return ReadFileResult::READ_OK;
  1067. }
  1068. cmCMakePresetsFile::ReadFileResult
  1069. cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit()
  1070. {
  1071. auto& preset = *this;
  1072. if (preset.Environment.count("") != 0) {
  1073. return ReadFileResult::INVALID_PRESET;
  1074. }
  1075. return ReadFileResult::READ_OK;
  1076. }
  1077. cmCMakePresetsFile::ReadFileResult
  1078. cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit()
  1079. {
  1080. auto& preset = *this;
  1081. if (!preset.Hidden) {
  1082. if (preset.Generator.empty()) {
  1083. return ReadFileResult::INVALID_PRESET;
  1084. }
  1085. if (preset.BinaryDir.empty()) {
  1086. return ReadFileResult::INVALID_PRESET;
  1087. }
  1088. if (preset.WarnDev == false && preset.ErrorDev == true) {
  1089. return ReadFileResult::INVALID_PRESET;
  1090. }
  1091. if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) {
  1092. return ReadFileResult::INVALID_PRESET;
  1093. }
  1094. if (preset.CacheVariables.count("") != 0) {
  1095. return ReadFileResult::INVALID_PRESET;
  1096. }
  1097. }
  1098. return ReadFileResult::READ_OK;
  1099. }
  1100. cmCMakePresetsFile::ReadFileResult
  1101. cmCMakePresetsFile::BuildPreset::VisitPresetInherit(
  1102. const cmCMakePresetsFile::Preset& parentPreset)
  1103. {
  1104. auto& preset = *this;
  1105. const BuildPreset& parent = static_cast<const BuildPreset&>(parentPreset);
  1106. InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
  1107. InheritOptionalValue(preset.InheritConfigureEnvironment,
  1108. parent.InheritConfigureEnvironment);
  1109. InheritOptionalValue(preset.Jobs, parent.Jobs);
  1110. InheritVector(preset.Targets, parent.Targets);
  1111. InheritString(preset.Configuration, parent.Configuration);
  1112. InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
  1113. InheritOptionalValue(preset.Verbose, parent.Verbose);
  1114. InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
  1115. return ReadFileResult::READ_OK;
  1116. }
  1117. cmCMakePresetsFile::ReadFileResult
  1118. cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit()
  1119. {
  1120. auto& preset = *this;
  1121. if (!preset.Hidden && preset.ConfigurePreset.empty()) {
  1122. return ReadFileResult::INVALID_PRESET;
  1123. }
  1124. return ReadFileResult::READ_OK;
  1125. }
  1126. cmCMakePresetsFile::ReadFileResult
  1127. cmCMakePresetsFile::TestPreset::VisitPresetInherit(
  1128. const cmCMakePresetsFile::Preset& parentPreset)
  1129. {
  1130. auto& preset = *this;
  1131. const TestPreset& parent = static_cast<const TestPreset&>(parentPreset);
  1132. InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
  1133. InheritOptionalValue(preset.InheritConfigureEnvironment,
  1134. parent.InheritConfigureEnvironment);
  1135. InheritString(preset.Configuration, parent.Configuration);
  1136. InheritVector(preset.OverwriteConfigurationFile,
  1137. parent.OverwriteConfigurationFile);
  1138. if (parent.Output) {
  1139. if (preset.Output) {
  1140. auto& output = preset.Output.value();
  1141. const auto& parentOutput = parent.Output.value();
  1142. InheritOptionalValue(output.ShortProgress, parentOutput.ShortProgress);
  1143. InheritOptionalValue(output.Verbosity, parentOutput.Verbosity);
  1144. InheritOptionalValue(output.Debug, parentOutput.Debug);
  1145. InheritOptionalValue(output.OutputOnFailure,
  1146. parentOutput.OutputOnFailure);
  1147. InheritOptionalValue(output.Quiet, parentOutput.Quiet);
  1148. InheritString(output.OutputLogFile, parentOutput.OutputLogFile);
  1149. InheritOptionalValue(output.LabelSummary, parentOutput.LabelSummary);
  1150. InheritOptionalValue(output.SubprojectSummary,
  1151. parentOutput.SubprojectSummary);
  1152. InheritOptionalValue(output.MaxPassedTestOutputSize,
  1153. parentOutput.MaxPassedTestOutputSize);
  1154. InheritOptionalValue(output.MaxFailedTestOutputSize,
  1155. parentOutput.MaxFailedTestOutputSize);
  1156. InheritOptionalValue(output.MaxTestNameWidth,
  1157. parentOutput.MaxTestNameWidth);
  1158. } else {
  1159. preset.Output = parent.Output;
  1160. }
  1161. }
  1162. if (parent.Filter) {
  1163. if (parent.Filter->Include) {
  1164. if (preset.Filter && preset.Filter->Include) {
  1165. auto& include = *preset.Filter->Include;
  1166. const auto& parentInclude = *parent.Filter->Include;
  1167. InheritString(include.Name, parentInclude.Name);
  1168. InheritString(include.Label, parentInclude.Label);
  1169. InheritOptionalValue(include.Index, parentInclude.Index);
  1170. } else {
  1171. if (!preset.Filter) {
  1172. preset.Filter.emplace();
  1173. }
  1174. preset.Filter->Include = parent.Filter->Include;
  1175. }
  1176. }
  1177. if (parent.Filter->Exclude) {
  1178. if (preset.Filter && preset.Filter->Exclude) {
  1179. auto& exclude = *preset.Filter->Exclude;
  1180. const auto& parentExclude = *parent.Filter->Exclude;
  1181. InheritString(exclude.Name, parentExclude.Name);
  1182. InheritString(exclude.Label, parentExclude.Label);
  1183. InheritOptionalValue(exclude.Fixtures, parentExclude.Fixtures);
  1184. } else {
  1185. if (!preset.Filter) {
  1186. preset.Filter.emplace();
  1187. }
  1188. preset.Filter->Exclude = parent.Filter->Exclude;
  1189. }
  1190. }
  1191. }
  1192. if (parent.Execution) {
  1193. if (preset.Execution) {
  1194. auto& execution = *preset.Execution;
  1195. const auto& parentExecution = *parent.Execution;
  1196. InheritOptionalValue(execution.StopOnFailure,
  1197. parentExecution.StopOnFailure);
  1198. InheritOptionalValue(execution.EnableFailover,
  1199. parentExecution.EnableFailover);
  1200. InheritOptionalValue(execution.Jobs, parentExecution.Jobs);
  1201. InheritString(execution.ResourceSpecFile,
  1202. parentExecution.ResourceSpecFile);
  1203. InheritOptionalValue(execution.TestLoad, parentExecution.TestLoad);
  1204. InheritOptionalValue(execution.ShowOnly, parentExecution.ShowOnly);
  1205. InheritOptionalValue(execution.Repeat, parentExecution.Repeat);
  1206. InheritOptionalValue(execution.InteractiveDebugging,
  1207. parentExecution.InteractiveDebugging);
  1208. InheritOptionalValue(execution.ScheduleRandom,
  1209. parentExecution.ScheduleRandom);
  1210. InheritOptionalValue(execution.Timeout, parentExecution.Timeout);
  1211. InheritOptionalValue(execution.NoTestsAction,
  1212. parentExecution.NoTestsAction);
  1213. } else {
  1214. preset.Execution = parent.Execution;
  1215. }
  1216. }
  1217. return ReadFileResult::READ_OK;
  1218. }
  1219. cmCMakePresetsFile::ReadFileResult
  1220. cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit()
  1221. {
  1222. auto& preset = *this;
  1223. if (!preset.Hidden && preset.ConfigurePreset.empty()) {
  1224. return ReadFileResult::INVALID_PRESET;
  1225. }
  1226. return ReadFileResult::READ_OK;
  1227. }
  1228. std::string cmCMakePresetsFile::GetFilename(const std::string& sourceDir)
  1229. {
  1230. return cmStrCat(sourceDir, "/CMakePresets.json");
  1231. }
  1232. std::string cmCMakePresetsFile::GetUserFilename(const std::string& sourceDir)
  1233. {
  1234. return cmStrCat(sourceDir, "/CMakeUserPresets.json");
  1235. }
  1236. cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
  1237. const std::string& sourceDir, bool allowNoFiles)
  1238. {
  1239. this->SourceDir = sourceDir;
  1240. this->ClearPresets();
  1241. auto result = this->ReadProjectPresetsInternal(allowNoFiles);
  1242. if (result != ReadFileResult::READ_OK) {
  1243. this->ClearPresets();
  1244. }
  1245. return result;
  1246. }
  1247. cmCMakePresetsFile::ReadFileResult
  1248. cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles)
  1249. {
  1250. bool haveOneFile = false;
  1251. std::string filename = GetUserFilename(this->SourceDir);
  1252. if (cmSystemTools::FileExists(filename)) {
  1253. auto result = this->ReadJSONFile(filename, true);
  1254. if (result != ReadFileResult::READ_OK) {
  1255. return result;
  1256. }
  1257. haveOneFile = true;
  1258. }
  1259. filename = GetFilename(this->SourceDir);
  1260. if (cmSystemTools::FileExists(filename)) {
  1261. auto result = this->ReadJSONFile(filename, false);
  1262. if (result != ReadFileResult::READ_OK) {
  1263. return result;
  1264. }
  1265. haveOneFile = true;
  1266. }
  1267. if (!haveOneFile) {
  1268. return allowNoFiles ? ReadFileResult::READ_OK
  1269. : ReadFileResult::FILE_NOT_FOUND;
  1270. }
  1271. CHECK_OK(ComputePresetInheritance(this->ConfigurePresets))
  1272. CHECK_OK(ComputePresetInheritance(this->BuildPresets))
  1273. CHECK_OK(ComputePresetInheritance(this->TestPresets))
  1274. for (auto& it : this->ConfigurePresets) {
  1275. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  1276. return ReadFileResult::INVALID_MACRO_EXPANSION;
  1277. }
  1278. }
  1279. for (auto& it : this->BuildPresets) {
  1280. if (!it.second.Unexpanded.Hidden) {
  1281. const auto configurePreset =
  1282. this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
  1283. if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true) &&
  1284. configurePreset != this->ConfigurePresets.end()) {
  1285. it.second.Unexpanded.Environment.insert(
  1286. configurePreset->second.Unexpanded.Environment.begin(),
  1287. configurePreset->second.Unexpanded.Environment.end());
  1288. }
  1289. }
  1290. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  1291. return ReadFileResult::INVALID_MACRO_EXPANSION;
  1292. }
  1293. }
  1294. for (auto& it : this->TestPresets) {
  1295. if (!it.second.Unexpanded.Hidden) {
  1296. const auto configurePreset =
  1297. this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
  1298. if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true) &&
  1299. configurePreset != this->ConfigurePresets.end()) {
  1300. it.second.Unexpanded.Environment.insert(
  1301. configurePreset->second.Unexpanded.Environment.begin(),
  1302. configurePreset->second.Unexpanded.Environment.end());
  1303. }
  1304. }
  1305. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  1306. return ReadFileResult::INVALID_MACRO_EXPANSION;
  1307. }
  1308. }
  1309. return ReadFileResult::READ_OK;
  1310. }
  1311. const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
  1312. {
  1313. switch (result) {
  1314. case ReadFileResult::READ_OK:
  1315. return "OK";
  1316. case ReadFileResult::FILE_NOT_FOUND:
  1317. return "File not found";
  1318. case ReadFileResult::JSON_PARSE_ERROR:
  1319. return "JSON parse error";
  1320. case ReadFileResult::INVALID_ROOT:
  1321. return "Invalid root object";
  1322. case ReadFileResult::NO_VERSION:
  1323. return "No \"version\" field";
  1324. case ReadFileResult::INVALID_VERSION:
  1325. return "Invalid \"version\" field";
  1326. case ReadFileResult::UNRECOGNIZED_VERSION:
  1327. return "Unrecognized \"version\" field";
  1328. case ReadFileResult::INVALID_CMAKE_VERSION:
  1329. return "Invalid \"cmakeMinimumRequired\" field";
  1330. case ReadFileResult::UNRECOGNIZED_CMAKE_VERSION:
  1331. return "\"cmakeMinimumRequired\" version too new";
  1332. case ReadFileResult::INVALID_PRESETS:
  1333. return "Invalid \"configurePresets\" field";
  1334. case ReadFileResult::INVALID_PRESET:
  1335. return "Invalid preset";
  1336. case ReadFileResult::INVALID_VARIABLE:
  1337. return "Invalid CMake variable definition";
  1338. case ReadFileResult::DUPLICATE_PRESETS:
  1339. return "Duplicate presets";
  1340. case ReadFileResult::CYCLIC_PRESET_INHERITANCE:
  1341. return "Cyclic preset inheritance";
  1342. case ReadFileResult::USER_PRESET_INHERITANCE:
  1343. return "Project preset inherits from user preset";
  1344. case ReadFileResult::INVALID_MACRO_EXPANSION:
  1345. return "Invalid macro expansion";
  1346. case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
  1347. return "File version must be 2 or higher for build and test preset "
  1348. "support.";
  1349. case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
  1350. return "File version must be 3 or higher for installDir preset "
  1351. "support.";
  1352. }
  1353. return "Unknown error";
  1354. }
  1355. cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
  1356. const std::string& filename, bool user)
  1357. {
  1358. cmsys::ifstream fin(filename.c_str());
  1359. if (!fin) {
  1360. return ReadFileResult::FILE_NOT_FOUND;
  1361. }
  1362. // If there's a BOM, toss it.
  1363. cmsys::FStream::ReadBOM(fin);
  1364. Json::Value root;
  1365. Json::CharReaderBuilder builder;
  1366. Json::CharReaderBuilder::strictMode(&builder.settings_);
  1367. if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
  1368. return ReadFileResult::JSON_PARSE_ERROR;
  1369. }
  1370. int v = 0;
  1371. auto result = RootVersionHelper(v, &root);
  1372. if (result != ReadFileResult::READ_OK) {
  1373. return result;
  1374. }
  1375. if (v < MIN_VERSION || v > MAX_VERSION) {
  1376. return ReadFileResult::UNRECOGNIZED_VERSION;
  1377. }
  1378. if (user) {
  1379. this->UserVersion = v;
  1380. } else {
  1381. this->Version = v;
  1382. }
  1383. // Support for build and test presets added in version 2.
  1384. if (v < 2 &&
  1385. (root.isMember("buildPresets") || root.isMember("testPresets"))) {
  1386. return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
  1387. }
  1388. RootPresets presets;
  1389. if ((result = RootPresetsHelper(presets, &root)) !=
  1390. ReadFileResult::READ_OK) {
  1391. return result;
  1392. }
  1393. unsigned int currentMajor = cmVersion::GetMajorVersion();
  1394. unsigned int currentMinor = cmVersion::GetMinorVersion();
  1395. unsigned int currentPatch = cmVersion::GetPatchVersion();
  1396. auto const& required = presets.CMakeMinimumRequired;
  1397. if (required.Major > currentMajor ||
  1398. (required.Major == currentMajor &&
  1399. (required.Minor > currentMinor ||
  1400. (required.Minor == currentMinor &&
  1401. (required.Patch > currentPatch))))) {
  1402. return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
  1403. }
  1404. for (auto& preset : presets.ConfigurePresets) {
  1405. preset.User = user;
  1406. if (preset.Name.empty()) {
  1407. return ReadFileResult::INVALID_PRESET;
  1408. }
  1409. PresetPair<ConfigurePreset> presetPair;
  1410. presetPair.Unexpanded = preset;
  1411. presetPair.Expanded = cm::nullopt;
  1412. if (!this->ConfigurePresets
  1413. .emplace(std::make_pair(preset.Name, presetPair))
  1414. .second) {
  1415. return ReadFileResult::DUPLICATE_PRESETS;
  1416. }
  1417. // Support for installDir presets added in version 3.
  1418. if (v < 3 && !preset.InstallDir.empty()) {
  1419. return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
  1420. }
  1421. this->ConfigurePresetOrder.push_back(preset.Name);
  1422. }
  1423. for (auto& preset : presets.BuildPresets) {
  1424. preset.User = user;
  1425. if (preset.Name.empty()) {
  1426. return ReadFileResult::INVALID_PRESET;
  1427. }
  1428. PresetPair<BuildPreset> presetPair;
  1429. presetPair.Unexpanded = preset;
  1430. presetPair.Expanded = cm::nullopt;
  1431. if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
  1432. return ReadFileResult::DUPLICATE_PRESETS;
  1433. }
  1434. this->BuildPresetOrder.push_back(preset.Name);
  1435. }
  1436. for (auto& preset : presets.TestPresets) {
  1437. preset.User = user;
  1438. if (preset.Name.empty()) {
  1439. return ReadFileResult::INVALID_PRESET;
  1440. }
  1441. PresetPair<TestPreset> presetPair;
  1442. presetPair.Unexpanded = preset;
  1443. presetPair.Expanded = cm::nullopt;
  1444. if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
  1445. return ReadFileResult::DUPLICATE_PRESETS;
  1446. }
  1447. this->TestPresetOrder.push_back(preset.Name);
  1448. }
  1449. return ReadFileResult::READ_OK;
  1450. }
  1451. void cmCMakePresetsFile::ClearPresets()
  1452. {
  1453. this->ConfigurePresets.clear();
  1454. this->BuildPresets.clear();
  1455. this->TestPresets.clear();
  1456. this->ConfigurePresetOrder.clear();
  1457. this->BuildPresetOrder.clear();
  1458. this->TestPresetOrder.clear();
  1459. }
  1460. void cmCMakePresetsFile::PrintPresets(
  1461. const std::vector<const cmCMakePresetsFile::Preset*>& presets)
  1462. {
  1463. if (presets.empty()) {
  1464. return;
  1465. }
  1466. auto longestPresetName =
  1467. std::max_element(presets.begin(), presets.end(),
  1468. [](const cmCMakePresetsFile::Preset* a,
  1469. const cmCMakePresetsFile::Preset* b) {
  1470. return a->Name.length() < b->Name.length();
  1471. });
  1472. auto longestLength = (*longestPresetName)->Name.length();
  1473. for (const auto* preset : presets) {
  1474. std::cout << " \"" << preset->Name << '"';
  1475. const auto& description = preset->DisplayName;
  1476. if (!description.empty()) {
  1477. for (std::size_t i = 0; i < longestLength - preset->Name.length(); ++i) {
  1478. std::cout << ' ';
  1479. }
  1480. std::cout << " - " << description;
  1481. }
  1482. std::cout << '\n';
  1483. }
  1484. }
  1485. void cmCMakePresetsFile::PrintConfigurePresetList() const
  1486. {
  1487. PrintConfigurePresetList([](const ConfigurePreset&) { return true; });
  1488. }
  1489. void cmCMakePresetsFile::PrintConfigurePresetList(
  1490. const std::function<bool(const ConfigurePreset&)>& filter) const
  1491. {
  1492. std::vector<const cmCMakePresetsFile::Preset*> presets;
  1493. for (auto const& p : this->ConfigurePresetOrder) {
  1494. auto const& preset = this->ConfigurePresets.at(p);
  1495. if (!preset.Unexpanded.Hidden && preset.Expanded &&
  1496. filter(preset.Unexpanded)) {
  1497. presets.push_back(
  1498. static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
  1499. }
  1500. }
  1501. if (!presets.empty()) {
  1502. std::cout << "Available configure presets:\n\n";
  1503. cmCMakePresetsFile::PrintPresets(presets);
  1504. }
  1505. }
  1506. void cmCMakePresetsFile::PrintBuildPresetList() const
  1507. {
  1508. std::vector<const cmCMakePresetsFile::Preset*> presets;
  1509. for (auto const& p : this->BuildPresetOrder) {
  1510. auto const& preset = this->BuildPresets.at(p);
  1511. if (!preset.Unexpanded.Hidden && preset.Expanded) {
  1512. presets.push_back(
  1513. static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
  1514. }
  1515. }
  1516. if (!presets.empty()) {
  1517. std::cout << "Available build presets:\n\n";
  1518. cmCMakePresetsFile::PrintPresets(presets);
  1519. }
  1520. }
  1521. void cmCMakePresetsFile::PrintTestPresetList() const
  1522. {
  1523. std::vector<const cmCMakePresetsFile::Preset*> presets;
  1524. for (auto const& p : this->TestPresetOrder) {
  1525. auto const& preset = this->TestPresets.at(p);
  1526. if (!preset.Unexpanded.Hidden && preset.Expanded) {
  1527. presets.push_back(
  1528. static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
  1529. }
  1530. }
  1531. if (!presets.empty()) {
  1532. std::cout << "Available test presets:\n\n";
  1533. cmCMakePresetsFile::PrintPresets(presets);
  1534. }
  1535. }
  1536. void cmCMakePresetsFile::PrintAllPresets() const
  1537. {
  1538. this->PrintConfigurePresetList();
  1539. std::cout << std::endl;
  1540. this->PrintBuildPresetList();
  1541. std::cout << std::endl;
  1542. this->PrintTestPresetList();
  1543. }