Skip to content

Latest commit

 

History

History
157 lines (118 loc) · 7.15 KB

File metadata and controls

157 lines (118 loc) · 7.15 KB

CMake Diagnostics Guide

The following is a guide on how CMake should issue diagnostics. See documentation on CMake Development for more information.

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:

mf->IssueMessage(MessageType::AUTHOR_WARNING, ...);

CMake 4.4 and later should write:

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:

    #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.