From 8bc5c8961e552a15091b7f4d2c205ce90b8f764f Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 10 Mar 2021 14:59:14 -0500 Subject: CMakePresets.json: Add the ability to conditionally disable presets --- Help/manual/cmake-presets.7.rst | 96 ++++++ Help/manual/presets/example.json | 13 +- Help/manual/presets/schema.json | 356 ++++++++++++++++++++- Help/release/dev/cmake-presets-condition.rst | 4 + Source/QtDialog/QCMake.cxx | 2 +- Source/cmCMakePresetsFile.cxx | 109 ++++++- Source/cmCMakePresetsFile.h | 10 + Source/cmCMakePresetsFileInternal.h | 80 +++++ Source/cmCMakePresetsFileReadJSON.cxx | 205 +++++++++++- Source/cmCTest.cxx | 7 + Source/cmJSONHelpers.h | 2 +- Source/cmake.cxx | 13 + .../CMakePresets/ConditionFuture-result.txt | 1 + .../CMakePresets/ConditionFuture-stderr.txt | 2 + .../RunCMake/CMakePresets/ConditionFuture.json.in | 11 + Tests/RunCMake/CMakePresets/Conditions.json.in | 349 ++++++++++++++++++++ .../CMakePresets/ListConditions-stdout.txt | 22 ++ Tests/RunCMake/CMakePresets/RunCMakeTest.cmake | 8 + Tests/RunCMake/CMakePresets/SimpleFalse-result.txt | 1 + Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt | 1 + Tests/RunCMake/CMakePresets/SimpleTrue.cmake | 0 .../CMakePresets/SubConditionNull-result.txt | 1 + .../CMakePresets/SubConditionNull-stderr.txt | 2 + .../RunCMake/CMakePresets/SubConditionNull.json.in | 14 + .../Condition-build-disabled-result.txt | 1 + .../Condition-build-disabled-stderr.txt | 2 + Tests/RunCMake/CMakePresetsBuild/Condition.cmake | 0 Tests/RunCMake/CMakePresetsBuild/Condition.json.in | 22 ++ ...onditionFuture-build-conditionFuture-result.txt | 1 + ...onditionFuture-build-conditionFuture-stderr.txt | 2 + .../CMakePresetsBuild/ConditionFuture.json.in | 17 + .../ListPresets-build-x-stdout.txt | 3 +- .../RunCMake/CMakePresetsBuild/ListPresets.json.in | 12 +- .../RunCMake/CMakePresetsBuild/RunCMakeTest.cmake | 2 + Tests/RunCMake/CMakePresetsTest/Condition.json.in | 22 ++ .../ConditionFuture-test-x-result.txt | 1 + .../ConditionFuture-test-x-stderr.txt | 2 + .../CMakePresetsTest/ConditionFuture.json.in | 17 + .../ConditionListPresets-test-x-stdout.txt | 3 + .../ConditionRunTests-test-disabled-result.txt | 1 + .../ConditionRunTests-test-disabled-stderr.txt | 2 + .../CMakePresetsTest/ConditionRunTests.cmake | 2 + Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake | 7 + Utilities/IWYU/mapping.imp | 1 + 44 files changed, 1410 insertions(+), 19 deletions(-) create mode 100644 Help/release/dev/cmake-presets-condition.rst create mode 100644 Tests/RunCMake/CMakePresets/ConditionFuture-result.txt create mode 100644 Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/ConditionFuture.json.in create mode 100644 Tests/RunCMake/CMakePresets/Conditions.json.in create mode 100644 Tests/RunCMake/CMakePresets/ListConditions-stdout.txt create mode 100644 Tests/RunCMake/CMakePresets/SimpleFalse-result.txt create mode 100644 Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/SimpleTrue.cmake create mode 100644 Tests/RunCMake/CMakePresets/SubConditionNull-result.txt create mode 100644 Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/SubConditionNull.json.in create mode 100644 Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt create mode 100644 Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsBuild/Condition.cmake create mode 100644 Tests/RunCMake/CMakePresetsBuild/Condition.json.in create mode 100644 Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt create mode 100644 Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in create mode 100644 Tests/RunCMake/CMakePresetsTest/Condition.json.in create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst index 5273236..cc72603 100644 --- a/Help/manual/cmake-presets.7.rst +++ b/Help/manual/cmake-presets.7.rst @@ -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 ^^^^^^^^^^^^^^^ diff --git a/Help/manual/presets/example.json b/Help/manual/presets/example.json index dfc2910..346f342 100644 --- a/Help/manual/presets/example.json +++ b/Help/manual/presets/example.json @@ -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": [ diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json index a5025bb..dbcead5 100644 --- a/Help/manual/presets/schema.json +++ b/Help/manual/presets/schema.json @@ -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": { @@ -515,11 +527,84 @@ }, "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": { @@ -831,9 +916,264 @@ }, "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." + } + ] } } } diff --git a/Help/release/dev/cmake-presets-condition.rst b/Help/release/dev/cmake-presets-condition.rst new file mode 100644 index 0000000..aa01bc1 --- /dev/null +++ b/Help/release/dev/cmake-presets-condition.rst @@ -0,0 +1,4 @@ +cmake-presets-condition +----------------------- + +* :manual:`cmake-presets(7)` now support conditional enabling of presets. diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index f593f83..7d037e3 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -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) { diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsFile.cxx index c0b0981..fbe9fe5 100644 --- a/Source/cmCMakePresetsFile.cxx +++ b/Source/cmCMakePresetsFile.cxx @@ -9,6 +9,8 @@ #include #include +#include + #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 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& expanders, int version, + cm::optional& 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& expanders, int version, + cm::optional& 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& expanders, int version, + cm::optional& out) const +{ + for (auto const& condition : this->Conditions) { + cm::optional 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& expanders, int version, + cm::optional& 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(&preset.Unexpanded)); } @@ -935,7 +1036,8 @@ void cmCMakePresetsFile::PrintBuildPresetList() const std::vector 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(&preset.Unexpanded)); } @@ -952,7 +1054,8 @@ void cmCMakePresetsFile::PrintTestPresetList() const std::vector 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(&preset.Unexpanded)); } diff --git a/Source/cmCMakePresetsFile.h b/Source/cmCMakePresetsFile.h index 02e6a32..0999d5a 100644 --- a/Source/cmCMakePresetsFile.h +++ b/Source/cmCMakePresetsFile.h @@ -2,8 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include "cmConfigure.h" // IWYU pragma: keep + #include #include +#include #include #include #include @@ -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 ConditionEvaluator; + bool ConditionResult = true; + std::map> Environment; virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0; diff --git a/Source/cmCMakePresetsFileInternal.h b/Source/cmCMakePresetsFileInternal.h index f05b8ce..ffb6ce9 100644 --- a/Source/cmCMakePresetsFileInternal.h +++ b/Source/cmCMakePresetsFileInternal.h @@ -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 + #include "cmCMakePresetsFile.h" #define CHECK_OK(expr) \ @@ -20,3 +22,81 @@ enum class ExpandMacroResult using MacroExpander = std::function; } + +class cmCMakePresetsFile::Condition +{ +public: + virtual ~Condition() = default; + + virtual bool Evaluate( + const std::vector& expanders, + int version, cm::optional& out) const = 0; + virtual bool IsNull() const { return false; } +}; + +namespace cmCMakePresetsFileInternal { + +class NullCondition : public cmCMakePresetsFile::Condition +{ + bool Evaluate(const std::vector& /*expanders*/, + int /*version*/, cm::optional& out) const override + { + out = true; + return true; + } + + bool IsNull() const override { return true; } +}; + +class ConstCondition : public cmCMakePresetsFile::Condition +{ +public: + bool Evaluate(const std::vector& /*expanders*/, + int /*version*/, cm::optional& out) const override + { + out = this->Value; + return true; + } + + bool Value; +}; + +class EqualsCondition : public cmCMakePresetsFile::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::string Lhs; + std::string Rhs; +}; + +class InListCondition : public cmCMakePresetsFile::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::string String; + std::vector List; +}; + +class AnyAllOfCondition : public cmCMakePresetsFile::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::vector> Conditions; + bool StopValue; +}; + +class NotCondition : public cmCMakePresetsFile::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::unique_ptr SubCondition; +}; +} diff --git a/Source/cmCMakePresetsFileReadJSON.cxx b/Source/cmCMakePresetsFileReadJSON.cxx index b71b176..e26e7b4 100644 --- a/Source/cmCMakePresetsFileReadJSON.cxx +++ b/Source/cmCMakePresetsFileReadJSON.cxx @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -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 TestPresets; }; +std::unique_ptr InvertCondition( + std::unique_ptr condition) +{ + auto retval = cm::make_unique(); + retval->SubCondition = std::move(condition); + return retval; +} + +auto const ConditionStringHelper = cmJSONStringHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); + +auto const ConditionBoolHelper = cmJSONBoolHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); + +auto const ConditionStringListHelper = + cmJSONVectorHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, + ConditionStringHelper); + +auto const ConstConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value, + ConditionBoolHelper, true); + +auto const EqualsConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("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(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("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& out, + const Json::Value* value); + +auto const ListConditionVectorHelper = + cmJSONVectorHelper, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, + SubConditionHelper); +auto const AnyAllOfConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("conditions"_s, + &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions, + ListConditionVectorHelper); + +auto const NotConditionHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("condition"_s, + &cmCMakePresetsFileInternal::NotCondition::SubCondition, + SubConditionHelper); + +ReadFileResult ConditionHelper( + std::unique_ptr& out, + const Json::Value* value) +{ + if (!value) { + out.reset(); + return ReadFileResult::READ_OK; + } + + if (value->isBool()) { + auto c = cm::make_unique(); + c->Value = value->asBool(); + out = std::move(c); + return ReadFileResult::READ_OK; + } + + if (value->isNull()) { + out = cm::make_unique(); + 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(); + CHECK_OK(ConstConditionHelper(*c, value)); + out = std::move(c); + return ReadFileResult::READ_OK; + } + + if (type == "equals" || type == "notEquals") { + auto c = cm::make_unique(); + 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(); + 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(); + 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(); + CHECK_OK(NotConditionHelper(*c, value)); + out = std::move(c); + return ReadFileResult::READ_OK; + } + } + + return ReadFileResult::INVALID_CONDITION; +} + +ReadFileResult PresetConditionHelper( + std::shared_ptr& out, + const Json::Value* value) +{ + std::unique_ptr ptr; + auto result = ConditionHelper(ptr, value); + out = std::move(ptr); + return result; +} + +ReadFileResult SubConditionHelper( + std::unique_ptr& out, + const Json::Value* value) +{ + std::unique_ptr ptr; + auto result = ConditionHelper(ptr, value); + if (ptr && ptr->IsNull()) { + return ReadFileResult::INVALID_CONDITION; + } + out = std::move(ptr); + return result; +} + cmJSONHelper 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( @@ -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( @@ -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); } diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 77b4441..4228d30 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -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()) { diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h index a63347d..6690aef 100644 --- a/Source/cmJSONHelpers.h +++ b/Source/cmJSONHelpers.h @@ -239,7 +239,7 @@ cmJSONHelper, E> cmJSONVectorFilterHelper(E success, E fail, if (!filter(t)) { continue; } - out.push_back(t); + out.push_back(std::move(t)); } return success; }; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index b12eeee..61ce154 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1217,6 +1217,11 @@ void cmake::SetArgs(const std::vector& 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 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()) { diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt b/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt b/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt new file mode 100644 index 0000000..ea5f47f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt @@ -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$ diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture.json.in b/Tests/RunCMake/CMakePresets/ConditionFuture.json.in new file mode 100644 index 0000000..9d4798b --- /dev/null +++ b/Tests/RunCMake/CMakePresets/ConditionFuture.json.in @@ -0,0 +1,11 @@ +{ + "version": 2, + "configurePresets": [ + { + "name": "ConditionFuture", + "generator": "@RunCMake_GENERATOR@", + "binaryDir": "${sourceDir}/build", + "condition": true + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/Conditions.json.in b/Tests/RunCMake/CMakePresets/Conditions.json.in new file mode 100644 index 0000000..9a01e2f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/Conditions.json.in @@ -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" + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt b/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt new file mode 100644 index 0000000..19f91d4 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt @@ -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"$ diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake index 24ac0e9..22425b2 100644 --- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake @@ -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}") diff --git a/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt b/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt b/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt new file mode 100644 index 0000000..6a9a7de --- /dev/null +++ b/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Could not use disabled preset "SimpleFalse"$ diff --git a/Tests/RunCMake/CMakePresets/SimpleTrue.cmake b/Tests/RunCMake/CMakePresets/SimpleTrue.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt b/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt b/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt new file mode 100644 index 0000000..42b74d6 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/SubConditionNull: Invalid preset condition$ diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull.json.in b/Tests/RunCMake/CMakePresets/SubConditionNull.json.in new file mode 100644 index 0000000..eed3da6 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/SubConditionNull.json.in @@ -0,0 +1,14 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "SubConditionNull", + "generator": "@RunCMake_GENERATOR@", + "binaryDir": "${sourceDir}/build", + "condition": { + "type": "not", + "condition": null + } + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt new file mode 100644 index 0000000..c35f5d7 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Cannot use disabled build preset in [^ +]*/Tests/RunCMake/CMakePresetsBuild/Condition: "disabled"$ diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition.cmake b/Tests/RunCMake/CMakePresetsBuild/Condition.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition.json.in b/Tests/RunCMake/CMakePresetsBuild/Condition.json.in new file mode 100644 index 0000000..aaee96a --- /dev/null +++ b/Tests/RunCMake/CMakePresetsBuild/Condition.json.in @@ -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 + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt new file mode 100644 index 0000000..f08f4c1 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt @@ -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$ diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in new file mode 100644 index 0000000..2f3f7d8 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in @@ -0,0 +1,17 @@ +{ + "version": 2, + "configurePresets": [ + { + "name": "default", + "generator": "@RunCMake_GENERATOR@", + "binaryDir": "${sourceDir}/build" + } + ], + "buildPresets": [ + { + "name": "conditionFuture", + "configurePreset": "default", + "condition": true + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt index 4d30707..2d362d4 100644 --- a/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt +++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt @@ -1,5 +1,6 @@ -Available build presets: +^Available build presets: "build-default" - build-default displayName "empty" "display" - display displayName + "true"$ diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in index 3f5e02c..26504d3 100644 --- a/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in +++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in @@ -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 } ] } diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake index 2559b12..afa22eb 100644 --- a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake @@ -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) diff --git a/Tests/RunCMake/CMakePresetsTest/Condition.json.in b/Tests/RunCMake/CMakePresetsTest/Condition.json.in new file mode 100644 index 0000000..0baf176 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/Condition.json.in @@ -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 + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt new file mode 100644 index 0000000..b814bbb --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt @@ -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$ diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in b/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in new file mode 100644 index 0000000..4b9f33f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in @@ -0,0 +1,17 @@ +{ + "version": 2, + "configurePresets": [ + { + "name": "default", + "generator": "@RunCMake_GENERATOR@", + "binaryDir": "${sourceDir}/build" + } + ], + "testPresets": [ + { + "name": "conditionFuture", + "configurePreset": "default", + "condition": true + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt new file mode 100644 index 0000000..11918e5 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt @@ -0,0 +1,3 @@ +^Available test presets: + + "enabled"$ diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt new file mode 100644 index 0000000..5db3b77 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Cannot use disabled test preset in [^ +]*/Tests/RunCMake/CMakePresetsTest/ConditionRunTests: "disabled"$ diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake new file mode 100644 index 0000000..b29161e --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake @@ -0,0 +1,2 @@ +enable_testing() +add_test(true ${CMAKE_COMMAND} -E true) diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake index c93dff3..70d25d4 100644 --- a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake @@ -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) diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp index c2aced5..f2aef3e 100644 --- a/Utilities/IWYU/mapping.imp +++ b/Utilities/IWYU/mapping.imp @@ -96,6 +96,7 @@ { symbol: [ "std::enable_if > >::type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::enable_if > >::type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::enable_if > >::type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "__gnu_cxx::__enable_if::__type", private, "\"cmConfigure.h\"", public ] }, # Wrappers for 3rd-party libraries { include: [ "@<.*curl/curlver.h>", private, "", public ] }, -- cgit v0.12