Diagnostics: Use categories for presets

Modify diagnostics to track which preset schema version corresponds to
the introduction of each diagnostic. Modify how we parse presets to use
the set of diagnostics to generate bindings, and to store diagnostics as
maps rather than as fixed members. Enforce that only diagnostics known
to the specified preset version are present.

This is a first and necessary step toward moving CMake's internals over
to flexible categories rather than each category having its own bespoke
variables and member functions.

Note that the presets documentation currently contains some broken
links, as it is anticipating further documentation updates that will
happen in a future commit.
This commit is contained in:
Matthew Woehlke
2026-04-02 13:07:28 -04:00
parent 95a07e2fc6
commit 618c074a8c
38 changed files with 798 additions and 124 deletions

View File

@@ -69,3 +69,20 @@ to the project's developer(s).
Warn about use of a deprecated function or package. This is the category
triggered by :command:`message(DEPRECATION)`.
``CMD_UNINITIALIZED`` (``-Wuninitialized``)
-------------------------------------------
:Default: Ignore
Warn if an uninitialized variable is dereferenced.
``CMD_UNUSED_CLI`` (``-Wunused-cli``)
-------------------------------------
:Default: Warn
Warn about variables that are declared on the command line, but not used.
Although the action of this warning category can be queried as usual, changes
made using the :command:`cmake_diagnostic` command have no effect.

View File

@@ -465,6 +465,15 @@ they were added and a summary of the new features and changes is given below.
``12``
.. versionadded:: 4.4
* Changes to `Configure Presets <Configure Preset_>`_:
* The ``dev`` field is renamed to ``author`` in
:preset:`configurePresets.warnings` and
:preset:`configurePresets.errors`.
* The ``uninitialized`` and ``unusedCli`` fields were added to
:preset:`configurePresets.errors`.
* Changes to `Macro Expansion`_
* The `${fileDir} <CMakePresets fileDir_>`_ macro now always expands to

View File

@@ -1,6 +1,18 @@
.. This file was generated by Utilities/Scripts/regenerate-presets.py
from Help/manual/presets/schema.yaml. Do not edit.
.. _`CMakePresets.configurePresets.errors.author`:
``author``
.. presets-versionadded:: 12
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=author` or
:cmake-option:`-Wno-error=author`
on the command line.
This may not be set to ``true``
if ``warnings.author`` is set to ``false``.
.. _`CMakePresets.configurePresets.errors.deprecated`:
``deprecated``
@@ -14,9 +26,35 @@
.. _`CMakePresets.configurePresets.errors.dev`:
``dev``
.. presets-versionremoved:: 12
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=dev` or
:cmake-option:`-Wno-error=dev`
on the command line.
This may not be set to ``true``
if ``warnings.dev`` is set to ``false``.
.. _`CMakePresets.configurePresets.errors.uninitialized`:
``uninitialized``
.. presets-versionadded:: 12
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=uninitialized` or
:cmake-option:`-Wno-error=uninitialized`
on the command line.
This may not be set to ``true``
if ``warnings.uninitialized`` is set to ``false``.
.. _`CMakePresets.configurePresets.errors.unusedCli`:
``unusedCli``
.. presets-versionadded:: 12
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=unused-cli` or
:cmake-option:`-Wno-error=unused-cli`
on the command line.
This may not be set to ``true``
if ``warnings.unusedCli`` is set to ``false``.

View File

@@ -326,7 +326,7 @@
"$ref": "#/definitions/vendor@v1.."
},
"configurePresets": {
"$ref": "#/definitions/configurePresets@v10.."
"$ref": "#/definitions/configurePresets@v10..v11"
},
"buildPresets": {
"$ref": "#/definitions/buildPresets@v10.."
@@ -370,7 +370,7 @@
"$ref": "#/definitions/vendor@v1.."
},
"configurePresets": {
"$ref": "#/definitions/configurePresets@v10.."
"$ref": "#/definitions/configurePresets@v10..v11"
},
"buildPresets": {
"$ref": "#/definitions/buildPresets@v10.."
@@ -414,7 +414,7 @@
"$ref": "#/definitions/vendor@v1.."
},
"configurePresets": {
"$ref": "#/definitions/configurePresets@v10.."
"$ref": "#/definitions/configurePresets@v12"
},
"buildPresets": {
"$ref": "#/definitions/buildPresets@v10.."
@@ -733,7 +733,7 @@
]
}
},
"configurePresets@v10..": {
"configurePresets@v10..v11": {
"type": "array",
"description": "An optional array of configure preset objects.",
"items": {
@@ -793,10 +793,90 @@
"$ref": "#/definitions/configurePresets.environment@v1.."
},
"warnings": {
"$ref": "#/definitions/configurePresets.warnings@v10.."
"$ref": "#/definitions/configurePresets.warnings@v10..v11"
},
"errors": {
"$ref": "#/definitions/configurePresets.errors@v10.."
"$ref": "#/definitions/configurePresets.errors@v10..v11"
},
"debug": {
"$ref": "#/definitions/configurePresets.debug@v10.."
},
"trace": {
"$ref": "#/definitions/configurePresets.trace@v10.."
},
"$comment": {
"$ref": "#/definitions/$comment@v10.."
}
},
"required": [
"name"
]
}
},
"configurePresets@v12": {
"type": "array",
"description": "An optional array of configure preset objects.",
"items": {
"type": "object",
"description": "A configure preset object.",
"unevaluatedProperties": false,
"properties": {
"name": {
"$ref": "#/definitions/configurePresets.name@v1.."
},
"hidden": {
"$ref": "#/definitions/configurePresets.hidden@v1.."
},
"inherits": {
"$ref": "#/definitions/configurePresets.inherits@v1.."
},
"condition": {
"$ref": "#/definitions/configurePresets.condition@v10.."
},
"vendor": {
"$ref": "#/definitions/configurePresets.vendor@v1.."
},
"displayName": {
"$ref": "#/definitions/configurePresets.displayName@v1.."
},
"description": {
"$ref": "#/definitions/configurePresets.description@v1.."
},
"generator": {
"$ref": "#/definitions/configurePresets.generator@v3.."
},
"architecture": {
"$ref": "#/definitions/configurePresets.architecture@v10.."
},
"toolset": {
"$ref": "#/definitions/configurePresets.toolset@v10.."
},
"toolchainFile": {
"$ref": "#/definitions/configurePresets.toolchainFile@v3.."
},
"graphviz": {
"$ref": "#/definitions/configurePresets.graphviz@v10.."
},
"binaryDir": {
"$ref": "#/definitions/configurePresets.binaryDir@v3.."
},
"installDir": {
"$ref": "#/definitions/configurePresets.installDir@v3.."
},
"cmakeExecutable": {
"$ref": "#/definitions/configurePresets.cmakeExecutable@v1.."
},
"cacheVariables": {
"$ref": "#/definitions/configurePresets.cacheVariables@v10.."
},
"environment": {
"$ref": "#/definitions/configurePresets.environment@v1.."
},
"warnings": {
"$ref": "#/definitions/configurePresets.warnings@v12"
},
"errors": {
"$ref": "#/definitions/configurePresets.errors@v12"
},
"debug": {
"$ref": "#/definitions/configurePresets.debug@v10.."
@@ -1157,7 +1237,7 @@
"$ref": "#/definitions/configurePresets.warnings.deprecated@v1.."
},
"dev": {
"$ref": "#/definitions/configurePresets.warnings.dev@v1.."
"$ref": "#/definitions/configurePresets.warnings.dev@v1..v11"
},
"uninitialized": {
"$ref": "#/definitions/configurePresets.warnings.uninitialized@v1.."
@@ -1170,7 +1250,7 @@
}
}
},
"configurePresets.warnings@v10..": {
"configurePresets.warnings@v10..v11": {
"type": "object",
"description": "An optional object specifying the warnings to enable.",
"unevaluatedProperties": false,
@@ -1179,7 +1259,7 @@
"$ref": "#/definitions/configurePresets.warnings.deprecated@v1.."
},
"dev": {
"$ref": "#/definitions/configurePresets.warnings.dev@v1.."
"$ref": "#/definitions/configurePresets.warnings.dev@v1..v11"
},
"uninitialized": {
"$ref": "#/definitions/configurePresets.warnings.uninitialized@v1.."
@@ -1195,21 +1275,50 @@
}
}
},
"configurePresets.warnings@v12": {
"type": "object",
"description": "An optional object specifying the warnings to enable.",
"unevaluatedProperties": false,
"properties": {
"author": {
"$ref": "#/definitions/configurePresets.warnings.author@v12"
},
"deprecated": {
"$ref": "#/definitions/configurePresets.warnings.deprecated@v1.."
},
"uninitialized": {
"$ref": "#/definitions/configurePresets.warnings.uninitialized@v1.."
},
"unusedCli": {
"$ref": "#/definitions/configurePresets.warnings.unusedCli@v1.."
},
"systemVars": {
"$ref": "#/definitions/configurePresets.warnings.systemVars@v1.."
},
"$comment": {
"$ref": "#/definitions/$comment@v10.."
}
}
},
"configurePresets.warnings.author@v12": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Wauthor or -Wno-author on the command line. This may not be set to false if errors.author is set to true."
},
"configurePresets.warnings.deprecated@v1..": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Wdeprecated or -Wno-deprecated on the command line. This may not be set to false if errors.deprecated is set to true."
},
"configurePresets.warnings.dev@v1..": {
"configurePresets.warnings.dev@v1..v11": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Wdev or -Wno-dev on the command line. This may not be set to false if errors.dev is set to true."
},
"configurePresets.warnings.uninitialized@v1..": {
"type": "boolean",
"description": "An optional boolean. Setting this to true is equivalent to passing --warn-uninitialized on the command line."
"description": "An optional boolean. Equivalent to passing -Wuninitialized or -Wno-uninitialized on the command line. This may not be set to false if errors.uninitialized is set to true."
},
"configurePresets.warnings.unusedCli@v1..": {
"type": "boolean",
"description": "An optional boolean. Setting this to false is equivalent to passing --no-warn-unused-cli on the command line."
"description": "An optional boolean. Equivalent to passing -Wunused-cli or -Wno-unused-cli on the command line. This may not be set to false if errors.unusedCli is set to true."
},
"configurePresets.warnings.systemVars@v1..": {
"type": "boolean",
@@ -1224,11 +1333,11 @@
"$ref": "#/definitions/configurePresets.errors.deprecated@v1.."
},
"dev": {
"$ref": "#/definitions/configurePresets.errors.dev@v1.."
"$ref": "#/definitions/configurePresets.errors.dev@v1..v11"
}
}
},
"configurePresets.errors@v10..": {
"configurePresets.errors@v10..v11": {
"type": "object",
"description": "An optional object specifying the errors to enable.",
"unevaluatedProperties": false,
@@ -1237,21 +1346,55 @@
"$ref": "#/definitions/configurePresets.errors.deprecated@v1.."
},
"dev": {
"$ref": "#/definitions/configurePresets.errors.dev@v1.."
"$ref": "#/definitions/configurePresets.errors.dev@v1..v11"
},
"$comment": {
"$ref": "#/definitions/$comment@v10.."
}
}
},
"configurePresets.errors@v12": {
"type": "object",
"description": "An optional object specifying the errors to enable.",
"unevaluatedProperties": false,
"properties": {
"author": {
"$ref": "#/definitions/configurePresets.errors.author@v12"
},
"deprecated": {
"$ref": "#/definitions/configurePresets.errors.deprecated@v1.."
},
"uninitialized": {
"$ref": "#/definitions/configurePresets.errors.uninitialized@v12"
},
"unusedCli": {
"$ref": "#/definitions/configurePresets.errors.unusedCli@v12"
},
"$comment": {
"$ref": "#/definitions/$comment@v10.."
}
}
},
"configurePresets.errors.author@v12": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Werror=author or -Wno-error=author on the command line. This may not be set to true if warnings.author is set to false."
},
"configurePresets.errors.deprecated@v1..": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Werror=deprecated or -Wno-error=deprecated on the command line. This may not be set to true if warnings.deprecated is set to false."
},
"configurePresets.errors.dev@v1..": {
"configurePresets.errors.dev@v1..v11": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Werror=dev or -Wno-error=dev on the command line. This may not be set to true if warnings.dev is set to false."
},
"configurePresets.errors.uninitialized@v12": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Werror=uninitialized or -Wno-error=uninitialized on the command line. This may not be set to true if warnings.uninitialized is set to false."
},
"configurePresets.errors.unusedCli@v12": {
"type": "boolean",
"description": "An optional boolean. Equivalent to passing -Werror=unused-cli or -Wno-error=unused-cli on the command line. This may not be set to true if warnings.unusedCli is set to false."
},
"configurePresets.debug@v1..v9": {
"type": "object",
"description": "An optional object specifying debug options.",

View File

@@ -658,6 +658,20 @@ properties:
.. include:: presets/warnings-properties.rst
properties:
# These should be in lexicographical order, except for systemVars.
author:
since: 12
type: boolean
description:
An optional boolean. Equivalent to passing -Wauthor or
-Wno-author on the command line. This may not be set
to false if errors.author is set to true.
sphinxDescription: |
An optional boolean. Equivalent to passing
:option:`-Wauthor <cmake -W>` or
:option:`-Wno-author <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.author`` is set to ``true``.
deprecated:
type: boolean
description:
@@ -666,12 +680,13 @@ properties:
to false if errors.deprecated is set to true.
sphinxDescription: |
An optional boolean. Equivalent to passing
:cmake-option:`-Wdeprecated` or
:cmake-option:`-Wno-deprecated`
:option:`-Wdeprecated <cmake -W>` or
:option:`-Wno-deprecated <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.deprecated`` is set to ``true``.
dev:
until: 12
type: boolean
description:
An optional boolean. Equivalent to passing -Wdev or
@@ -679,29 +694,37 @@ properties:
to false if errors.dev is set to true.
sphinxDescription: |
An optional boolean. Equivalent to passing
:cmake-option:`-Wdev` or
:cmake-option:`-Wno-dev`
:option:`-Wdev <cmake -W>` or
:option:`-Wno-dev <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.dev`` is set to ``true``.
uninitialized:
type: boolean
description:
An optional boolean. Setting this to true is equivalent to
passing --warn-uninitialized on the command line.
An optional boolean. Equivalent to passing -Wuninitialized or
-Wno-uninitialized on the command line. This may not be set
to false if errors.uninitialized is set to true.
sphinxDescription: |
An optional boolean. Setting this to ``true`` is equivalent to
passing :cmake-option:`--warn-uninitialized` on the command
line.
An optional boolean. Equivalent to passing
:option:`-Wuninitialized <cmake -W>` or
:option:`-Wno-uninitialized <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.uninitialized`` is set to ``true``.
unusedCli:
type: boolean
description:
An optional boolean. Setting this to false is equivalent to
passing --no-warn-unused-cli on the command line.
An optional boolean. Equivalent to passing -Wunused-cli or
-Wno-unused-cli on the command line. This may not be set
to false if errors.unusedCli is set to true.
sphinxDescription: |
An optional boolean. Setting this to ``false`` is equivalent to
passing :cmake-option:`--no-warn-unused-cli` on the command
line.
An optional boolean. Equivalent to passing
:option:`-Wunused-cli <cmake -W>` or
:option:`-Wno-unused-cli <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.unusedCli`` is set to ``true``.
# systemVars should be last.
systemVars:
type: boolean
@@ -724,6 +747,21 @@ properties:
.. include:: presets/errors-properties.rst
properties:
# These should be in lexicographical order.
author:
since: 12
type: boolean
description:
An optional boolean. Equivalent to passing
-Werror=author or -Wno-error=author
on the command line. This may not be set
to true if warnings.author is set to false.
sphinxDescription: |
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=author` or
:cmake-option:`-Wno-error=author`
on the command line.
This may not be set to ``true``
if ``warnings.author`` is set to ``false``.
deprecated:
type: boolean
description:
@@ -739,6 +777,7 @@ properties:
This may not be set to ``true``
if ``warnings.deprecated`` is set to ``false``.
dev:
until: 12
type: boolean
description:
An optional boolean. Equivalent to passing
@@ -752,6 +791,36 @@ properties:
on the command line.
This may not be set to ``true``
if ``warnings.dev`` is set to ``false``.
uninitialized:
since: 12
type: boolean
description:
An optional boolean. Equivalent to passing
-Werror=uninitialized or -Wno-error=uninitialized
on the command line. This may not be set
to true if warnings.uninitialized is set to false.
sphinxDescription: |
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=uninitialized` or
:cmake-option:`-Wno-error=uninitialized`
on the command line.
This may not be set to ``true``
if ``warnings.uninitialized`` is set to ``false``.
unusedCli:
since: 12
type: boolean
description:
An optional boolean. Equivalent to passing
-Werror=unused-cli or -Wno-error=unused-cli
on the command line. This may not be set
to true if warnings.unusedCli is set to false.
sphinxDescription: |
An optional boolean. Equivalent to passing
:cmake-option:`-Werror=unused-cli` or
:cmake-option:`-Wno-error=unused-cli`
on the command line.
This may not be set to ``true``
if ``warnings.unusedCli`` is set to ``false``.
unevaluatedProperties: false
debug:
type: object

View File

@@ -1,12 +1,24 @@
.. This file was generated by Utilities/Scripts/regenerate-presets.py
from Help/manual/presets/schema.yaml. Do not edit.
.. _`CMakePresets.configurePresets.warnings.author`:
``author``
.. presets-versionadded:: 12
An optional boolean. Equivalent to passing
:option:`-Wauthor <cmake -W>` or
:option:`-Wno-author <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.author`` is set to ``true``.
.. _`CMakePresets.configurePresets.warnings.deprecated`:
``deprecated``
An optional boolean. Equivalent to passing
:cmake-option:`-Wdeprecated` or
:cmake-option:`-Wno-deprecated`
:option:`-Wdeprecated <cmake -W>` or
:option:`-Wno-deprecated <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.deprecated`` is set to ``true``.
@@ -14,9 +26,11 @@
.. _`CMakePresets.configurePresets.warnings.dev`:
``dev``
.. presets-versionremoved:: 12
An optional boolean. Equivalent to passing
:cmake-option:`-Wdev` or
:cmake-option:`-Wno-dev`
:option:`-Wdev <cmake -W>` or
:option:`-Wno-dev <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.dev`` is set to ``true``.
@@ -24,16 +38,22 @@
.. _`CMakePresets.configurePresets.warnings.uninitialized`:
``uninitialized``
An optional boolean. Setting this to ``true`` is equivalent to
passing :cmake-option:`--warn-uninitialized` on the command
line.
An optional boolean. Equivalent to passing
:option:`-Wuninitialized <cmake -W>` or
:option:`-Wno-uninitialized <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.uninitialized`` is set to ``true``.
.. _`CMakePresets.configurePresets.warnings.unusedCli`:
``unusedCli``
An optional boolean. Setting this to ``false`` is equivalent to
passing :cmake-option:`--no-warn-unused-cli` on the command
line.
An optional boolean. Equivalent to passing
:option:`-Wunused-cli <cmake -W>` or
:option:`-Wno-unused-cli <cmake -Wno->`
on the command line.
This may not be set to ``false``
if ``errors.unusedCli`` is set to ``true``.
.. _`CMakePresets.configurePresets.warnings.systemVars`:

View File

@@ -172,27 +172,18 @@ void QCMake::setPreset(QString const& name, bool setBinary)
QString::fromStdString(expandedPreset->BinaryDir);
this->setBinaryDirectory(binaryDir);
}
if (expandedPreset->WarnDev) {
this->CMakeInstance->SetSuppressDevWarnings(
!*expandedPreset->WarnDev);
}
if (expandedPreset->ErrorDev) {
this->CMakeInstance->SetDevWarningsAsErrors(
*expandedPreset->ErrorDev);
}
if (expandedPreset->WarnDeprecated) {
this->CMakeInstance->SetSuppressDeprecatedWarnings(
!*expandedPreset->WarnDeprecated);
}
if (expandedPreset->ErrorDeprecated) {
this->CMakeInstance->SetDeprecatedWarningsAsErrors(
*expandedPreset->ErrorDeprecated);
}
if (expandedPreset->WarnUninitialized) {
this->WarnUninitializedMode = *expandedPreset->WarnUninitialized;
emit this->warnUninitializedModeChanged(
*expandedPreset->WarnUninitialized);
}
this->CMakeInstance->SetWarningFromPreset(
"dev", expandedPreset->Warnings, expandedPreset->Errors,
cmDiagnostics::CMD_AUTHOR);
this->CMakeInstance->SetWarningFromPreset(
"deprecated", expandedPreset->Warnings, expandedPreset->Errors,
cmDiagnostics::CMD_DEPRECATED);
this->CMakeInstance->SetWarningFromPreset(
&cmake::SetWarnUninitialized, expandedPreset->Warnings, true,
cmDiagnostics::CMD_UNINITIALIZED);
this->CMakeInstance->SetWarningFromPreset(
&cmake::SetWarnUnusedCli, expandedPreset->Warnings, false,
cmDiagnostics::CMD_UNUSED_CLI);
this->Environment = this->StartEnvironment;
for (auto const& v : expandedPreset->Environment) {
if (v.second) {

View File

@@ -335,4 +335,18 @@ void SCHEMA_UNSUPPORTED(cmJSONState* state)
{
state->AddError("File version must be 8 or higher for $schema support");
}
void DIAGNOSTIC_UNSUPPORTED(cm::string_view name, cm::string_view context,
int version, cmJSONState* state)
{
state->AddError(cmStrCat("File version must be ", std::to_string(version),
" or higher for ", context, '.', name, " support"));
}
void DIAGNOSTIC_REMOVED(cm::string_view name, cm::string_view context,
int version, cmJSONState* state)
{
state->AddError(cmStrCat("File version must be ", std::to_string(version),
" or lower for ", context, '.', name, " support"));
}
}

View File

@@ -6,6 +6,8 @@
#include <string>
#include <cm/string_view>
#include <cm3p/json/value.h>
#include "cmJSONHelpers.h"
@@ -123,4 +125,10 @@ void PRESET_MISSING_FIELD(std::string const& presetName,
std::string const& missingField, cmJSONState* state);
void SCHEMA_UNSUPPORTED(cmJSONState* state);
void DIAGNOSTIC_UNSUPPORTED(cm::string_view name, cm::string_view context,
int version, cmJSONState* state);
void DIAGNOSTIC_REMOVED(cm::string_view name, cm::string_view context,
int version, cmJSONState* state);
}

View File

@@ -85,12 +85,11 @@ void InheritVector(std::vector<T>& child, std::vector<T> const& parent)
}
}
template <typename T>
void InheritMap(std::map<std::string, T>& child,
std::map<std::string, T> const& parent)
template <typename K, typename V>
void InheritMap(std::map<K, V>& child, std::map<K, V> const& parent)
{
for (auto const& v : parent) {
child.insert(v);
for (auto const& item : parent) {
child.insert(item);
}
}
@@ -828,12 +827,8 @@ bool cmCMakePresetsGraph::ConfigurePreset::VisitPresetInherit(
InheritString(preset.InstallDir, parent.InstallDir);
InheritString(preset.ToolchainFile, parent.ToolchainFile);
InheritString(preset.GraphVizFile, parent.GraphVizFile);
InheritOptionalValue(preset.WarnDev, parent.WarnDev);
InheritOptionalValue(preset.ErrorDev, parent.ErrorDev);
InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated);
InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated);
InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized);
InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli);
InheritMap(preset.Warnings, parent.Warnings);
InheritMap(preset.Errors, parent.Errors);
InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars);
InheritMap(preset.CacheVariables, parent.CacheVariables);
@@ -868,12 +863,15 @@ bool cmCMakePresetsGraph::ConfigurePreset::VisitPresetAfterInherit(
}
}
if (preset.WarnDev == false && preset.ErrorDev == true) {
return false;
}
if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) {
return false;
for (auto const& w : preset.Warnings) {
auto const ei = preset.Errors.find(w.first);
if (ei != preset.Errors.end()) {
if (w.second == false && ei->second == true) {
return false;
}
}
}
if (preset.CacheVariables.count("") != 0) {
return false;
}

View File

@@ -14,6 +14,7 @@
#include <cm/optional>
#include "cmDiagnostics.h"
#include "cmJSONState.h"
#include "cmStateTypes.h" // IWYU pragma: keep
@@ -126,13 +127,11 @@ public:
std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
cm::optional<bool> WarnDev;
cm::optional<bool> ErrorDev;
cm::optional<bool> WarnDeprecated;
cm::optional<bool> ErrorDeprecated;
cm::optional<bool> WarnUninitialized;
cm::optional<bool> WarnUnusedCli;
std::map<cmDiagnosticCategory, bool> Warnings;
std::map<cmDiagnosticCategory, bool> Errors;
cm::optional<bool> WarnSystemVars;
cm::optional<bool> WarnDev; // Deprecated synonym for Warnings.CMD_AUTHOR
cm::optional<bool> ErrorDev; // Deprecated synonym for Errors.CMD_AUTHOR
cm::optional<bool> DebugOutput;
cm::optional<bool> DebugTryCompile;

View File

@@ -7,6 +7,8 @@
#include <string>
#include <vector>
#include <cm/optional>
#include <cm3p/json/value.h>
#include "cmCMakePresetsGraph.h"
@@ -257,6 +259,22 @@ bool PresetBoolHelper(bool& out, Json::Value const* value, cmJSONState* state);
bool PresetOptionalBoolHelper(cm::optional<bool>& out,
Json::Value const* value, cmJSONState* state);
template <typename K>
bool PresetMapToBoolHelper(std::map<K, bool>& out, Json::Value const* value,
K key, cmJSONState* state)
{
cm::optional<bool> temp;
if (!PresetOptionalBoolHelper(temp, value, state)) {
return false;
}
if (temp) {
out[key] = *temp;
}
return true;
}
bool PresetIntHelper(int& out, Json::Value const* value, cmJSONState* state);
bool PresetOptionalIntHelper(cm::optional<int>& out, Json::Value const* value,
@@ -303,4 +321,7 @@ bool EnvironmentMapHelper(
Json::Value const* value, cmJSONState* state);
cmJSONHelper<std::nullptr_t> SchemaHelper();
bool CheckDiagnostics(cmJSONState* state, int version,
cmCMakePresetsGraph::ConfigurePreset& preset);
}

View File

@@ -598,14 +598,6 @@ bool cmCMakePresetsGraph::ReadJSONFile(std::string const& filename,
return false;
}
PresetPair<ConfigurePreset> presetPair;
presetPair.Unexpanded = preset;
presetPair.Expanded = cm::nullopt;
if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) {
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
return false;
}
// Support for installDir presets added in version 3.
if (v < 3 && !preset.InstallDir.empty()) {
cmCMakePresetsErrors::INSTALL_PREFIX_UNSUPPORTED(&root["installDir"],
@@ -639,6 +631,20 @@ bool cmCMakePresetsGraph::ReadJSONFile(std::string const& filename,
return false;
}
// Support for diagnostics.
if (!cmCMakePresetsGraphInternal::CheckDiagnostics(&this->parseState, v,
preset)) {
return false;
}
PresetPair<ConfigurePreset> presetPair;
presetPair.Unexpanded = preset;
presetPair.Expanded = cm::nullopt;
if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) {
cmCMakePresetsErrors::DUPLICATE_PRESETS(preset.Name, &this->parseState);
return false;
}
this->ConfigurePresetOrder.push_back(preset.Name);
}

View File

@@ -1,20 +1,27 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#include <cassert>
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <cm/optional>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
#include <cm3p/json/value.h>
#include "cmsys/String.h"
#include "cmCMakePresetsErrors.h"
#include "cmCMakePresetsGraph.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmDiagnostics.h"
#include "cmJSONHelpers.h"
#include "cmStateTypes.h"
@@ -204,27 +211,68 @@ auto const VariablesHelper =
JSONHelperBuilder::Map<cm::optional<CacheVariable>>(
cmCMakePresetsErrors::INVALID_PRESET, VariableHelper);
template <cmDiagnosticCategory C>
cm::string_view GetJSONName()
{
static std::string storage = [] {
cm::string_view const in = cmDiagnostics::GetCategoryString(C).substr(4);
std::string out;
bool sep = false;
for (char const c : in) {
if (sep) {
out += c;
sep = false;
} else if (c == '_') {
sep = true;
} else {
out += static_cast<char>(cmsysString_tolower(c));
}
}
return out;
}();
return storage;
}
cm::string_view GetJSONName(cmDiagnosticCategory category)
{
static cm::string_view const names[] = {
"none"_s, // CMD_NONE
#define DIAGNOSTIC_JSON_NAME(C) GetJSONName<cmDiagnostics::C>(),
CM_FOR_EACH_DIAGNOSTIC_CATEGORY(DIAGNOSTIC_JSON_NAME)
#undef DIAGNOSTIC_JSON_NAME
};
assert(category > 0 && category < cmDiagnostics::CategoryCount);
return names[category];
}
auto const PresetDiagnosticMapHelper =
cmCMakePresetsGraphInternal::PresetMapToBoolHelper<cmDiagnosticCategory>;
#define BIND_DIAGNOSTIC(C) \
.Bind(GetJSONName<cmDiagnostics::C>(), &DIAGNOSTIC_MEMBER, \
PresetDiagnosticMapHelper, cmDiagnostics::C, false)
#define DIAGNOSTIC_MEMBER ConfigurePreset::Warnings
auto const PresetWarningsHelper =
JSONHelperBuilder::Object<ConfigurePreset>(
JsonErrors::INVALID_NAMED_OBJECT_KEY, false)
.Bind("dev"_s, &ConfigurePreset::WarnDev,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
CM_FOR_EACH_DIAGNOSTIC_CATEGORY(BIND_DIAGNOSTIC)
.Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
#undef DIAGNOSTIC_MEMBER
#define DIAGNOSTIC_MEMBER ConfigurePreset::Errors
auto const PresetErrorsHelper =
JSONHelperBuilder::Object<ConfigurePreset>(
JsonErrors::INVALID_NAMED_OBJECT_KEY, false)
.Bind("dev"_s, &ConfigurePreset::ErrorDev,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
.Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
CM_FOR_EACH_DIAGNOSTIC_CATEGORY(BIND_DIAGNOSTIC);
#undef DIAGNOSTIC_MEMBER
#undef BIND_DIAGNOSTIC
auto const PresetDebugHelper =
JSONHelperBuilder::Object<ConfigurePreset>(
@@ -301,4 +349,71 @@ bool ConfigurePresetsHelper(std::vector<ConfigurePreset>& out,
return helper(out, value, state);
}
bool CheckDiagnostics(cmJSONState* state, int version,
std::map<cmDiagnosticCategory, bool> values,
cm::string_view group)
{
// NOLINTNEXTLINE(readability-use-anyofallof)
for (auto const& i : values) {
assert(i.first > 0 && i.first < cmDiagnostics::CategoryCount);
int const minVersion = cmDiagnostics::CategoryInfo[i.first].PresetVersion;
if (version < minVersion) {
cm::string_view dn = GetJSONName(i.first);
cmCMakePresetsErrors::DIAGNOSTIC_UNSUPPORTED(dn, group, minVersion,
state);
return false;
}
}
return true;
}
bool CheckDiagnostics(cmJSONState* state, int version,
cmCMakePresetsGraph::ConfigurePreset& preset)
{
// Check for diagnostics added in later schemes.
if (!CheckDiagnostics(state, version, preset.Warnings, "warnings"_s) ||
!CheckDiagnostics(state, version, preset.Errors, "errors"_s)) {
return false;
}
if (version < 12) {
// Handle 'dev'.
if (preset.WarnDev) {
preset.Warnings.emplace(cmDiagnostics::CMD_AUTHOR, *preset.WarnDev);
}
if (preset.ErrorDev) {
preset.Errors.emplace(cmDiagnostics::CMD_AUTHOR, *preset.ErrorDev);
}
// Check for diagnostics only present as warnings before v12.
constexpr cmDiagnosticCategory unsupportedErrors[] = {
cmDiagnostics::CMD_UNINITIALIZED,
cmDiagnostics::CMD_UNUSED_CLI,
};
for (cmDiagnosticCategory c : unsupportedErrors) {
if (cm::contains(preset.Errors, c)) {
cm::string_view dn = GetJSONName(c);
cmCMakePresetsErrors::DIAGNOSTIC_UNSUPPORTED(dn, "errors"_s, 12,
state);
return false;
}
}
} else {
// Check for diagnostics removed in v12.
if (preset.WarnDev) {
cmCMakePresetsErrors::DIAGNOSTIC_REMOVED("dev"_s, "warnings"_s, 11,
state);
return false;
}
if (preset.ErrorDev) {
cmCMakePresetsErrors::DIAGNOSTIC_REMOVED("dev"_s, "errors"_s, 11, state);
return false;
}
}
return true;
}
}

View File

@@ -19,12 +19,16 @@
// Each entry is of the form `SELECT(ACTION, <default>, <parent>, <name>)`.
// Entries MUST appear in the order that a depth-first enumeration would
// produce.
//
// When this changes, Help/manual/presets/schema.json must also be updated.
#define CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, SELECT) \
SELECT(ACTION, Warn, CMD_NONE, CMD_AUTHOR) \
SELECT(ACTION, Warn, CMD_NONE, CMD_DEPRECATED)
SELECT(ACTION, Warn, CMD_NONE, CMD_AUTHOR, 12) \
SELECT(ACTION, Warn, CMD_AUTHOR, CMD_DEPRECATED, 1) \
SELECT(ACTION, Ignore, CMD_NONE, CMD_UNINITIALIZED, 1) \
SELECT(ACTION, Warn, CMD_NONE, CMD_UNUSED_CLI, 1)
#define CM_SELECT_CATEGORY(F, D, P, C) F(C)
#define CM_SELECT_CATEGORY(F, D, P, C, V) F(C)
#define CM_FOR_EACH_DIAGNOSTIC_CATEGORY(ACTION) \
CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, CM_SELECT_CATEGORY)
@@ -67,12 +71,13 @@ public:
{
DiagnosticCategory Parent;
DiagnosticAction DefaultAction;
int PresetVersion;
};
constexpr static DiagnosticCategoryInformation
CategoryInfo[CategoryCount] = {
{ CMD_NONE, Undefined }, // CMD_NONE
#define DIAGNOSTIC_CATEGORY_INFO(F, D, P, C) { P, D },
{ CMD_NONE, Undefined, 0 }, // CMD_NONE
#define DIAGNOSTIC_CATEGORY_INFO(F, D, P, C, V) { P, D, V },
CM_FOR_EACH_DIAGNOSTIC_TABLE(UNUSED, DIAGNOSTIC_CATEGORY_INFO)
#undef DIAGNOSTIC_CATEGORY_INFO
};

View File

@@ -105,6 +105,18 @@ struct cmJSONHelperBuilder
-> bool { return func(out.*member, value, state); },
required);
}
template <typename U, typename M, typename F, typename C>
Object& Bind(cm::string_view name, M U::*member, F func, C constant,
bool required = true)
{
return this->BindPrivate(
name,
[func, member, constant](T& out, Json::Value const* value,
cmJSONState* state) -> bool {
return func(out.*member, value, constant, state);
},
required);
}
template <typename M, typename F>
Object& Bind(cm::string_view name, std::nullptr_t, F func,
bool required = true)

View File

@@ -48,6 +48,7 @@
# include "cmDebuggerPosixPipeConnection.h"
# endif //_WIN32
#endif
#include "cmDiagnostics.h"
#include "cmDocumentation.h"
#include "cmDocumentationEntry.h"
#include "cmDuration.h"
@@ -479,19 +480,24 @@ void cmake::CleanupCommandsAndMacros()
}
#ifndef CMAKE_BOOTSTRAP
using DiagnosticMap = std::map<cmDiagnosticCategory, bool>;
void cmake::SetWarningFromPreset(std::string const& name,
cm::optional<bool> warning,
cm::optional<bool> error)
DiagnosticMap const& warnings,
DiagnosticMap const& errors,
cmDiagnosticCategory key)
{
if (warning) {
if (*warning) {
auto const wi = warnings.find(key);
if (wi != warnings.end()) {
if (wi->second) {
this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN);
} else {
this->DiagLevels[name] = DIAG_IGNORE;
}
}
if (error) {
if (*error) {
auto const ei = errors.find(key);
if (ei != errors.end()) {
if (ei->second) {
this->DiagLevels[name] = DIAG_ERROR;
} else {
this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
@@ -499,6 +505,16 @@ void cmake::SetWarningFromPreset(std::string const& name,
}
}
void cmake::SetWarningFromPreset(void (cmake::*func)(bool),
DiagnosticMap const& warnings,
bool allowedValue, cmDiagnosticCategory key)
{
auto const wi = warnings.find(key);
if (wi != warnings.end() && wi->second == allowedValue) {
(this->*func)(wi->second);
}
}
void cmake::ProcessPresetVariables()
{
for (auto const& var : this->UnprocessedPresetVariables) {
@@ -2080,16 +2096,18 @@ bool cmake::SetArgsFromPreset(std::string const& presetName,
}
}
this->SetWarningFromPreset("dev", expandedPreset->WarnDev,
expandedPreset->ErrorDev);
this->SetWarningFromPreset("deprecated", expandedPreset->WarnDeprecated,
expandedPreset->ErrorDeprecated);
if (expandedPreset->WarnUninitialized == true) {
this->SetWarnUninitialized(true);
}
if (expandedPreset->WarnUnusedCli == false) {
this->SetWarnUnusedCli(false);
}
this->SetWarningFromPreset("dev", expandedPreset->Warnings,
expandedPreset->Errors,
cmDiagnostics::CMD_AUTHOR);
this->SetWarningFromPreset("deprecated", expandedPreset->Warnings,
expandedPreset->Errors,
cmDiagnostics::CMD_DEPRECATED);
this->SetWarningFromPreset(&cmake::SetWarnUninitialized,
expandedPreset->Warnings, true,
cmDiagnostics::CMD_UNINITIALIZED);
this->SetWarningFromPreset(&cmake::SetWarnUnusedCli,
expandedPreset->Warnings, false,
cmDiagnostics::CMD_UNUSED_CLI);
if (expandedPreset->WarnSystemVars == true) {
this->SetCheckSystemVars(true);
}

View File

@@ -396,9 +396,15 @@ public:
bool GetIsInTryCompile() const;
#ifndef CMAKE_BOOTSTRAP
void SetWarningFromPreset(std::string const& name,
cm::optional<bool> warning,
cm::optional<bool> error);
void SetWarningFromPreset(
std::string const& name,
std::map<cmDiagnosticCategory, bool> const& warnings,
std::map<cmDiagnosticCategory, bool> const& errors,
cmDiagnosticCategory key);
void SetWarningFromPreset(
void (cmake::*func)(bool),
std::map<cmDiagnosticCategory, bool> const& warnings, bool allowedValue,
cmDiagnosticCategory key);
void ProcessPresetVariables();
void PrintPresetVariables();
void ProcessPresetEnvironment();

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/ErrorAuthorNotSupported:
File version must be 12 or higher for errors\.author support$

View File

@@ -0,0 +1,13 @@
{
"version": 11,
"configurePresets": [
{
"name": "ErrorAuthorNotSupported",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"errors": {
"author": true
}
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/ErrorDevNotSupported:
File version must be 11 or lower for errors\.dev support$

View File

@@ -0,0 +1,13 @@
{
"version": 12,
"configurePresets": [
{
"name": "ErrorDevNotSupported",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"errors": {
"dev": true
}
}
]
}

View File

@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/ErrorUninitializedNotSupported:
File version must be 12 or higher for errors\.uninitialized support$

View File

@@ -0,0 +1,13 @@
{
"version": 11,
"configurePresets": [
{
"name": "ErrorUninitializedNotSupported",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"errors": {
"uninitialized": true
}
}
]
}

View File

@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/ErrorUnusedCliNotSupported:
File version must be 12 or higher for errors\.unusedCli support$

View File

@@ -0,0 +1,13 @@
{
"version": 11,
"configurePresets": [
{
"name": "ErrorUnusedCliNotSupported",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"errors": {
"unusedCli": true
}
}
]
}

View File

@@ -174,6 +174,13 @@ set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_presets(ConditionFuture)
run_cmake_presets(SubConditionNull)
run_cmake_presets(TraceNotSupported)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_presets(WarningDevNotSupported)
run_cmake_presets(WarningAuthorNotSupported)
run_cmake_presets(ErrorDevNotSupported)
run_cmake_presets(ErrorAuthorNotSupported)
run_cmake_presets(ErrorUninitializedNotSupported)
run_cmake_presets(ErrorUnusedCliNotSupported)
set(CMakePresets_NO_PRESET 1)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
@@ -343,13 +350,19 @@ set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/ListAllPresetsNoTest.json.in")
run_cmake_presets(ListAllPresetsNoTest --list-presets=all)
# Test warning and error flags
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Warnings.json.in")
set(CMakePresets_WARN_UNUSED_CLI 1)
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Warnings.json.in")
run_cmake_presets(NoWarningFlags)
run_cmake_presets(WarningFlags)
run_cmake_presets(DisableWarningFlags)
run_cmake_presets(ErrorDev)
run_cmake_presets(ErrorDeprecated)
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Warnings12.json.in")
run_cmake_presets(NoWarningFlags)
run_cmake_presets(WarningFlags)
run_cmake_presets(DisableWarningFlags)
run_cmake_presets(ErrorDev)
unset(CMakePresets_WARN_UNUSED_CLI)
# Test debug

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/WarningAuthorNotSupported:
File version must be 12 or higher for warnings\.author support$

View File

@@ -0,0 +1,13 @@
{
"version": 11,
"configurePresets": [
{
"name": "WarningAuthorNotSupported",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"warnings": {
"author": true
}
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/WarningDevNotSupported:
File version must be 11 or lower for warnings\.dev support$

View File

@@ -0,0 +1,13 @@
{
"version": 12,
"configurePresets": [
{
"name": "WarningDevNotSupported",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"warnings": {
"dev": true
}
}
]
}

View File

@@ -0,0 +1,70 @@
{
"version": 12,
"configurePresets": [
{
"name": "NoWarningFlags",
"generator": "@RunCMake_GENERATOR@",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"UNUSED_VARIABLE": "Unused"
}
},
{
"name": "WarningFlags",
"inherits": "NoWarningFlags",
"warnings": {
"author": true,
"deprecated": true,
"uninitialized": true,
"unusedCli": false,
"systemVars": true
}
},
{
"name": "DisableWarningFlags",
"inherits": "NoWarningFlags",
"warnings": {
"author": false,
"deprecated": false,
"unusedCli": false
}
},
{
"name": "ErrorDev",
"inherits": "NoWarningFlags",
"errors": {
"author": true
}
},
{
"name": "ErrorDeprecated",
"inherits": "NoWarningFlags",
"warnings": {
"author": false
},
"errors": {
"deprecated": true
}
},
{
"name": "ErrorUninitialized",
"inherits": "NoWarningFlags",
"warnings": {
"author": false
},
"errors": {
"uninitialized": true
}
},
{
"name": "ErrorUnusedCli",
"inherits": "NoWarningFlags",
"warnings": {
"author": false
},
"errors": {
"unusedCli": true
}
}
]
}