1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 02:08:27 +08:00

CMakePresets.json: Add the ability to conditionally disable presets

This commit is contained in:
Kyle Edwards
2021-03-10 14:59:14 -05:00
committed by Brad King
parent ce6ea7c927
commit 8bc5c8961e
44 changed files with 1410 additions and 19 deletions

View File

@@ -119,6 +119,11 @@ that may contain the following fields:
This field can also be a string, which is equivalent to an array
containing one string.
``condition``
An optional `Condition`_ object. This is allowed in preset files specifying
version ``3`` or above.
``vendor``
An optional map containing vendor-specific information. CMake does not
@@ -345,6 +350,11 @@ that may contain the following fields:
This field can also be a string, which is equivalent to an array
containing one string.
``condition``
An optional `Condition`_ object. This is allowed in preset files specifying
version ``3`` or above.
``vendor``
An optional map containing vendor-specific information. CMake does not
@@ -464,6 +474,11 @@ that may contain the following fields:
This field can also be a string, which is equivalent to an array
containing one string.
``condition``
An optional `Condition`_ object. This is allowed in preset files specifying
version ``3`` or above.
``vendor``
An optional map containing vendor-specific information. CMake does not
@@ -789,6 +804,87 @@ that may contain the following fields:
Equivalent to passing ``--no-tests=ignore`` on the command line.
Condition
^^^^^^^^^
The ``condition`` field of a preset, allowed in preset files specifying version
``3`` or above, is used to determine whether or not the preset is enabled. For
example, this can be used to disable a preset on platforms other than Windows.
``condition`` may be either a boolean, ``null``, or an object. If it is a
boolean, the boolean indicates whether the preset is enabled or disabled. If it
is ``null``, the preset is enabled, but the ``null`` condition is not inherited
by any presets that may inherit from the preset. Sub-conditions (for example in
a ``not``, ``anyOf``, or ``allOf`` condition) may not be ``null``. If it is an
object, it has the following fields:
``type``
A required string with one of the following values:
``"const"``
Indicates that the condition is constant. This is equivalent to using a
boolean in place of the object. The condition object will have the
following additional fields:
``value``
A required boolean which provides a constant value for the condition's
evaluation.
``"equals"``
``"notEquals"``
Indicates that the condition compares two strings to see if they are equal
(or not equal). The condition object will have the following additional
fields:
``lhs``
First string to compare. This field supports macro expansion.
``rhs``
Second string to compare. This field supports macro expansion.
``"inList"``
``"notInList"``
Indicates that the condition searches for a string in a list of strings.
The condition object will have the following additional fields:
``string``
A required string to search for. This field supports macro expansion.
``list``
A required list of strings to search. This field supports macro
expansion, and uses short-circuit evaluation.
``"anyOf"``
``"allOf"``
Indicates that the condition is an aggregation of zero or more nested
conditions. The condition object will have the following additional fields:
``conditions``
A required array of condition objects. These conditions use short-circuit
evaluation.
``"not"``
Indicates that the condition is an inversion of another condition. The
condition object will have the following additional fields:
``condition``
A required condition object.
Macro Expansion
^^^^^^^^^^^^^^^

View File

@@ -1,5 +1,5 @@
{
"version": 2,
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
@@ -35,6 +35,17 @@
"displayName": "Ninja Multi-Config",
"description": "Default build using Ninja Multi-Config generator",
"generator": "Ninja Multi-Config"
},
{
"name": "windows-only",
"inherits": "default",
"displayName": "Windows-only configuration",
"description": "This build is only available on Windows",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
}
],
"buildPresets": [

View File

@@ -24,8 +24,8 @@
"cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
"vendor": { "$ref": "#/definitions/vendor" },
"configurePresets": { "$ref": "#/definitions/configurePresetsV1"},
"buildPresets": { "$ref": "#/definitions/buildPresets"},
"testPresets": { "$ref": "#/definitions/testPresets"}
"buildPresets": { "$ref": "#/definitions/buildPresetsV2"},
"testPresets": { "$ref": "#/definitions/testPresetsV2"}
},
"additionalProperties": false
},
@@ -38,8 +38,8 @@
"cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
"vendor": { "$ref": "#/definitions/vendor" },
"configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
"buildPresets": { "$ref": "#/definitions/buildPresets"},
"testPresets": { "$ref": "#/definitions/testPresets"}
"buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
"testPresets": { "$ref": "#/definitions/testPresetsV3"}
},
"additionalProperties": false
}
@@ -82,7 +82,8 @@
"installDir": {
"type": "string",
"description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden)."
}
},
"condition": { "$ref": "#/definitions/topCondition" }
}
}
},
@@ -358,7 +359,8 @@
"environment": {},
"warnings": {},
"errors": {},
"debug": {}
"debug": {},
"condition": {}
},
"required": [
"name"
@@ -397,7 +399,17 @@
"additionalProperties": false
}
},
"buildPresets": {
"buildPresetsItemsV3": {
"type": "array",
"description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
"items": {
"type": "object",
"properties": {
"condition": { "$ref": "#/definitions/topCondition" }
}
}
},
"buildPresetsItemsV2": {
"type": "array",
"description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
"items": {
@@ -513,13 +525,86 @@
}
}
},
"required": [
"name"
]
}
},
"buildPresetsV3": {
"type": "array",
"description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
"allOf": [
{ "$ref": "#/definitions/buildPresetsItemsV3" },
{ "$ref": "#/definitions/buildPresetsItemsV2" }
],
"items": {
"type": "object",
"properties": {
"name": {},
"hidden": {},
"inherits": {},
"configurePreset": {},
"vendor": {},
"displayName": {},
"description": {},
"inheritConfigureEnvironment": {},
"environment": {},
"jobs": {},
"targets": {},
"configuration": {},
"cleanFirst": {},
"verbose": {},
"nativeToolOptions": {},
"condition": {}
},
"required": [
"name"
],
"additionalProperties": false
}
},
"testPresets": {
"buildPresetsV2": {
"type": "array",
"description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
"allOf": [
{ "$ref": "#/definitions/buildPresetsItemsV2" }
],
"items": {
"type": "object",
"properties": {
"name": {},
"hidden": {},
"inherits": {},
"configurePreset": {},
"vendor": {},
"displayName": {},
"description": {},
"inheritConfigureEnvironment": {},
"environment": {},
"jobs": {},
"targets": {},
"configuration": {},
"cleanFirst": {},
"verbose": {},
"nativeToolOptions": {}
},
"required": [
"name"
],
"additionalProperties": false
}
},
"testPresetsItemsV3": {
"type": "array",
"description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
"items": {
"type": "object",
"properties": {
"condition": { "$ref": "#/definitions/topCondition" }
}
}
},
"testPresetsItemsV2": {
"type": "array",
"description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
"items": {
@@ -829,11 +914,266 @@
"additionalProperties": false
}
},
"required": [
"name"
]
}
},
"testPresetsV3": {
"type": "array",
"description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
"allOf": [
{ "$ref": "#/definitions/testPresetsItemsV2" },
{ "$ref": "#/definitions/testPresetsItemsV3" }
],
"items": {
"type": "object",
"properties": {
"name": {},
"hidden": {},
"inherits": {},
"configurePreset": {},
"vendor": {},
"displayName": {},
"description": {},
"inheritConfigureEnvironment": {},
"environment": {},
"configuration": {},
"overwriteConfigurationFile": {},
"output": {},
"filter": {},
"execution": {},
"condition": {}
},
"required": [
"name"
],
"additionalProperties": false
}
},
"testPresetsV2": {
"type": "array",
"description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
"allOf": [
{ "$ref": "#/definitions/testPresetsItemsV2" }
],
"items": {
"type": "object",
"properties": {
"name": {},
"hidden": {},
"inherits": {},
"configurePreset": {},
"vendor": {},
"displayName": {},
"description": {},
"inheritConfigureEnvironment": {},
"environment": {},
"configuration": {},
"overwriteConfigurationFile": {},
"output": {},
"filter": {},
"execution": {}
},
"required": [
"name"
],
"additionalProperties": false
}
},
"condition": {
"anyOf": [
{
"type": "boolean",
"description": "A boolean which provides a constant value for the condition's evaluation."
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "const"
},
"value": {
"type": "boolean",
"description": "A required boolean which provides a constant value for the condition's evaluation."
}
},
"required": [
"type",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "equals"
},
"lhs": {
"type": "string",
"description": "First string to compare. This field supports macro expansion."
},
"rhs": {
"type": "string",
"description": "Second string to compare. This field supports macro expansion."
}
},
"required": [
"type",
"lhs",
"rhs"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "notEquals"
},
"lhs": {
"type": "string",
"description": "First string to compare. This field supports macro expansion."
},
"rhs": {
"type": "string",
"description": "Second string to compare. This field supports macro expansion."
}
},
"required": [
"type",
"lhs",
"rhs"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "inList"
},
"string": {
"type": "string",
"description": "A required string to search for. This field supports macro expansion."
},
"list": {
"type": "array",
"description": "A required list of strings to search. This field supports macro expansion, and uses short-circuit evaluation.",
"items": {
"type": "string"
}
}
},
"required": [
"type",
"string",
"list"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "notInList"
},
"string": {
"type": "string",
"description": "A required string to search for. This field supports macro expansion."
},
"list": {
"type": "array",
"description": "A required list of strings to search. This field supports macro expansion, and uses short-circuit evaluation.",
"items": {
"type": "string"
}
}
},
"required": [
"type",
"string",
"list"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "anyOf"
},
"conditions": {
"type": "array",
"description": "A required array of condition objects. These conditions use short-circuit evaluation.",
"items": { "$ref": "#/definitions/condition" }
}
},
"required": [
"type",
"conditions"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "allOf"
},
"conditions": {
"type": "array",
"description": "A required array of condition objects. These conditions use short-circuit evaluation.",
"items": { "$ref": "#/definitions/condition" }
}
},
"required": [
"type",
"conditions"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string specifying the type of the condition.",
"const": "not"
},
"condition": { "$ref": "#/definitions/condition" }
},
"required": [
"type",
"condition"
],
"additionalProperties": false
}
]
},
"topCondition": {
"anyOf": [
{ "$ref": "#/definitions/condition" },
{
"type": "null",
"description": "Null indicates that the condition always evaluates to true and is not inherited."
}
]
}
}
}

View File

@@ -0,0 +1,4 @@
cmake-presets-condition
-----------------------
* :manual:`cmake-presets(7)` now support conditional enabling of presets.

View File

@@ -557,7 +557,7 @@ void QCMake::loadPresets()
preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
preset.setToolset = !p.ToolsetStrategy ||
p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
preset.enabled = it.Expanded &&
preset.enabled = it.Expanded && it.Expanded->ConditionResult &&
std::find_if(this->AvailableGenerators.begin(),
this->AvailableGenerators.end(),
[&p](const cmake::GeneratorInfo& g) {

View File

@@ -9,6 +9,8 @@
#include <iterator>
#include <utility>
#include <cm/string_view>
#include "cmCMakePresetsFileInternal.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -114,6 +116,14 @@ ReadFileResult VisitPreset(
for (auto const& v : parentPreset.Environment) {
preset.Environment.insert(v);
}
if (!preset.ConditionEvaluator) {
preset.ConditionEvaluator = parentPreset.ConditionEvaluator;
}
}
if (preset.ConditionEvaluator && preset.ConditionEvaluator->IsNull()) {
preset.ConditionEvaluator.reset();
}
CHECK_OK(preset.VisitPresetAfterInherit())
@@ -382,6 +392,19 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
}
}
if (preset.ConditionEvaluator) {
cm::optional<bool> result;
if (!preset.ConditionEvaluator->Evaluate(
macroExpanders, file.GetVersion(preset), result)) {
return false;
}
if (!result) {
out.reset();
return true;
}
out->ConditionResult = *result;
}
return ExpandMacros(file, preset, out, macroExpanders);
}
@@ -505,6 +528,80 @@ ExpandMacroResult ExpandMacro(std::string& out,
}
}
bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
std::string lhs = this->Lhs;
CHECK_EXPAND(out, lhs, expanders, version);
std::string rhs = this->Rhs;
CHECK_EXPAND(out, rhs, expanders, version);
out = (lhs == rhs);
return true;
}
bool cmCMakePresetsFileInternal::InListCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
std::string str = this->String;
CHECK_EXPAND(out, str, expanders, version);
for (auto item : this->List) {
CHECK_EXPAND(out, item, expanders, version);
if (str == item) {
out = true;
return true;
}
}
out = false;
return true;
}
bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
for (auto const& condition : this->Conditions) {
cm::optional<bool> result;
if (!condition->Evaluate(expanders, version, result)) {
out.reset();
return false;
}
if (!result) {
out.reset();
return true;
}
if (result == this->StopValue) {
out = result;
return true;
}
}
out = !this->StopValue;
return true;
}
bool cmCMakePresetsFileInternal::NotCondition::Evaluate(
const std::vector<MacroExpander>& expanders, int version,
cm::optional<bool>& out) const
{
out.reset();
if (!this->SubCondition->Evaluate(expanders, version, out)) {
out.reset();
return false;
}
if (out) {
*out = !*out;
}
return true;
}
cmCMakePresetsFile::ReadFileResult
cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
const cmCMakePresetsFile::Preset& parentPreset)
@@ -862,6 +959,10 @@ const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
return "File version must be 3 or higher for installDir preset "
"support.";
case ReadFileResult::INVALID_CONDITION:
return "Invalid preset condition";
case ReadFileResult::CONDITION_UNSUPPORTED:
return "File version must be 3 or higher for condition support";
}
return "Unknown error";
@@ -918,7 +1019,7 @@ void cmCMakePresetsFile::PrintConfigurePresetList(
for (auto const& p : this->ConfigurePresetOrder) {
auto const& preset = this->ConfigurePresets.at(p);
if (!preset.Unexpanded.Hidden && preset.Expanded &&
filter(preset.Unexpanded)) {
preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
presets.push_back(
static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
}
@@ -935,7 +1036,8 @@ void cmCMakePresetsFile::PrintBuildPresetList() const
std::vector<const cmCMakePresetsFile::Preset*> presets;
for (auto const& p : this->BuildPresetOrder) {
auto const& preset = this->BuildPresets.at(p);
if (!preset.Unexpanded.Hidden && preset.Expanded) {
if (!preset.Unexpanded.Hidden && preset.Expanded &&
preset.Expanded->ConditionResult) {
presets.push_back(
static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
}
@@ -952,7 +1054,8 @@ void cmCMakePresetsFile::PrintTestPresetList() const
std::vector<const cmCMakePresetsFile::Preset*> presets;
for (auto const& p : this->TestPresetOrder) {
auto const& preset = this->TestPresets.at(p);
if (!preset.Unexpanded.Hidden && preset.Expanded) {
if (!preset.Unexpanded.Hidden && preset.Expanded &&
preset.Expanded->ConditionResult) {
presets.push_back(
static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
}

View File

@@ -2,8 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -34,6 +37,8 @@ public:
BUILD_TEST_PRESETS_UNSUPPORTED,
INVALID_CONFIGURE_PRESET,
INSTALL_PREFIX_UNSUPPORTED,
INVALID_CONDITION,
CONDITION_UNSUPPORTED,
};
enum class ArchToolsetStrategy
@@ -49,6 +54,8 @@ public:
std::string Value;
};
class Condition;
class Preset
{
public:
@@ -71,6 +78,9 @@ public:
std::string DisplayName;
std::string Description;
std::shared_ptr<Condition> ConditionEvaluator;
bool ConditionResult = true;
std::map<std::string, cm::optional<std::string>> Environment;
virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0;

View File

@@ -1,5 +1,7 @@
/* 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) \
@@ -20,3 +22,81 @@ enum class ExpandMacroResult
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 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;
};
}

View File

@@ -6,6 +6,7 @@
#include <utility>
#include <vector>
#include <cm/memory>
#include <cm/optional>
#include <cmext/string_view>
@@ -15,6 +16,7 @@
#include "cmsys/FStream.hxx"
#include "cmCMakePresetsFile.h"
#include "cmCMakePresetsFileInternal.h"
#include "cmJSONHelpers.h"
#include "cmVersion.h"
@@ -44,6 +46,180 @@ struct RootPresets
std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
};
std::unique_ptr<cmCMakePresetsFileInternal::NotCondition> InvertCondition(
std::unique_ptr<cmCMakePresetsFile::Condition> condition)
{
auto retval = cm::make_unique<cmCMakePresetsFileInternal::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<cmCMakePresetsFileInternal::ConstCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value,
ConditionBoolHelper, true);
auto const EqualsConditionHelper =
cmJSONObjectHelper<cmCMakePresetsFileInternal::EqualsCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("lhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Lhs,
ConditionStringHelper, true)
.Bind("rhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Rhs,
ConditionStringHelper, true);
auto const InListConditionHelper =
cmJSONObjectHelper<cmCMakePresetsFileInternal::InListCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("string"_s, &cmCMakePresetsFileInternal::InListCondition::String,
ConditionStringHelper, true)
.Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List,
ConditionStringListHelper, true);
ReadFileResult SubConditionHelper(
std::unique_ptr<cmCMakePresetsFile::Condition>& out,
const Json::Value* value);
auto const ListConditionVectorHelper =
cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsFile::Condition>,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION,
SubConditionHelper);
auto const AnyAllOfConditionHelper =
cmJSONObjectHelper<cmCMakePresetsFileInternal::AnyAllOfCondition,
ReadFileResult>(ReadFileResult::READ_OK,
ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("conditions"_s,
&cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions,
ListConditionVectorHelper);
auto const NotConditionHelper =
cmJSONObjectHelper<cmCMakePresetsFileInternal::NotCondition, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
.Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
.Bind("condition"_s,
&cmCMakePresetsFileInternal::NotCondition::SubCondition,
SubConditionHelper);
ReadFileResult ConditionHelper(
std::unique_ptr<cmCMakePresetsFile::Condition>& out,
const Json::Value* value)
{
if (!value) {
out.reset();
return ReadFileResult::READ_OK;
}
if (value->isBool()) {
auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
c->Value = value->asBool();
out = std::move(c);
return ReadFileResult::READ_OK;
}
if (value->isNull()) {
out = cm::make_unique<cmCMakePresetsFileInternal::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<cmCMakePresetsFileInternal::ConstCondition>();
CHECK_OK(ConstConditionHelper(*c, value));
out = std::move(c);
return ReadFileResult::READ_OK;
}
if (type == "equals" || type == "notEquals") {
auto c = cm::make_unique<cmCMakePresetsFileInternal::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<cmCMakePresetsFileInternal::InListCondition>();
CHECK_OK(InListConditionHelper(*c, value));
out = std::move(c);
if (type == "notInList") {
out = InvertCondition(std::move(out));
}
return ReadFileResult::READ_OK;
}
if (type == "anyOf" || type == "allOf") {
auto c =
cm::make_unique<cmCMakePresetsFileInternal::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<cmCMakePresetsFileInternal::NotCondition>();
CHECK_OK(NotConditionHelper(*c, value));
out = std::move(c);
return ReadFileResult::READ_OK;
}
}
return ReadFileResult::INVALID_CONDITION;
}
ReadFileResult PresetConditionHelper(
std::shared_ptr<cmCMakePresetsFile::Condition>& out,
const Json::Value* value)
{
std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
auto result = ConditionHelper(ptr, value);
out = std::move(ptr);
return result;
}
ReadFileResult SubConditionHelper(
std::unique_ptr<cmCMakePresetsFile::Condition>& out,
const Json::Value* value)
{
std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
auto result = ConditionHelper(ptr, value);
if (ptr && ptr->IsNull()) {
return ReadFileResult::INVALID_CONDITION;
}
out = std::move(ptr);
return result;
}
cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
{
return [error](std::nullptr_t& /*out*/,
@@ -306,7 +482,9 @@ auto const ConfigurePresetHelper =
false)
.Bind("warnings"_s, PresetWarningsHelper, false)
.Bind("errors"_s, PresetErrorsHelper, false)
.Bind("debug"_s, PresetDebugHelper, false);
.Bind("debug"_s, PresetDebugHelper, false)
.Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
PresetConditionHelper, false);
auto const BuildPresetHelper =
cmJSONObjectHelper<BuildPreset, ReadFileResult>(
@@ -335,7 +513,9 @@ auto const BuildPresetHelper =
false)
.Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
.Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
PresetVectorStringHelper, false);
PresetVectorStringHelper, false)
.Bind("condition"_s, &BuildPreset::ConditionEvaluator,
PresetConditionHelper, false);
ReadFileResult TestPresetOutputVerbosityHelper(
TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
@@ -651,7 +831,9 @@ auto const TestPresetHelper =
false)
.Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
.Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
false);
false)
.Bind("condition"_s, &TestPreset::ConditionEvaluator,
PresetConditionHelper, false);
auto const ConfigurePresetsHelper =
cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
@@ -766,6 +948,11 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
}
// Support for conditions added in version 3.
if (v < 3 && preset.ConditionEvaluator) {
return ReadFileResult::CONDITION_UNSUPPORTED;
}
this->ConfigurePresetOrder.push_back(preset.Name);
}
@@ -781,6 +968,12 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
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);
}
@@ -796,6 +989,12 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
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);
}

View File

@@ -2310,6 +2310,13 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
return false;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled test preset in ",
workingDirectory, ": \"", presetName, '"'));
settingsFile.PrintTestPresetList();
return false;
}
auto configurePresetPair =
settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
if (configurePresetPair == settingsFile.ConfigurePresets.end()) {

View File

@@ -239,7 +239,7 @@ cmJSONHelper<std::vector<T>, E> cmJSONVectorFilterHelper(E success, E fail,
if (!filter(t)) {
continue;
}
out.push_back(t);
out.push_back(std::move(t));
}
return success;
};

View File

@@ -1217,6 +1217,11 @@ void cmake::SetArgs(const std::vector<std::string>& args)
"\": Invalid macro expansion"));
return;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Could not use disabled preset \"",
preset->second.Unexpanded.Name, "\""));
return;
}
if (!this->State->IsCacheLoaded() && !haveBArg) {
this->SetHomeOutputDirectory(expandedPreset->BinaryDir);
@@ -3164,6 +3169,14 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
return 1;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled build preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
settingsFile.PrintBuildPresetList();
return 1;
}
auto configurePresetPair =
settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
if (configurePresetPair == settingsFile.ConfigurePresets.end()) {

View File

@@ -0,0 +1 @@
1

View File

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

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"configurePresets": [
{
"name": "ConditionFuture",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"condition": true
}
]
}

View File

@@ -0,0 +1,349 @@
{
"version": 3,
"configurePresets": [
{
"name": "Base",
"hidden": true,
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build"
},
{
"name": "SimpleTrue",
"inherits": "Base",
"condition": true
},
{
"name": "SimpleFalse",
"inherits": "Base",
"condition": false
},
{
"name": "Null",
"inherits": "Base",
"condition": null
},
{
"name": "ConstTrue",
"inherits": "Base",
"condition": {
"type": "const",
"value": true
}
},
{
"name": "ConstFalse",
"inherits": "Base",
"condition": {
"type": "const",
"value": false
}
},
{
"name": "EqualsTrue",
"inherits": "Base",
"condition": {
"type": "equals",
"lhs": "abc",
"rhs": "abc"
}
},
{
"name": "EqualsFalse",
"inherits": "Base",
"condition": {
"type": "equals",
"lhs": "abc",
"rhs": "abcd"
}
},
{
"name": "EqualsMacroLeft",
"inherits": "Base",
"condition": {
"type": "equals",
"lhs": "${presetName}",
"rhs": "EqualsMacroLeft"
}
},
{
"name": "EqualsMacroRight",
"inherits": "Base",
"condition": {
"type": "equals",
"lhs": "EqualsMacroRight",
"rhs": "${presetName}"
}
},
{
"name": "NotEqualsTrue",
"inherits": "Base",
"condition": {
"type": "notEquals",
"lhs": "abc",
"rhs": "abcd"
}
},
{
"name": "NotEqualsFalse",
"inherits": "Base",
"condition": {
"type": "notEquals",
"lhs": "abc",
"rhs": "abc"
}
},
{
"name": "InListTrue",
"inherits": "Base",
"condition": {
"type": "inList",
"string": "b",
"list": [
"a",
"b",
"c"
]
}
},
{
"name": "InListFalse",
"inherits": "Base",
"condition": {
"type": "inList",
"string": "d",
"list": [
"a",
"b",
"c"
]
}
},
{
"name": "InListMacroString",
"inherits": "Base",
"condition": {
"type": "inList",
"string": "${presetName}",
"list": [
"InListMacroString",
"AnotherString"
]
}
},
{
"name": "InListMacroList",
"inherits": "Base",
"condition": {
"type": "inList",
"string": "InListMacroList",
"list": [
"${presetName}",
"AnotherString"
]
}
},
{
"name": "InListShortCircuit",
"inherits": "Base",
"condition": {
"type": "inList",
"string": "a",
"list": [
"a",
"${invalidMacro}"
]
}
},
{
"name": "NotInListTrue",
"inherits": "Base",
"condition": {
"type": "notInList",
"string": "d",
"list": [
"a",
"b",
"c"
]
}
},
{
"name": "NotInListFalse",
"inherits": "Base",
"condition": {
"type": "notInList",
"string": "a",
"list": [
"a",
"b",
"c"
]
}
},
{
"name": "AnyOfTrue1",
"inherits": "Base",
"condition": {
"type": "anyOf",
"conditions": [
true,
false
]
}
},
{
"name": "AnyOfTrue2",
"inherits": "Base",
"condition": {
"type": "anyOf",
"conditions": [
false,
true
]
}
},
{
"name": "AnyOfFalse",
"inherits": "Base",
"condition": {
"type": "anyOf",
"conditions": [
false,
{
"type": "equals",
"lhs": "abc",
"rhs": "abcd"
}
]
}
},
{
"name": "AnyOfShortCircuit",
"inherits": "Base",
"condition": {
"type": "anyOf",
"conditions": [
true,
{
"type": "equals",
"lhs": "${invalidMacro}",
"rhs": ""
}
]
}
},
{
"name": "AnyOfEmpty",
"inherits": "Base",
"condition": {
"type": "anyOf",
"conditions": []
}
},
{
"name": "AllOfTrue",
"inherits": "Base",
"condition": {
"type": "allOf",
"conditions": [
true,
{
"type": "equals",
"lhs": "abc",
"rhs": "abc"
}
]
}
},
{
"name": "AllOfFalse1",
"inherits": "Base",
"condition": {
"type": "allOf",
"conditions": [
false,
true
]
}
},
{
"name": "AllOfFalse2",
"inherits": "Base",
"condition": {
"type": "allOf",
"conditions": [
true,
false
]
}
},
{
"name": "AllOfShortCircuit",
"inherits": "Base",
"condition": {
"type": "allOf",
"conditions": [
false,
{
"type": "equals",
"lhs": "${invalidMacro}",
"rhs": ""
}
]
}
},
{
"name": "AllOfEmpty",
"inherits": "Base",
"condition": {
"type": "allOf",
"conditions": []
}
},
{
"name": "NotTrue",
"inherits": "Base",
"condition": {
"type": "not",
"condition": true
}
},
{
"name": "NotFalse",
"inherits": "Base",
"condition": {
"type": "not",
"condition": false
}
},
{
"name": "InheritanceBase",
"inherits": "Base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${presetName}",
"rhs": "InheritanceChildTrue"
}
},
{
"name": "InheritanceChildTrue",
"inherits": "InheritanceBase"
},
{
"name": "InheritanceChildFalse",
"inherits": "InheritanceBase"
},
{
"name": "InheritanceNull",
"inherits": "Null"
},
{
"name": "InheritanceNullFalse",
"inherits": [
"Null",
"SimpleFalse"
]
}
]
}

View File

@@ -0,0 +1,22 @@
Available configure presets:
"SimpleTrue"
"Null"
"ConstTrue"
"EqualsTrue"
"EqualsMacroLeft"
"EqualsMacroRight"
"NotEqualsTrue"
"InListTrue"
"InListMacroString"
"InListMacroList"
"InListShortCircuit"
"NotInListTrue"
"AnyOfTrue1"
"AnyOfTrue2"
"AnyOfShortCircuit"
"AllOfTrue"
"AllOfEmpty"
"NotFalse"
"InheritanceChildTrue"
"InheritanceNull"$

View File

@@ -118,6 +118,8 @@ run_cmake_presets(EnvCycle)
run_cmake_presets(EmptyEnv)
run_cmake_presets(EmptyPenv)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_presets(ConditionFuture)
run_cmake_presets(SubConditionNull)
# Test cmakeMinimumRequired field
run_cmake_presets(MinimumRequiredInvalid)
@@ -267,6 +269,12 @@ run_cmake_presets(HostSystemName)
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/HostSystemNameFuture.json.in")
run_cmake_presets(HostSystemNameFuture)
# Test conditions
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Conditions.json.in")
run_cmake_presets(ListConditions --list-presets)
run_cmake_presets(SimpleTrue)
run_cmake_presets(SimpleFalse)
# 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

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1 @@
^CMake Error: Could not use disabled preset "SimpleFalse"$

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/SubConditionNull: Invalid preset condition$

View File

@@ -0,0 +1,14 @@
{
"version": 3,
"configurePresets": [
{
"name": "SubConditionNull",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"condition": {
"type": "not",
"condition": null
}
}
]
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Cannot use disabled build preset in [^
]*/Tests/RunCMake/CMakePresetsBuild/Condition: "disabled"$

View File

@@ -0,0 +1,22 @@
{
"version": 3,
"configurePresets": [
{
"name": "default",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build"
}
],
"buildPresets": [
{
"name": "enabled",
"configurePreset": "default",
"condition": true
},
{
"name": "disabled",
"configurePreset": "default",
"condition": false
}
]
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsBuild/ConditionFuture: File version must be 3 or higher for condition support$

View File

@@ -0,0 +1,17 @@
{
"version": 2,
"configurePresets": [
{
"name": "default",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build"
}
],
"buildPresets": [
{
"name": "conditionFuture",
"configurePreset": "default",
"condition": true
}
]
}

View File

@@ -1,5 +1,6 @@
Available build presets:
^Available build presets:
"build-default" - build-default displayName
"empty"
"display" - display displayName
"true"$

View File

@@ -1,5 +1,5 @@
{
"version": 2,
"version": 3,
"configurePresets": [
{
"name": "default",
@@ -26,6 +26,16 @@
{
"name": "hidden",
"hidden": true
},
{
"name": "true",
"inherits": "build-default",
"condition": true
},
{
"name": "false",
"inherits": "build-default",
"condition": false
}
]
}

View File

@@ -64,6 +64,7 @@ set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject")
run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
run_cmake_build_presets(Condition "default" "enabled;disabled")
set(CMakePresetsBuild_BUILD_ONLY 1)
run_cmake_build_presets(ListPresets "x" "x" "--list-presets")
@@ -72,5 +73,6 @@ run_cmake_build_presets(Invalid "x" "hidden;vendorMacro")
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_build_presets(PresetsUnsupported "x" "x")
run_cmake_build_presets(ConditionFuture "x" "conditionFuture")
set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
set(CMakePresetsBuild_BUILD_ONLY 0)

View File

@@ -0,0 +1,22 @@
{
"version": 3,
"configurePresets": [
{
"name": "default",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build"
}
],
"testPresets": [
{
"name": "enabled",
"configurePreset": "default",
"condition": true
},
{
"name": "disabled",
"configurePreset": "default",
"condition": false
}
]
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsTest/ConditionFuture: File version must be 3 or higher for condition support$

View File

@@ -0,0 +1,17 @@
{
"version": 2,
"configurePresets": [
{
"name": "default",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build"
}
],
"testPresets": [
{
"name": "conditionFuture",
"configurePreset": "default",
"condition": true
}
]
}

View File

@@ -0,0 +1,3 @@
^Available test presets:
"enabled"$

View File

@@ -0,0 +1,2 @@
^CMake Error: Cannot use disabled test preset in [^
]*/Tests/RunCMake/CMakePresetsTest/ConditionRunTests: "disabled"$

View File

@@ -0,0 +1,2 @@
enable_testing()
add_test(true ${CMAKE_COMMAND} -E true)

View File

@@ -90,6 +90,12 @@ run_cmake_test_presets(InvalidConfigurePreset "default" "" "badConfigurePreset")
set(CMakePresetsTest_NO_CONFIGURE 1)
set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Good.json.in")
run_cmake_test_presets(ListPresets "" "" "x" "--list-presets")
set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Condition.json.in")
run_cmake_test_presets(ConditionListPresets "" "" "x" "--list-presets")
unset(CMakePresetsTest_NO_CONFIGURE)
run_cmake_test_presets(ConditionRunTests "default" "" "enabled;disabled")
set(CMakePresetsTest_NO_CONFIGURE 1)
unset(CMakePresetsTest_FILE)
run_cmake_test_presets(NoConfigurePreset "" "" "noConfigurePreset")
@@ -98,6 +104,7 @@ run_cmake_test_presets(Invalid "" "" "hidden;vendorMacro")
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_test_presets(PresetsUnsupported "" "" "x")
run_cmake_test_presets(ConditionFuture "" "" "x")
set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
set(CMakePresetsTest_NO_CONFIGURE 0)

View File

@@ -96,6 +96,7 @@
{ symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1> > >::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<60, 1> > >::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1000> > >::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "__gnu_cxx::__enable_if<true, bool>::__type", private, "\"cmConfigure.h\"", public ] },
# Wrappers for 3rd-party libraries
{ include: [ "@<.*curl/curlver.h>", private, "<cm3p/curl/curl.h>", public ] },