mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Presets: Generate diagnostics schema from header
Modify the script that generates the CMake presets schema to extract the list of available diagnostics from the `cmDiagnostics.h` header and generate the relevant properties. This information is combined with a partial set that remains in the YAML for those diagnostics whose definitions differ from what is easily generated. While these special cases will remain, the addition of new diagnostics should no longer require manual updates to the YAML. (The presets version log will still require manual updates.)
This commit is contained in:
@@ -6,12 +6,9 @@
|
||||
``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``.
|
||||
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`:
|
||||
|
||||
|
||||
@@ -657,21 +657,9 @@ 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``.
|
||||
# This should ONLY have diagnostics whose definitions require
|
||||
# special handling (i.e. anything from preset version < 12). Others
|
||||
# will be generated from cmDiagnostics.h.
|
||||
deprecated:
|
||||
type: boolean
|
||||
description:
|
||||
@@ -725,8 +713,8 @@ properties:
|
||||
on the command line.
|
||||
This may not be set to ``false``
|
||||
if ``errors.unusedCli`` is set to ``true``.
|
||||
# systemVars should be last.
|
||||
systemVars:
|
||||
sort: false
|
||||
type: boolean
|
||||
description:
|
||||
An optional boolean. Setting this to true is equivalent to
|
||||
@@ -746,22 +734,9 @@ 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``.
|
||||
# This should ONLY have diagnostics whose definitions require
|
||||
# special handling (i.e. anything from preset version < 12). Others
|
||||
# will be generated from cmDiagnostics.h.
|
||||
deprecated:
|
||||
type: boolean
|
||||
description:
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
``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``.
|
||||
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`:
|
||||
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
// IWYU pragma: no_forward_declare cmDiagnostics::DiagnosticCategory
|
||||
|
||||
// The list of diagnostic categories along with their associated data.
|
||||
// Each entry is of the form `SELECT(ACTION, <default>, <parent>, <name>)`.
|
||||
// Each entry is of the form:
|
||||
// `SELECT(ACTION, <default>, <parent>, <name>, <preset-version>)`
|
||||
// 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.
|
||||
// When changing this table, Utilities/Scripts/regenerate-presets.py must be
|
||||
// run to update the JSON schema for CMake presets. If the _TABLE macro name
|
||||
// changes, said script will also need to be updated with the new name.
|
||||
|
||||
#define CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, SELECT) \
|
||||
SELECT(ACTION, Warn, CMD_NONE, CMD_AUTHOR, 12) \
|
||||
|
||||
@@ -14,7 +14,9 @@ Usage: python3 regenerate-presets.py
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Self
|
||||
|
||||
@@ -30,12 +32,45 @@ SCHEMA_JSON_FILENAME = 'schema.json'
|
||||
|
||||
WORKSPACE = Path(__file__).parent.parent.parent.absolute()
|
||||
PRESETS = WORKSPACE / PRESETS_REL
|
||||
DIAGNOSTICS = WORKSPACE / 'Source/cmDiagnostics.h'
|
||||
|
||||
RST_BANNER = f"""\
|
||||
.. This file was generated by {Path(__file__).relative_to(WORKSPACE)}
|
||||
from {PRESETS_REL}/{SCHEMA_YAML_FILENAME}. Do not edit.
|
||||
"""
|
||||
|
||||
DIAGNOSTIC_TABLE_MACRO = 'CM_FOR_EACH_DIAGNOSTIC_TABLE'
|
||||
CONFIGURE_PRESET_PROPERTIES_PATH = (
|
||||
'properties', 'configurePresets', 'items', 'properties'
|
||||
)
|
||||
WARNING_DESCRIPTION = (
|
||||
'An optional boolean. '
|
||||
'Equivalent to passing -W{c} or -Wno-{c} on the command line. '
|
||||
'This may not be set to false if errors.{c} is set to true.'
|
||||
)
|
||||
WARNING_SPHINX_DESCRIPTION = """
|
||||
An optional boolean. Equivalent to passing :option:`-W{c} <cmake -W>` or
|
||||
:option:`-Wno-{c} <cmake -Wno->` on the command line.
|
||||
This may not be set to ``false`` if ``errors.{c}`` is set to ``true``.
|
||||
""".strip()
|
||||
ERROR_DESCRIPTION = (
|
||||
'An optional boolean. '
|
||||
'Equivalent to passing -Werror={c} or -Wno-error={c} on the command line. '
|
||||
'This may not be set to true if warnings.{c} is set to false.'
|
||||
)
|
||||
ERROR_SPHINX_DESCRIPTION = """
|
||||
An optional boolean. Equivalent to passing :cmake-option:`-Werror={c}` or
|
||||
:cmake-option:`-Wno-error={c}` on the command line.
|
||||
This may not be set to ``true`` if ``warnings.{c}`` is set to ``false``.
|
||||
""".strip()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@dataclass
|
||||
class Diagnostic:
|
||||
name: str
|
||||
since: int
|
||||
|
||||
|
||||
# =============================================================================
|
||||
class Value:
|
||||
@@ -596,6 +631,105 @@ def trimDescriptions(data: Any):
|
||||
return data
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def getPath(data: Any, path: tuple[str]) -> Any:
|
||||
if len(path) == 0:
|
||||
return data
|
||||
return getPath(data[path[0]], path[1:])
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def diagnosticPresetName(symbol: str) -> str:
|
||||
sep = False
|
||||
out = ''
|
||||
for c in symbol[4:]:
|
||||
if c == '_':
|
||||
sep = True
|
||||
elif sep:
|
||||
out += c
|
||||
sep = False
|
||||
else:
|
||||
out += c.lower()
|
||||
return out
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def buildDiagnosticsSchema(
|
||||
diagnostics: list[Diagnostic],
|
||||
descriptionTemplate: str,
|
||||
sphinxDescriptionTemplate: str,
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
out = {}
|
||||
|
||||
for d in diagnostics:
|
||||
out[d.name] = {
|
||||
'since': d.since,
|
||||
'type': 'boolean',
|
||||
'description': descriptionTemplate.format(c=d.name),
|
||||
'sphinxDescription': sphinxDescriptionTemplate.format(c=d.name),
|
||||
}
|
||||
|
||||
return out
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def mergeDiagnostics(
|
||||
generated: dict[str, dict[str, Any]],
|
||||
extra: dict[str, dict[str, Any]],
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
# Get unsorted names.
|
||||
tail = {}
|
||||
for k in list(extra.keys()):
|
||||
s = extra[k].pop('sort', True)
|
||||
if not s:
|
||||
tail[k] = extra.pop(k)
|
||||
|
||||
# Combine inputs and sort.
|
||||
out = {}
|
||||
combined = deepcopy(generated)
|
||||
combined.update(extra)
|
||||
for k in sorted(combined.keys()):
|
||||
out[k] = combined[k]
|
||||
|
||||
# Add unsorted items and return result.
|
||||
out.update(tail)
|
||||
return out
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def readDiagnostics(path: Path | str) -> list[Diagnostic]:
|
||||
content = ''
|
||||
|
||||
# Extract diagnostics table from header.
|
||||
with open(path, 'r') as f:
|
||||
extracting = False
|
||||
for line in f:
|
||||
if DIAGNOSTIC_TABLE_MACRO in line:
|
||||
extracting = True
|
||||
continue
|
||||
|
||||
if extracting:
|
||||
content += line.replace('\\\n', ' ')
|
||||
if not line.strip().endswith('\\'):
|
||||
break
|
||||
|
||||
out = []
|
||||
while True:
|
||||
m = re.match(r'\s*SELECT[(]([^)]+)[)]', content)
|
||||
if m is None:
|
||||
break
|
||||
|
||||
args = [a.strip() for a in m.group(1).split(',')]
|
||||
n = diagnosticPresetName(args[3])
|
||||
v = int(args[4])
|
||||
if v > 1:
|
||||
out.append(Diagnostic(n, v))
|
||||
|
||||
content = content[m.span()[1]:]
|
||||
|
||||
return out
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def main():
|
||||
# Read the schema definition.
|
||||
@@ -611,6 +745,18 @@ def main():
|
||||
# Remove whitespace around descriptions.
|
||||
schema = trimDescriptions(schema)
|
||||
|
||||
# Read diagnostics and update schema.
|
||||
diagnostics = readDiagnostics(DIAGNOSTICS)
|
||||
configureSchema = getPath(schema, CONFIGURE_PRESET_PROPERTIES_PATH)
|
||||
configureSchema['warnings']['properties'] = mergeDiagnostics(
|
||||
buildDiagnosticsSchema(diagnostics, WARNING_DESCRIPTION,
|
||||
WARNING_SPHINX_DESCRIPTION),
|
||||
configureSchema['warnings']['properties'])
|
||||
configureSchema['errors']['properties'] = mergeDiagnostics(
|
||||
buildDiagnosticsSchema(diagnostics, ERROR_DESCRIPTION,
|
||||
ERROR_SPHINX_DESCRIPTION),
|
||||
configureSchema['errors']['properties'])
|
||||
|
||||
# Extract global type definitions.
|
||||
global TYPES, REFS
|
||||
|
||||
|
||||
Reference in New Issue
Block a user