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 policy :policy:`CMP0174` controls whether a corresponding
``<prefix>_<keyword>`` variable is defined or not. ``<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 .. code-block:: cmake
arguments to the real :command:`install` command:
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 .. code-block:: cmake
@ -86,40 +119,63 @@ arguments to the real :command:`install` command:
set(options OPTIONAL FAST) set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME) set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS) set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" cmake_parse_arguments(arg_my_install
"${multiValueArgs}" ${ARGN} ) "${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 .. code-block:: cmake
my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS) 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 After these two calls, the following describes the variables that will be
the following variables:: set or unset::
MY_INSTALL_OPTIONAL = TRUE arg_my_install_OPTIONAL = TRUE
MY_INSTALL_FAST = FALSE # was not used in call to my_install arg_my_install_FAST = FALSE # was not present in call to my_install
MY_INSTALL_DESTINATION = "bin" arg_my_install_DESTINATION = "bin"
MY_INSTALL_RENAME <UNDEFINED> # was not used arg_my_install_RENAME <UNSET> # was not present
MY_INSTALL_TARGETS = "foo;bar" arg_my_install_TARGETS = "foo;bar"
MY_INSTALL_CONFIGURATIONS <UNDEFINED> # was not used arg_my_install_CONFIGURATIONS <UNSET> # was not present
MY_INSTALL_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL" arg_my_install_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
MY_INSTALL_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS" arg_my_install_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS" # value was missing
# No value for "CONFIGURATIONS" given
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 Keywords terminate lists of values. If a keyword is given directly after a
``<one_value_keyword>``, that preceding ``<one_value_keyword>`` receives no ``<one_value_keyword>``, that preceding ``<one_value_keyword>`` receives no
value and the keyword is added to the ``<prefix>_KEYWORDS_MISSING_VALUES`` value and the keyword is added to the ``<prefix>_KEYWORDS_MISSING_VALUES``
variable. For the above example, the call variable. In the above example, the call to ``my_special_install()`` contains
``my_install(TARGETS foo DESTINATION OPTIONAL)`` would result in the ``RENAME`` keyword immediately followed by the ``FAST`` keyword.
``MY_INSTALL_OPTIONAL`` being set to ``TRUE`` and ``MY_INSTALL_DESTINATION`` In this case, ``FAST`` terminates processing of the ``RENAME`` keyword.
being unset. The ``MY_INSTALL_KEYWORDS_MISSING_VALUES`` variable would hold ``arg_my_special_install_FAST`` is set to ``TRUE``,
the value ``DESTINATION``. ``arg_my_special_install_RENAME`` is unset, and
``arg_my_special_install_KEYWORDS_MISSING_VALUES`` contains the value
``RENAME``.
See Also See Also
^^^^^^^^ ^^^^^^^^