From d6af93546710bb8b034f0687b68b1891b84846bd Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Tue, 19 Jul 2022 17:04:38 +1000 Subject: Help: Add Whitespace And Quoting section to genex manual --- Help/manual/cmake-generator-expressions.7.rst | 87 +++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 357a20c..9949772 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -43,6 +43,93 @@ The above would expand to ``OLD_COMPILER`` if the :variable:`CMAKE_CXX_COMPILER_VERSION _COMPILER_VERSION>` is less than 4.2.0. +Whitespace And Quoting +====================== + +Generator expressions are typically parsed after command arguments. +If a generator expression contains spaces, new lines, semicolons or +other characters that may be interpreted as command argument separators, +the whole expression should be surrounded by quotes when passed to a +command. Failure to do so may result in the expression being split and +it may no longer be recognized as a generator expression. + +When using :command:`add_custom_command` or :command:`add_custom_target`, +use the ``VERBATIM`` and ``COMMAND_EXPAND_LISTS`` options to obtain robust +argument splitting and quoting. + +.. code-block:: cmake + + # WRONG: Embedded space will be treated as an argument separator. + # This ends up not being seen as a generator expression at all. + add_custom_target(run_some_tool + COMMAND some_tool -I$, -I> + VERBATIM + ) + +.. code-block:: cmake + + # Better, but still not robust. Quotes prevent the space from splitting the + # expression. However, the tool will receive the expanded value as a single + # argument. + add_custom_target(run_some_tool + COMMAND some_tool "-I$, -I>" + VERBATIM + ) + +.. code-block:: cmake + + # Nearly correct. Using a semicolon to separate arguments and adding the + # COMMAND_EXPAND_LISTS option means that paths with spaces will be handled + # correctly. Quoting the whole expression ensures it is seen as a generator + # expression. But if the target property is empty, we will get a bare -I + # with nothing after it. + add_custom_target(run_some_tool + COMMAND some_tool "-I$,;-I>" + COMMAND_EXPAND_LISTS + VERBATIM + ) + +Using variables to build up a more complex generator expression is also a +good way to reduce errors and improve readability. The above example can be +improved further like so: + +.. code-block:: cmake + + # The $ check prevents adding anything if the property is empty, + # assuming the property value cannot be one of CMake's false constants. + set(prop "$") + add_custom_target(run_some_tool + COMMAND some_tool "$<$:-I$>" + COMMAND_EXPAND_LISTS + VERBATIM + ) + +A common mistake is to try to split a generator expression across multiple +lines with indenting: + +.. code-block:: cmake + + # WRONG: New lines and spaces all treated as argument separators, so the + # generator expression is split and not recognized correctly. + target_compile_definitions(tgt PRIVATE + $<$, + $,5> + >:HAVE_5_OR_LATER> + ) + +Again, use helper variables with well-chosen names to build up a readable +expression instead: + +.. code-block:: cmake + + set(is_gnu "$") + set(v5_or_later "$,5>") + set(meet_requirements "$") + target_compile_definitions(tgt PRIVATE + "$<${meet_requirements}:HAVE_5_OR_LATER>" + ) + Debugging ========= -- cgit v0.12