Help: Improve diagnostics documentation

Make diagnostics into Sphinx objects so that they can be more readily
cross-referenced. (This is also needed to enable --help-diagnostic.)
Update various places that can make use of the same. Significantly
expand the documentation on controlling diagnostics.
This commit is contained in:
Matthew Woehlke
2026-04-30 15:14:02 -04:00
parent 3cccce8ca2
commit 97d13c3053
11 changed files with 195 additions and 75 deletions

View File

@@ -61,9 +61,8 @@ signatures that specify them. The common options are:
but not recommended.
.. versionadded:: 4.4
The :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION <CMD_INSTALL_ABSOLUTE_DESTINATION>`
diagnostic can be enabled to warn or error out when an absolute destination
is provided.
The :diagnostic:`CMD_INSTALL_ABSOLUTE_DESTINATION` diagnostic can be
enabled to warn or error out when an absolute destination is provided.
When a relative path is given, it is interpreted relative to the value
of the :variable:`CMAKE_INSTALL_PREFIX` variable.

View File

@@ -0,0 +1,16 @@
CMD_AUTHOR
----------
.. diagnostic::
:default: warn
Warn about a build system's incorrect use of CMake, or of a CMake interface
provided by a dependency. This is the category triggered by
:command:`message(AUTHOR_WARNING)`. It is also the ancestor of many other
diagnostic categories.
The most important aspect of this category is that it represents issues with
a project's build system which typically require alteration to the same.
This is to say that users simply trying to build a project obtained elsewhere
will typically not be interested in these warnings, except to perhaps report
them to the project's developer(s).

View File

@@ -0,0 +1,9 @@
CMD_DEPRECATED
--------------
.. diagnostic::
:default: warn
:parent: CMD_AUTHOR
Warn about use of a deprecated function or package. This is the category
triggered by :command:`message(DEPRECATION)`.

View File

@@ -0,0 +1,9 @@
CMD_INSTALL_ABSOLUTE_DESTINATION
--------------------------------
.. diagnostic::
:default: ignore
Warn when an :command:`install` command specifies an absolute ``DESTINATION``
path. Absolute destinations are typically undesirable because they prevent
the installation prefix from being overridden at install time.

View File

@@ -0,0 +1,7 @@
CMD_UNINITIALIZED
-----------------
.. diagnostic::
:default: ignore
Warn if an uninitialized variable is dereferenced.

View File

@@ -0,0 +1,12 @@
CMD_UNUSED_CLI
--------------
.. diagnostic::
:default: ignore
Warn about variables that are declared on the command line, but not used.
This diagnostic is issued outside of the configuration / generation phases.
Accordingly, while the action of this warning category can be queried as
usual, the :command:`cmake_diagnostic` command is unable to affect the action
of this diagnostic.

View File

@@ -32,71 +32,62 @@ issues in several categories:
* Issues that may impact the ability of the project
to be built with newer versions of CMake.
Diagnostic Actions
------------------
Controlling Diagnostics
=======================
The action taken when a particular diagnostic is triggered depends on the
diagnostic category. Most categories will warn by default. The
:command:`cmake_diagnostic` command and :option:`-W <cmake -W>` options can be
used to control what action occurs when a diagnostic of a particular category
is triggered. The possible actions are described in the documentation of the
same.
Each diagnostic category has an associated action to be taken when that
diagnostic is triggered. Most categories will warn by default. The available
actions are described in the :command:`cmake_diagnostic` command documentation.
CMake maintains a diagnostic state stack that is similar to the policy state.
The initial state of the stack is determined by four factors, which are, in
order of precedence:
* The default action associated with the diagnostic.
* The action associated with the diagnostic stored in the CMake variable cache,
which is used to persist the initial state between CMake runs.
* The :preset:`configurePresets.warnings` and :preset:`configurePresets.errors`
fields of :manual:`CMake Presets <cmake-presets(7)>`.
* The :option:`-W[no-][error=] <cmake -W>` command line arguments.
.. note::
Because command line arguments operate both recursively and in the order
specified, some combinations of diagnostic arguments may result in later
arguments completely overwriting the action of earlier arguments. For
example, ``-Wno-child -Wparent`` will result in the ``child`` warning being
enabled, because ``-Wparent`` promotes both ``parent`` and ``child`` to at
least ``WARN`` severity. CMake presets are evaluated in order from most
ancestral to least ancestral.
During script execution, the :command:`cmake_diagnostic` command can be used to
query or alter the state, or to perform limited stack manipulations.
When a diagnostic is issued at configure time (or during script execution, when
CMake is running in script mode), the current diagnostic state controls the
action. Diagnostics issued at generate time, or outside of the configuration
and generation phases must make use of recorded state information. While CMake
strives to preserve this information in a way that matches the recorded state
to the state as of the CMake command which ultimately causes a diagnostic to be
issued, CMake may sometimes fall back to the state when processing of a
subdirectory completed, or even the root state. This may limit the ability of
the :command:`cmake_diagnostic` command to control such diagnostics, especially
if called from a function or included file. This is especially the case for
diagnostics that are not directly coupled to a CMake command.
Diagnostic Categories
=====================
The following categories are defined.
The following categories are defined:
``CMD_AUTHOR`` (``-Wauthor``)
-----------------------------
.. toctree::
:maxdepth: 1
:Default: Warn
Warn about a build system's incorrect use of CMake, or of a CMake interface
provided by a dependency. This is the category triggered by
:command:`message(AUTHOR_WARNING)`. It is also the ancestor of many other
diagnostic categories.
The most important aspect of this category is that it represents issues with
a project's build system which typically require alteration to the same. This
is to say that users simply trying to build a project obtained elsewhere will
typically not be interested in these warnings, except to perhaps report them
to the project's developer(s).
``CMD_DEPRECATED`` (``-Wdeprecated``)
-------------------------------------
:Default: Warn
:Parent: ``CMD_AUTHOR``
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.
.. _CMD_INSTALL_ABSOLUTE_DESTINATION:
``CMD_INSTALL_ABSOLUTE_DESTINATION`` (``-Winstall-absolute-destination``)
-------------------------------------------------------------------------
:Default: Ignore
Warn when an :command:`install` command specifies an absolute
``DESTINATION`` path. Absolute destinations are typically undesirable
because they prevent the installation prefix from being overridden at
install time.
/diagnostic/CMD_AUTHOR
/diagnostic/CMD_DEPRECATED
/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION
/diagnostic/CMD_UNINITIALIZED
/diagnostic/CMD_UNUSED_CLI

View File

@@ -3,8 +3,10 @@ install-absolute-dest-configure-time
* CMake gained the ability to diagnose :command:`install` commands that
specify an absolute ``DESTINATION`` path via the
:ref:`CMD_INSTALL_ABSOLUTE_DESTINATION <CMD_INSTALL_ABSOLUTE_DESTINATION>`
diagnostic category. This diagnostic may be controlled with the
:option:`-Winstall-absolute-destination <cmake -W>` command-line option, the
``installAbsoluteDestination`` field in a :manual:`cmake-presets(7)`
``warnings`` object, or the :command:`cmake_diagnostic` command.
:diagnostic:`CMD_INSTALL_ABSOLUTE_DESTINATION` diagnostic category.
This diagnostic may be controlled with the
:option:`-Winstall-absolute-destination <cmake -W>` command-line option,
the ``installAbsoluteDestination`` field in a
:manual:`CMake Presets <cmake-presets(7)>`
:preset:`configurePresets.warnings` object,
or the :command:`cmake_diagnostic` command.

View File

@@ -11,8 +11,7 @@ running the script, it may get fatal error messages from the script.
.. versionadded:: 4.4
The :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION <CMD_INSTALL_ABSOLUTE_DESTINATION>`
diagnostic can be used to to generate errors for absolute install destinations
at generate time.
The :diagnostic:`CMD_INSTALL_ABSOLUTE_DESTINATION` diagnostic can be used to
generate errors for absolute install destinations at generate time.
See also :variable:`CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION`.

View File

@@ -10,8 +10,7 @@ warning messages from the script.
.. versionadded:: 4.4
The :ref:`CMD_INSTALL_ABSOLUTE_DESTINATION <CMD_INSTALL_ABSOLUTE_DESTINATION>`
diagnostic can be used to to generate warnings for absolute install destinations
at generate time.
The :diagnostic:`CMD_INSTALL_ABSOLUTE_DESTINATION` diagnostic can be used to
generate warnings for absolute install destinations at generate time.
See also :variable:`CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION`.

View File

@@ -234,6 +234,7 @@ class _cmake_index_entry:
_cmake_index_objs = {
'command': _cmake_index_entry('command'),
'cpack_gen': _cmake_index_entry('cpack generator'),
'diagnostic': _cmake_index_entry('diagnostic'),
'envvar': _cmake_index_entry('envvar'),
'generator': _cmake_index_entry('generator'),
'genex': _cmake_index_entry('genex'),
@@ -523,6 +524,79 @@ class CMakeSignatureObject(CMakeObject):
return super().run()
class CMakeDiagnosticObject(CMakeObject):
object_type = 'diagnostic'
required_arguments = 0
optional_arguments = 0
DEFAULT_CHOICES = {'ignore', 'warn', 'error'}
def default_option(argument):
return directives.choice(
argument, CMakeDiagnosticObject.DEFAULT_CHOICES)
option_spec = {
'default': default_option,
'parent': directives.unchanged,
}
def __init__(self, *args, **kwargs):
self.targetname = None
super().__init__(*args, **kwargs)
def _preset_name(self) -> str:
sep = False
out = ''
for c in self.targetname[4:]:
if c == '_':
sep = True
elif sep:
out += c
sep = False
else:
out += c.lower()
return out
def _build_field(self, name: str, content: str | list[Node]) -> Node:
if type(content) is not list:
content = self.parse_text_to_nodes(content)
name_node = nodes.field_name(text=name)
body_node = nodes.field_body('', *content)
return nodes.field('', name_node, body_node)
def _build_cli(self) -> list[Node]:
cname = self.targetname[4:].lower().replace('_', '-')
ctext = f'-W[no-][error=]{cname}'
return self.parse_text_to_nodes(f':option:`{ctext} <cmake -W>`')
def _build_preset_refs(self) -> list[Node]:
p = self._preset_name()
w = f':preset:`warnings.{p} <configurePresets.warnings.{p}>`'
e = f':preset:`errors.{p} <configurePresets.errors.{p}>`'
return self.parse_text_to_nodes(f'{w}, {e}')
def run(self) -> list[Node]:
self.domain, self.objtype = self.name.split(':', 1)
doc = self.state.document
self.targetname = doc.next_node(nodes.title).astext()
default = self.options['default'].capitalize()
parent = self.options.get('parent')
headers = nodes.field_list()
headers += self._build_field('Command Line', self._build_cli())
headers += self._build_field('Presets', self._build_preset_refs())
headers += self._build_field('Default', default)
if parent:
parentRef = self.parse_text_to_nodes(f':diagnostic:`{parent}`')
headers += self._build_field('Parent', parentRef)
content = self.parse_content_to_nodes()
return [headers] + content
class CMakeReferenceRole:
# See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
_re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)
@@ -680,6 +754,7 @@ class CMakeDomain(Domain):
object_types = {
'command': ObjType('command', 'command'),
'cpack_gen': ObjType('cpack_gen', 'cpack_gen'),
'diagnostic': ObjType('diagnostic', 'diagnostic'),
'envvar': ObjType('envvar', 'envvar'),
'generator': ObjType('generator', 'generator'),
'genex': ObjType('genex', 'genex'),
@@ -700,6 +775,7 @@ class CMakeDomain(Domain):
directives = {
'command': CMakeObject,
'envvar': CMakeObject,
'diagnostic': CMakeDiagnosticObject,
'genex': CMakeGenexObject,
'signature': CMakeSignatureObject,
'variable': CMakeObject,
@@ -710,6 +786,7 @@ class CMakeDomain(Domain):
'cref': CMakeCRefRole(),
'command': CMakeXRefRole(fix_parens=True, lowercase=True),
'cpack_gen': CMakeXRefRole(),
'diagnostic': CMakeXRefRole(),
'envvar': CMakeXRefRole(),
'generator': CMakeXRefRole(),
'genex': CMakeXRefRole(),