1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #pragma once
4 
5 #include "cmConfigure.h" // IWYU pragma: keep
6 
7 #include <functional>
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include <cm/optional>
15 
16 class cmCMakePresetsFile
17 {
18 public:
19   enum class ReadFileResult
20   {
21     READ_OK,
22     FILE_NOT_FOUND,
23     JSON_PARSE_ERROR,
24     INVALID_ROOT,
25     NO_VERSION,
26     INVALID_VERSION,
27     UNRECOGNIZED_VERSION,
28     INVALID_CMAKE_VERSION,
29     UNRECOGNIZED_CMAKE_VERSION,
30     INVALID_PRESETS,
31     INVALID_PRESET,
32     INVALID_VARIABLE,
33     DUPLICATE_PRESETS,
34     CYCLIC_PRESET_INHERITANCE,
35     USER_PRESET_INHERITANCE,
36     INVALID_MACRO_EXPANSION,
37     BUILD_TEST_PRESETS_UNSUPPORTED,
38     INVALID_CONFIGURE_PRESET,
39     INSTALL_PREFIX_UNSUPPORTED,
40     INVALID_CONDITION,
41     CONDITION_UNSUPPORTED,
42     TOOLCHAIN_FILE_UNSUPPORTED,
43   };
44 
45   enum class ArchToolsetStrategy
46   {
47     Set,
48     External,
49   };
50 
51   class CacheVariable
52   {
53   public:
54     std::string Type;
55     std::string Value;
56   };
57 
58   class Condition;
59 
60   class Preset
61   {
62   public:
63 #if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
64     // The move assignment operators for several STL classes did not become
65     // noexcept until C++17, which causes some tools to warn about this move
66     // assignment operator throwing an exception when it shouldn't. Disable the
67     // move assignment operator until C++17 is enabled.
68     // Explicitly defining a copy assignment operator prevents the compiler
69     // from automatically generating a move assignment operator.
70     Preset& operator=(const Preset& /*other*/) = default;
71 #endif
72 
73     virtual ~Preset() = default;
74 
75     std::string Name;
76     std::vector<std::string> Inherits;
77     bool Hidden;
78     bool User;
79     std::string DisplayName;
80     std::string Description;
81 
82     std::shared_ptr<Condition> ConditionEvaluator;
83     bool ConditionResult = true;
84 
85     std::map<std::string, cm::optional<std::string>> Environment;
86 
87     virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0;
VisitPresetBeforeInherit()88     virtual ReadFileResult VisitPresetBeforeInherit()
89     {
90       return ReadFileResult::READ_OK;
91     }
92 
VisitPresetAfterInherit(int)93     virtual ReadFileResult VisitPresetAfterInherit(int /* version */)
94     {
95       return ReadFileResult::READ_OK;
96     }
97   };
98 
99   class ConfigurePreset : public Preset
100   {
101   public:
102 #if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
103     // The move assignment operators for several STL classes did not become
104     // noexcept until C++17, which causes some tools to warn about this move
105     // assignment operator throwing an exception when it shouldn't. Disable the
106     // move assignment operator until C++17 is enabled.
107     // Explicitly defining a copy assignment operator prevents the compiler
108     // from automatically generating a move assignment operator.
109     ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default;
110 #endif
111 
112     std::string Generator;
113     std::string Architecture;
114     cm::optional<ArchToolsetStrategy> ArchitectureStrategy;
115     std::string Toolset;
116     cm::optional<ArchToolsetStrategy> ToolsetStrategy;
117     std::string ToolchainFile;
118     std::string BinaryDir;
119     std::string InstallDir;
120 
121     std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
122 
123     cm::optional<bool> WarnDev;
124     cm::optional<bool> ErrorDev;
125     cm::optional<bool> WarnDeprecated;
126     cm::optional<bool> ErrorDeprecated;
127     cm::optional<bool> WarnUninitialized;
128     cm::optional<bool> WarnUnusedCli;
129     cm::optional<bool> WarnSystemVars;
130 
131     cm::optional<bool> DebugOutput;
132     cm::optional<bool> DebugTryCompile;
133     cm::optional<bool> DebugFind;
134 
135     ReadFileResult VisitPresetInherit(const Preset& parent) override;
136     ReadFileResult VisitPresetBeforeInherit() override;
137     ReadFileResult VisitPresetAfterInherit(int version) override;
138   };
139 
140   class BuildPreset : public Preset
141   {
142   public:
143 #if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
144     // The move assignment operators for several STL classes did not become
145     // noexcept until C++17, which causes some tools to warn about this move
146     // assignment operator throwing an exception when it shouldn't. Disable the
147     // move assignment operator until C++17 is enabled.
148     // Explicitly defining a copy assignment operator prevents the compiler
149     // from automatically generating a move assignment operator.
150     BuildPreset& operator=(const BuildPreset& /*other*/) = default;
151 #endif
152 
153     std::string ConfigurePreset;
154     cm::optional<bool> InheritConfigureEnvironment;
155     cm::optional<int> Jobs;
156     std::vector<std::string> Targets;
157     std::string Configuration;
158     cm::optional<bool> CleanFirst;
159     cm::optional<bool> Verbose;
160     std::vector<std::string> NativeToolOptions;
161 
162     ReadFileResult VisitPresetInherit(const Preset& parent) override;
163     ReadFileResult VisitPresetAfterInherit(int /* version */) override;
164   };
165 
166   class TestPreset : public Preset
167   {
168   public:
169 #if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
170     // The move assignment operators for several STL classes did not become
171     // noexcept until C++17, which causes some tools to warn about this move
172     // assignment operator throwing an exception when it shouldn't. Disable the
173     // move assignment operator until C++17 is enabled.
174     // Explicitly defining a copy assignment operator prevents the compiler
175     // from automatically generating a move assignment operator.
176     TestPreset& operator=(const TestPreset& /*other*/) = default;
177 #endif
178 
179     struct OutputOptions
180     {
181       enum class VerbosityEnum
182       {
183         Default,
184         Verbose,
185         Extra
186       };
187 
188       cm::optional<bool> ShortProgress;
189       cm::optional<VerbosityEnum> Verbosity;
190       cm::optional<bool> Debug;
191       cm::optional<bool> OutputOnFailure;
192       cm::optional<bool> Quiet;
193       std::string OutputLogFile;
194       cm::optional<bool> LabelSummary;
195       cm::optional<bool> SubprojectSummary;
196       cm::optional<int> MaxPassedTestOutputSize;
197       cm::optional<int> MaxFailedTestOutputSize;
198       cm::optional<int> MaxTestNameWidth;
199     };
200 
201     struct IncludeOptions
202     {
203       struct IndexOptions
204       {
205         cm::optional<int> Start;
206         cm::optional<int> End;
207         cm::optional<int> Stride;
208         std::vector<int> SpecificTests;
209 
210         std::string IndexFile;
211       };
212 
213       std::string Name;
214       std::string Label;
215       cm::optional<IndexOptions> Index;
216       cm::optional<bool> UseUnion;
217     };
218 
219     struct ExcludeOptions
220     {
221       struct FixturesOptions
222       {
223         std::string Any;
224         std::string Setup;
225         std::string Cleanup;
226       };
227 
228       std::string Name;
229       std::string Label;
230       cm::optional<FixturesOptions> Fixtures;
231     };
232 
233     struct FilterOptions
234     {
235       cm::optional<IncludeOptions> Include;
236       cm::optional<ExcludeOptions> Exclude;
237     };
238 
239     struct ExecutionOptions
240     {
241       enum class ShowOnlyEnum
242       {
243         Human,
244         JsonV1
245       };
246 
247       struct RepeatOptions
248       {
249         enum class ModeEnum
250         {
251           UntilFail,
252           UntilPass,
253           AfterTimeout
254         };
255 
256         ModeEnum Mode;
257         int Count;
258       };
259 
260       enum class NoTestsActionEnum
261       {
262         Default,
263         Error,
264         Ignore
265       };
266 
267       cm::optional<bool> StopOnFailure;
268       cm::optional<bool> EnableFailover;
269       cm::optional<int> Jobs;
270       std::string ResourceSpecFile;
271       cm::optional<int> TestLoad;
272       cm::optional<ShowOnlyEnum> ShowOnly;
273 
274       cm::optional<RepeatOptions> Repeat;
275       cm::optional<bool> InteractiveDebugging;
276       cm::optional<bool> ScheduleRandom;
277       cm::optional<int> Timeout;
278       cm::optional<NoTestsActionEnum> NoTestsAction;
279     };
280 
281     std::string ConfigurePreset;
282     cm::optional<bool> InheritConfigureEnvironment;
283     std::string Configuration;
284     std::vector<std::string> OverwriteConfigurationFile;
285     cm::optional<OutputOptions> Output;
286     cm::optional<FilterOptions> Filter;
287     cm::optional<ExecutionOptions> Execution;
288 
289     ReadFileResult VisitPresetInherit(const Preset& parent) override;
290     ReadFileResult VisitPresetAfterInherit(int /* version */) override;
291   };
292 
293   template <class T>
294   class PresetPair
295   {
296   public:
297     T Unexpanded;
298     cm::optional<T> Expanded;
299   };
300 
301   std::map<std::string, PresetPair<ConfigurePreset>> ConfigurePresets;
302   std::map<std::string, PresetPair<BuildPreset>> BuildPresets;
303   std::map<std::string, PresetPair<TestPreset>> TestPresets;
304 
305   std::vector<std::string> ConfigurePresetOrder;
306   std::vector<std::string> BuildPresetOrder;
307   std::vector<std::string> TestPresetOrder;
308 
309   std::string SourceDir;
310   int Version;
311   int UserVersion;
312 
GetVersion(const Preset & preset)313   int GetVersion(const Preset& preset) const
314   {
315     return preset.User ? this->UserVersion : this->Version;
316   }
317 
318   static std::string GetFilename(const std::string& sourceDir);
319   static std::string GetUserFilename(const std::string& sourceDir);
320   ReadFileResult ReadProjectPresets(const std::string& sourceDir,
321                                     bool allowNoFiles = false);
322   static const char* ResultToString(ReadFileResult result);
323 
GetGeneratorForPreset(const std::string & presetName)324   std::string GetGeneratorForPreset(const std::string& presetName) const
325   {
326     auto configurePresetName = presetName;
327 
328     auto buildPresetIterator = this->BuildPresets.find(presetName);
329     if (buildPresetIterator != this->BuildPresets.end()) {
330       configurePresetName =
331         buildPresetIterator->second.Unexpanded.ConfigurePreset;
332     } else {
333       auto testPresetIterator = this->TestPresets.find(presetName);
334       if (testPresetIterator != this->TestPresets.end()) {
335         configurePresetName =
336           testPresetIterator->second.Unexpanded.ConfigurePreset;
337       }
338     }
339 
340     auto configurePresetIterator =
341       this->ConfigurePresets.find(configurePresetName);
342     if (configurePresetIterator != this->ConfigurePresets.end()) {
343       return configurePresetIterator->second.Unexpanded.Generator;
344     }
345 
346     // This should only happen if the preset is hidden
347     // or (for build or test presets) if ConfigurePreset is invalid.
348     return "";
349   }
350 
351   static void PrintPresets(
352     const std::vector<const cmCMakePresetsFile::Preset*>& presets);
353   void PrintConfigurePresetList() const;
354   void PrintConfigurePresetList(
355     const std::function<bool(const ConfigurePreset&)>& filter) const;
356   void PrintBuildPresetList() const;
357   void PrintTestPresetList() const;
358   void PrintAllPresets() const;
359 
360 private:
361   ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
362   ReadFileResult ReadJSONFile(const std::string& filename, bool user);
363   void ClearPresets();
364 };
365