From ffe4c2a8ff27bf8e4daf7e70597a20ec9c68d1be Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Mon, 20 Apr 2026 10:48:27 -0400 Subject: [PATCH 1/5] Help: Fix developer documentation HTML is not normally generated for developer documentation. As a result, the validity of the reST is effectively never checked, and thus contains a small handful of issues (mostly bad indent). Fix these. --- Help/dev/experimental.rst | 4 ++-- Help/dev/source.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst index 30d53ff8ff..61b77c02dc 100644 --- a/Help/dev/experimental.rst +++ b/Help/dev/experimental.rst @@ -37,7 +37,7 @@ When activated, this experimental feature provides the following: * The package name associated with specific targets may be specified using the ``CMAKE_EXPORT_FIND_PACKAGE_NAME`` variable and/or -``EXPORT_FIND_PACKAGE_NAME`` target property. + ``EXPORT_FIND_PACKAGE_NAME`` target property. Export |CPS| Package Information for ``install(EXPORT)`` ======================================================== @@ -102,7 +102,7 @@ When activated, this experimental feature provides the following: * Targets with the property set to a true value will have their C++ build information exported to the build database. -Software Bill Of Materials |SBOM| +Software Bill Of Materials (SBOM) ================================= In order to activate support for the :command:`install(SBOM)` command, diff --git a/Help/dev/source.rst b/Help/dev/source.rst index ec4e12c0e0..046be1e4d1 100644 --- a/Help/dev/source.rst +++ b/Help/dev/source.rst @@ -287,10 +287,10 @@ These are: * ````: * ``cm::is_pair``: - Checks if a type is a std::pair<> type. + Checks if a type is a std::pair<> type. * ``cm::is_tuple``: - Checks if a type is a std::tuple<> type. + Checks if a type is a std::tuple<> type. * ``cm::is_container``: Checks if a type is a container type. From 3cccce8ca201fbc03c3a870640b77eaf9385c035 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 30 Apr 2026 13:54:57 -0400 Subject: [PATCH 2/5] Help: Add developer documentation for new diagnostics Add a developer-targeted document explaining the basics of how to use CMake 4.4's new diagnostic framework. --- Help/dev/README.rst | 2 + Help/dev/diagnostics.rst | 157 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 Help/dev/diagnostics.rst diff --git a/Help/dev/README.rst b/Help/dev/README.rst index 84766a67d6..050ec0707b 100644 --- a/Help/dev/README.rst +++ b/Help/dev/README.rst @@ -41,12 +41,14 @@ CMake developer documentation is provided by the following documents: * The `CMake Testing Guide`_. * The `CMake Experimental Features Guide`_. * The `CMake Debugging Guide`_. +* The `CMake Diagnostics Guide`_. .. _`CMake Source Code Guide`: source.rst .. _`CMake Documentation Guide`: documentation.rst .. _`CMake Testing Guide`: testing.rst .. _`CMake Experimental Features Guide`: experimental.rst .. _`CMake Debugging Guide`: debug.rst +.. _`CMake Diagnostics Guide`: diagnostics.rst Maintainer Documentation ======================== diff --git a/Help/dev/diagnostics.rst b/Help/dev/diagnostics.rst new file mode 100644 index 0000000000..394f4d6988 --- /dev/null +++ b/Help/dev/diagnostics.rst @@ -0,0 +1,157 @@ +CMake Diagnostics Guide +*********************** + +The following is a guide on how CMake should issue diagnostics. +See documentation on `CMake Development`_ for more information. + +.. _`CMake Development`: README.rst + +TL;DR Porting Guide (from CMake < 4.4) +====================================== + +I want to write ``IssueMessage(MessageType::AUTHOR_WARNING, ...``: + Write ``IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, ...`` instead. + +I want to write ``IssueMessage(MessageType::DEPRECATION_WARNING, ...``: + Write ``IssueDiagnostic(cmDiagnostics::CMD_DEPRECATED, ...`` instead. + +I want to write ``IssueMessage(MessageType::AUTHOR_ERROR, ...``: + No, you don't. Under the old system, there isn't a meaningful difference + between ``AUTHOR_WARNING`` and ``AUTHOR_ERROR``; at least, not as arguments + to ``IssueMessage``. + +I want to write ``IssueMessage(MessageType::DEPRECATION_ERROR, ...``: + See ``AUTHOR_ERROR``. + +History +======= + +Prior to CMake 4.4, CMake did not have a formal system for issuing diagnostics. +The messaging system had message types for author diagnostics and deprecation +diagnostics which conflated category and severity. Worse, although these types +*purported* to allow the caller to specify severity, this information is not +actually honored. Other diagnostics existed which did not use these types. + +More importantly, the mechanisms for managing severity differed depending on +the diagnostic. Variables to control a diagnostic might be documented, +undocumented, or non-existent. Spelling of command-line options to control +diagnostics was inconsistent, as was the ability to make diagnostics fatal. +Adding new categories required significant effort, as the logic to handle a +diagnostic was bespoke at every layer. + +CMake Diagnostic Framework +========================== + +CMake 4.4 introduced a structured framework for issuing and managing +diagnostics. The ``cmDiagnostics.h`` header enumerates all available +diagnostic categories. All code to manage diagnostics leverages either this +table or helper code generated from the same, such that it is the *only* +non-documentation location that needs to be updated to add a new diagnostic +category. The framework is also responsible for determining the severity of a +diagnostic, based on the combination of category defaults and user preferences, +and for presenting the user with a consistent set of control mechanisms. + +Numeric identifiers associated with diagnostic categories are only used +internally and are never persisted. This means that numbers can be reassigned +at any time. This also permits ensuring that numbers are consecutive, which +allows iterating over all categories using a simple ``for`` loop. (Note that +such loops will typically start from ``1``, not ``0``, as ``0`` is reserved +for the 'NONE' category which is used primarily as a virtual parent.) Where +necessary, macros provided by ``cmDiagnostics.h`` can generate code for each +diagnostic category. + +Refer to ``Help/manual/cmake-diagnostics.7.rst`` for user-facing documentation. + +Issuing Diagnostics +=================== + +Diagnostics are the CMake equivalent of compiler warnings, with categorization +providing both additional information and additional response control to users. + +Diagnostics are issued via the ``IssueDiagnostic`` method. This method is +provided on various objects, with ``cmMakefile`` being the most prominent, and +typically exists alongside an ``IssueMessage`` method. The latter is not +deprecated, and should still be used to issue messages outside of the +diagnostic categories, such as hard errors or informational messages. + +The historic ``{AUTHOR,DEPRECATION}_{WARNING,ERROR}`` message types, however, +have been removed. These are replaced by ``IssueDiagnostic`` and the +``CMD_{AUTHOR,DEPRECATED}`` diagnostic categories. Because the methods have +similar signatures, porting in many cases can be accomplished by replacing the +method name and first argument (the former message type, newly the diagnostic +category). For example, where prior versions of CMake wrote: + +.. code:: c++ + + mf->IssueMessage(MessageType::AUTHOR_WARNING, ...); + +CMake 4.4 and later should write: + +.. code:: c++ + + mf->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, ...); + +(Note that the ``"cmDiagnostics.h"`` header may need to be newly included.) + +As previously mentioned, the purported severity was ignored by ``cmMessenger``, +which instead used its own internal state to decide whether a message should +be a warning or an error. This logic overrode the severity component of the +message type as passed into the method. As a result, although the new method +does not accept a severity, this is actually consistent with the historic +behavior and does not represent any loss of functionality. + +.. note:: + + When issuing diagnostics targeted at build-system authors, please consult the + complete list of available diagnostics, as a more specific category may be + available. In some cases, it may even make sense to add a new category. + +Adding Diagnostic Categories +============================ + +Adding new diagnostic categories involves four steps. + +1. The new category must be added to ``cmDiagnostics.h``. The diagnostics + table looks like this: + + .. code:: c++ + + #define CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, SELECT) \ + SELECT(ACTION, Warn, CMD_NONE, CMD_AUTHOR, 12) \ + SELECT(ACTION, Warn, CMD_AUTHOR, CMD_DEPRECATED, 1) \ + ... + + Add a new entry. All entries must begin with ``SELECT(ACTION,``. The + second argument is the *default* state of the diagnostic and should + typically be ``Warn``, but may be ``Ignore`` if the diagnostic should be + opt-in. Defaulting to ``SendError`` would be exceptional, and defaulting + to ``FatalError`` is not recommended under any circumstances. The third + argument is the *parent* of the diagnostic (see below). The fourth is the + actual name of the diagnostic. The fifth and final argument is the CMake + preset version corresponding to the introduction of the argument, which + should be the latest preset version as used by the version of CMake under + development. + + .. note:: + + In the event that the development version has not already introduced a + new preset version, adding a new diagnostic will additionally require + introducing a new preset version. + + Diagnostics are hierarchical and **must** be listed in order of a + depth-first search. (If you imagine the order of items in a typical tree + view which has been fully expanded, that is depth-first order.) Each + diagnostic has a direct parent. Recursive alterations to a diagnostic will + also affect all descendant diagnostics. + +2. A documentation page for the new diagnostic must be created under + ``Help/diagnostic``, and a link to the same added to the Diagnostics + manual, ``Help/manual/cmake-diagnostics.7.rst``. + +3. The new presets fields must be mentioned in the CMake presets version + history, found at the bottom of ``Help/manual/cmake-presets.7.rst``. Note + that the documentation of the fields themselves is generated. + +4. The ``Utilities/Scripts/regenerate-presets.py`` script must be run to + generate the updated presets schema and documentation. Don't forget to + review and commit the changes made by this script. From 97d13c3053797f97fedef66a12c1e9ec621c693c Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 30 Apr 2026 15:14:02 -0400 Subject: [PATCH 3/5] 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. --- Help/command/install.rst | 5 +- Help/diagnostic/CMD_AUTHOR.rst | 16 +++ Help/diagnostic/CMD_DEPRECATED.rst | 9 ++ .../CMD_INSTALL_ABSOLUTE_DESTINATION.rst | 9 ++ Help/diagnostic/CMD_UNINITIALIZED.rst | 7 ++ Help/diagnostic/CMD_UNUSED_CLI.rst | 12 ++ Help/manual/cmake-diagnostics.7.rst | 113 ++++++++---------- .../install-absolute-dest-configure-time.rst | 12 +- ..._ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst | 5 +- ...E_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst | 5 +- Utilities/Sphinx/cmake.py | 77 ++++++++++++ 11 files changed, 195 insertions(+), 75 deletions(-) create mode 100644 Help/diagnostic/CMD_AUTHOR.rst create mode 100644 Help/diagnostic/CMD_DEPRECATED.rst create mode 100644 Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst create mode 100644 Help/diagnostic/CMD_UNINITIALIZED.rst create mode 100644 Help/diagnostic/CMD_UNUSED_CLI.rst diff --git a/Help/command/install.rst b/Help/command/install.rst index 0d6ccb6116..e69d266749 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -61,9 +61,8 @@ signatures that specify them. The common options are: but not recommended. .. versionadded:: 4.4 - The :ref:`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. diff --git a/Help/diagnostic/CMD_AUTHOR.rst b/Help/diagnostic/CMD_AUTHOR.rst new file mode 100644 index 0000000000..c309f310a6 --- /dev/null +++ b/Help/diagnostic/CMD_AUTHOR.rst @@ -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). diff --git a/Help/diagnostic/CMD_DEPRECATED.rst b/Help/diagnostic/CMD_DEPRECATED.rst new file mode 100644 index 0000000000..dfb23d59fc --- /dev/null +++ b/Help/diagnostic/CMD_DEPRECATED.rst @@ -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)`. diff --git a/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst b/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst new file mode 100644 index 0000000000..90380d08a9 --- /dev/null +++ b/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst @@ -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. diff --git a/Help/diagnostic/CMD_UNINITIALIZED.rst b/Help/diagnostic/CMD_UNINITIALIZED.rst new file mode 100644 index 0000000000..8c2edc84e2 --- /dev/null +++ b/Help/diagnostic/CMD_UNINITIALIZED.rst @@ -0,0 +1,7 @@ +CMD_UNINITIALIZED +----------------- + +.. diagnostic:: + :default: ignore + + Warn if an uninitialized variable is dereferenced. diff --git a/Help/diagnostic/CMD_UNUSED_CLI.rst b/Help/diagnostic/CMD_UNUSED_CLI.rst new file mode 100644 index 0000000000..718598eb8d --- /dev/null +++ b/Help/diagnostic/CMD_UNUSED_CLI.rst @@ -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. diff --git a/Help/manual/cmake-diagnostics.7.rst b/Help/manual/cmake-diagnostics.7.rst index 5612299aae..de2b7057ce 100644 --- a/Help/manual/cmake-diagnostics.7.rst +++ b/Help/manual/cmake-diagnostics.7.rst @@ -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 ` 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 `. + +* The :option:`-W[no-][error=] ` 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 diff --git a/Help/release/dev/install-absolute-dest-configure-time.rst b/Help/release/dev/install-absolute-dest-configure-time.rst index 25a9c0add3..580a46c9f1 100644 --- a/Help/release/dev/install-absolute-dest-configure-time.rst +++ b/Help/release/dev/install-absolute-dest-configure-time.rst @@ -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 ` - diagnostic category. This diagnostic may be controlled with the - :option:`-Winstall-absolute-destination ` 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 ` command-line option, + the ``installAbsoluteDestination`` field in a + :manual:`CMake Presets ` + :preset:`configurePresets.warnings` object, + or the :command:`cmake_diagnostic` command. diff --git a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst index 84a27e5fe0..5ee7bf3a10 100644 --- a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst +++ b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst @@ -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 ` - 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`. diff --git a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst index fac680ea95..ac40b3d8ab 100644 --- a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst +++ b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst @@ -10,8 +10,7 @@ warning messages from the script. .. versionadded:: 4.4 - The :ref:`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`. diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py index ca0b7a1377..9cac302b32 100644 --- a/Utilities/Sphinx/cmake.py +++ b/Utilities/Sphinx/cmake.py @@ -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} `') + + def _build_preset_refs(self) -> list[Node]: + p = self._preset_name() + w = f':preset:`warnings.{p} `' + e = f':preset:`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*)(?$', 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(), From a882ec84ec09d30d203183c8f4af540f514df646 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 30 Apr 2026 15:27:44 -0400 Subject: [PATCH 4/5] cmDocumentation: Add diagnostics Teach cmDocumentation to provide help for diagnostics. Teach cmRST about the new diagnostic role and directive. --- Source/cmDocumentation.cxx | 45 +++++++++++++++++++++++++++++++++++++- Source/cmDocumentation.h | 4 ++++ Source/cmRST.cxx | 4 ++-- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 66e3730dcf..0cc2b64d07 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -26,7 +26,7 @@ #include "cmVersion.h" namespace { -cmDocumentationEntry const cmDocumentationStandardOptions[21] = { +cmDocumentationEntry const cmDocumentationStandardOptions[] = { { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." }, { "--version[=json-v1],-version[=json-v1],/V[=json-v1],/version[=json-v1] " "[]", @@ -39,6 +39,12 @@ cmDocumentationEntry const cmDocumentationStandardOptions[21] = { { "--help-command-list []", "List commands with help available and exit." }, { "--help-commands []", "Print cmake-commands manual and exit." }, + { "--help-diagnostic []", + "Print help for one diagnostic and exit." }, + { "--help-diagnostic-list []", + "List diagnostics with help available and exit." }, + { "--help-diagnostics []", + "Print cmake-diagnostics manual and exit." }, { "--help-module []", "Print help for one module and exit." }, { "--help-module-list []", "List modules with help available and exit." }, @@ -164,6 +170,8 @@ bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os) return this->PrintHelpOneManual(os); case cmDocumentation::OneCommand: return this->PrintHelpOneCommand(os); + case cmDocumentation::OneDiagnostic: + return this->PrintHelpOneDiagnostic(os); case cmDocumentation::OneModule: return this->PrintHelpOneModule(os); case cmDocumentation::OnePolicy: @@ -176,6 +184,8 @@ bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os) return this->PrintHelpListManuals(os); case cmDocumentation::ListCommands: return this->PrintHelpListCommands(os); + case cmDocumentation::ListDiagnostics: + return this->PrintHelpListDiagnostics(os); case cmDocumentation::ListModules: return this->PrintHelpListModules(os); case cmDocumentation::ListProperties: @@ -377,6 +387,11 @@ bool cmDocumentation::CheckOptions(int argc, char const* const* argv, cmSystemTools::Message( "Warning: --help-compatcommands no longer supported"); return true; + } else if (strcmp(argv[i], "--help-diagnostics") == 0) { + help.HelpType = cmDocumentation::OneManual; + help.Argument = "cmake-diagnostics.7"; + i += int(get_opt_argument(i + 1, help.Filename)); + this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-full") == 0) { help.HelpType = cmDocumentation::Full; i += int(get_opt_argument(i + 1, help.Filename)); @@ -393,6 +408,12 @@ bool cmDocumentation::CheckOptions(int argc, char const* const* argv, i += int(get_opt_argument(i + 1, help.Filename)); help.Argument = cmSystemTools::LowerCase(help.Argument); this->WarnFormFromFilename(help, result); + } else if (strcmp(argv[i], "--help-diagnostic") == 0) { + help.HelpType = cmDocumentation::OneDiagnostic; + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); + help.Argument = cmSystemTools::UpperCase(help.Argument); + this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-module") == 0) { help.HelpType = cmDocumentation::OneModule; i += int(get_opt_argument(i + 1, help.Argument)); @@ -421,6 +442,9 @@ bool cmDocumentation::CheckOptions(int argc, char const* const* argv, } else if (strcmp(argv[i], "--help-command-list") == 0) { help.HelpType = cmDocumentation::ListCommands; i += int(get_opt_argument(i + 1, help.Filename)); + } else if (strcmp(argv[i], "--help-diagnostic-list") == 0) { + help.HelpType = cmDocumentation::ListDiagnostics; + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-module-list") == 0) { help.HelpType = cmDocumentation::ListModules; i += int(get_opt_argument(i + 1, help.Filename)); @@ -622,6 +646,25 @@ bool cmDocumentation::PrintHelpListCommands(std::ostream& os) return true; } +bool cmDocumentation::PrintHelpOneDiagnostic(std::ostream& os) +{ + std::string dname = cmSystemTools::UpperCase(this->CurrentArgument); + if (this->PrintFiles(os, cmStrCat("diagnostic/", dname))) { + return true; + } + // Argument was not a command. Complain. + os << "Argument \"" << this->CurrentArgument + << "\" to --help-command is not a CMake diagnostic. " + "Use --help-diagnostic-list to see all diagnostics.\n"; + return false; +} + +bool cmDocumentation::PrintHelpListDiagnostics(std::ostream& os) +{ + this->PrintNames(os, "diagnostic/*"); + return true; +} + bool cmDocumentation::PrintHelpOneModule(std::ostream& os) { std::string mname = this->CurrentArgument; diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h index dd0fadba0f..e23cee9fe9 100644 --- a/Source/cmDocumentation.h +++ b/Source/cmDocumentation.h @@ -30,6 +30,7 @@ public: Full, ListManuals, ListCommands, + ListDiagnostics, ListModules, ListProperties, ListVariables, @@ -38,6 +39,7 @@ public: OneArbitrary, OneManual, OneCommand, + OneDiagnostic, OneModule, OneProperty, OneVariable, @@ -124,12 +126,14 @@ private: bool PrintHelpOneArbitrary(std::ostream& os); bool PrintHelpOneManual(std::ostream& os); bool PrintHelpOneCommand(std::ostream& os); + bool PrintHelpOneDiagnostic(std::ostream& os); bool PrintHelpOneModule(std::ostream& os); bool PrintHelpOnePolicy(std::ostream& os); bool PrintHelpOneProperty(std::ostream& os); bool PrintHelpOneVariable(std::ostream& os); bool PrintHelpListManuals(std::ostream& os); bool PrintHelpListCommands(std::ostream& os); + bool PrintHelpListDiagnostics(std::ostream& os); bool PrintHelpListModules(std::ostream& os); bool PrintHelpListProperties(std::ostream& os); bool PrintHelpListVariables(std::ostream& os); diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx index e49037099e..0d3f3bcfe2 100644 --- a/Source/cmRST.cxx +++ b/Source/cmRST.cxx @@ -20,7 +20,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot) : OS(os) , DocRoot(std::move(docroot)) , CMakeDirective("^.. (cmake:)?(" - "command|envvar|genex|signature|variable" + "command|diagnostic|envvar|genex|signature|variable" ")::") , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$") , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$") @@ -34,7 +34,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot) , ModuleRST(R"(^#\[(=*)\[\.rst:$)") , CMakeRole("(:cmake)?:(" "cref|" - "command|cpack_gen|generator|genex|" + "command|cpack_gen|diagnostic|generator|genex|" "variable|envvar|module|policy|" "prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|" "prop_test|prop_tgt|" From 95f7f8460964060eacc10bae26f66492f4541e7c Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Fri, 1 May 2026 13:00:10 -0400 Subject: [PATCH 5/5] Help: Fix CMD_INSTALL_ABSOLUTE_DESTINATION documentation CMD_INSTALL_ABSOLUTE_DESTINATION is a child of CMD_AUTHOR, but this was not noted in the documentation. Add the missing annotation. --- Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst b/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst index 90380d08a9..b7c6e0865a 100644 --- a/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst +++ b/Help/diagnostic/CMD_INSTALL_ABSOLUTE_DESTINATION.rst @@ -3,6 +3,7 @@ CMD_INSTALL_ABSOLUTE_DESTINATION .. diagnostic:: :default: ignore + :parent: CMD_AUTHOR Warn when an :command:`install` command specifies an absolute ``DESTINATION`` path. Absolute destinations are typically undesirable because they prevent