mirror of
https://github.com/Kitware/CMake.git
synced 2026-06-30 19:57:41 +00:00
Modify diagnostics to track which preset schema version corresponds to the introduction of each diagnostic. Modify how we parse presets to use the set of diagnostics to generate bindings, and to store diagnostics as maps rather than as fixed members. Enforce that only diagnostics known to the specified preset version are present. This is a first and necessary step toward moving CMake's internals over to flexible categories rather than each category having its own bespoke variables and member functions. Note that the presets documentation currently contains some broken links, as it is anticipating further documentation updates that will happen in a future commit.
853 lines
28 KiB
C++
853 lines
28 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#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/value.h>
|
|
|
|
#include "cmCMakePresetsErrors.h"
|
|
#include "cmCMakePresetsGraph.h"
|
|
#include "cmCMakePresetsGraphInternal.h"
|
|
#include "cmJSONHelpers.h"
|
|
#include "cmJSONState.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmVersion.h"
|
|
|
|
namespace {
|
|
using CacheVariable = cmCMakePresetsGraph::CacheVariable;
|
|
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
|
|
using BuildPreset = cmCMakePresetsGraph::BuildPreset;
|
|
using TestPreset = cmCMakePresetsGraph::TestPreset;
|
|
using PackagePreset = cmCMakePresetsGraph::PackagePreset;
|
|
using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset;
|
|
using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
|
|
using JSONHelperBuilder = cmJSONHelperBuilder;
|
|
using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult;
|
|
using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander;
|
|
using MacroExpanderVector = cmCMakePresetsGraphInternal::MacroExpanderVector;
|
|
using cmCMakePresetsGraphInternal::BaseMacroExpander;
|
|
using cmCMakePresetsGraphInternal::ExpandMacros;
|
|
using cmCMakePresetsGraphInternal::ExpandImmediateMacros;
|
|
|
|
constexpr int MIN_VERSION = 1;
|
|
constexpr int MAX_VERSION = 12;
|
|
|
|
struct CMakeVersion
|
|
{
|
|
unsigned int Major = 0;
|
|
unsigned int Minor = 0;
|
|
unsigned int Patch = 0;
|
|
};
|
|
|
|
struct RootPresets
|
|
{
|
|
CMakeVersion CMakeMinimumRequired;
|
|
std::vector<ConfigurePreset> ConfigurePresets;
|
|
std::vector<BuildPreset> BuildPresets;
|
|
std::vector<TestPreset> TestPresets;
|
|
std::vector<PackagePreset> PackagePresets;
|
|
std::vector<WorkflowPreset> WorkflowPresets;
|
|
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 = JSONHelperBuilder::String();
|
|
|
|
auto const ConditionBoolHelper = JSONHelperBuilder::Bool();
|
|
|
|
auto const ConditionStringListHelper = JSONHelperBuilder::Vector<std::string>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION, ConditionStringHelper);
|
|
|
|
auto const ConstConditionHelper =
|
|
JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::ConstCondition>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
|
|
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
|
|
.Bind("value"_s, &cmCMakePresetsGraphInternal::ConstCondition::Value,
|
|
ConditionBoolHelper, true);
|
|
|
|
auto const EqualsConditionHelper =
|
|
JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::EqualsCondition>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, 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 =
|
|
JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::InListCondition>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, 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 =
|
|
JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::MatchesCondition>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, 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);
|
|
|
|
bool SubConditionHelper(std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
|
|
Json::Value const* value, cmJSONState* state);
|
|
|
|
auto const ListConditionVectorHelper =
|
|
JSONHelperBuilder::Vector<std::unique_ptr<cmCMakePresetsGraph::Condition>>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION, SubConditionHelper);
|
|
auto const AnyAllOfConditionHelper =
|
|
JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::AnyAllOfCondition>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
|
|
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
|
|
.Bind("conditions"_s,
|
|
&cmCMakePresetsGraphInternal::AnyAllOfCondition::Conditions,
|
|
ListConditionVectorHelper);
|
|
|
|
auto const NotConditionHelper =
|
|
JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::NotCondition>(
|
|
cmCMakePresetsErrors::INVALID_CONDITION_OBJECT, false)
|
|
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
|
|
.Bind("condition"_s,
|
|
&cmCMakePresetsGraphInternal::NotCondition::SubCondition,
|
|
SubConditionHelper);
|
|
|
|
bool ConditionHelper(std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
if (!value) {
|
|
out.reset();
|
|
return true;
|
|
}
|
|
|
|
if (value->isBool()) {
|
|
auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
|
|
c->Value = value->asBool();
|
|
out = std::move(c);
|
|
return true;
|
|
}
|
|
|
|
if (value->isNull()) {
|
|
out = cm::make_unique<cmCMakePresetsGraphInternal::NullCondition>();
|
|
return true;
|
|
}
|
|
|
|
if (value->isObject()) {
|
|
if (!value->isMember("type")) {
|
|
cmCMakePresetsErrors::INVALID_CONDITION(value, state);
|
|
return false;
|
|
}
|
|
|
|
if (!(*value)["type"].isString()) {
|
|
cmCMakePresetsErrors::INVALID_CONDITION(value, state);
|
|
return false;
|
|
}
|
|
auto type = (*value)["type"].asString();
|
|
|
|
if (type == "const") {
|
|
auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
|
|
CHECK_OK(ConstConditionHelper(*c, value, state));
|
|
out = std::move(c);
|
|
return true;
|
|
}
|
|
|
|
if (type == "equals" || type == "notEquals") {
|
|
auto c = cm::make_unique<cmCMakePresetsGraphInternal::EqualsCondition>();
|
|
CHECK_OK(EqualsConditionHelper(*c, value, state));
|
|
out = std::move(c);
|
|
if (type == "notEquals") {
|
|
out = InvertCondition(std::move(out));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (type == "inList" || type == "notInList") {
|
|
auto c = cm::make_unique<cmCMakePresetsGraphInternal::InListCondition>();
|
|
CHECK_OK(InListConditionHelper(*c, value, state));
|
|
out = std::move(c);
|
|
if (type == "notInList") {
|
|
out = InvertCondition(std::move(out));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (type == "matches" || type == "notMatches") {
|
|
auto c =
|
|
cm::make_unique<cmCMakePresetsGraphInternal::MatchesCondition>();
|
|
CHECK_OK(MatchesConditionHelper(*c, value, state));
|
|
out = std::move(c);
|
|
if (type == "notMatches") {
|
|
out = InvertCondition(std::move(out));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (type == "anyOf" || type == "allOf") {
|
|
auto c =
|
|
cm::make_unique<cmCMakePresetsGraphInternal::AnyAllOfCondition>();
|
|
c->StopValue = (type == "anyOf");
|
|
CHECK_OK(AnyAllOfConditionHelper(*c, value, state));
|
|
out = std::move(c);
|
|
return true;
|
|
}
|
|
|
|
if (type == "not") {
|
|
auto c = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
|
|
CHECK_OK(NotConditionHelper(*c, value, state));
|
|
out = std::move(c);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
cmCMakePresetsErrors::INVALID_CONDITION(value, state);
|
|
return false;
|
|
}
|
|
|
|
bool SubConditionHelper(std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
|
|
auto result = ConditionHelper(ptr, value, state);
|
|
if (ptr && ptr->IsNull()) {
|
|
cmCMakePresetsErrors::INVALID_CONDITION(value, state);
|
|
return false;
|
|
}
|
|
out = std::move(ptr);
|
|
return result;
|
|
}
|
|
|
|
bool EnvironmentHelper(cm::optional<std::string>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
if (!value || value->isNull()) {
|
|
out = cm::nullopt;
|
|
return true;
|
|
}
|
|
if (value->isString()) {
|
|
out = value->asString();
|
|
return true;
|
|
}
|
|
cmCMakePresetsErrors::INVALID_PRESET(value, state);
|
|
return false;
|
|
}
|
|
|
|
auto const VersionIntHelper =
|
|
JSONHelperBuilder::Int(cmCMakePresetsErrors::INVALID_VERSION);
|
|
|
|
auto const VersionHelper = JSONHelperBuilder::Required<int>(
|
|
cmCMakePresetsErrors::NO_VERSION, VersionIntHelper);
|
|
|
|
auto const VersionRangeHelper = JSONHelperBuilder::Checked<int>(
|
|
cmCMakePresetsErrors::UNRECOGNIZED_VERSION_RANGE(MIN_VERSION, MAX_VERSION),
|
|
VersionHelper,
|
|
[](int const v) -> bool { return v >= MIN_VERSION && v <= MAX_VERSION; });
|
|
|
|
auto const RootVersionHelper =
|
|
JSONHelperBuilder::Object<int>(cmCMakePresetsErrors::INVALID_ROOT_OBJECT)
|
|
.Bind("version"_s, VersionRangeHelper, false);
|
|
|
|
auto const CMakeVersionUIntHelper =
|
|
JSONHelperBuilder::UInt(cmCMakePresetsErrors::INVALID_VERSION);
|
|
|
|
auto const CMakeVersionHelper =
|
|
JSONHelperBuilder::Object<CMakeVersion>(JsonErrors::INVALID_NAMED_OBJECT_KEY,
|
|
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 =
|
|
JSONHelperBuilder::String(cmCMakePresetsErrors::INVALID_INCLUDE);
|
|
|
|
auto const IncludeVectorHelper = JSONHelperBuilder::Vector<std::string>(
|
|
cmCMakePresetsErrors::INVALID_INCLUDE, IncludeHelper);
|
|
|
|
auto const RootPresetsHelper =
|
|
JSONHelperBuilder::Object<RootPresets>(
|
|
cmCMakePresetsErrors::INVALID_ROOT_OBJECT, 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("packagePresets"_s, &RootPresets::PackagePresets,
|
|
cmCMakePresetsGraphInternal::PackagePresetsHelper, false)
|
|
.Bind("workflowPresets"_s, &RootPresets::WorkflowPresets,
|
|
cmCMakePresetsGraphInternal::WorkflowPresetsHelper, false)
|
|
.Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
|
|
CMakeVersionHelper, false)
|
|
.Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
|
|
.Bind<std::nullptr_t>("vendor"_s, nullptr,
|
|
cmCMakePresetsGraphInternal::VendorHelper(
|
|
cmCMakePresetsErrors::INVALID_ROOT),
|
|
false)
|
|
.Bind<std::nullptr_t>("$schema"_s, nullptr,
|
|
cmCMakePresetsGraphInternal::SchemaHelper(), false);
|
|
|
|
class EnvironmentMacroExpander : public MacroExpander
|
|
{
|
|
public:
|
|
ExpandMacroResult operator()(std::string const& macroNamespace,
|
|
std::string const& macroName,
|
|
std::string& macroOut,
|
|
int /*version*/) const override
|
|
{
|
|
if (macroNamespace == "penv") {
|
|
if (macroName.empty()) {
|
|
return ExpandMacroResult::Error;
|
|
}
|
|
if (cm::optional<std::string> value =
|
|
cmSystemTools::GetEnvVar(macroName)) {
|
|
macroOut += *value;
|
|
}
|
|
return ExpandMacroResult::Ok;
|
|
}
|
|
|
|
return ExpandMacroResult::Ignore;
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace cmCMakePresetsGraphInternal {
|
|
bool PresetStringHelper(std::string& out, Json::Value const* value,
|
|
cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::String();
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetNameHelper(std::string& out, Json::Value const* value,
|
|
cmJSONState* state)
|
|
{
|
|
if (!value || !value->isString() || value->asString().empty()) {
|
|
cmCMakePresetsErrors::INVALID_PRESET_NAME(value, state);
|
|
return false;
|
|
}
|
|
out = value->asString();
|
|
return true;
|
|
}
|
|
|
|
bool PresetVectorStringHelper(std::vector<std::string>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::Vector<std::string>(
|
|
cmCMakePresetsErrors::INVALID_PRESET,
|
|
cmCMakePresetsGraphInternal::PresetStringHelper);
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetBoolHelper(bool& out, Json::Value const* value, cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::Bool();
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetOptionalBoolHelper(cm::optional<bool>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
static auto const helper =
|
|
JSONHelperBuilder::Optional<bool>(PresetBoolHelper);
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetIntHelper(int& out, Json::Value const* value, cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::Int();
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetOptionalIntHelper(cm::optional<int>& out, Json::Value const* value,
|
|
cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::Optional<int>(PresetIntHelper);
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetUIntHelper(unsigned int& out, Json::Value const* value,
|
|
cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::UInt();
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetOptionalUIntHelper(cm::optional<unsigned int>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
static auto const helper =
|
|
JSONHelperBuilder::Optional<unsigned int>(PresetUIntHelper);
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
bool PresetVectorIntHelper(std::vector<int>& out, Json::Value const* value,
|
|
cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::Vector<int>(
|
|
cmCMakePresetsErrors::INVALID_PRESET, PresetIntHelper);
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
cmJSONHelper<std::nullptr_t> VendorHelper(ErrorGenerator const& error)
|
|
{
|
|
return [error](std::nullptr_t& /*out*/, Json::Value const* value,
|
|
cmJSONState* state) -> bool {
|
|
if (!value) {
|
|
return true;
|
|
}
|
|
|
|
if (!value->isObject()) {
|
|
error(value, state);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
}
|
|
|
|
bool PresetConditionHelper(
|
|
std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
|
|
auto result = ConditionHelper(ptr, value, state);
|
|
out = std::move(ptr);
|
|
return result;
|
|
}
|
|
|
|
bool PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
|
|
Json::Value const* value,
|
|
cmJSONState* state)
|
|
{
|
|
out.clear();
|
|
if (!value) {
|
|
return true;
|
|
}
|
|
|
|
if (value->isString()) {
|
|
out.push_back(value->asString());
|
|
return true;
|
|
}
|
|
|
|
return PresetVectorStringHelper(out, value, state);
|
|
}
|
|
|
|
bool EnvironmentMapHelper(
|
|
std::map<std::string, cm::optional<std::string>>& out,
|
|
Json::Value const* value, cmJSONState* state)
|
|
{
|
|
static auto const helper = JSONHelperBuilder::Map<cm::optional<std::string>>(
|
|
cmCMakePresetsErrors::INVALID_PRESET, EnvironmentHelper);
|
|
|
|
return helper(out, value, state);
|
|
}
|
|
|
|
cmJSONHelper<std::nullptr_t> SchemaHelper()
|
|
{
|
|
return [](std::nullptr_t&, Json::Value const*, cmJSONState*) -> bool {
|
|
return true;
|
|
};
|
|
}
|
|
}
|
|
|
|
bool cmCMakePresetsGraph::ReadJSONFile(std::string const& filename,
|
|
RootType rootType,
|
|
ReadReason readReason,
|
|
std::vector<File*>& inProgressFiles,
|
|
File*& file, std::string& errMsg)
|
|
{
|
|
bool result;
|
|
|
|
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()) {
|
|
cmCMakePresetsErrors::CYCLIC_INCLUDE(filename, &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Json::Value root;
|
|
this->parseState = cmJSONState(filename, &root);
|
|
if (!this->parseState.errors.empty()) {
|
|
return false;
|
|
}
|
|
|
|
int v = 0;
|
|
if ((result = RootVersionHelper(v, &root, &parseState)) != true) {
|
|
return result;
|
|
}
|
|
|
|
// Support for build and test presets added in version 2.
|
|
if (v < 2) {
|
|
if (root.isMember("buildPresets")) {
|
|
cmCMakePresetsErrors::BUILD_TEST_PRESETS_UNSUPPORTED(
|
|
&root["buildPresets"], &this->parseState);
|
|
return false;
|
|
}
|
|
if (root.isMember("testPresets")) {
|
|
cmCMakePresetsErrors::BUILD_TEST_PRESETS_UNSUPPORTED(
|
|
&root["testPresets"], &this->parseState);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Support for package presets added in version 6.
|
|
if (v < 6 && root.isMember("packagePresets")) {
|
|
cmCMakePresetsErrors::PACKAGE_PRESETS_UNSUPPORTED(&root["packagePresets"],
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for workflow presets added in version 6.
|
|
if (v < 6 && root.isMember("workflowPresets")) {
|
|
cmCMakePresetsErrors::WORKFLOW_PRESETS_UNSUPPORTED(
|
|
&root["workflowPresets"], &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for include added in version 4.
|
|
if (v < 4 && root.isMember("include")) {
|
|
cmCMakePresetsErrors::INCLUDE_UNSUPPORTED(&root["include"],
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for $schema added in version 8.
|
|
if (v < 8 && root.isMember("$schema")) {
|
|
cmCMakePresetsErrors::SCHEMA_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for $comment added in version 10.
|
|
this->parseState.allowComments = (v >= 10);
|
|
|
|
RootPresets presets;
|
|
if ((result = RootPresetsHelper(presets, &root, &parseState)) != true) {
|
|
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) {
|
|
ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
|
|
"major", currentMajor, required.Major);
|
|
error(&root["cmakeMinimumRequired"]["major"], &this->parseState);
|
|
return false;
|
|
}
|
|
if (required.Major == currentMajor) {
|
|
if (required.Minor > currentMinor) {
|
|
ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
|
|
"minor", currentMinor, required.Minor);
|
|
error(&root["cmakeMinimumRequired"]["minor"], &this->parseState);
|
|
return false;
|
|
}
|
|
if (required.Minor == currentMinor && required.Patch > currentPatch) {
|
|
ErrorGenerator error = cmCMakePresetsErrors::UNRECOGNIZED_CMAKE_VERSION(
|
|
"patch", currentPatch, required.Patch);
|
|
error(&root["cmakeMinimumRequired"]["patch"], &this->parseState);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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()) {
|
|
// No error, already handled by PresetNameHelper
|
|
return false;
|
|
}
|
|
|
|
if (!ExpandImmediateMacros<ConfigurePreset>(preset)) {
|
|
cmCMakePresetsErrors::INVALID_MACRO_EXPANSION(preset.Name,
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for installDir presets added in version 3.
|
|
if (v < 3 && !preset.InstallDir.empty()) {
|
|
cmCMakePresetsErrors::INSTALL_PREFIX_UNSUPPORTED(&root["installDir"],
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for conditions added in version 3.
|
|
if (v < 3 && preset.ConditionEvaluator) {
|
|
cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for toolchainFile presets added in version 3.
|
|
if (v < 3 && !preset.ToolchainFile.empty()) {
|
|
cmCMakePresetsErrors::TOOLCHAIN_FILE_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for trace presets added in version 7.
|
|
if (v < 7 &&
|
|
(preset.TraceMode.has_value() || preset.TraceFormat.has_value() ||
|
|
!preset.TraceRedirect.empty() || !preset.TraceSource.empty())) {
|
|
cmCMakePresetsErrors::TRACE_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for graphviz argument added in version 10.
|
|
if (v < 10 && !preset.GraphVizFile.empty()) {
|
|
cmCMakePresetsErrors::GRAPHVIZ_FILE_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for diagnostics.
|
|
if (!cmCMakePresetsGraphInternal::CheckDiagnostics(&this->parseState, v,
|
|
preset)) {
|
|
return false;
|
|
}
|
|
|
|
PresetPair<ConfigurePreset> presetPair;
|
|
presetPair.Unexpanded = preset;
|
|
presetPair.Expanded = cm::nullopt;
|
|
if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) {
|
|
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
this->ConfigurePresetOrder.push_back(preset.Name);
|
|
}
|
|
|
|
for (auto& preset : presets.BuildPresets) {
|
|
preset.OriginFile = file;
|
|
if (preset.Name.empty()) {
|
|
// No error, already handled by PresetNameHelper
|
|
return false;
|
|
}
|
|
|
|
if (!ExpandImmediateMacros<BuildPreset>(preset)) {
|
|
cmCMakePresetsErrors::INVALID_MACRO_EXPANSION(preset.Name,
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
PresetPair<BuildPreset> presetPair;
|
|
presetPair.Unexpanded = preset;
|
|
presetPair.Expanded = cm::nullopt;
|
|
if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
|
|
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for conditions added in version 3.
|
|
if (v < 3 && preset.ConditionEvaluator) {
|
|
cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
this->BuildPresetOrder.push_back(preset.Name);
|
|
}
|
|
|
|
for (auto& preset : presets.TestPresets) {
|
|
preset.OriginFile = file;
|
|
if (preset.Name.empty()) {
|
|
// No error, already handled by PresetNameHelper
|
|
return false;
|
|
}
|
|
|
|
if (!ExpandImmediateMacros<TestPreset>(preset)) {
|
|
cmCMakePresetsErrors::INVALID_MACRO_EXPANSION(preset.Name,
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
PresetPair<TestPreset> presetPair;
|
|
presetPair.Unexpanded = preset;
|
|
presetPair.Expanded = cm::nullopt;
|
|
if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
|
|
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for conditions added in version 3.
|
|
if (v < 3 && preset.ConditionEvaluator) {
|
|
cmCMakePresetsErrors::CONDITION_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for TestOutputTruncation added in version 5.
|
|
if (v < 5 && preset.Output && preset.Output->TestOutputTruncation) {
|
|
cmCMakePresetsErrors::TEST_OUTPUT_TRUNCATION_UNSUPPORTED(
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for outputJUnitFile added in version 6.
|
|
if (v < 6 && preset.Output && !preset.Output->OutputJUnitFile.empty()) {
|
|
cmCMakePresetsErrors::CTEST_JUNIT_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for processor-count-based jobs added in version 11.
|
|
if (v < 11 && preset.Execution && preset.Execution->Jobs.has_value() &&
|
|
!preset.Execution->Jobs->has_value()) {
|
|
cmCMakePresetsErrors::JOBS_PROC_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for testPassthroughArguments added in version 12.
|
|
if (v < 12 && preset.Execution &&
|
|
!preset.Execution->TestPassthroughArguments.empty()) {
|
|
cmCMakePresetsErrors::PASSTHROUGH_ARGS_UNSUPPORTED(&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
this->TestPresetOrder.push_back(preset.Name);
|
|
}
|
|
|
|
for (auto& preset : presets.PackagePresets) {
|
|
preset.OriginFile = file;
|
|
if (preset.Name.empty()) {
|
|
// No error, already handled by PresetNameHelper
|
|
return false;
|
|
}
|
|
|
|
if (!ExpandImmediateMacros<PackagePreset>(preset)) {
|
|
cmCMakePresetsErrors::INVALID_MACRO_EXPANSION(preset.Name,
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
PresetPair<PackagePreset> presetPair;
|
|
presetPair.Unexpanded = preset;
|
|
presetPair.Expanded = cm::nullopt;
|
|
if (!this->PackagePresets.emplace(preset.Name, presetPair).second) {
|
|
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for conditions added in version 3, but this requires version 5
|
|
// already, so no action needed.
|
|
|
|
this->PackagePresetOrder.push_back(preset.Name);
|
|
}
|
|
|
|
for (auto& preset : presets.WorkflowPresets) {
|
|
preset.OriginFile = file;
|
|
if (preset.Name.empty()) {
|
|
// No error, already handled by PresetNameHelper
|
|
return false;
|
|
}
|
|
|
|
if (!ExpandImmediateMacros<WorkflowPreset>(preset)) {
|
|
cmCMakePresetsErrors::INVALID_MACRO_EXPANSION(preset.Name,
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
|
|
PresetPair<WorkflowPreset> presetPair;
|
|
presetPair.Unexpanded = preset;
|
|
presetPair.Expanded = cm::nullopt;
|
|
if (!this->WorkflowPresets.emplace(preset.Name, presetPair).second) {
|
|
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
|
|
return false;
|
|
}
|
|
|
|
// Support for conditions added in version 3, but this requires version 6
|
|
// already, so no action needed.
|
|
|
|
this->WorkflowPresetOrder.push_back(preset.Name);
|
|
}
|
|
|
|
auto const includeFile = [this, &inProgressFiles,
|
|
file](std::string const& include,
|
|
RootType rootType2, ReadReason readReason2,
|
|
std::string& FailureMessage) -> bool {
|
|
bool r;
|
|
File* includedFile;
|
|
if ((r =
|
|
this->ReadJSONFile(include, rootType2, readReason2, inProgressFiles,
|
|
includedFile, FailureMessage)) != true) {
|
|
return r;
|
|
}
|
|
|
|
file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
|
|
includedFile->ReachableFiles.end());
|
|
return true;
|
|
};
|
|
|
|
MacroExpanderVector macroExpanders{};
|
|
|
|
if (v >= 9) {
|
|
macroExpanders.push_back(
|
|
cm::make_unique<BaseMacroExpander>(*this, filename));
|
|
}
|
|
macroExpanders.push_back(cm::make_unique<EnvironmentMacroExpander>());
|
|
|
|
for (Json::ArrayIndex i = 0; i < presets.Include.size(); ++i) {
|
|
auto include = presets.Include[i];
|
|
|
|
// Support for macro expansion in includes added in version 7
|
|
if (v >= 7) {
|
|
if (ExpandMacros(include, macroExpanders, v) != ExpandMacroResult::Ok) {
|
|
cmCMakePresetsErrors::INVALID_INCLUDE(&root["include"][i],
|
|
&this->parseState);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!cmSystemTools::FileIsFullPath(include)) {
|
|
auto directory = cmSystemTools::GetFilenamePath(filename);
|
|
include = cmStrCat(directory, '/', include);
|
|
}
|
|
|
|
if ((result = includeFile(include, rootType, ReadReason::Included,
|
|
errMsg)) != true) {
|
|
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, errMsg)) != true) {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
inProgressFiles.pop_back();
|
|
return true;
|
|
}
|