Browse Source

Merge topic 'improve-doc-signatures'

533ebb072b Help: Use signature directive for string command
cd33f461a6 Help: Use signature directive for cmake_language command
74e3c1d313 Utilities/Sphinx: Add a directive to document command signatures
c09b760484 Utilities/Sphinx: Drop commented-out code from cmake domain impl
6e85ad7f8b Help/dev: Add per-directive sections in CMake Documentation Guide

Acked-by: Kitware Robot <[email protected]>
Merge-request: !8243
Brad King 2 years ago
parent
commit
3d6075da4d

+ 153 - 166
Help/command/cmake_language.rst

@@ -27,163 +27,155 @@ those created via the :command:`macro` or :command:`function` commands.
 Calling Commands
 ^^^^^^^^^^^^^^^^
 
-.. _CALL:
-
-.. code-block:: cmake
-
+.. signature::
   cmake_language(CALL <command> [<arg>...])
 
-Calls the named ``<command>`` with the given arguments (if any).
-For example, the code:
+  Calls the named ``<command>`` with the given arguments (if any).
+  For example, the code:
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  set(message_command "message")
-  cmake_language(CALL ${message_command} STATUS "Hello World!")
+    set(message_command "message")
+    cmake_language(CALL ${message_command} STATUS "Hello World!")
 
-is equivalent to
+  is equivalent to
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  message(STATUS "Hello World!")
+    message(STATUS "Hello World!")
 
-.. note::
-  To ensure consistency of the code, the following commands are not allowed:
+  .. note::
+    To ensure consistency of the code, the following commands are not allowed:
 
-  * ``if`` / ``elseif`` / ``else`` / ``endif``
-  * ``block`` / ``endblock``
-  * ``while`` / ``endwhile``
-  * ``foreach`` / ``endforeach``
-  * ``function`` / ``endfunction``
-  * ``macro`` / ``endmacro``
+    * ``if`` / ``elseif`` / ``else`` / ``endif``
+    * ``block`` / ``endblock``
+    * ``while`` / ``endwhile``
+    * ``foreach`` / ``endforeach``
+    * ``function`` / ``endfunction``
+    * ``macro`` / ``endmacro``
 
 Evaluating Code
 ^^^^^^^^^^^^^^^
 
-.. _EVAL:
-
-.. code-block:: cmake
-
+.. signature::
   cmake_language(EVAL CODE <code>...)
+  :target: EVAL
 
-Evaluates the ``<code>...`` as CMake code.
+  Evaluates the ``<code>...`` as CMake code.
 
-For example, the code:
+  For example, the code:
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  set(A TRUE)
-  set(B TRUE)
-  set(C TRUE)
-  set(condition "(A AND B) OR C")
+    set(A TRUE)
+    set(B TRUE)
+    set(C TRUE)
+    set(condition "(A AND B) OR C")
 
-  cmake_language(EVAL CODE "
-    if (${condition})
-      message(STATUS TRUE)
-    else()
-      message(STATUS FALSE)
-    endif()"
-  )
+    cmake_language(EVAL CODE "
+      if (${condition})
+        message(STATUS TRUE)
+      else()
+        message(STATUS FALSE)
+      endif()"
+    )
 
-is equivalent to
+  is equivalent to
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  set(A TRUE)
-  set(B TRUE)
-  set(C TRUE)
-  set(condition "(A AND B) OR C")
-
-  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "
-    if (${condition})
-      message(STATUS TRUE)
-    else()
-      message(STATUS FALSE)
-    endif()"
-  )
+    set(A TRUE)
+    set(B TRUE)
+    set(C TRUE)
+    set(condition "(A AND B) OR C")
 
-  include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)
+    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "
+      if (${condition})
+        message(STATUS TRUE)
+      else()
+        message(STATUS FALSE)
+      endif()"
+    )
+
+    include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)
 
 Deferring Calls
 ^^^^^^^^^^^^^^^
 
 .. versionadded:: 3.19
 
-.. _DEFER:
-
-.. code-block:: cmake
-
+.. signature::
   cmake_language(DEFER <options>... CALL <command> [<arg>...])
 
-Schedules a call to the named ``<command>`` with the given arguments (if any)
-to occur at a later time.  By default, deferred calls are executed as if
-written at the end of the current directory's ``CMakeLists.txt`` file,
-except that they run even after a :command:`return` call.  Variable
-references in arguments are evaluated at the time the deferred call is
-executed.
+  Schedules a call to the named ``<command>`` with the given arguments (if any)
+  to occur at a later time.  By default, deferred calls are executed as if
+  written at the end of the current directory's ``CMakeLists.txt`` file,
+  except that they run even after a :command:`return` call.  Variable
+  references in arguments are evaluated at the time the deferred call is
+  executed.
 
-The options are:
+  The options are:
 
-``DIRECTORY <dir>``
-  Schedule the call for the end of the given directory instead of the
-  current directory.  The ``<dir>`` may reference either a source
-  directory or its corresponding binary directory.  Relative paths are
-  treated as relative to the current source directory.
+  ``DIRECTORY <dir>``
+    Schedule the call for the end of the given directory instead of the
+    current directory.  The ``<dir>`` may reference either a source
+    directory or its corresponding binary directory.  Relative paths are
+    treated as relative to the current source directory.
 
-  The given directory must be known to CMake, being either the top-level
-  directory or one added by :command:`add_subdirectory`.  Furthermore,
-  the given directory must not yet be finished processing.  This means
-  it can be the current directory or one of its ancestors.
+    The given directory must be known to CMake, being either the top-level
+    directory or one added by :command:`add_subdirectory`.  Furthermore,
+    the given directory must not yet be finished processing.  This means
+    it can be the current directory or one of its ancestors.
 
-``ID <id>``
-  Specify an identification for the deferred call.
-  The ``<id>`` may not be empty and may not begin with a capital letter ``A-Z``.
-  The ``<id>`` may begin with an underscore (``_``) only if it was generated
-  automatically by an earlier call that used ``ID_VAR`` to get the id.
+  ``ID <id>``
+    Specify an identification for the deferred call.
+    The ``<id>`` may not be empty and may not begin with a capital letter ``A-Z``.
+    The ``<id>`` may begin with an underscore (``_``) only if it was generated
+    automatically by an earlier call that used ``ID_VAR`` to get the id.
 
-``ID_VAR <var>``
-  Specify a variable in which to store the identification for the
-  deferred call.  If ``ID <id>`` is not given, a new identification
-  will be generated and the generated id will start with an underscore (``_``).
+  ``ID_VAR <var>``
+    Specify a variable in which to store the identification for the
+    deferred call.  If ``ID <id>`` is not given, a new identification
+    will be generated and the generated id will start with an underscore (``_``).
 
-The currently scheduled list of deferred calls may be retrieved:
+  The currently scheduled list of deferred calls may be retrieved:
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>)
+    cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>)
 
-This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language
-Lists>` of deferred call ids.  The ids are for the directory scope in which
-the calls have been deferred to (i.e. where they will be executed), which can
-be different to the scope in which they were created.  The ``DIRECTORY``
-option can be used to specify the scope for which to retrieve the call ids.
-If that option is not given, the call ids for the current directory scope will
-be returned.
+  This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language
+  Lists>` of deferred call ids.  The ids are for the directory scope in which
+  the calls have been deferred to (i.e. where they will be executed), which can
+  be different to the scope in which they were created.  The ``DIRECTORY``
+  option can be used to specify the scope for which to retrieve the call ids.
+  If that option is not given, the call ids for the current directory scope
+  will be returned.
 
-Details of a specific call may be retrieved from its id:
+  Details of a specific call may be retrieved from its id:
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>)
+    cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>)
 
-This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language
-Lists>` in which the first element is the name of the command to be
-called, and the remaining elements are its unevaluated arguments (any
-contained ``;`` characters are included literally and cannot be distinguished
-from multiple arguments).  If multiple calls are scheduled with the same id,
-this retrieves the first one.  If no call is scheduled with the given id in
-the specified ``DIRECTORY`` scope (or the current directory scope if no
-``DIRECTORY`` option is given), this stores an empty string in the variable.
+  This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language
+  Lists>` in which the first element is the name of the command to be
+  called, and the remaining elements are its unevaluated arguments (any
+  contained ``;`` characters are included literally and cannot be distinguished
+  from multiple arguments).  If multiple calls are scheduled with the same id,
+  this retrieves the first one.  If no call is scheduled with the given id in
+  the specified ``DIRECTORY`` scope (or the current directory scope if no
+  ``DIRECTORY`` option is given), this stores an empty string in the variable.
 
-Deferred calls may be canceled by their id:
+  Deferred calls may be canceled by their id:
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...)
+    cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...)
 
-This cancels all deferred calls matching any of the given ids in the specified
-``DIRECTORY`` scope (or the current directory scope if no ``DIRECTORY`` option
-is given).  Unknown ids are silently ignored.
+  This cancels all deferred calls matching any of the given ids in the specified
+  ``DIRECTORY`` scope (or the current directory scope if no ``DIRECTORY`` option
+  is given).  Unknown ids are silently ignored.
 
 Deferred Call Examples
 """"""""""""""""""""""
@@ -229,8 +221,6 @@ also prints::
   Deferred Message 1
   Deferred Message 2
 
-
-.. _SET_DEPENDENCY_PROVIDER:
 .. _dependency_providers:
 
 Dependency Providers
@@ -241,51 +231,50 @@ Dependency Providers
 .. note:: A high-level introduction to this feature can be found in the
           :ref:`Using Dependencies Guide <dependency_providers_overview>`.
 
-.. code-block:: cmake
-
+.. signature::
   cmake_language(SET_DEPENDENCY_PROVIDER <command>
                  SUPPORTED_METHODS <methods>...)
 
-When a call is made to :command:`find_package` or
-:command:`FetchContent_MakeAvailable`, the call may be forwarded to a
-dependency provider which then has the opportunity to fulfill the request.
-If the request is for one of the ``<methods>`` specified when the provider
-was set, CMake calls the provider's ``<command>`` with a set of
-method-specific arguments.  If the provider does not fulfill the request,
-or if the provider doesn't support the request's method, or no provider
-is set, the built-in :command:`find_package` or
-:command:`FetchContent_MakeAvailable` implementation is used to fulfill
-the request in the usual way.
-
-One or more of the following values can be specified for the ``<methods>``
-when setting the provider:
-
-``FIND_PACKAGE``
-  The provider command accepts :command:`find_package` requests.
-
-``FETCHCONTENT_MAKEAVAILABLE_SERIAL``
-  The provider command accepts :command:`FetchContent_MakeAvailable`
-  requests.  It expects each dependency to be fed to the provider command
-  one at a time, not the whole list in one go.
-
-Only one provider can be set at any point in time.  If a provider is already
-set when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called, the new
-provider replaces the previously set one.  The specified ``<command>`` must
-already exist when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called.
-As a special case, providing an empty string for the ``<command>`` and no
-``<methods>`` will discard any previously set provider.
-
-The dependency provider can only be set while processing one of the files
-specified by the :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable.
-Thus, dependency providers can only be set as part of the first call to
-:command:`project`.  Calling ``cmake_language(SET_DEPENDENCY_PROVIDER)``
-outside of that context will result in an error.
-
-.. note::
-  The choice of dependency provider should always be under the user's control.
-  As a convenience, a project may choose to provide a file that users can
-  list in their :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable, but
-  the use of such a file should always be the user's choice.
+  When a call is made to :command:`find_package` or
+  :command:`FetchContent_MakeAvailable`, the call may be forwarded to a
+  dependency provider which then has the opportunity to fulfill the request.
+  If the request is for one of the ``<methods>`` specified when the provider
+  was set, CMake calls the provider's ``<command>`` with a set of
+  method-specific arguments.  If the provider does not fulfill the request,
+  or if the provider doesn't support the request's method, or no provider
+  is set, the built-in :command:`find_package` or
+  :command:`FetchContent_MakeAvailable` implementation is used to fulfill
+  the request in the usual way.
+
+  One or more of the following values can be specified for the ``<methods>``
+  when setting the provider:
+
+  ``FIND_PACKAGE``
+    The provider command accepts :command:`find_package` requests.
+
+  ``FETCHCONTENT_MAKEAVAILABLE_SERIAL``
+    The provider command accepts :command:`FetchContent_MakeAvailable`
+    requests.  It expects each dependency to be fed to the provider command
+    one at a time, not the whole list in one go.
+
+  Only one provider can be set at any point in time.  If a provider is already
+  set when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called, the new
+  provider replaces the previously set one.  The specified ``<command>`` must
+  already exist when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called.
+  As a special case, providing an empty string for the ``<command>`` and no
+  ``<methods>`` will discard any previously set provider.
+
+  The dependency provider can only be set while processing one of the files
+  specified by the :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable.
+  Thus, dependency providers can only be set as part of the first call to
+  :command:`project`.  Calling ``cmake_language(SET_DEPENDENCY_PROVIDER)``
+  outside of that context will result in an error.
+
+  .. note::
+    The choice of dependency provider should always be under the user's control.
+    As a convenience, a project may choose to provide a file that users can
+    list in their :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable, but
+    the use of such a file should always be the user's choice.
 
 Provider commands
 """""""""""""""""
@@ -499,23 +488,21 @@ Getting current message log level
 
 .. versionadded:: 3.25
 
-.. _GET_MESSAGE_LOG_LEVEL:
 .. _query_message_log_level:
 
-.. code-block:: cmake
-
+.. signature::
   cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)
 
-Writes the current :command:`message` logging level
-into the given ``<output_variable>``.
+  Writes the current :command:`message` logging level
+  into the given ``<output_variable>``.
 
-See :command:`message` for the possible logging levels.
+  See :command:`message` for the possible logging levels.
 
-The current message logging level can be set either using the
-:option:`--log-level <cmake --log-level>`
-command line option of the :manual:`cmake(1)` program or using
-the :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable.
+  The current message logging level can be set either using the
+  :option:`--log-level <cmake --log-level>`
+  command line option of the :manual:`cmake(1)` program or using
+  the :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable.
 
-If both the command line option and the variable are set, the command line
-option takes precedence. If neither are set, the default logging level
-is returned.
+  If both the command line option and the variable are set, the command line
+  option takes precedence. If neither are set, the default logging level
+  is returned.

+ 256 - 330
Help/command/string.rst

@@ -45,16 +45,16 @@ Synopsis
 
   `JSON`_
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
-           {:ref:`GET <JSON_GET>` | :ref:`TYPE <JSON_TYPE>` | :ref:`LENGTH <JSON_LENGTH>` | :ref:`REMOVE <JSON_REMOVE>`}
+           {`GET <JSON GET_>`_ | `TYPE <JSON TYPE_>`_ | `LENGTH <JSON LENGTH_>`_ | `REMOVE <JSON REMOVE_>`_}
            <json-string> <member|index> [<member|index> ...])
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
-           :ref:`MEMBER <JSON_MEMBER>` <json-string>
+           `MEMBER <JSON MEMBER_>`_ <json-string>
            [<member|index> ...] <index>)
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
-           :ref:`SET <JSON_SET>` <json-string>
+           `SET <JSON SET_>`_ <json-string>
            <member|index> [<member|index> ...] <value>)
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
-           :ref:`EQUAL <JSON_EQUAL>` <json-string1> <json-string2>)
+           `EQUAL <JSON EQUAL_>`_ <json-string1> <json-string2>)
 
 Search and Replace
 ^^^^^^^^^^^^^^^^^^
@@ -62,75 +62,60 @@ Search and Replace
 Search and Replace With Plain Strings
 """""""""""""""""""""""""""""""""""""
 
-.. _FIND:
-
-.. code-block:: cmake
-
+.. signature::
   string(FIND <string> <substring> <output_variable> [REVERSE])
 
-Return the position where the given ``<substring>`` was found in
-the supplied ``<string>``.  If the ``REVERSE`` flag was used, the command will
-search for the position of the last occurrence of the specified
-``<substring>``.  If the ``<substring>`` is not found, a position of -1 is
-returned.
-
-The ``string(FIND)`` subcommand treats all strings as ASCII-only characters.
-The index stored in ``<output_variable>`` will also be counted in bytes,
-so strings containing multi-byte characters may lead to unexpected results.
+  Return the position where the given ``<substring>`` was found in
+  the supplied ``<string>``.  If the ``REVERSE`` flag was used, the command
+  will search for the position of the last occurrence of the specified
+  ``<substring>``.  If the ``<substring>`` is not found, a position of -1 is
+  returned.
 
-.. _REPLACE:
-
-.. code-block:: cmake
+  The ``string(FIND)`` subcommand treats all strings as ASCII-only characters.
+  The index stored in ``<output_variable>`` will also be counted in bytes,
+  so strings containing multi-byte characters may lead to unexpected results.
 
+.. signature::
   string(REPLACE <match_string>
          <replace_string> <output_variable>
          <input> [<input>...])
 
-Replace all occurrences of ``<match_string>`` in the ``<input>``
-with ``<replace_string>`` and store the result in the ``<output_variable>``.
+  Replace all occurrences of ``<match_string>`` in the ``<input>``
+  with ``<replace_string>`` and store the result in the ``<output_variable>``.
 
 Search and Replace With Regular Expressions
 """""""""""""""""""""""""""""""""""""""""""
 
-.. _`REGEX MATCH`:
-
-.. code-block:: cmake
-
+.. signature::
   string(REGEX MATCH <regular_expression>
          <output_variable> <input> [<input>...])
 
-Match the ``<regular_expression>`` once and store the match in the
-``<output_variable>``.
-All ``<input>`` arguments are concatenated before matching.
-Regular expressions are specified in the subsection just below.
-
-.. _`REGEX MATCHALL`:
-
-.. code-block:: cmake
+  Match the ``<regular_expression>`` once and store the match in the
+  ``<output_variable>``.
+  All ``<input>`` arguments are concatenated before matching.
+  Regular expressions are specified in the subsection just below.
 
+.. signature::
   string(REGEX MATCHALL <regular_expression>
          <output_variable> <input> [<input>...])
 
-Match the ``<regular_expression>`` as many times as possible and store the
-matches in the ``<output_variable>`` as a list.
-All ``<input>`` arguments are concatenated before matching.
-
-.. _`REGEX REPLACE`:
-
-.. code-block:: cmake
+  Match the ``<regular_expression>`` as many times as possible and store the
+  matches in the ``<output_variable>`` as a list.
+  All ``<input>`` arguments are concatenated before matching.
 
+.. signature::
   string(REGEX REPLACE <regular_expression>
          <replacement_expression> <output_variable>
          <input> [<input>...])
 
-Match the ``<regular_expression>`` as many times as possible and substitute
-the ``<replacement_expression>`` for the match in the output.
-All ``<input>`` arguments are concatenated before matching.
+  Match the ``<regular_expression>`` as many times as possible and substitute
+  the ``<replacement_expression>`` for the match in the output.
+  All ``<input>`` arguments are concatenated before matching.
 
-The ``<replacement_expression>`` may refer to parenthesis-delimited
-subexpressions of the match using ``\1``, ``\2``, ..., ``\9``.  Note that
-two backslashes (``\\1``) are required in CMake code to get a backslash
-through argument parsing.
+  The ``<replacement_expression>`` may refer to parenthesis-delimited
+  subexpressions of the match using ``\1``, ``\2``, ..., ``\9``.  Note that
+  two backslashes (``\\1``) are required in CMake code to get a backslash
+  through argument parsing.
 
 .. _`Regex Specification`:
 
@@ -201,130 +186,100 @@ newlines, and backslashes (respectively) to pass in a regex.  For example:
 Manipulation
 ^^^^^^^^^^^^
 
-.. _APPEND:
-
-.. code-block:: cmake
-
+.. signature::
   string(APPEND <string_variable> [<input>...])
 
-.. versionadded:: 3.4
-
-Append all the ``<input>`` arguments to the string.
+  .. versionadded:: 3.4
 
-.. _PREPEND:
-
-.. code-block:: cmake
+  Append all the ``<input>`` arguments to the string.
 
+.. signature::
   string(PREPEND <string_variable> [<input>...])
 
-.. versionadded:: 3.10
-
-Prepend all the ``<input>`` arguments to the string.
-
-.. _CONCAT:
+  .. versionadded:: 3.10
 
-.. code-block:: cmake
+  Prepend all the ``<input>`` arguments to the string.
 
+.. signature::
   string(CONCAT <output_variable> [<input>...])
 
-Concatenate all the ``<input>`` arguments together and store
-the result in the named ``<output_variable>``.
-
-.. _JOIN:
-
-.. code-block:: cmake
+  Concatenate all the ``<input>`` arguments together and store
+  the result in the named ``<output_variable>``.
 
+.. signature::
   string(JOIN <glue> <output_variable> [<input>...])
 
-.. versionadded:: 3.12
-
-Join all the ``<input>`` arguments together using the ``<glue>``
-string and store the result in the named ``<output_variable>``.
-
-To join a list's elements, prefer to use the ``JOIN`` operator
-from the :command:`list` command.  This allows for the elements to have
-special characters like ``;`` in them.
+  .. versionadded:: 3.12
 
-.. _TOLOWER:
+  Join all the ``<input>`` arguments together using the ``<glue>``
+  string and store the result in the named ``<output_variable>``.
 
-.. code-block:: cmake
+  To join a list's elements, prefer to use the ``JOIN`` operator
+  from the :command:`list` command.  This allows for the elements to have
+  special characters like ``;`` in them.
 
+.. signature::
   string(TOLOWER <string> <output_variable>)
 
-Convert ``<string>`` to lower characters.
-
-.. _TOUPPER:
-
-.. code-block:: cmake
+  Convert ``<string>`` to lower characters.
 
+.. signature::
   string(TOUPPER <string> <output_variable>)
 
-Convert ``<string>`` to upper characters.
-
-.. _LENGTH:
-
-.. code-block:: cmake
+  Convert ``<string>`` to upper characters.
 
+.. signature::
   string(LENGTH <string> <output_variable>)
 
-Store in an ``<output_variable>`` a given string's length in bytes.
-Note that this means if ``<string>`` contains multi-byte characters, the
-result stored in ``<output_variable>`` will *not* be the number of characters.
-
-.. _SUBSTRING:
-
-.. code-block:: cmake
+  Store in an ``<output_variable>`` a given string's length in bytes.
+  Note that this means if ``<string>`` contains multi-byte characters,
+  the result stored in ``<output_variable>`` will *not* be
+  the number of characters.
 
+.. signature::
   string(SUBSTRING <string> <begin> <length> <output_variable>)
 
-Store in an ``<output_variable>`` a substring of a given ``<string>``.  If
-``<length>`` is ``-1`` the remainder of the string starting at ``<begin>``
-will be returned.
-
-.. versionchanged:: 3.2
-  If ``<string>`` is shorter than ``<length>`` then the end of the string
-  is used instead.  Previous versions of CMake reported an error in this case.
-
-Both ``<begin>`` and ``<length>`` are counted in bytes, so care must
-be exercised if ``<string>`` could contain multi-byte characters.
+  Store in an ``<output_variable>`` a substring of a given ``<string>``.  If
+  ``<length>`` is ``-1`` the remainder of the string starting at ``<begin>``
+  will be returned.
 
-.. _STRIP:
+  .. versionchanged:: 3.2
+    If ``<string>`` is shorter than ``<length>``
+    then the end of the string is used instead.
+    Previous versions of CMake reported an error in this case.
 
-.. code-block:: cmake
+  Both ``<begin>`` and ``<length>`` are counted in bytes, so care must
+  be exercised if ``<string>`` could contain multi-byte characters.
 
+.. signature::
   string(STRIP <string> <output_variable>)
 
-Store in an ``<output_variable>`` a substring of a given ``<string>`` with
-leading and trailing spaces removed.
-
-.. _GENEX_STRIP:
-
-.. code-block:: cmake
+  Store in an ``<output_variable>`` a substring of a given ``<string>``
+  with leading and trailing spaces removed.
 
+.. signature::
   string(GENEX_STRIP <string> <output_variable>)
 
-.. versionadded:: 3.1
-
-Strip any :manual:`generator expressions <cmake-generator-expressions(7)>`
-from the input ``<string>`` and store the result in the ``<output_variable>``.
-
-.. _REPEAT:
+  .. versionadded:: 3.1
 
-.. code-block:: cmake
+  Strip any :manual:`generator expressions <cmake-generator-expressions(7)>`
+  from the input ``<string>`` and store the result
+  in the ``<output_variable>``.
 
+.. signature::
   string(REPEAT <string> <count> <output_variable>)
 
-.. versionadded:: 3.15
+  .. versionadded:: 3.15
 
-Produce the output string as the input ``<string>`` repeated ``<count>`` times.
+  Produce the output string as the input ``<string>``
+  repeated ``<count>`` times.
 
 Comparison
 ^^^^^^^^^^
 
 .. _COMPARE:
 
-.. code-block:: cmake
-
+.. signature::
   string(COMPARE LESS <string1> <string2> <output_variable>)
   string(COMPARE GREATER <string1> <string2> <output_variable>)
   string(COMPARE EQUAL <string1> <string2> <output_variable>)
@@ -332,240 +287,217 @@ Comparison
   string(COMPARE LESS_EQUAL <string1> <string2> <output_variable>)
   string(COMPARE GREATER_EQUAL <string1> <string2> <output_variable>)
 
-Compare the strings and store true or false in the ``<output_variable>``.
+  Compare the strings and store true or false in the ``<output_variable>``.
 
-.. versionadded:: 3.7
-  Added the ``LESS_EQUAL`` and ``GREATER_EQUAL`` options.
+  .. versionadded:: 3.7
+    Added the ``LESS_EQUAL`` and ``GREATER_EQUAL`` options.
 
 .. _`Supported Hash Algorithms`:
 
 Hashing
 ^^^^^^^
 
-.. _`HASH`:
-
-.. code-block:: cmake
-
+.. signature::
   string(<HASH> <output_variable> <input>)
+  :target: HASH
+
+  Compute a cryptographic hash of the ``<input>`` string.
+  The supported ``<HASH>`` algorithm names are:
+
+  ``MD5``
+    Message-Digest Algorithm 5, RFC 1321.
+  ``SHA1``
+    US Secure Hash Algorithm 1, RFC 3174.
+  ``SHA224``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA256``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA384``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA512``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA3_224``
+    Keccak SHA-3.
+  ``SHA3_256``
+    Keccak SHA-3.
+  ``SHA3_384``
+    Keccak SHA-3.
+  ``SHA3_512``
+    Keccak SHA-3.
 
-Compute a cryptographic hash of the ``<input>`` string.
-The supported ``<HASH>`` algorithm names are:
-
-``MD5``
-  Message-Digest Algorithm 5, RFC 1321.
-``SHA1``
-  US Secure Hash Algorithm 1, RFC 3174.
-``SHA224``
-  US Secure Hash Algorithms, RFC 4634.
-``SHA256``
-  US Secure Hash Algorithms, RFC 4634.
-``SHA384``
-  US Secure Hash Algorithms, RFC 4634.
-``SHA512``
-  US Secure Hash Algorithms, RFC 4634.
-``SHA3_224``
-  Keccak SHA-3.
-``SHA3_256``
-  Keccak SHA-3.
-``SHA3_384``
-  Keccak SHA-3.
-``SHA3_512``
-  Keccak SHA-3.
-
-.. versionadded:: 3.8
-  Added the ``SHA3_*`` hash algorithms.
+  .. versionadded:: 3.8
+    Added the ``SHA3_*`` hash algorithms.
 
 Generation
 ^^^^^^^^^^
 
-.. _ASCII:
-
-.. code-block:: cmake
-
+.. signature::
   string(ASCII <number> [<number> ...] <output_variable>)
 
-Convert all numbers into corresponding ASCII characters.
-
-.. _HEX:
-
-.. code-block:: cmake
+  Convert all numbers into corresponding ASCII characters.
 
+.. signature::
   string(HEX <string> <output_variable>)
 
-.. versionadded:: 3.18
-
-Convert each byte in the input ``<string>`` to its hexadecimal representation
-and store the concatenated hex digits in the ``<output_variable>``. Letters in
-the output (``a`` through ``f``) are in lowercase.
+  .. versionadded:: 3.18
 
-.. _CONFIGURE:
-
-.. code-block:: cmake
+  Convert each byte in the input ``<string>`` to its hexadecimal representation
+  and store the concatenated hex digits in the ``<output_variable>``.
+  Letters in the output (``a`` through ``f``) are in lowercase.
 
+.. signature::
   string(CONFIGURE <string> <output_variable>
          [@ONLY] [ESCAPE_QUOTES])
 
-Transform a ``<string>`` like :command:`configure_file` transforms a file.
-
-.. _MAKE_C_IDENTIFIER:
-
-.. code-block:: cmake
+  Transform a ``<string>`` like :command:`configure_file` transforms a file.
 
+.. signature::
   string(MAKE_C_IDENTIFIER <string> <output_variable>)
 
-Convert each non-alphanumeric character in the input ``<string>`` to an
-underscore and store the result in the ``<output_variable>``.  If the first
-character of the ``<string>`` is a digit, an underscore will also be prepended
-to the result.
-
-.. _RANDOM:
-
-.. code-block:: cmake
+  Convert each non-alphanumeric character in the input ``<string>`` to an
+  underscore and store the result in the ``<output_variable>``.  If the first
+  character of the ``<string>`` is a digit, an underscore will also be
+  prepended to the result.
 
+.. signature::
   string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]
          [RANDOM_SEED <seed>] <output_variable>)
 
-Return a random string of given ``<length>`` consisting of
-characters from the given ``<alphabet>``.  Default length is 5 characters
-and default alphabet is all numbers and upper and lower case letters.
-If an integer ``RANDOM_SEED`` is given, its value will be used to seed the
-random number generator.
-
-.. _TIMESTAMP:
-
-.. code-block:: cmake
+  Return a random string of given ``<length>`` consisting of
+  characters from the given ``<alphabet>``.  Default length is 5 characters
+  and default alphabet is all numbers and upper and lower case letters.
+  If an integer ``RANDOM_SEED`` is given, its value will be used to seed the
+  random number generator.
 
+.. signature::
   string(TIMESTAMP <output_variable> [<format_string>] [UTC])
 
-Write a string representation of the current date
-and/or time to the ``<output_variable>``.
-
-If the command is unable to obtain a timestamp, the ``<output_variable>``
-will be set to the empty string ``""``.
+  Write a string representation of the current date
+  and/or time to the ``<output_variable>``.
 
-The optional ``UTC`` flag requests the current date/time representation to
-be in Coordinated Universal Time (UTC) rather than local time.
+  If the command is unable to obtain a timestamp, the ``<output_variable>``
+  will be set to the empty string ``""``.
 
-The optional ``<format_string>`` may contain the following format
-specifiers:
-
-``%%``
-  .. versionadded:: 3.8
+  The optional ``UTC`` flag requests the current date/time representation to
+  be in Coordinated Universal Time (UTC) rather than local time.
 
-  A literal percent sign (%).
+  The optional ``<format_string>`` may contain the following format
+  specifiers:
 
-``%d``
-  The day of the current month (01-31).
+  ``%%``
+    .. versionadded:: 3.8
 
-``%H``
-  The hour on a 24-hour clock (00-23).
+    A literal percent sign (%).
 
-``%I``
-  The hour on a 12-hour clock (01-12).
+  ``%d``
+    The day of the current month (01-31).
 
-``%j``
-  The day of the current year (001-366).
+  ``%H``
+    The hour on a 24-hour clock (00-23).
 
-``%m``
-  The month of the current year (01-12).
+  ``%I``
+    The hour on a 12-hour clock (01-12).
 
-``%b``
-  .. versionadded:: 3.7
+  ``%j``
+    The day of the current year (001-366).
 
-  Abbreviated month name (e.g. Oct).
+  ``%m``
+    The month of the current year (01-12).
 
-``%B``
-  .. versionadded:: 3.10
+  ``%b``
+    .. versionadded:: 3.7
 
-  Full month name (e.g. October).
+    Abbreviated month name (e.g. Oct).
 
-``%M``
-  The minute of the current hour (00-59).
+  ``%B``
+    .. versionadded:: 3.10
 
-``%s``
-  .. versionadded:: 3.6
+    Full month name (e.g. October).
 
-  Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
+  ``%M``
+    The minute of the current hour (00-59).
 
-``%S``
-  The second of the current minute.  60 represents a leap second. (00-60)
+  ``%s``
+    .. versionadded:: 3.6
 
-``%f``
-  .. versionadded:: 3.23
+    Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
 
-  The microsecond of the current second (000000-999999).
+  ``%S``
+    The second of the current minute.  60 represents a leap second. (00-60)
 
-``%U``
-  The week number of the current year (00-53).
+  ``%f``
+    .. versionadded:: 3.23
 
-``%V``
-  .. versionadded:: 3.22
+    The microsecond of the current second (000000-999999).
 
-  The ISO 8601 week number of the current year (01-53).
+  ``%U``
+    The week number of the current year (00-53).
 
-``%w``
-  The day of the current week. 0 is Sunday. (0-6)
+  ``%V``
+    .. versionadded:: 3.22
 
-``%a``
-  .. versionadded:: 3.7
+    The ISO 8601 week number of the current year (01-53).
 
-  Abbreviated weekday name (e.g. Fri).
+  ``%w``
+    The day of the current week. 0 is Sunday. (0-6)
 
-``%A``
-  .. versionadded:: 3.10
+  ``%a``
+    .. versionadded:: 3.7
 
-  Full weekday name (e.g. Friday).
+    Abbreviated weekday name (e.g. Fri).
 
-``%y``
-  The last two digits of the current year (00-99).
+  ``%A``
+    .. versionadded:: 3.10
 
-``%Y``
-  The current year.
+    Full weekday name (e.g. Friday).
 
-``%z``
-  .. versionadded:: 3.26
+  ``%y``
+    The last two digits of the current year (00-99).
 
-  The offset of the time zone from UTC, in hours and minutes,
-  with format ``+hhmm`` or ``-hhmm``.
+  ``%Y``
+    The current year.
 
-``%Z``
-  .. versionadded:: 3.26
+  ``%z``
+    .. versionadded:: 3.26
 
-  The time zone name.
+    The offset of the time zone from UTC, in hours and minutes,
+    with format ``+hhmm`` or ``-hhmm``.
 
-Unknown format specifiers will be ignored and copied to the output
-as-is.
+  ``%Z``
+    .. versionadded:: 3.26
 
-If no explicit ``<format_string>`` is given, it will default to:
+    The time zone name.
 
-::
+  Unknown format specifiers will be ignored and copied to the output
+  as-is.
 
-   %Y-%m-%dT%H:%M:%S    for local time.
-   %Y-%m-%dT%H:%M:%SZ   for UTC.
+  If no explicit ``<format_string>`` is given, it will default to:
 
-.. versionadded:: 3.8
-  If the ``SOURCE_DATE_EPOCH`` environment variable is set,
-  its value will be used instead of the current time.
-  See https://reproducible-builds.org/specs/source-date-epoch/ for details.
+  ::
 
-.. _UUID:
+    %Y-%m-%dT%H:%M:%S    for local time.
+    %Y-%m-%dT%H:%M:%SZ   for UTC.
 
-.. code-block:: cmake
+  .. versionadded:: 3.8
+    If the ``SOURCE_DATE_EPOCH`` environment variable is set,
+    its value will be used instead of the current time.
+    See https://reproducible-builds.org/specs/source-date-epoch/ for details.
 
+.. signature::
   string(UUID <output_variable> NAMESPACE <namespace> NAME <name>
          TYPE <MD5|SHA1> [UPPER])
 
-.. versionadded:: 3.1
+  .. versionadded:: 3.1
 
-Create a universally unique identifier (aka GUID) as per RFC4122
-based on the hash of the combined values of ``<namespace>``
-(which itself has to be a valid UUID) and ``<name>``.
-The hash algorithm can be either ``MD5`` (Version 3 UUID) or
-``SHA1`` (Version 5 UUID).
-A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``
-where each ``x`` represents a lower case hexadecimal character.
-Where required, an uppercase representation can be requested
-with the optional ``UPPER`` flag.
+  Create a universally unique identifier (aka GUID) as per RFC4122
+  based on the hash of the combined values of ``<namespace>``
+  (which itself has to be a valid UUID) and ``<name>``.
+  The hash algorithm can be either ``MD5`` (Version 3 UUID) or
+  ``SHA1`` (Version 5 UUID).
+  A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``
+  where each ``x`` represents a lower case hexadecimal character.
+  Where required, an uppercase representation can be requested
+  with the optional ``UPPER`` flag.
 
 .. _JSON:
 
@@ -586,78 +518,72 @@ Functionality for querying a JSON string.
   option is not present, a fatal error message is generated.  If no error
   occurs, the ``<error-variable>`` will be set to ``NOTFOUND``.
 
-.. _JSON_GET:
-.. code-block:: cmake
-
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
          GET <json-string> <member|index> [<member|index> ...])
+  :target: JSON GET
 
-Get an element from ``<json-string>`` at the location given
-by the list of ``<member|index>`` arguments.
-Array and object elements will be returned as a JSON string.
-Boolean elements will be returned as ``ON`` or ``OFF``.
-Null elements will be returned as an empty string.
-Number and string types will be returned as strings.
-
-.. _JSON_TYPE:
-.. code-block:: cmake
+  Get an element from ``<json-string>`` at the location given
+  by the list of ``<member|index>`` arguments.
+  Array and object elements will be returned as a JSON string.
+  Boolean elements will be returned as ``ON`` or ``OFF``.
+  Null elements will be returned as an empty string.
+  Number and string types will be returned as strings.
 
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
          TYPE <json-string> <member|index> [<member|index> ...])
+  :target: JSON TYPE
 
-Get the type of an element in ``<json-string>`` at the location
-given by the list of ``<member|index>`` arguments. The ``<out-var>``
-will be set to one of ``NULL``, ``NUMBER``, ``STRING``, ``BOOLEAN``,
-``ARRAY``, or ``OBJECT``.
-
-.. _JSON_MEMBER:
-.. code-block:: cmake
+  Get the type of an element in ``<json-string>`` at the location
+  given by the list of ``<member|index>`` arguments. The ``<out-var>``
+  will be set to one of ``NULL``, ``NUMBER``, ``STRING``, ``BOOLEAN``,
+  ``ARRAY``, or ``OBJECT``.
 
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-var>]
          MEMBER <json-string>
          [<member|index> ...] <index>)
+  :target: JSON MEMBER
 
-Get the name of the ``<index>``-th member in ``<json-string>`` at the location
-given by the list of ``<member|index>`` arguments.
-Requires an element of object type.
-
-.. _JSON_LENGTH:
-.. code-block:: cmake
+  Get the name of the ``<index>``-th member in ``<json-string>``
+  at the location given by the list of ``<member|index>`` arguments.
+  Requires an element of object type.
 
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
          LENGTH <json-string> [<member|index> ...])
+  :target: JSON LENGTH
 
-Get the length of an element in ``<json-string>`` at the location
-given by the list of ``<member|index>`` arguments.
-Requires an element of array or object type.
-
-.. _JSON_REMOVE:
-.. code-block:: cmake
+  Get the length of an element in ``<json-string>`` at the location
+  given by the list of ``<member|index>`` arguments.
+  Requires an element of array or object type.
 
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
          REMOVE <json-string> <member|index> [<member|index> ...])
+  :target: JSON REMOVE
 
-Remove an element from ``<json-string>`` at the location
-given by the list of ``<member|index>`` arguments. The JSON string
-without the removed element will be stored in ``<out-var>``.
-
-.. _JSON_SET:
-.. code-block:: cmake
+  Remove an element from ``<json-string>`` at the location
+  given by the list of ``<member|index>`` arguments. The JSON string
+  without the removed element will be stored in ``<out-var>``.
 
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
          SET <json-string> <member|index> [<member|index> ...] <value>)
+  :target: JSON SET
 
-Set an element in ``<json-string>`` at the location
-given by the list of ``<member|index>`` arguments to ``<value>``.
-The contents of ``<value>`` should be valid JSON.
-
-.. _JSON_EQUAL:
-.. code-block:: cmake
+  Set an element in ``<json-string>`` at the location
+  given by the list of ``<member|index>`` arguments to ``<value>``.
+  The contents of ``<value>`` should be valid JSON.
 
+.. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-var>]
          EQUAL <json-string1> <json-string2>)
+  :target: JSON EQUAL
 
-Compare the two JSON objects given by ``<json-string1>`` and ``<json-string2>``
-for equality.  The contents of ``<json-string1>`` and ``<json-string2>``
-should be valid JSON.  The ``<out-var>`` will be set to a true value if the
-JSON objects are considered equal, or a false value otherwise.
+  Compare the two JSON objects given by ``<json-string1>``
+  and ``<json-string2>`` for equality.  The contents of ``<json-string1>``
+  and ``<json-string2>`` should be valid JSON.  The ``<out-var>``
+  will be set to a true value if the JSON objects are considered equal,
+  or a false value otherwise.

+ 152 - 38
Help/dev/documentation.rst

@@ -168,46 +168,154 @@ documentation:
  See the `cmake-variables(7)`_ manual
  and the `set()`_ command.
 
-Documentation objects in the CMake Domain come from two sources.
-First, the CMake extension to Sphinx transforms every document named
-with the form ``Help/<type>/<file-name>.rst`` to a domain object with
-type ``<type>``.  The object name is extracted from the document title,
-which is expected to be of the form::
-
- <object-name>
- -------------
-
-and to appear at or near the top of the ``.rst`` file before any other
-lines starting in a letter, digit, ``<``, or ``$``.  If no such title appears
-literally in the ``.rst`` file, the object name is the ``<file-name>``.
-If a title does appear, it is expected that ``<file-name>`` is equal
-to ``<object-name>`` with any ``<`` and ``>`` characters removed,
-or in the case of a ``$<genex-name>`` or ``$<genex-name:...>``, the
-``genex-name``.
-
-Second, the CMake Domain provides directives to define objects inside
-other documents:
+Documentation objects in the CMake Domain come from two sources:
+
+1. The CMake extension to Sphinx transforms every document named
+   with the form ``Help/<type>/<file-name>.rst`` to a domain object with
+   type ``<type>``.  The object name is extracted from the document title,
+   which is expected to be of the form::
+
+    <object-name>
+    -------------
+
+   and to appear at or near the top of the ``.rst`` file before any other lines
+   starting in a letter, digit, ``<``, or ``$``.  If no such title appears
+   literally in the ``.rst`` file, the object name is the ``<file-name>``.
+   If a title does appear, it is expected that ``<file-name>`` is equal
+   to ``<object-name>`` with any ``<`` and ``>`` characters removed,
+   or in the case of a ``$<genex-name>`` or ``$<genex-name:...>``, the
+   ``genex-name``.
+
+2. `CMake Domain directives`_ may be used in documents to explicitly define
+   some object types:
+
+   * `command directive`_
+   * `envvar directive`_
+   * `genex directive`_
+   * `variable directive`_
+
+   Object types for which no directive is available must be defined using
+   the document transform above.
+
+CMake Domain Directives
+-----------------------
+
+The CMake Domain provides the following directives.
+
+``command`` directive
+^^^^^^^^^^^^^^^^^^^^^
+
+Document a "command" object:
 
 .. code-block:: rst
 
- .. command:: <command-name>
+  .. command:: <command-name>
+
+    This indented block documents <command-name>.
 
-  This indented block documents <command-name>.
+The directive requires a single argument, the command name.
 
- .. envvar:: <envvar-name>
+``envvar`` directive
+^^^^^^^^^^^^^^^^^^^^
+
+Document an "envvar" object:
+
+.. code-block:: rst
 
-  This indented block documents <envvar-name>.
+  .. envvar:: <envvar-name>
+
+    This indented block documents <envvar-name>.
+
+The directive requires a single argument, the environment variable name.
+
+``genex`` directive
+^^^^^^^^^^^^^^^^^^^
+
+Document a "genex" object:
+
+.. code-block:: rst
 
  .. genex:: <genex-name>
 
   This indented block documents <genex-name>.
 
+The directive requires a single argument, the generator expression name.
+
+``signature`` directive
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Document `CMake Command Signatures <Style: CMake Command Signatures_>`_
+within a ``Help/command/<command-name>.rst`` document.
+
+.. code-block:: rst
+
+  .. signature:: <command-name>(<signature>)
+
+    This indented block documents one or more signatures of a CMake command.
+
+The ``signature`` directive requires one argument, the signature summary:
+
+* One or more signatures must immediately follow the ``::``.
+  The first signature may optionally be placed on the same line.
+  A blank line following the ``signature`` directive will result in a
+  documentation generation error: ``1 argument(s) required, 0 supplied``.
+
+* Signatures may be split across multiple lines, but the final ``)`` of each
+  signature must be the last character on its line.
+
+* Blank lines between signatures are not allowed.  (Content after a blank line
+  is treated as part of the description.)
+
+* Whitespace in signatures is not preserved.  To document a complex signature,
+  abbreviate it in the ``signature`` directive argument and specify the full
+  signature in a ``code-block`` in the description.
+
+The ``signature`` directive generates a document-local hyperlink target
+for each signature:
+
+* Default target names are automatically extracted from leading "keyword"
+  arguments in the signatures, where a keyword is any sequence of
+  non-space starting with a letter.  For example, the signature
+  ``string(REGEX REPLACE <match-regex> ...)`` generates the target
+  ``REGEX REPLACE``, similar to ``.. _`REGEX REPLACE`:``.
+
+* Custom target names may be specified using a ``:target:`` option.
+  For example:
+
+  .. code-block:: rst
+
+    .. signature::
+      cmake_path(GET <path-var> ROOT_NAME <out-var>)
+      cmake_path(GET <path-var> ROOT_PATH <out-var>)
+      :target:
+        GET ROOT_NAME
+        GET ROOT_PATH
+
+  Provide a custom target name for each signature, one per line.
+  The first target may optionally be placed on the same line as ``:target:``.
+
+* If a target name is already in use earlier in the document, no hyperlink
+  target will be generated.
+
+* The targets may be referenced from within the same document using
+  ```REF`_`` or ```TEXT <REF_>`_`` syntax.  Like reStructuredText section
+  headers, the targets do not work with Sphinx ``:ref:`` syntax.
+
+The directive treats its content as the documentation of the signature(s).
+Indent the signature documentation accordingly.
+
+``variable`` directive
+^^^^^^^^^^^^^^^^^^^^^^
+
+Document a "variable" object:
+
+.. code-block:: rst
+
  .. variable:: <variable-name>
 
   This indented block documents <variable-name>.
 
-Object types for which no directive is available must be defined using
-the first approach above.
+The directive requires a single argument, the variable name.
 
 .. _`Sphinx Domain`: http://sphinx-doc.org/domains.html
 .. _`cmake(1)`: https://cmake.org/cmake/help/latest/manual/cmake.1.html
@@ -329,11 +437,11 @@ paragraph.
 Style: CMake Command Signatures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Command signatures should be marked up as plain literal blocks, not as
-cmake ``code-blocks``.
-
-Signatures are separated from preceding content by a section header.
-That is, use:
+A ``Help/command/<command-name>.rst`` document defines one ``command``
+object in the `CMake Domain`_, but some commands have multiple signatures.
+Use the CMake Domain's `signature directive`_ to document each signature.
+Separate signatures from preceding content by a section header.
+For example:
 
 .. code-block:: rst
 
@@ -342,17 +450,23 @@ That is, use:
   Normal Libraries
   ^^^^^^^^^^^^^^^^
 
-  ::
-
+  .. signature::
     add_library(<lib> ...)
 
-  This signature is used for ...
+    This signature is used for ...
+
+Use the following conventions in command signature documentation:
+
+* Use an angle-bracket ``<placeholder>`` for arguments to be specified
+  by the caller.  Refer to them in prose using
+  `inline literal <Style: Inline Literals_>`_ syntax.
+
+* Wrap optional parts with square brackets.
+
+* Mark repeatable parts with a trailing ellipsis (``...``).
 
-Signatures of commands should wrap optional parts with square brackets,
-and should mark list of optional arguments with an ellipsis (``...``).
-Elements of the signature which are specified by the user should be
-specified with angle brackets, and may be referred to in prose using
-``inline-literal`` syntax.
+The ``signature`` directive may be used multiple times for different
+signatures of the same command.
 
 Style: Boolean Constants
 ^^^^^^^^^^^^^^^^^^^^^^^^

+ 1 - 1
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|variable"
+                   "command|envvar|genex|signature|variable"
                    ")::[ \t]+([^ \t\n]+)$")
   , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$")
   , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$")

+ 8 - 0
Tests/CMakeLib/testRST.expect

@@ -70,6 +70,14 @@ Bracket Comment Content
 
    Generator expression $<OTHER_GENEX> description.
 
+.. cmake:signature:: some_command(SOME_SIGNATURE)
+
+   Command some_command SOME_SIGNATURE description.
+
+.. signature:: other_command(OTHER_SIGNATURE)
+
+   Command other_command OTHER_SIGNATURE description.
+
 .. cmake:variable:: some_var
 
    Variable some_var description.

+ 8 - 0
Tests/CMakeLib/testRST.rst

@@ -73,6 +73,14 @@ Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_.
 
    Generator expression $<OTHER_GENEX> description.
 
+.. cmake:signature:: some_command(SOME_SIGNATURE)
+
+   Command some_command SOME_SIGNATURE description.
+
+.. signature:: other_command(OTHER_SIGNATURE)
+
+   Command other_command OTHER_SIGNATURE description.
+
 .. cmake:variable:: some_var
 
    Variable some_var description.

+ 83 - 15
Utilities/Sphinx/cmake.py

@@ -16,6 +16,9 @@ from pygments.lexers import CMakeLexer
 from pygments.token import Name, Operator, Punctuation, String, Text, Comment, Generic, Whitespace, Number
 from pygments.lexer import bygroups
 
+# RE to split multiple command signatures
+sig_end_re = re.compile(r'(?<=[)])\n')
+
 # Notes on regular expressions below:
 # - [\.\+-] are needed for string constants like gtk+-2.0
 # - Unix paths are recognized by '/'; support for Windows paths may be added if needed
@@ -57,14 +60,16 @@ CMakeLexer.tokens["root"] = [
   #  (r'[^<>\])\}\|$"# \t\n]+', Name.Exception),            # fallback, for debugging only
 ]
 
+from docutils.utils.code_analyzer import Lexer, LexerError
 from docutils.parsers.rst import Directive, directives
 from docutils.transforms import Transform
 from docutils import io, nodes
 
-from sphinx.directives import ObjectDescription
+from sphinx.directives import ObjectDescription, nl_escape_re
 from sphinx.domains import Domain, ObjType
 from sphinx.roles import XRefRole
 from sphinx.util.nodes import make_refnode
+from sphinx.util import ws_re
 from sphinx import addnodes
 
 sphinx_before_1_4 = False
@@ -286,9 +291,9 @@ class CMakeObject(ObjectDescription):
 
     def add_target_and_index(self, name, sig, signode):
         if self.objtype == 'command':
-           targetname = name.lower()
+            targetname = name.lower()
         else:
-           targetname = name
+            targetname = name
         targetid = '%s:%s' % (self.objtype, targetname)
         if targetid not in self.state.document.ids:
             signode['names'].append(targetid)
@@ -302,6 +307,79 @@ class CMakeObject(ObjectDescription):
         if make_index_entry:
             self.indexnode['entries'].append(make_index_entry(name, targetid))
 
+class CMakeSignatureObject(CMakeObject):
+    object_type = 'signature'
+
+    option_spec = {
+        'target': directives.unchanged,
+    }
+
+    def get_signatures(self):
+        content = nl_escape_re.sub('', self.arguments[0])
+        lines = sig_end_re.split(content)
+        return [ws_re.sub(' ', line.strip()) for line in lines]
+
+    def handle_signature(self, sig, signode):
+        language = 'cmake'
+        classes = ['code', 'cmake', 'highlight']
+
+        node = addnodes.desc_name(sig, '', classes=classes)
+
+        try:
+            tokens = Lexer(sig, language, 'short')
+        except LexerError as error:
+            if self.state.document.settings.report_level > 2:
+                # Silently insert without syntax highlighting.
+                tokens = Lexer(sig, language, 'none')
+            else:
+                raise self.warning(error)
+
+        for classes, value in tokens:
+            if classes:
+                node += nodes.inline(value, value, classes=classes)
+            else:
+                node += nodes.Text(value)
+
+        signode.clear()
+        signode += node
+
+        return sig
+
+    def __init__(self, *args, **kwargs):
+        self.targetnames = {}
+        super().__init__(*args, **kwargs)
+
+    def add_target_and_index(self, name, sig, signode):
+        if name in self.targetnames:
+            targetname = self.targetnames[name].lower()
+        else:
+            def extract_keywords(params):
+                for p in params:
+                    if p[0].isalpha():
+                        yield p
+                    else:
+                        return
+
+            keywords = extract_keywords(name.split('(')[1].split())
+            targetname = ' '.join(keywords).lower()
+        targetid = nodes.make_id(targetname)
+
+        if targetid not in self.state.document.ids:
+            signode['names'].append(targetname)
+            signode['ids'].append(targetid)
+            signode['first'] = (not self.names)
+            self.state.document.note_explicit_target(signode)
+
+    def run(self):
+        targets = self.options.get('target')
+        if targets is not None:
+            signatures = self.get_signatures()
+            targets = [t.strip() for t in targets.split('\n')]
+            for signature, target in zip(signatures, targets):
+                self.targetnames[signature] = target
+
+        return super().run()
+
 class CMakeXRefRole(XRefRole):
 
     # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
@@ -411,19 +489,9 @@ class CMakeDomain(Domain):
         'command':    CMakeObject,
         'envvar':     CMakeObject,
         'genex':      CMakeObject,
+        'signature':  CMakeSignatureObject,
         'variable':   CMakeObject,
-        # Other object types cannot be created except by the CMakeTransform
-        # 'generator':  CMakeObject,
-        # 'module':     CMakeObject,
-        # 'policy':     CMakeObject,
-        # 'prop_cache': CMakeObject,
-        # 'prop_dir':   CMakeObject,
-        # 'prop_gbl':   CMakeObject,
-        # 'prop_inst':  CMakeObject,
-        # 'prop_sf':    CMakeObject,
-        # 'prop_test':  CMakeObject,
-        # 'prop_tgt':   CMakeObject,
-        # 'manual':     CMakeObject,
+        # Other `object_types` cannot be created except by the `CMakeTransform`
     }
     roles = {
         'command':    CMakeXRefRole(fix_parens = True, lowercase = True),

+ 23 - 0
Utilities/Sphinx/static/cmake.css

@@ -17,6 +17,29 @@ div.sphinxsidebarwrapper {
   background-color: #dfdfdf;
 }
 
+/* Apply <pre> style (from classic.css) to signature directive argument. */
+.signature .sig {
+  padding: 5px;
+  background-color: #eeeeee;
+  color: #333333;
+  line-height: 120%;
+  border: 1px solid #ac9;
+  border-left: none;
+  border-right: none;
+}
+
+/* Add additional styling to signature directive argument. */
+.signature .sig {
+  margin-bottom: 5px;
+  padding-left: calc(5px + 3em);
+  text-indent: -3em;
+  font-family: monospace;
+}
+
+.signature .sig .code.sig-name {
+  font-weight: normal;
+}
+
 /* Remove unwanted margin in case list item contains a div-wrapping
    directive like `.. versionadded` or `.. deprecated`. */
 dd > :first-child > p {