Help: Recommend good prefixes for cmake_parse_arguments, expand example

Fixes: #25773
This commit is contained in:
Craig Scott 2024-08-31 18:33:14 +10:00
parent bb37d0e1a5
commit 2000abe74f
No known key found for this signature in database
GPG Key ID: 6FF37CBDCCADED9F

View File

@ -76,9 +76,42 @@ whether your macro or function was called with unrecognized parameters.
policy :policy:`CMP0174` controls whether a corresponding
``<prefix>_<keyword>`` variable is defined or not.
Choose a ``<prefix>`` carefully to avoid clashing with existing variable names.
When used inside a function, it is usually suitable to use the prefix ``arg``.
There is a very strong convention that all keywords are fully uppercase, so
this prefix results in variables of the form ``arg_SOME_KEYWORD``. This makes
the code more readable, and it minimizes the chance of clashing with cache
variables, which also have a strong convention of being all uppercase.
Consider the following example macro, ``my_install()``, which takes similar
arguments to the real :command:`install` command:
.. code-block:: cmake
function(my_install)
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}" "${oneValueArgs}" "${multiValueArgs}"
)
# The above will set or unset variables with the following names:
# arg_OPTIONAL
# arg_FAST
# arg_DESTINATION
# arg_RENAME
# arg_TARGETS
# arg_CONFIGURATIONS
#
# The following will also be set or unset:
# arg_UNPARSED_ARGUMENTS
# arg_KEYWORDS_MISSING_VALUES
When used inside a macro, ``arg`` might not be a suitable prefix because the
code will affect the calling scope. If another macro also called in the same
scope were to use ``arg`` in its own call to ``cmake_parse_arguments()``,
and if there are any common keywords between the two macros, the later call's
variables can overwrite or remove those of the earlier macro's call.
Therefore, it is advisable to incorporate something unique from the macro name
in the ``<prefix>``, such as ``arg_lowercase_macro_name``.
.. code-block:: cmake
@ -86,40 +119,63 @@ arguments to the real :command:`install` command:
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
cmake_parse_arguments(arg_my_install
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
# ...
endmacro()
Assume ``my_install()`` has been called like this:
macro(my_special_install)
# NOTE: Has the same keywords as my_install()
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(arg_my_special_install
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
# ...
endmacro()
Suppose the above macros are called one after the other, like so:
.. code-block:: cmake
my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
my_special_install(TARGETS barry DESTINATION sbin RENAME FAST)
After the ``cmake_parse_arguments`` call, the macro will have set or undefined
the following variables::
After these two calls, the following describes the variables that will be
set or unset::
MY_INSTALL_OPTIONAL = TRUE
MY_INSTALL_FAST = FALSE # was not used in call to my_install
MY_INSTALL_DESTINATION = "bin"
MY_INSTALL_RENAME <UNDEFINED> # was not used
MY_INSTALL_TARGETS = "foo;bar"
MY_INSTALL_CONFIGURATIONS <UNDEFINED> # was not used
MY_INSTALL_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
MY_INSTALL_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS"
# No value for "CONFIGURATIONS" given
arg_my_install_OPTIONAL = TRUE
arg_my_install_FAST = FALSE # was not present in call to my_install
arg_my_install_DESTINATION = "bin"
arg_my_install_RENAME <UNSET> # was not present
arg_my_install_TARGETS = "foo;bar"
arg_my_install_CONFIGURATIONS <UNSET> # was not present
arg_my_install_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
arg_my_install_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS" # value was missing
You can then continue and process these variables.
arg_my_special_install_OPTIONAL = FALSE # was not present
arg_my_special_install_FAST = TRUE
arg_my_special_install_DESTINATION = "sbin"
arg_my_special_install_RENAME <UNSET> # value was missing
arg_my_special_install_TARGETS = "barry"
arg_my_special_install_CONFIGURATIONS <UNSET> # was not present
arg_my_special_install_UNPARSED_ARGUMENTS <UNSET>
arg_my_special_install_KEYWORDS_MISSING_VALUES = "RENAME"
Keywords terminate lists of values. If a keyword is given directly after a
``<one_value_keyword>``, that preceding ``<one_value_keyword>`` receives no
value and the keyword is added to the ``<prefix>_KEYWORDS_MISSING_VALUES``
variable. For the above example, the call
``my_install(TARGETS foo DESTINATION OPTIONAL)`` would result in
``MY_INSTALL_OPTIONAL`` being set to ``TRUE`` and ``MY_INSTALL_DESTINATION``
being unset. The ``MY_INSTALL_KEYWORDS_MISSING_VALUES`` variable would hold
the value ``DESTINATION``.
variable. In the above example, the call to ``my_special_install()`` contains
the ``RENAME`` keyword immediately followed by the ``FAST`` keyword.
In this case, ``FAST`` terminates processing of the ``RENAME`` keyword.
``arg_my_special_install_FAST`` is set to ``TRUE``,
``arg_my_special_install_RENAME`` is unset, and
``arg_my_special_install_KEYWORDS_MISSING_VALUES`` contains the value
``RENAME``.
See Also
^^^^^^^^