Merge topic 'cmake-presets-include'

26a5512c0f CMakePresets: Add include field
a239f23a98 Refactor: Generalize file graph in CMakePresets
84d440caac Refactor: Split JSON processing into configure, build, and test presets
fd6ea2f67f Refactor: Rename cmCMakePresetsFile to cmCMakePresetsGraph

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !6829
This commit is contained in:
Brad King
2022-01-10 22:11:55 +00:00
committed by Kitware Robot
58 changed files with 1983 additions and 1331 deletions

View File

@@ -12,9 +12,10 @@ Introduction
One problem that CMake users often face is sharing settings with other people
for common ways to configure a project. This may be done to support CI builds,
or for users who frequently use the same build. CMake supports two files,
or for users who frequently use the same build. CMake supports two main files,
``CMakePresets.json`` and ``CMakeUserPresets.json``, that allow users to
specify common configure options and share them with others.
specify common configure options and share them with others. CMake also
supports files included with the ``include`` field.
``CMakePresets.json`` and ``CMakeUserPresets.json`` live in the project's root
directory. They both have exactly the same format, and both are optional
@@ -26,6 +27,21 @@ builds. ``CMakePresets.json`` may be checked into a version control system, and
is using Git, ``CMakePresets.json`` may be tracked, and
``CMakeUserPresets.json`` should be added to the ``.gitignore``.
``CMakePresets.json`` and ``CMakeUserPresets.json`` can include other files
with the ``include`` field in file version ``4`` and later. Files included by
these files can also include other files. If a preset file contains presets
that inherit from presets in another file, the file must include the other file
either directly or indirectly. Include cycles are not allowed among files (if
``a.json`` includes ``b.json``, ``b.json`` cannot include ``a.json``). However,
a file may be included multiple times from the same file or from different
files. If ``CMakePresets.json`` and ``CMakeUserPresets.json`` are both present,
``CMakeUserPresets.json`` implicitly includes ``CMakePresets.json``, even with
no ``include`` field, in all versions of the format. Files directly or
indirectly included from ``CMakePresets.json`` must be inside the project
directory. This restriction does not apply to ``CMakeUserPresets.json`` and
files that it includes, unless those files are also included by
``CMakePresets.json``.
Format
======
@@ -39,7 +55,7 @@ The root object recognizes the following fields:
``version``
A required integer representing the version of the JSON schema.
The supported versions are ``1``, ``2``, and ``3``.
The supported versions are ``1``, ``2``, ``3``, and ``4``.
``cmakeMinimumRequired``
@@ -82,6 +98,12 @@ The root object recognizes the following fields:
An optional array of `Test Preset`_ objects.
This is allowed in preset files specifying version ``2`` or above.
``include``
An optional array of strings representing files to include. If the filenames
are not absolute, they are considered relative to the current file.
This is allowed in preset files specifying version ``4`` or above.
Configure Preset
^^^^^^^^^^^^^^^^

View File

@@ -1,5 +1,5 @@
{
"version": 3,
"version": 4,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,

View File

@@ -42,6 +42,21 @@
"testPresets": { "$ref": "#/definitions/testPresetsV3"}
},
"additionalProperties": false
},
{
"properties": {
"version": {
"const": 4,
"description": "A required integer representing the version of the JSON schema."
},
"cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
"vendor": { "$ref": "#/definitions/vendor" },
"configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
"buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
"testPresets": { "$ref": "#/definitions/testPresetsV3"},
"include": { "$ref": "#/definitions/include"}
},
"additionalProperties": false
}
],
"required": [
@@ -1235,6 +1250,13 @@
"description": "Null indicates that the condition always evaluates to true and is not inherited."
}
]
},
"include": {
"type": "array",
"description": "An optional array of strings representing files to include. If the filenames are not absolute, they are considered relative to the current file.",
"items": {
"type": "string"
}
}
}
}

View File

@@ -0,0 +1,6 @@
cmake-presets-include
---------------------
* :manual:`cmake-presets(7)` files now support schema version ``4``.
* :manual:`cmake-presets(7)` files now have an optional ``include`` field,
which allows the files to include other files.

View File

@@ -161,10 +161,13 @@ set(SRCS
cmCLocaleEnvironmentScope.cxx
cmCMakePath.h
cmCMakePath.cxx
cmCMakePresetsFile.cxx
cmCMakePresetsFile.h
cmCMakePresetsFileInternal.h
cmCMakePresetsFileReadJSON.cxx
cmCMakePresetsGraph.cxx
cmCMakePresetsGraph.h
cmCMakePresetsGraphInternal.h
cmCMakePresetsGraphReadJSON.cxx
cmCMakePresetsGraphReadJSONBuildPresets.cxx
cmCMakePresetsGraphReadJSONConfigurePresets.cxx
cmCMakePresetsGraphReadJSONTestPresets.cxx
cmCommandArgumentParserHelper.cxx
cmCommonTargetGenerator.cxx
cmCommonTargetGenerator.h

View File

@@ -730,12 +730,12 @@ void CMakeSetupDialog::updatePreset(const QString& name)
}
void CMakeSetupDialog::showPresetLoadError(
const QString& dir, cmCMakePresetsFile::ReadFileResult result)
const QString& dir, cmCMakePresetsGraph::ReadFileResult result)
{
QMessageBox::warning(
this, "Error Reading CMake Presets",
QString::fromLocal8Bit("Could not read presets from %1: %2")
.arg(dir, cmCMakePresetsFile::ResultToString(result)));
.arg(dir, cmCMakePresetsGraph::ResultToString(result)));
}
void CMakeSetupDialog::doBinaryBrowse()

View File

@@ -60,7 +60,7 @@ protected slots:
void updatePresets(const QVector<QCMakePreset>& presets);
void updatePreset(const QString& name);
void showPresetLoadError(const QString& dir,
cmCMakePresetsFile::ReadFileResult result);
cmCMakePresetsGraph::ReadFileResult result);
void showProgress(const QString& msg, float percent);
void setEnabledState(bool);
bool setupFirstConfigure();

View File

@@ -32,7 +32,7 @@ QCMake::QCMake(QObject* p)
qRegisterMetaType<QCMakePropertyList>();
qRegisterMetaType<QProcessEnvironment>();
qRegisterMetaType<QVector<QCMakePreset>>();
qRegisterMetaType<cmCMakePresetsFile::ReadFileResult>();
qRegisterMetaType<cmCMakePresetsGraph::ReadFileResult>();
cmSystemTools::DisableRunCommandOutput();
cmSystemTools::SetRunCommandHideConsole(true);
@@ -69,9 +69,9 @@ QCMake::QCMake(QObject* p)
connect(&this->LoadPresetsTimer, &QTimer::timeout, this, [this]() {
this->loadPresets();
if (!this->PresetName.isEmpty() &&
this->CMakePresetsFile.ConfigurePresets.find(
this->CMakePresetsGraph.ConfigurePresets.find(
std::string(this->PresetName.toLocal8Bit())) ==
this->CMakePresetsFile.ConfigurePresets.end()) {
this->CMakePresetsGraph.ConfigurePresets.end()) {
this->setPreset(QString{});
}
});
@@ -159,7 +159,7 @@ void QCMake::setPreset(const QString& name, bool setBinary)
if (!name.isNull()) {
std::string presetName(name.toLocal8Bit());
auto const& expandedPreset =
this->CMakePresetsFile.ConfigurePresets[presetName].Expanded;
this->CMakePresetsGraph.ConfigurePresets[presetName].Expanded;
if (expandedPreset) {
if (setBinary && !expandedPreset->BinaryDir.empty()) {
QString binaryDir =
@@ -427,7 +427,7 @@ QCMakePropertyList QCMake::properties() const
if (!this->PresetName.isNull()) {
std::string presetName(this->PresetName.toLocal8Bit());
auto const& p =
this->CMakePresetsFile.ConfigurePresets.at(presetName).Expanded;
this->CMakePresetsGraph.ConfigurePresets.at(presetName).Expanded;
if (p) {
for (auto const& v : p->CacheVariables) {
if (!v.second) {
@@ -533,17 +533,17 @@ void QCMake::setUpEnvironment() const
void QCMake::loadPresets()
{
auto result = this->CMakePresetsFile.ReadProjectPresets(
auto result = this->CMakePresetsGraph.ReadProjectPresets(
this->SourceDirectory.toLocal8Bit().data(), true);
if (result != this->LastLoadPresetsResult &&
result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
emit this->presetLoadError(this->SourceDirectory, result);
}
this->LastLoadPresetsResult = result;
QVector<QCMakePreset> presets;
for (auto const& name : this->CMakePresetsFile.ConfigurePresetOrder) {
auto const& it = this->CMakePresetsFile.ConfigurePresets[name];
for (auto const& name : this->CMakePresetsGraph.ConfigurePresetOrder) {
auto const& it = this->CMakePresetsGraph.ConfigurePresets[name];
auto const& p = it.Unexpanded;
if (p.Hidden) {
continue;
@@ -556,10 +556,10 @@ void QCMake::loadPresets()
preset.generator = QString::fromLocal8Bit(p.Generator.data());
preset.architecture = QString::fromLocal8Bit(p.Architecture.data());
preset.setArchitecture = !p.ArchitectureStrategy ||
p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
p.ArchitectureStrategy == cmCMakePresetsGraph::ArchToolsetStrategy::Set;
preset.toolset = QString::fromLocal8Bit(p.Toolset.data());
preset.setToolset = !p.ToolsetStrategy ||
p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
p.ToolsetStrategy == cmCMakePresetsGraph::ArchToolsetStrategy::Set;
preset.enabled = it.Expanded && it.Expanded->ConditionResult &&
std::find_if(this->AvailableGenerators.begin(),
this->AvailableGenerators.end(),

View File

@@ -4,7 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmCMakePresetsFile.h"
#include "cmCMakePresetsGraph.h"
#include "cmake.h"
#ifdef _MSC_VER
@@ -60,7 +60,7 @@ using QCMakePropertyList = QList<QCMakeProperty>;
Q_DECLARE_METATYPE(QCMakeProperty)
Q_DECLARE_METATYPE(QCMakePropertyList)
Q_DECLARE_METATYPE(QProcessEnvironment)
Q_DECLARE_METATYPE(cmCMakePresetsFile::ReadFileResult)
Q_DECLARE_METATYPE(cmCMakePresetsGraph::ReadFileResult)
/// Qt API for CMake library.
/// Wrapper like class allows for easier integration with
@@ -159,7 +159,7 @@ signals:
void presetChanged(const QString& name);
/// signal when there's an error reading the presets files
void presetLoadError(const QString& dir,
cmCMakePresetsFile::ReadFileResult error);
cmCMakePresetsGraph::ReadFileResult error);
/// signal when uninitialized warning changes
void warnUninitializedModeChanged(bool value);
/// signal for progress events
@@ -202,9 +202,9 @@ protected:
QString Platform;
QString Toolset;
std::vector<cmake::GeneratorInfo> AvailableGenerators;
cmCMakePresetsFile CMakePresetsFile;
cmCMakePresetsFile::ReadFileResult LastLoadPresetsResult =
cmCMakePresetsFile::ReadFileResult::READ_OK;
cmCMakePresetsGraph CMakePresetsGraph;
cmCMakePresetsGraph::ReadFileResult LastLoadPresetsResult =
cmCMakePresetsGraph::ReadFileResult::READ_OK;
QString PresetName;
QString CMakeExecutable;
QAtomicInt InterruptFlag;

View File

@@ -5,7 +5,7 @@
#include <QString>
#include <QVariant>
#include "cmCMakePresetsFile.h"
#include "cmCMakePresetsGraph.h"
class QCMakePreset
{

View File

@@ -1,112 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <memory>
#include "cmCMakePresetsFile.h"
#define CHECK_OK(expr) \
do { \
auto _result = expr; \
if (_result != ReadFileResult::READ_OK) \
return _result; \
} while (false)
namespace cmCMakePresetsFileInternal {
enum class ExpandMacroResult
{
Ok,
Ignore,
Error,
};
using MacroExpander = std::function<ExpandMacroResult(
const std::string&, const std::string&, std::string&, int version)>;
}
class cmCMakePresetsFile::Condition
{
public:
virtual ~Condition() = default;
virtual bool Evaluate(
const std::vector<cmCMakePresetsFileInternal::MacroExpander>& expanders,
int version, cm::optional<bool>& out) const = 0;
virtual bool IsNull() const { return false; }
};
namespace cmCMakePresetsFileInternal {
class NullCondition : public cmCMakePresetsFile::Condition
{
bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
int /*version*/, cm::optional<bool>& out) const override
{
out = true;
return true;
}
bool IsNull() const override { return true; }
};
class ConstCondition : public cmCMakePresetsFile::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
int /*version*/, cm::optional<bool>& out) const override
{
out = this->Value;
return true;
}
bool Value;
};
class EqualsCondition : public cmCMakePresetsFile::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::string Lhs;
std::string Rhs;
};
class InListCondition : public cmCMakePresetsFile::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::string String;
std::vector<std::string> List;
};
class MatchesCondition : public cmCMakePresetsFile::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::string String;
std::string Regex;
};
class AnyAllOfCondition : public cmCMakePresetsFile::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::vector<std::unique_ptr<Condition>> Conditions;
bool StopValue;
};
class NotCondition : public cmCMakePresetsFile::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::unique_ptr<Condition> SubCondition;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCMakePresetsFile.h"
#include "cmCMakePresetsGraph.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <functional>
#include <iostream>
@@ -13,7 +14,7 @@
#include "cmsys/RegularExpression.hxx"
#include "cmCMakePresetsFileInternal.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -38,12 +39,12 @@ enum class CycleStatus
Verified,
};
using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
using BuildPreset = cmCMakePresetsFile::BuildPreset;
using TestPreset = cmCMakePresetsFile::TestPreset;
using ExpandMacroResult = cmCMakePresetsFileInternal::ExpandMacroResult;
using MacroExpander = cmCMakePresetsFileInternal::MacroExpander;
using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
using BuildPreset = cmCMakePresetsGraph::BuildPreset;
using TestPreset = cmCMakePresetsGraph::TestPreset;
using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult;
using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander;
void InheritString(std::string& child, const std::string& parent)
{
@@ -77,9 +78,10 @@ void InheritVector(std::vector<T>& child, const std::vector<T>& parent)
*/
template <class T>
ReadFileResult VisitPreset(
T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
T& preset,
std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets,
std::map<std::string, CycleStatus> cycleStatus,
const cmCMakePresetsFile& file)
const cmCMakePresetsGraph& graph)
{
switch (cycleStatus[preset.Name]) {
case CycleStatus::InProgress:
@@ -105,11 +107,11 @@ ReadFileResult VisitPreset(
}
auto& parentPreset = parent->second.Unexpanded;
if (!preset.User && parentPreset.User) {
return ReadFileResult::USER_PRESET_INHERITANCE;
if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) {
return ReadFileResult::PRESET_UNREACHABLE_FROM_FILE;
}
auto result = VisitPreset(parentPreset, presets, cycleStatus, file);
auto result = VisitPreset(parentPreset, presets, cycleStatus, graph);
if (result != ReadFileResult::READ_OK) {
return result;
}
@@ -129,7 +131,7 @@ ReadFileResult VisitPreset(
preset.ConditionEvaluator.reset();
}
CHECK_OK(preset.VisitPresetAfterInherit(file.GetVersion(preset)));
CHECK_OK(preset.VisitPresetAfterInherit(graph.GetVersion(preset)));
cycleStatus[preset.Name] = CycleStatus::Verified;
return ReadFileResult::READ_OK;
@@ -137,8 +139,8 @@ ReadFileResult VisitPreset(
template <class T>
ReadFileResult ComputePresetInheritance(
std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
const cmCMakePresetsFile& file)
std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets,
const cmCMakePresetsGraph& graph)
{
std::map<std::string, CycleStatus> cycleStatus;
for (auto const& it : presets) {
@@ -147,7 +149,7 @@ ReadFileResult ComputePresetInheritance(
for (auto& it : presets) {
auto& preset = it.second.Unexpanded;
auto result = VisitPreset<T>(preset, presets, cycleStatus, file);
auto result = VisitPreset<T>(preset, presets, cycleStatus, graph);
if (result != ReadFileResult::READ_OK) {
return result;
}
@@ -189,17 +191,17 @@ ExpandMacroResult ExpandMacro(std::string& out,
const std::vector<MacroExpander>& macroExpanders,
int version);
bool ExpandMacros(const cmCMakePresetsFile& file,
bool ExpandMacros(const cmCMakePresetsGraph& graph,
const ConfigurePreset& preset,
cm::optional<ConfigurePreset>& out,
const std::vector<MacroExpander>& macroExpanders)
{
std::string binaryDir = preset.BinaryDir;
CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset));
CHECK_EXPAND(out, binaryDir, macroExpanders, graph.GetVersion(preset));
if (!binaryDir.empty()) {
if (!cmSystemTools::FileIsFullPath(binaryDir)) {
binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
binaryDir = cmStrCat(graph.SourceDir, '/', binaryDir);
}
out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
@@ -207,10 +209,10 @@ bool ExpandMacros(const cmCMakePresetsFile& file,
if (!preset.InstallDir.empty()) {
std::string installDir = preset.InstallDir;
CHECK_EXPAND(out, installDir, macroExpanders, file.GetVersion(preset));
CHECK_EXPAND(out, installDir, macroExpanders, graph.GetVersion(preset));
if (!cmSystemTools::FileIsFullPath(installDir)) {
installDir = cmStrCat(file.SourceDir, '/', installDir);
installDir = cmStrCat(graph.SourceDir, '/', installDir);
}
out->InstallDir = cmSystemTools::CollapseFullPath(installDir);
cmSystemTools::ConvertToUnixSlashes(out->InstallDir);
@@ -218,89 +220,89 @@ bool ExpandMacros(const cmCMakePresetsFile& file,
if (!preset.ToolchainFile.empty()) {
std::string toolchain = preset.ToolchainFile;
CHECK_EXPAND(out, toolchain, macroExpanders, file.GetVersion(preset));
CHECK_EXPAND(out, toolchain, macroExpanders, graph.GetVersion(preset));
out->ToolchainFile = toolchain;
}
for (auto& variable : out->CacheVariables) {
if (variable.second) {
CHECK_EXPAND(out, variable.second->Value, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
}
}
return true;
}
bool ExpandMacros(const cmCMakePresetsFile& file, const BuildPreset& preset,
bool ExpandMacros(const cmCMakePresetsGraph& graph, const BuildPreset& preset,
cm::optional<BuildPreset>& out,
const std::vector<MacroExpander>& macroExpanders)
{
for (auto& target : out->Targets) {
CHECK_EXPAND(out, target, macroExpanders, file.GetVersion(preset));
CHECK_EXPAND(out, target, macroExpanders, graph.GetVersion(preset));
}
for (auto& nativeToolOption : out->NativeToolOptions) {
CHECK_EXPAND(out, nativeToolOption, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
}
return true;
}
bool ExpandMacros(const cmCMakePresetsFile& file, const TestPreset& preset,
bool ExpandMacros(const cmCMakePresetsGraph& graph, const TestPreset& preset,
cm::optional<TestPreset>& out,
const std::vector<MacroExpander>& macroExpanders)
{
for (auto& overwrite : out->OverwriteConfigurationFile) {
CHECK_EXPAND(out, overwrite, macroExpanders, file.GetVersion(preset));
CHECK_EXPAND(out, overwrite, macroExpanders, graph.GetVersion(preset));
}
if (out->Output) {
CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
}
if (out->Filter) {
if (out->Filter->Include) {
CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
if (out->Filter->Include->Index) {
CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile,
macroExpanders, file.GetVersion(preset));
macroExpanders, graph.GetVersion(preset));
}
}
if (out->Filter->Exclude) {
CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
if (out->Filter->Exclude->Fixtures) {
CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup,
macroExpanders, file.GetVersion(preset));
macroExpanders, graph.GetVersion(preset));
CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup,
macroExpanders, file.GetVersion(preset));
macroExpanders, graph.GetVersion(preset));
}
}
}
if (out->Execution) {
CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders,
file.GetVersion(preset));
graph.GetVersion(preset));
}
return true;
}
template <class T>
bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset,
cm::optional<T>& out)
{
out.emplace(preset);
@@ -313,20 +315,20 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
std::vector<MacroExpander> macroExpanders;
MacroExpander defaultMacroExpander =
[&file, &preset](const std::string& macroNamespace,
const std::string& macroName, std::string& macroOut,
int version) -> ExpandMacroResult {
[&graph, &preset](const std::string& macroNamespace,
const std::string& macroName, std::string& macroOut,
int version) -> ExpandMacroResult {
if (macroNamespace.empty()) {
if (macroName == "sourceDir") {
macroOut += file.SourceDir;
macroOut += graph.SourceDir;
return ExpandMacroResult::Ok;
}
if (macroName == "sourceParentDir") {
macroOut += cmSystemTools::GetParentDirectory(file.SourceDir);
macroOut += cmSystemTools::GetParentDirectory(graph.SourceDir);
return ExpandMacroResult::Ok;
}
if (macroName == "sourceDirName") {
macroOut += cmSystemTools::GetFilenameName(file.SourceDir);
macroOut += cmSystemTools::GetFilenameName(graph.SourceDir);
return ExpandMacroResult::Ok;
}
if (macroName == "presetName") {
@@ -336,7 +338,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
if (macroName == "generator") {
// Generator only makes sense if preset is not hidden.
if (!preset.Hidden) {
macroOut += file.GetGeneratorForPreset(preset.Name);
macroOut += graph.GetGeneratorForPreset(preset.Name);
}
return ExpandMacroResult::Ok;
}
@@ -393,7 +395,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
for (auto& v : out->Environment) {
if (v.second) {
switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
file.GetVersion(preset))) {
graph.GetVersion(preset))) {
case ExpandMacroResult::Error:
return false;
case ExpandMacroResult::Ignore:
@@ -408,7 +410,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
if (preset.ConditionEvaluator) {
cm::optional<bool> result;
if (!preset.ConditionEvaluator->Evaluate(
macroExpanders, file.GetVersion(preset), result)) {
macroExpanders, graph.GetVersion(preset), result)) {
return false;
}
if (!result) {
@@ -418,7 +420,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
out->ConditionResult = *result;
}
return ExpandMacros(file, preset, out, macroExpanders);
return ExpandMacros(graph, preset, out, macroExpanders);
}
ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
@@ -541,7 +543,7 @@ ExpandMacroResult ExpandMacro(std::string& out,
}
}
bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate(
bool cmCMakePresetsGraphInternal::EqualsCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
@@ -555,7 +557,7 @@ bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate(
return true;
}
bool cmCMakePresetsFileInternal::InListCondition::Evaluate(
bool cmCMakePresetsGraphInternal::InListCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
@@ -574,7 +576,7 @@ bool cmCMakePresetsFileInternal::InListCondition::Evaluate(
return true;
}
bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate(
bool cmCMakePresetsGraphInternal::MatchesCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
@@ -592,7 +594,7 @@ bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate(
return true;
}
bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate(
bool cmCMakePresetsGraphInternal::AnyAllOfCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
@@ -618,7 +620,7 @@ bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate(
return true;
}
bool cmCMakePresetsFileInternal::NotCondition::Evaluate(
bool cmCMakePresetsGraphInternal::NotCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
@@ -633,9 +635,9 @@ bool cmCMakePresetsFileInternal::NotCondition::Evaluate(
return true;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
const cmCMakePresetsFile::Preset& parentPreset)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::ConfigurePreset::VisitPresetInherit(
const cmCMakePresetsGraph::Preset& parentPreset)
{
auto& preset = *this;
const ConfigurePreset& parent =
@@ -667,8 +669,8 @@ cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
return ReadFileResult::READ_OK;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit()
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::ConfigurePreset::VisitPresetBeforeInherit()
{
auto& preset = *this;
if (preset.Environment.count("") != 0) {
@@ -678,8 +680,8 @@ cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit()
return ReadFileResult::READ_OK;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::ConfigurePreset::VisitPresetAfterInherit(int version)
{
auto& preset = *this;
if (!preset.Hidden) {
@@ -706,9 +708,9 @@ cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version)
return ReadFileResult::READ_OK;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::BuildPreset::VisitPresetInherit(
const cmCMakePresetsFile::Preset& parentPreset)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::BuildPreset::VisitPresetInherit(
const cmCMakePresetsGraph::Preset& parentPreset)
{
auto& preset = *this;
const BuildPreset& parent = static_cast<const BuildPreset&>(parentPreset);
@@ -726,8 +728,8 @@ cmCMakePresetsFile::BuildPreset::VisitPresetInherit(
return ReadFileResult::READ_OK;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::BuildPreset::VisitPresetAfterInherit(int /* version */)
{
auto& preset = *this;
if (!preset.Hidden && preset.ConfigurePreset.empty()) {
@@ -736,9 +738,9 @@ cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */)
return ReadFileResult::READ_OK;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::TestPreset::VisitPresetInherit(
const cmCMakePresetsFile::Preset& parentPreset)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::TestPreset::VisitPresetInherit(
const cmCMakePresetsGraph::Preset& parentPreset)
{
auto& preset = *this;
const TestPreset& parent = static_cast<const TestPreset&>(parentPreset);
@@ -836,8 +838,8 @@ cmCMakePresetsFile::TestPreset::VisitPresetInherit(
return ReadFileResult::READ_OK;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(int /* version */)
{
auto& preset = *this;
if (!preset.Hidden && preset.ConfigurePreset.empty()) {
@@ -846,17 +848,17 @@ cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */)
return ReadFileResult::READ_OK;
}
std::string cmCMakePresetsFile::GetFilename(const std::string& sourceDir)
std::string cmCMakePresetsGraph::GetFilename(const std::string& sourceDir)
{
return cmStrCat(sourceDir, "/CMakePresets.json");
}
std::string cmCMakePresetsFile::GetUserFilename(const std::string& sourceDir)
std::string cmCMakePresetsGraph::GetUserFilename(const std::string& sourceDir)
{
return cmStrCat(sourceDir, "/CMakeUserPresets.json");
}
cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadProjectPresets(
const std::string& sourceDir, bool allowNoFiles)
{
this->SourceDir = sourceDir;
@@ -870,28 +872,33 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
return result;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles)
cmCMakePresetsGraph::ReadFileResult
cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
{
bool haveOneFile = false;
File* file;
std::string filename = GetUserFilename(this->SourceDir);
std::vector<File*> inProgressFiles;
if (cmSystemTools::FileExists(filename)) {
auto result = this->ReadJSONFile(filename, true);
auto result = this->ReadJSONFile(filename, RootType::User,
ReadReason::Root, inProgressFiles, file);
if (result != ReadFileResult::READ_OK) {
return result;
}
haveOneFile = true;
}
filename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(filename)) {
auto result = this->ReadJSONFile(filename, false);
if (result != ReadFileResult::READ_OK) {
return result;
} else {
filename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(filename)) {
auto result = this->ReadJSONFile(
filename, RootType::Project, ReadReason::Root, inProgressFiles, file);
if (result != ReadFileResult::READ_OK) {
return result;
}
haveOneFile = true;
}
haveOneFile = true;
}
assert(inProgressFiles.empty());
if (!haveOneFile) {
return allowNoFiles ? ReadFileResult::READ_OK
@@ -951,7 +958,7 @@ cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles)
return ReadFileResult::READ_OK;
}
const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
{
switch (result) {
case ReadFileResult::READ_OK:
@@ -982,13 +989,17 @@ const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
return "Duplicate presets";
case ReadFileResult::CYCLIC_PRESET_INHERITANCE:
return "Cyclic preset inheritance";
case ReadFileResult::USER_PRESET_INHERITANCE:
return "Project preset inherits from user preset";
case ReadFileResult::PRESET_UNREACHABLE_FROM_FILE:
return "Inherited preset is unreachable from preset's file";
case ReadFileResult::INVALID_MACRO_EXPANSION:
return "Invalid macro expansion";
case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
return "File version must be 2 or higher for build and test preset "
"support.";
case ReadFileResult::INCLUDE_UNSUPPORTED:
return "File version must be 4 or higher for include support";
case ReadFileResult::INVALID_INCLUDE:
return "Invalid \"include\" field";
case ReadFileResult::INVALID_CONFIGURE_PRESET:
return "Invalid \"configurePreset\" field";
case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
@@ -1001,12 +1012,16 @@ const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED:
return "File version must be 3 or higher for toolchainFile preset "
"support.";
case ReadFileResult::CYCLIC_INCLUDE:
return "Cyclic include among preset files";
case ReadFileResult::INCLUDE_OUTSIDE_PROJECT:
return "File included from outside project directory";
}
return "Unknown error";
}
void cmCMakePresetsFile::ClearPresets()
void cmCMakePresetsGraph::ClearPresets()
{
this->ConfigurePresets.clear();
this->BuildPresets.clear();
@@ -1015,10 +1030,12 @@ void cmCMakePresetsFile::ClearPresets()
this->ConfigurePresetOrder.clear();
this->BuildPresetOrder.clear();
this->TestPresetOrder.clear();
this->Files.clear();
}
void cmCMakePresetsFile::PrintPresets(
const std::vector<const cmCMakePresetsFile::Preset*>& presets)
void cmCMakePresetsGraph::PrintPresets(
const std::vector<const cmCMakePresetsGraph::Preset*>& presets)
{
if (presets.empty()) {
return;
@@ -1026,8 +1043,8 @@ void cmCMakePresetsFile::PrintPresets(
auto longestPresetName =
std::max_element(presets.begin(), presets.end(),
[](const cmCMakePresetsFile::Preset* a,
const cmCMakePresetsFile::Preset* b) {
[](const cmCMakePresetsGraph::Preset* a,
const cmCMakePresetsGraph::Preset* b) {
return a->Name.length() < b->Name.length();
});
auto longestLength = (*longestPresetName)->Name.length();
@@ -1045,67 +1062,67 @@ void cmCMakePresetsFile::PrintPresets(
}
}
void cmCMakePresetsFile::PrintConfigurePresetList() const
void cmCMakePresetsGraph::PrintConfigurePresetList() const
{
PrintConfigurePresetList([](const ConfigurePreset&) { return true; });
}
void cmCMakePresetsFile::PrintConfigurePresetList(
void cmCMakePresetsGraph::PrintConfigurePresetList(
const std::function<bool(const ConfigurePreset&)>& filter) const
{
std::vector<const cmCMakePresetsFile::Preset*> presets;
std::vector<const cmCMakePresetsGraph::Preset*> presets;
for (auto const& p : this->ConfigurePresetOrder) {
auto const& preset = this->ConfigurePresets.at(p);
if (!preset.Unexpanded.Hidden && preset.Expanded &&
preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
presets.push_back(
static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
}
}
if (!presets.empty()) {
std::cout << "Available configure presets:\n\n";
cmCMakePresetsFile::PrintPresets(presets);
cmCMakePresetsGraph::PrintPresets(presets);
}
}
void cmCMakePresetsFile::PrintBuildPresetList() const
void cmCMakePresetsGraph::PrintBuildPresetList() const
{
std::vector<const cmCMakePresetsFile::Preset*> presets;
std::vector<const cmCMakePresetsGraph::Preset*> presets;
for (auto const& p : this->BuildPresetOrder) {
auto const& preset = this->BuildPresets.at(p);
if (!preset.Unexpanded.Hidden && preset.Expanded &&
preset.Expanded->ConditionResult) {
presets.push_back(
static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
}
}
if (!presets.empty()) {
std::cout << "Available build presets:\n\n";
cmCMakePresetsFile::PrintPresets(presets);
cmCMakePresetsGraph::PrintPresets(presets);
}
}
void cmCMakePresetsFile::PrintTestPresetList() const
void cmCMakePresetsGraph::PrintTestPresetList() const
{
std::vector<const cmCMakePresetsFile::Preset*> presets;
std::vector<const cmCMakePresetsGraph::Preset*> presets;
for (auto const& p : this->TestPresetOrder) {
auto const& preset = this->TestPresets.at(p);
if (!preset.Unexpanded.Hidden && preset.Expanded &&
preset.Expanded->ConditionResult) {
presets.push_back(
static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
}
}
if (!presets.empty()) {
std::cout << "Available test presets:\n\n";
cmCMakePresetsFile::PrintPresets(presets);
cmCMakePresetsGraph::PrintPresets(presets);
}
}
void cmCMakePresetsFile::PrintAllPresets() const
void cmCMakePresetsGraph::PrintAllPresets() const
{
this->PrintConfigurePresetList();
std::cout << std::endl;

View File

@@ -8,12 +8,13 @@
#include <map>
#include <memory>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cm/optional>
class cmCMakePresetsFile
class cmCMakePresetsGraph
{
public:
enum class ReadFileResult
@@ -32,14 +33,18 @@ public:
INVALID_VARIABLE,
DUPLICATE_PRESETS,
CYCLIC_PRESET_INHERITANCE,
USER_PRESET_INHERITANCE,
PRESET_UNREACHABLE_FROM_FILE,
INVALID_MACRO_EXPANSION,
BUILD_TEST_PRESETS_UNSUPPORTED,
INCLUDE_UNSUPPORTED,
INVALID_INCLUDE,
INVALID_CONFIGURE_PRESET,
INSTALL_PREFIX_UNSUPPORTED,
INVALID_CONDITION,
CONDITION_UNSUPPORTED,
TOOLCHAIN_FILE_UNSUPPORTED,
CYCLIC_INCLUDE,
INCLUDE_OUTSIDE_PROJECT,
};
enum class ArchToolsetStrategy
@@ -57,6 +62,15 @@ public:
class Condition;
class File
{
public:
std::string Filename;
int Version;
std::unordered_set<File*> ReachableFiles;
};
class Preset
{
public:
@@ -77,7 +91,7 @@ public:
std::string Name;
std::vector<std::string> Inherits;
bool Hidden;
bool User;
File* OriginFile;
std::string DisplayName;
std::string Description;
@@ -321,12 +335,11 @@ public:
std::vector<std::string> TestPresetOrder;
std::string SourceDir;
int Version;
int UserVersion;
std::vector<std::unique_ptr<File>> Files;
int GetVersion(const Preset& preset) const
{
return preset.User ? this->UserVersion : this->Version;
return preset.OriginFile->Version;
}
static std::string GetFilename(const std::string& sourceDir);
@@ -363,7 +376,7 @@ public:
}
static void PrintPresets(
const std::vector<const cmCMakePresetsFile::Preset*>& presets);
const std::vector<const cmCMakePresetsGraph::Preset*>& presets);
void PrintConfigurePresetList() const;
void PrintConfigurePresetList(
const std::function<bool(const ConfigurePreset&)>& filter) const;
@@ -372,7 +385,22 @@ public:
void PrintAllPresets() const;
private:
enum class RootType
{
Project,
User,
};
enum class ReadReason
{
Root,
Included,
};
ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
ReadFileResult ReadJSONFile(const std::string& filename, bool user);
ReadFileResult ReadJSONFile(const std::string& filename, RootType rootType,
ReadReason readReason,
std::vector<File*>& inProgressFiles,
File*& file);
void ClearPresets();
};

View File

@@ -0,0 +1,163 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <memory>
#include <string>
#include <vector>
#include <cm3p/json/value.h>
#include "cmCMakePresetsGraph.h"
#include "cmJSONHelpers.h"
#define CHECK_OK(expr) \
do { \
auto _result = expr; \
if (_result != ReadFileResult::READ_OK) \
return _result; \
} while (false)
namespace cmCMakePresetsGraphInternal {
enum class ExpandMacroResult
{
Ok,
Ignore,
Error,
};
using MacroExpander = std::function<ExpandMacroResult(
const std::string&, const std::string&, std::string&, int version)>;
}
class cmCMakePresetsGraph::Condition
{
public:
virtual ~Condition() = default;
virtual bool Evaluate(
const std::vector<cmCMakePresetsGraphInternal::MacroExpander>& expanders,
int version, cm::optional<bool>& out) const = 0;
virtual bool IsNull() const { return false; }
};
namespace cmCMakePresetsGraphInternal {
class NullCondition : public cmCMakePresetsGraph::Condition
{
bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
int /*version*/, cm::optional<bool>& out) const override
{
out = true;
return true;
}
bool IsNull() const override { return true; }
};
class ConstCondition : public cmCMakePresetsGraph::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
int /*version*/, cm::optional<bool>& out) const override
{
out = this->Value;
return true;
}
bool Value;
};
class EqualsCondition : public cmCMakePresetsGraph::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::string Lhs;
std::string Rhs;
};
class InListCondition : public cmCMakePresetsGraph::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::string String;
std::vector<std::string> List;
};
class MatchesCondition : public cmCMakePresetsGraph::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::string String;
std::string Regex;
};
class AnyAllOfCondition : public cmCMakePresetsGraph::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::vector<std::unique_ptr<Condition>> Conditions;
bool StopValue;
};
class NotCondition : public cmCMakePresetsGraph::Condition
{
public:
bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const override;
std::unique_ptr<Condition> SubCondition;
};
cmCMakePresetsGraph::ReadFileResult PresetStringHelper(
std::string& out, const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper(
std::vector<std::string>& out, const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out,
const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper(
cm::optional<bool>& out, const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out,
const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper(
cm::optional<int>& out, const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper(
std::vector<int>& out, const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult ConfigurePresetsHelper(
std::vector<cmCMakePresetsGraph::ConfigurePreset>& out,
const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult BuildPresetsHelper(
std::vector<cmCMakePresetsGraph::BuildPreset>& out,
const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult TestPresetsHelper(
std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value);
cmJSONHelper<std::nullptr_t, cmCMakePresetsGraph::ReadFileResult> VendorHelper(
cmCMakePresetsGraph::ReadFileResult error);
cmCMakePresetsGraph::ReadFileResult PresetConditionHelper(
std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult PresetVectorOneOrMoreStringHelper(
std::vector<std::string>& out, const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
std::map<std::string, cm::optional<std::string>>& out,
const Json::Value* value);
}

View File

@@ -0,0 +1,641 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cm/memory>
#include <cm/optional>
#include <cmext/string_view>
#include <cm3p/json/reader.h>
#include <cm3p/json/value.h>
#include "cmsys/FStream.hxx"
#include "cmCMakePresetsGraph.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmJSONHelpers.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
namespace {
using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
using CacheVariable = cmCMakePresetsGraph::CacheVariable;
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
using BuildPreset = cmCMakePresetsGraph::BuildPreset;
using TestPreset = cmCMakePresetsGraph::TestPreset;
using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
constexpr int MIN_VERSION = 1;
constexpr int MAX_VERSION = 4;
struct CMakeVersion
{
unsigned int Major = 0;
unsigned int Minor = 0;
unsigned int Patch = 0;
};
struct RootPresets
{
CMakeVersion CMakeMinimumRequired;
std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
std::vector<std::string> Include;
};
std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition(
std::unique_ptr<cmCMakePresetsGraph::Condition> condition)
{
auto retval = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
retval->SubCondition = std::move(condition);
return retval;
}
auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
auto const ConditionStringListHelper =
cmJSONVectorHelper<std::string, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION,
ConditionStringHelper);
auto const ConstConditionHelper =
cmJSONObjectHelper<cmCMakePresetsGraphInternal::ConstCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("value"_s, &cmCMakePresetsGraphInternal::ConstCondition::Value,
ConditionBoolHelper, true);
auto const EqualsConditionHelper =
cmJSONObjectHelper<cmCMakePresetsGraphInternal::EqualsCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("lhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Lhs,
ConditionStringHelper, true)
.Bind("rhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Rhs,
ConditionStringHelper, true);
auto const InListConditionHelper =
cmJSONObjectHelper<cmCMakePresetsGraphInternal::InListCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("string"_s, &cmCMakePresetsGraphInternal::InListCondition::String,
ConditionStringHelper, true)
.Bind("list"_s, &cmCMakePresetsGraphInternal::InListCondition::List,
ConditionStringListHelper, true);
auto const MatchesConditionHelper =
cmJSONObjectHelper<cmCMakePresetsGraphInternal::MatchesCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("string"_s, &cmCMakePresetsGraphInternal::MatchesCondition::String,
ConditionStringHelper, true)
.Bind("regex"_s, &cmCMakePresetsGraphInternal::MatchesCondition::Regex,
ConditionStringHelper, true);
ReadFileResult SubConditionHelper(
std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
const Json::Value* value);
auto const ListConditionVectorHelper =
cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsGraph::Condition>,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION,
SubConditionHelper);
auto const AnyAllOfConditionHelper =
cmJSONObjectHelper<cmCMakePresetsGraphInternal::AnyAllOfCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("conditions"_s,
&cmCMakePresetsGraphInternal::AnyAllOfCondition::Conditions,
ListConditionVectorHelper);
auto const NotConditionHelper =
cmJSONObjectHelper<cmCMakePresetsGraphInternal::NotCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("condition"_s,
&cmCMakePresetsGraphInternal::NotCondition::SubCondition,
SubConditionHelper);
ReadFileResult ConditionHelper(
std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
const Json::Value* value)
{
if (!value) {
out.reset();
return ReadFileResult::READ_OK;
}
if (value->isBool()) {
auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
c->Value = value->asBool();
out = std::move(c);
return ReadFileResult::READ_OK;
}
if (value->isNull()) {
out = cm::make_unique<cmCMakePresetsGraphInternal::NullCondition>();
return ReadFileResult::READ_OK;
}
if (value->isObject()) {
if (!value->isMember("type")) {
return ReadFileResult::INVALID_CONDITION;
}
if (!(*value)["type"].isString()) {
return ReadFileResult::INVALID_CONDITION;
}
auto type = (*value)["type"].asString();
if (type == "const") {
auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
CHECK_OK(ConstConditionHelper(*c, value));
out = std::move(c);
return ReadFileResult::READ_OK;
}
if (type == "equals" || type == "notEquals") {
auto c = cm::make_unique<cmCMakePresetsGraphInternal::EqualsCondition>();
CHECK_OK(EqualsConditionHelper(*c, value));
out = std::move(c);
if (type == "notEquals") {
out = InvertCondition(std::move(out));
}
return ReadFileResult::READ_OK;
}
if (type == "inList" || type == "notInList") {
auto c = cm::make_unique<cmCMakePresetsGraphInternal::InListCondition>();
CHECK_OK(InListConditionHelper(*c, value));
out = std::move(c);
if (type == "notInList") {
out = InvertCondition(std::move(out));
}
return ReadFileResult::READ_OK;
}
if (type == "matches" || type == "notMatches") {
auto c =
cm::make_unique<cmCMakePresetsGraphInternal::MatchesCondition>();
CHECK_OK(MatchesConditionHelper(*c, value));
out = std::move(c);
if (type == "notMatches") {
out = InvertCondition(std::move(out));
}
return ReadFileResult::READ_OK;
}
if (type == "anyOf" || type == "allOf") {
auto c =
cm::make_unique<cmCMakePresetsGraphInternal::AnyAllOfCondition>();
c->StopValue = (type == "anyOf");
CHECK_OK(AnyAllOfConditionHelper(*c, value));
out = std::move(c);
return ReadFileResult::READ_OK;
}
if (type == "not") {
auto c = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
CHECK_OK(NotConditionHelper(*c, value));
out = std::move(c);
return ReadFileResult::READ_OK;
}
}
return ReadFileResult::INVALID_CONDITION;
}
ReadFileResult SubConditionHelper(
std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
const Json::Value* value)
{
std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
auto result = ConditionHelper(ptr, value);
if (ptr && ptr->IsNull()) {
return ReadFileResult::INVALID_CONDITION;
}
out = std::move(ptr);
return result;
}
ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
const Json::Value* value)
{
if (!value || value->isNull()) {
out = cm::nullopt;
return ReadFileResult::READ_OK;
}
if (value->isString()) {
out = value->asString();
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_PRESET;
}
auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>(
ReadFileResult::NO_VERSION, VersionIntHelper);
auto const RootVersionHelper =
cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_ROOT)
.Bind("version"_s, VersionHelper, false);
auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
auto const CMakeVersionHelper =
cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
.Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
.Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
.Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
auto const IncludeHelper = cmJSONStringHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE);
auto const IncludeVectorHelper =
cmJSONVectorHelper<std::string, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE, IncludeHelper);
auto const RootPresetsHelper =
cmJSONObjectHelper<RootPresets, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
.Bind<int>("version"_s, nullptr, VersionHelper)
.Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
cmCMakePresetsGraphInternal::ConfigurePresetsHelper, false)
.Bind("buildPresets"_s, &RootPresets::BuildPresets,
cmCMakePresetsGraphInternal::BuildPresetsHelper, false)
.Bind("testPresets"_s, &RootPresets::TestPresets,
cmCMakePresetsGraphInternal::TestPresetsHelper, false)
.Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
CMakeVersionHelper, false)
.Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
.Bind<std::nullptr_t>(
"vendor"_s, nullptr,
cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT),
false);
}
namespace cmCMakePresetsGraphInternal {
cmCMakePresetsGraph::ReadFileResult PresetStringHelper(
std::string& out, const Json::Value* value)
{
static auto const helper = cmJSONStringHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
return helper(out, value);
}
cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper(
std::vector<std::string>& out, const Json::Value* value)
{
static auto const helper = cmJSONVectorHelper<std::string, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
cmCMakePresetsGraphInternal::PresetStringHelper);
return helper(out, value);
}
cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out,
const Json::Value* value)
{
static auto const helper = cmJSONBoolHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
return helper(out, value);
}
cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper(
cm::optional<bool>& out, const Json::Value* value)
{
static auto const helper = cmJSONOptionalHelper<bool, ReadFileResult>(
ReadFileResult::READ_OK, PresetBoolHelper);
return helper(out, value);
}
cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out,
const Json::Value* value)
{
static auto const helper = cmJSONIntHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
return helper(out, value);
}
cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper(
cm::optional<int>& out, const Json::Value* value)
{
static auto const helper = cmJSONOptionalHelper<int, ReadFileResult>(
ReadFileResult::READ_OK, PresetIntHelper);
return helper(out, value);
}
cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper(
std::vector<int>& out, const Json::Value* value)
{
static auto const helper = cmJSONVectorHelper<int, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
return helper(out, value);
}
cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
{
return [error](std::nullptr_t& /*out*/,
const Json::Value* value) -> ReadFileResult {
if (!value) {
return ReadFileResult::READ_OK;
}
if (!value->isObject()) {
return error;
}
return ReadFileResult::READ_OK;
};
}
ReadFileResult PresetConditionHelper(
std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
const Json::Value* value)
{
std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
auto result = ConditionHelper(ptr, value);
out = std::move(ptr);
return result;
}
ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
const Json::Value* value)
{
out.clear();
if (!value) {
return ReadFileResult::READ_OK;
}
if (value->isString()) {
out.push_back(value->asString());
return ReadFileResult::READ_OK;
}
return PresetVectorStringHelper(out, value);
}
cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
std::map<std::string, cm::optional<std::string>>& out,
const Json::Value* value)
{
static auto const helper =
cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
EnvironmentHelper);
return helper(out, value);
}
}
cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
const std::string& filename, RootType rootType, ReadReason readReason,
std::vector<File*>& inProgressFiles, File*& file)
{
ReadFileResult result;
if (rootType == RootType::Project) {
auto normalizedFilename = cmSystemTools::CollapseFullPath(filename);
auto normalizedProjectDir =
cmSystemTools::CollapseFullPath(this->SourceDir);
if (!cmSystemTools::IsSubDirectory(normalizedFilename,
normalizedProjectDir)) {
return ReadFileResult::INCLUDE_OUTSIDE_PROJECT;
}
}
for (auto const& f : this->Files) {
if (cmSystemTools::SameFile(filename, f->Filename)) {
file = f.get();
auto fileIt =
std::find(inProgressFiles.begin(), inProgressFiles.end(), file);
if (fileIt != inProgressFiles.end()) {
return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE;
}
// Check files included by this file again to make sure they're in the
// project directory.
if (rootType == RootType::Project) {
for (auto* f2 : file->ReachableFiles) {
if (!cmSystemTools::SameFile(filename, f2->Filename)) {
File* file2;
if ((result = this->ReadJSONFile(
f2->Filename, rootType, ReadReason::Included,
inProgressFiles, file2)) != ReadFileResult::READ_OK) {
return result;
}
}
}
}
return cmCMakePresetsGraph::ReadFileResult::READ_OK;
}
}
cmsys::ifstream fin(filename.c_str());
if (!fin) {
return ReadFileResult::FILE_NOT_FOUND;
}
// If there's a BOM, toss it.
cmsys::FStream::ReadBOM(fin);
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReaderBuilder::strictMode(&builder.settings_);
if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
return ReadFileResult::JSON_PARSE_ERROR;
}
int v = 0;
if ((result = RootVersionHelper(v, &root)) != ReadFileResult::READ_OK) {
return result;
}
if (v < MIN_VERSION || v > MAX_VERSION) {
return ReadFileResult::UNRECOGNIZED_VERSION;
}
// Support for build and test presets added in version 2.
if (v < 2 &&
(root.isMember("buildPresets") || root.isMember("testPresets"))) {
return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
}
// Support for include added in version 4.
if (v < 4 && root.isMember("include")) {
return ReadFileResult::INCLUDE_UNSUPPORTED;
}
RootPresets presets;
if ((result = RootPresetsHelper(presets, &root)) !=
ReadFileResult::READ_OK) {
return result;
}
unsigned int currentMajor = cmVersion::GetMajorVersion();
unsigned int currentMinor = cmVersion::GetMinorVersion();
unsigned int currentPatch = cmVersion::GetPatchVersion();
auto const& required = presets.CMakeMinimumRequired;
if (required.Major > currentMajor ||
(required.Major == currentMajor &&
(required.Minor > currentMinor ||
(required.Minor == currentMinor &&
(required.Patch > currentPatch))))) {
return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
}
auto filePtr = cm::make_unique<File>();
file = filePtr.get();
this->Files.emplace_back(std::move(filePtr));
inProgressFiles.emplace_back(file);
file->Filename = filename;
file->Version = v;
file->ReachableFiles.insert(file);
for (auto& preset : presets.ConfigurePresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
return ReadFileResult::INVALID_PRESET;
}
PresetPair<ConfigurePreset> presetPair;
presetPair.Unexpanded = preset;
presetPair.Expanded = cm::nullopt;
if (!this->ConfigurePresets
.emplace(std::make_pair(preset.Name, presetPair))
.second) {
return ReadFileResult::DUPLICATE_PRESETS;
}
// Support for installDir presets added in version 3.
if (v < 3 && !preset.InstallDir.empty()) {
return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
}
// Support for conditions added in version 3.
if (v < 3 && preset.ConditionEvaluator) {
return ReadFileResult::CONDITION_UNSUPPORTED;
}
// Support for toolchainFile presets added in version 3.
if (v < 3 && !preset.ToolchainFile.empty()) {
return ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED;
}
this->ConfigurePresetOrder.push_back(preset.Name);
}
for (auto& preset : presets.BuildPresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
return ReadFileResult::INVALID_PRESET;
}
PresetPair<BuildPreset> presetPair;
presetPair.Unexpanded = preset;
presetPair.Expanded = cm::nullopt;
if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
return ReadFileResult::DUPLICATE_PRESETS;
}
// Support for conditions added in version 3.
if (v < 3 && preset.ConditionEvaluator) {
return ReadFileResult::CONDITION_UNSUPPORTED;
}
this->BuildPresetOrder.push_back(preset.Name);
}
for (auto& preset : presets.TestPresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
return ReadFileResult::INVALID_PRESET;
}
PresetPair<TestPreset> presetPair;
presetPair.Unexpanded = preset;
presetPair.Expanded = cm::nullopt;
if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
return ReadFileResult::DUPLICATE_PRESETS;
}
// Support for conditions added in version 3.
if (v < 3 && preset.ConditionEvaluator) {
return ReadFileResult::CONDITION_UNSUPPORTED;
}
this->TestPresetOrder.push_back(preset.Name);
}
auto const includeFile = [this, &inProgressFiles, file](
const std::string& include, RootType rootType2,
ReadReason readReason2) -> ReadFileResult {
ReadFileResult r;
File* includedFile;
if ((r = this->ReadJSONFile(include, rootType2, readReason2,
inProgressFiles, includedFile)) !=
ReadFileResult::READ_OK) {
return r;
}
file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
includedFile->ReachableFiles.end());
return ReadFileResult::READ_OK;
};
for (auto include : presets.Include) {
if (!cmSystemTools::FileIsFullPath(include)) {
auto directory = cmSystemTools::GetFilenamePath(filename);
include = cmStrCat(directory, '/', include);
}
if ((result = includeFile(include, rootType, ReadReason::Included)) !=
ReadFileResult::READ_OK) {
return result;
}
}
if (rootType == RootType::User && readReason == ReadReason::Root) {
auto cmakePresetsFilename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(cmakePresetsFilename)) {
if ((result = includeFile(cmakePresetsFilename, RootType::Project,
ReadReason::Root)) !=
ReadFileResult::READ_OK) {
return result;
}
}
}
inProgressFiles.pop_back();
return ReadFileResult::READ_OK;
}

View File

@@ -0,0 +1,75 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <cm/optional>
#include <cmext/string_view>
#include <cm3p/json/value.h>
#include "cmCMakePresetsGraph.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmJSONHelpers.h"
namespace {
using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
using BuildPreset = cmCMakePresetsGraph::BuildPreset;
auto const BuildPresetHelper =
cmJSONObjectHelper<BuildPreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("name"_s, &BuildPreset::Name,
cmCMakePresetsGraphInternal::PresetStringHelper)
.Bind("inherits"_s, &BuildPreset::Inherits,
cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
false)
.Bind("hidden"_s, &BuildPreset::Hidden,
cmCMakePresetsGraphInternal::PresetBoolHelper, false)
.Bind<std::nullptr_t>("vendor"_s, nullptr,
cmCMakePresetsGraphInternal::VendorHelper(
ReadFileResult::INVALID_PRESET),
false)
.Bind("displayName"_s, &BuildPreset::DisplayName,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("description"_s, &BuildPreset::Description,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("environment"_s, &BuildPreset::Environment,
cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
.Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("inheritConfigureEnvironment"_s,
&BuildPreset::InheritConfigureEnvironment,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("jobs"_s, &BuildPreset::Jobs,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("targets"_s, &BuildPreset::Targets,
cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
false)
.Bind("configuration"_s, &BuildPreset::Configuration,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("cleanFirst"_s, &BuildPreset::CleanFirst,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("verbose"_s, &BuildPreset::Verbose,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
.Bind("condition"_s, &BuildPreset::ConditionEvaluator,
cmCMakePresetsGraphInternal::PresetConditionHelper, false);
}
namespace cmCMakePresetsGraphInternal {
ReadFileResult BuildPresetsHelper(std::vector<BuildPreset>& out,
const Json::Value* value)
{
static auto const helper = cmJSONVectorHelper<BuildPreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
BuildPresetHelper);
return helper(out, value);
}
}

View File

@@ -0,0 +1,228 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <cm/optional>
#include <cmext/string_view>
#include <cm3p/json/value.h>
#include "cmCMakePresetsGraph.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmJSONHelpers.h"
namespace {
using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
using CacheVariable = cmCMakePresetsGraph::CacheVariable;
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
ReadFileResult ArchToolsetStrategyHelper(
cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
{
if (!value) {
out = cm::nullopt;
return ReadFileResult::READ_OK;
}
if (!value->isString()) {
return ReadFileResult::INVALID_PRESET;
}
if (value->asString() == "set") {
out = ArchToolsetStrategy::Set;
return ReadFileResult::READ_OK;
}
if (value->asString() == "external") {
out = ArchToolsetStrategy::External;
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_PRESET;
}
std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
ArchToolsetHelper(
std::string ConfigurePreset::*valueField,
cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
{
auto const objectHelper =
cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("value", valueField,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
return [valueField, strategyField, objectHelper](
ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
if (!value) {
(out.*valueField).clear();
out.*strategyField = cm::nullopt;
return ReadFileResult::READ_OK;
}
if (value->isString()) {
out.*valueField = value->asString();
out.*strategyField = cm::nullopt;
return ReadFileResult::READ_OK;
}
if (value->isObject()) {
return objectHelper(out, value);
}
return ReadFileResult::INVALID_PRESET;
};
}
auto const ArchitectureHelper = ArchToolsetHelper(
&ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
auto const ToolsetHelper = ArchToolsetHelper(
&ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
{
if (!value) {
out.clear();
return ReadFileResult::READ_OK;
}
if (value->isBool()) {
out = value->asBool() ? "TRUE" : "FALSE";
return ReadFileResult::READ_OK;
}
return VariableStringHelper(out, value);
}
auto const VariableObjectHelper =
cmJSONObjectHelper<CacheVariable, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
.Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
.Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
const Json::Value* value)
{
if (value->isBool()) {
out = CacheVariable{
/*Type=*/"BOOL",
/*Value=*/value->asBool() ? "TRUE" : "FALSE",
};
return ReadFileResult::READ_OK;
}
if (value->isString()) {
out = CacheVariable{
/*Type=*/"",
/*Value=*/value->asString(),
};
return ReadFileResult::READ_OK;
}
if (value->isObject()) {
out.emplace();
return VariableObjectHelper(*out, value);
}
if (value->isNull()) {
out = cm::nullopt;
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_VARIABLE;
}
auto const VariablesHelper =
cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
auto const PresetWarningsHelper =
cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("dev"_s, &ConfigurePreset::WarnDev,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
auto const PresetErrorsHelper =
cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("dev"_s, &ConfigurePreset::ErrorDev,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
auto const PresetDebugHelper =
cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("output"_s, &ConfigurePreset::DebugOutput,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("find"_s, &ConfigurePreset::DebugFind,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
auto const ConfigurePresetHelper =
cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("name"_s, &ConfigurePreset::Name,
cmCMakePresetsGraphInternal::PresetStringHelper)
.Bind("inherits"_s, &ConfigurePreset::Inherits,
cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
false)
.Bind("hidden"_s, &ConfigurePreset::Hidden,
cmCMakePresetsGraphInternal::PresetBoolHelper, false)
.Bind<std::nullptr_t>("vendor"_s, nullptr,
cmCMakePresetsGraphInternal::VendorHelper(
ReadFileResult::INVALID_PRESET),
false)
.Bind("displayName"_s, &ConfigurePreset::DisplayName,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("description"_s, &ConfigurePreset::Description,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("generator"_s, &ConfigurePreset::Generator,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("architecture"_s, ArchitectureHelper, false)
.Bind("toolset"_s, ToolsetHelper, false)
.Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("binaryDir"_s, &ConfigurePreset::BinaryDir,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("installDir"_s, &ConfigurePreset::InstallDir,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind<std::string>("cmakeExecutable"_s, nullptr,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
VariablesHelper, false)
.Bind("environment"_s, &ConfigurePreset::Environment,
cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
.Bind("warnings"_s, PresetWarningsHelper, false)
.Bind("errors"_s, PresetErrorsHelper, false)
.Bind("debug"_s, PresetDebugHelper, false)
.Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
cmCMakePresetsGraphInternal::PresetConditionHelper, false);
}
namespace cmCMakePresetsGraphInternal {
ReadFileResult ConfigurePresetsHelper(std::vector<ConfigurePreset>& out,
const Json::Value* value)
{
static auto const helper =
cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
ConfigurePresetHelper);
return helper(out, value);
}
}

View File

@@ -0,0 +1,360 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <cm/optional>
#include <cmext/string_view>
#include <cm3p/json/value.h>
#include "cmCMakePresetsGraph.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmJSONHelpers.h"
namespace {
using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
using TestPreset = cmCMakePresetsGraph::TestPreset;
ReadFileResult TestPresetOutputVerbosityHelper(
TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
{
if (!value) {
out = TestPreset::OutputOptions::VerbosityEnum::Default;
return ReadFileResult::READ_OK;
}
if (!value->isString()) {
return ReadFileResult::INVALID_PRESET;
}
if (value->asString() == "default") {
out = TestPreset::OutputOptions::VerbosityEnum::Default;
return ReadFileResult::READ_OK;
}
if (value->asString() == "verbose") {
out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
return ReadFileResult::READ_OK;
}
if (value->asString() == "extra") {
out = TestPreset::OutputOptions::VerbosityEnum::Extra;
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_PRESET;
}
auto const TestPresetOptionalOutputVerbosityHelper =
cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
ReadFileResult>(ReadFileResult::READ_OK,
TestPresetOutputVerbosityHelper);
auto const TestPresetOptionalOutputHelper =
cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
TestPresetOptionalOutputVerbosityHelper, false)
.Bind("debug"_s, &TestPreset::OutputOptions::Debug,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("subprojectSummary"_s,
&TestPreset::OutputOptions::SubprojectSummary,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("maxPassedTestOutputSize"_s,
&TestPreset::OutputOptions::MaxPassedTestOutputSize,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("maxFailedTestOutputSize"_s,
&TestPreset::OutputOptions::MaxFailedTestOutputSize,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false));
auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_PRESET)
.Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("specificTests"_s,
&TestPreset::IncludeOptions::IndexOptions::SpecificTests,
cmCMakePresetsGraphInternal::PresetVectorIntHelper, false));
ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
const Json::Value* value)
{
if (!value) {
out = cm::nullopt;
return ReadFileResult::READ_OK;
}
if (value->isString()) {
out.emplace();
out->IndexFile = value->asString();
return ReadFileResult::READ_OK;
}
if (value->isObject()) {
return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
}
return ReadFileResult::INVALID_PRESET;
}
auto const TestPresetOptionalFilterIncludeHelper =
cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
.Bind("name"_s, &TestPreset::IncludeOptions::Name,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("label"_s, &TestPreset::IncludeOptions::Label,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("index"_s, &TestPreset::IncludeOptions::Index,
TestPresetOptionalFilterIncludeIndexHelper, false)
.Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false));
auto const TestPresetOptionalFilterExcludeFixturesHelper =
cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_PRESET)
.Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
cmCMakePresetsGraphInternal::PresetStringHelper, false));
auto const TestPresetOptionalFilterExcludeHelper =
cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
.Bind("name"_s, &TestPreset::ExcludeOptions::Name,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("label"_s, &TestPreset::ExcludeOptions::Label,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
TestPresetOptionalFilterExcludeFixturesHelper, false));
ReadFileResult TestPresetExecutionShowOnlyHelper(
TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
{
if (!value || !value->isString()) {
return ReadFileResult::INVALID_PRESET;
}
if (value->asString() == "human") {
out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
return ReadFileResult::READ_OK;
}
if (value->asString() == "json-v1") {
out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_PRESET;
}
auto const TestPresetOptionalExecutionShowOnlyHelper =
cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
ReadFileResult>(ReadFileResult::READ_OK,
TestPresetExecutionShowOnlyHelper);
ReadFileResult TestPresetExecutionModeHelper(
TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
const Json::Value* value)
{
if (!value) {
return ReadFileResult::READ_OK;
}
if (!value->isString()) {
return ReadFileResult::INVALID_PRESET;
}
if (value->asString() == "until-fail") {
out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
return ReadFileResult::READ_OK;
}
if (value->asString() == "until-pass") {
out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
return ReadFileResult::READ_OK;
}
if (value->asString() == "after-timeout") {
out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_PRESET;
}
auto const TestPresetOptionalExecutionRepeatHelper =
cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_PRESET)
.Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
TestPresetExecutionModeHelper, true)
.Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
cmCMakePresetsGraphInternal::PresetIntHelper, true));
ReadFileResult TestPresetExecutionNoTestsActionHelper(
TestPreset::ExecutionOptions::NoTestsActionEnum& out,
const Json::Value* value)
{
if (!value) {
out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
return ReadFileResult::READ_OK;
}
if (!value->isString()) {
return ReadFileResult::INVALID_PRESET;
}
if (value->asString() == "default") {
out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
return ReadFileResult::READ_OK;
}
if (value->asString() == "error") {
out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
return ReadFileResult::READ_OK;
}
if (value->asString() == "ignore") {
out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
return ReadFileResult::READ_OK;
}
return ReadFileResult::INVALID_PRESET;
}
auto const TestPresetOptionalExecutionNoTestsActionHelper =
cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
ReadFileResult>(ReadFileResult::READ_OK,
TestPresetExecutionNoTestsActionHelper);
auto const TestPresetExecutionHelper =
cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
.Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("resourceSpecFile"_s,
&TestPreset::ExecutionOptions::ResourceSpecFile,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
TestPresetOptionalExecutionShowOnlyHelper, false)
.Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
TestPresetOptionalExecutionRepeatHelper, false)
.Bind("interactiveDebugging"_s,
&TestPreset::ExecutionOptions::InteractiveDebugging,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
TestPresetOptionalExecutionNoTestsActionHelper, false));
auto const TestPresetFilterHelper =
cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
ReadFileResult::READ_OK,
cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
.Bind("include"_s, &TestPreset::FilterOptions::Include,
TestPresetOptionalFilterIncludeHelper, false)
.Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
TestPresetOptionalFilterExcludeHelper, false));
auto const TestPresetHelper =
cmJSONObjectHelper<TestPreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("name"_s, &TestPreset::Name,
cmCMakePresetsGraphInternal::PresetStringHelper)
.Bind("inherits"_s, &TestPreset::Inherits,
cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
false)
.Bind("hidden"_s, &TestPreset::Hidden,
cmCMakePresetsGraphInternal::PresetBoolHelper, false)
.Bind<std::nullptr_t>("vendor"_s, nullptr,
cmCMakePresetsGraphInternal::VendorHelper(
ReadFileResult::INVALID_PRESET),
false)
.Bind("displayName"_s, &TestPreset::DisplayName,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("description"_s, &TestPreset::Description,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("environment"_s, &TestPreset::Environment,
cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
.Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("inheritConfigureEnvironment"_s,
&TestPreset::InheritConfigureEnvironment,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("configuration"_s, &TestPreset::Configuration,
cmCMakePresetsGraphInternal::PresetStringHelper, false)
.Bind("overwriteConfigurationFile"_s,
&TestPreset::OverwriteConfigurationFile,
cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
.Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
false)
.Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
.Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
false)
.Bind("condition"_s, &TestPreset::ConditionEvaluator,
cmCMakePresetsGraphInternal::PresetConditionHelper, false);
}
namespace cmCMakePresetsGraphInternal {
cmCMakePresetsGraph::ReadFileResult TestPresetsHelper(
std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value)
{
static auto const helper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
TestPresetHelper);
return helper(out, value);
}
}

View File

@@ -38,7 +38,7 @@
# include <unistd.h> // IWYU pragma: keep
#endif
#include "cmCMakePresetsFile.h"
#include "cmCMakePresetsGraph.h"
#include "cmCTestBuildAndTestHandler.h"
#include "cmCTestBuildHandler.h"
#include "cmCTestConfigureHandler.h"
@@ -2327,12 +2327,12 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
{
const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
cmCMakePresetsFile settingsFile;
cmCMakePresetsGraph settingsFile;
auto result = settingsFile.ReadProjectPresets(workingDirectory);
if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
cmSystemTools::Error(cmStrCat("Could not read presets from ",
workingDirectory, ": ",
cmCMakePresetsFile::ResultToString(result)));
if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
cmSystemTools::Error(
cmStrCat("Could not read presets from ", workingDirectory, ": ",
cmCMakePresetsGraph::ResultToString(result)));
return false;
}
@@ -2422,15 +2422,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
if (expandedPreset->Output->Verbosity) {
const auto& verbosity = *expandedPreset->Output->Verbosity;
switch (verbosity) {
case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum::
Extra:
this->Impl->ExtraVerbose = true;
CM_FALLTHROUGH;
case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum::
Verbose:
this->Impl->Verbose = true;
break;
case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum::
Default:
default:
// leave default settings
@@ -2548,13 +2548,13 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
this->Impl->ShowOnly = true;
switch (*expandedPreset->Execution->ShowOnly) {
case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::ShowOnlyEnum::
JsonV1:
this->Impl->Quiet = true;
this->Impl->OutputAsJson = true;
this->Impl->OutputAsJsonVersion = 1;
break;
case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::ShowOnlyEnum::
Human:
// intentional fallthrough (human is the default)
default:
@@ -2565,15 +2565,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
if (expandedPreset->Execution->Repeat) {
this->Impl->RepeatCount = expandedPreset->Execution->Repeat->Count;
switch (expandedPreset->Execution->Repeat->Mode) {
case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions::
ModeEnum::UntilFail:
this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
break;
case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions::
ModeEnum::UntilPass:
this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
break;
case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions::
ModeEnum::AfterTimeout:
this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
break;
@@ -2599,15 +2599,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
if (expandedPreset->Execution->NoTestsAction) {
switch (*expandedPreset->Execution->NoTestsAction) {
case cmCMakePresetsFile::TestPreset::ExecutionOptions::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::
NoTestsActionEnum::Error:
this->Impl->NoTestsMode = cmCTest::NoTests::Error;
break;
case cmCMakePresetsFile::TestPreset::ExecutionOptions::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::
NoTestsActionEnum::Ignore:
this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
break;
case cmCMakePresetsFile::TestPreset::ExecutionOptions::
case cmCMakePresetsGraph::TestPreset::ExecutionOptions::
NoTestsActionEnum::Default:
break;
default:

View File

@@ -29,7 +29,7 @@
#include "cm_sys_stat.h"
#include "cmCMakePath.h"
#include "cmCMakePresetsFile.h"
#include "cmCMakePresetsGraph.h"
#include "cmCommandLineArgument.h"
#include "cmCommands.h"
#include "cmDocumentation.h"
@@ -1239,43 +1239,43 @@ void cmake::SetArgs(const std::vector<std::string>& args)
#if !defined(CMAKE_BOOTSTRAP)
if (listPresets != ListPresets::None || !presetName.empty()) {
cmCMakePresetsFile settingsFile;
auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
cmCMakePresetsGraph presetsGraph;
auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory());
if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
cmSystemTools::Error(
cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
": ", cmCMakePresetsFile::ResultToString(result)));
": ", cmCMakePresetsGraph::ResultToString(result)));
return;
}
if (listPresets != ListPresets::None) {
if (listPresets == ListPresets::Configure) {
this->PrintPresetList(settingsFile);
this->PrintPresetList(presetsGraph);
} else if (listPresets == ListPresets::Build) {
settingsFile.PrintBuildPresetList();
presetsGraph.PrintBuildPresetList();
} else if (listPresets == ListPresets::Test) {
settingsFile.PrintTestPresetList();
presetsGraph.PrintTestPresetList();
} else if (listPresets == ListPresets::All) {
settingsFile.PrintAllPresets();
presetsGraph.PrintAllPresets();
}
this->SetWorkingMode(WorkingMode::HELP_MODE);
return;
}
auto preset = settingsFile.ConfigurePresets.find(presetName);
if (preset == settingsFile.ConfigurePresets.end()) {
auto preset = presetsGraph.ConfigurePresets.find(presetName);
if (preset == presetsGraph.ConfigurePresets.end()) {
cmSystemTools::Error(cmStrCat("No such preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
this->PrintPresetList(settingsFile);
this->PrintPresetList(presetsGraph);
return;
}
if (preset->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
this->PrintPresetList(settingsFile);
this->PrintPresetList(presetsGraph);
return;
}
auto const& expandedPreset = preset->second.Expanded;
@@ -1319,14 +1319,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
if (!expandedPreset->ArchitectureStrategy ||
expandedPreset->ArchitectureStrategy ==
cmCMakePresetsFile::ArchToolsetStrategy::Set) {
cmCMakePresetsGraph::ArchToolsetStrategy::Set) {
if (!this->GeneratorPlatformSet) {
this->SetGeneratorPlatform(expandedPreset->Architecture);
}
}
if (!expandedPreset->ToolsetStrategy ||
expandedPreset->ToolsetStrategy ==
cmCMakePresetsFile::ArchToolsetStrategy::Set) {
cmCMakePresetsGraph::ArchToolsetStrategy::Set) {
if (!this->GeneratorToolsetSet) {
this->SetGeneratorToolset(expandedPreset->Toolset);
}
@@ -1707,12 +1707,12 @@ bool cmake::CreateAndSetGlobalGenerator(const std::string& name,
}
#ifndef CMAKE_BOOTSTRAP
void cmake::PrintPresetList(const cmCMakePresetsFile& file) const
void cmake::PrintPresetList(const cmCMakePresetsGraph& graph) const
{
std::vector<GeneratorInfo> generators;
this->GetRegisteredGenerators(generators, false);
auto filter =
[&generators](const cmCMakePresetsFile::ConfigurePreset& preset) -> bool {
[&generators](const cmCMakePresetsGraph::ConfigurePreset& preset) -> bool {
if (preset.Generator.empty()) {
return true;
}
@@ -1723,7 +1723,7 @@ void cmake::PrintPresetList(const cmCMakePresetsFile& file) const
return it != generators.end();
};
file.PrintConfigurePresetList(filter);
graph.PrintConfigurePresetList(filter);
}
#endif
@@ -3230,12 +3230,12 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
cmCMakePresetsFile settingsFile;
cmCMakePresetsGraph settingsFile;
auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
cmSystemTools::Error(
cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
": ", cmCMakePresetsFile::ResultToString(result)));
": ", cmCMakePresetsGraph::ResultToString(result)));
return 1;
}

View File

@@ -31,7 +31,7 @@
# include <cm3p/json/value.h>
# include "cmCMakePresetsFile.h"
# include "cmCMakePresetsGraph.h"
#endif
class cmExternalMakefileProjectGeneratorFactory;
@@ -248,7 +248,7 @@ public:
#ifndef CMAKE_BOOTSTRAP
//! Print list of configure presets
void PrintPresetList(const cmCMakePresetsFile& file) const;
void PrintPresetList(const cmCMakePresetsGraph& graph) const;
#endif
//! Return the global generator assigned to this instance of cmake
@@ -691,7 +691,7 @@ private:
std::string GraphVizFile;
InstalledFilesMap InstalledFiles;
#ifndef CMAKE_BOOTSTRAP
std::map<std::string, cm::optional<cmCMakePresetsFile::CacheVariable>>
std::map<std::string, cm::optional<cmCMakePresetsGraph::CacheVariable>>
UnprocessedPresetVariables;
std::map<std::string, cm::optional<std::string>>
UnprocessedPresetEnvironment;

View File

@@ -0,0 +1,8 @@
^Not searching for unused variables given on the command line\.
Available configure presets:
"IncludeUser"
"IncludeUserCommon"
"Include"
"Subdir"
"IncludeCommon"$

View File

@@ -0,0 +1,16 @@
{
"version": 4,
"include": [
"subdir/CMakePresets.json",
"@RunCMake_TEST_SOURCE_DIR@/IncludeCommon.json"
],
"configurePresets": [
{
"name": "Include",
"inherits": [
"IncludeCommon",
"Subdir"
]
}
]
}

View File

@@ -0,0 +1,8 @@
{
"version": 3,
"configurePresets": [
{
"name": "IncludeCommon"
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/IncludeCycle: Cyclic include among preset files$

View File

@@ -0,0 +1,11 @@
{
"version": 4,
"include": [
"CMakeUserPresets.json"
],
"configurePresets": [
{
"name": "IncludeCycle"
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/IncludeCycle3Files: Cyclic include among preset files$

View File

@@ -0,0 +1,6 @@
{
"version": 4,
"include": [
"IncludeCycle3Files2.json"
]
}

View File

@@ -0,0 +1,6 @@
{
"version": 4,
"include": [
"IncludeCycle3Files3.json"
]
}

View File

@@ -0,0 +1,6 @@
{
"version": 4,
"include": [
"CMakePresets.json"
]
}

View File

@@ -0,0 +1,3 @@
{
"version": 3
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/IncludeNotFound: File not found$

View File

@@ -0,0 +1,11 @@
{
"version": 4,
"include": [
"NotFound.json"
],
"configurePresets": [
{
"name": "IncludeNotFound"
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/IncludeOutsideProject: File included from outside project directory$

View File

@@ -0,0 +1,11 @@
{
"version": 4,
"include": [
"IncludeOutsideProjectIntermediate.json"
],
"configurePresets": [
{
"name": "IncludeOutsideProject"
}
]
}

View File

@@ -0,0 +1,3 @@
{
"version": 4
}

View File

@@ -0,0 +1,6 @@
{
"version": 4,
"include": [
"@RunCMake_SOURCE_DIR@/IncludeOutsideProjectInclude.json"
]
}

View File

@@ -0,0 +1,6 @@
{
"version": 4,
"include": [
"IncludeOutsideProjectIntermediate.json"
]
}

View File

@@ -0,0 +1,15 @@
{
"version": 4,
"include": [
"IncludeUserCommon.json"
],
"configurePresets": [
{
"name": "IncludeUser",
"inherits": [
"Include",
"IncludeUserCommon"
]
}
]
}

View File

@@ -0,0 +1,8 @@
{
"version": 3,
"configurePresets": [
{
"name": "IncludeUserCommon"
}
]
}

View File

@@ -0,0 +1,11 @@
{
"version": 4,
"include": [
"@RunCMake_SOURCE_DIR@/IncludeOutsideProjectInclude.json"
],
"configurePresets": [
{
"name": "IncludeUserOutsideProject"
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/IncludeV3: File version must be 4 or higher for include support$

View File

@@ -0,0 +1,4 @@
{
"version": 3,
"include": []
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/IncludeV4V3: File version must be 4 or higher for include support$

View File

@@ -0,0 +1,6 @@
{
"version": 4,
"include": [
"IncludeV4V3Extra.json"
]
}

View File

@@ -0,0 +1,4 @@
{
"version": 3,
"include": []
}

View File

@@ -44,6 +44,20 @@ function(run_cmake_presets name)
configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
endif()
set(_CMakePresets_EXTRA_FILES_OUT)
set(_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
foreach(_extra_file IN LISTS CMakePresets_EXTRA_FILES)
cmake_path(RELATIVE_PATH _extra_file
BASE_DIRECTORY "${RunCMake_SOURCE_DIR}"
OUTPUT_VARIABLE _extra_file_relative
)
string(REGEX REPLACE "\\.in$" "" _extra_file_out_relative "${_extra_file_relative}")
set(_extra_file_out "${RunCMake_TEST_SOURCE_DIR}/${_extra_file_out_relative}")
configure_file("${_extra_file}" "${_extra_file_out}")
list(APPEND _CMakePresets_EXTRA_FILES_OUT "${_extra_file_out}")
list(APPEND _CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS 0)
endforeach()
set(_s_arg -S)
if(CMakePresets_NO_S_ARG)
set(_s_arg)
@@ -319,6 +333,37 @@ run_cmake_presets(OptionalBinaryDirFieldNoS)
unset(CMakePresets_SOURCE_ARG)
unset(CMakePresets_NO_S_ARG)
# Test include field
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_presets(IncludeV3)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
set(CMakePresets_EXTRA_FILES
"${RunCMake_SOURCE_DIR}/IncludeV4V3Extra.json.in"
)
set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS 1)
run_cmake_presets(IncludeV4V3)
unset(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
set(CMakePresets_EXTRA_FILES
"${RunCMake_SOURCE_DIR}/IncludeCommon.json.in"
"${RunCMake_SOURCE_DIR}/IncludeUserCommon.json.in"
"${RunCMake_SOURCE_DIR}/subdir/CMakePresets.json.in"
)
run_cmake_presets(Include --list-presets)
unset(CMakePresets_EXTRA_FILES)
run_cmake_presets(IncludeNotFound)
run_cmake_presets(IncludeCycle)
set(CMakePresets_EXTRA_FILES
"${RunCMake_SOURCE_DIR}/IncludeCycle3Files2.json.in"
"${RunCMake_SOURCE_DIR}/IncludeCycle3Files3.json.in"
)
run_cmake_presets(IncludeCycle3Files)
set(CMakePresets_EXTRA_FILES
"${RunCMake_SOURCE_DIR}/IncludeOutsideProjectIntermediate.json.in"
)
run_cmake_presets(IncludeOutsideProject)
unset(CMakePresets_EXTRA_FILES)
run_cmake_presets(IncludeUserOutsideProject)
# Test the example from the documentation
file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}")

View File

@@ -1,2 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/UserInheritance: Project preset inherits from user preset$
]*/Tests/RunCMake/CMakePresets/UserInheritance: Inherited preset is unreachable from preset's file$

View File

@@ -12,4 +12,11 @@ if(PYTHON_EXECUTABLE AND CMake_TEST_JSON_SCHEMA)
if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json")
validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}")
endif()
if(NOT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS "${_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS}")
endif()
foreach(_f _r IN ZIP_LISTS _CMakePresets_EXTRA_FILES_OUT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
validate_schema("${_f}" "${_r}")
endforeach()
endif()

View File

@@ -0,0 +1,12 @@
{
"version": 4,
"include": [
"../IncludeCommon.json"
],
"configurePresets": [
{
"name": "Subdir",
"inherits": "IncludeCommon"
}
]
}