From 2000abe74ff2e61bf3dc21edd257da9c6e78abc6 Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Sat, 31 Aug 2024 18:33:14 +1000 Subject: [PATCH] Help: Recommend good prefixes for cmake_parse_arguments, expand example Fixes: #25773 --- Help/command/cmake_parse_arguments.rst | 102 +++++++++++++++++++------ 1 file changed, 79 insertions(+), 23 deletions(-) diff --git a/Help/command/cmake_parse_arguments.rst b/Help/command/cmake_parse_arguments.rst index 746e1f1619..441cbfa470 100644 --- a/Help/command/cmake_parse_arguments.rst +++ b/Help/command/cmake_parse_arguments.rst @@ -76,9 +76,42 @@ whether your macro or function was called with unrecognized parameters. policy :policy:`CMP0174` controls whether a corresponding ``_`` variable is defined or not. +Choose a ```` 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 ````, 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 # was not used - MY_INSTALL_TARGETS = "foo;bar" - MY_INSTALL_CONFIGURATIONS # 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 # was not present + arg_my_install_TARGETS = "foo;bar" + arg_my_install_CONFIGURATIONS # 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 # value was missing + arg_my_special_install_TARGETS = "barry" + arg_my_special_install_CONFIGURATIONS # was not present + arg_my_special_install_UNPARSED_ARGUMENTS + arg_my_special_install_KEYWORDS_MISSING_VALUES = "RENAME" Keywords terminate lists of values. If a keyword is given directly after a ````, that preceding ```` receives no value and the keyword is added to the ``_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 ^^^^^^^^