mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Preserve backslashes in arguments passed to macros by re-escaping them before substituting in the macro body, where they will be parsed again. Fixes: #19281, #22157, #23641, #25803, #27645, #20891
104 lines
3.9 KiB
ReStructuredText
104 lines
3.9 KiB
ReStructuredText
CMP0219
|
|
-------
|
|
|
|
.. versionadded:: 4.4
|
|
|
|
:command:`macro` invocations preserve backslashes in arguments.
|
|
|
|
In CMake 4.3 and below, macro argument references (``${ARGN}``, ``${ARGV}``,
|
|
``${ARGV<n>}``, and named macro arguments) are substituted textually and then
|
|
evaluated by the called command. Backslashes in substituted values are
|
|
re-evaluated as escape prefixes, and invalid escape sequences (such as
|
|
``\b`` in Windows paths) can cause errors. The same re-evaluation can also
|
|
occur for arguments passed to a :command:`variable_watch` callback command.
|
|
|
|
CMake 4.4 and above prefer to preserve literal backslashes in those macro
|
|
argument references.
|
|
|
|
The ``OLD`` behavior for this policy is to interpret escape sequences in macro
|
|
argument references and in arguments passed to ``variable_watch()`` callback
|
|
commands. The ``NEW`` behavior is to preserve backslashes in those values
|
|
before command invocation.
|
|
|
|
This policy applies to macro argument references and to arguments passed to
|
|
``variable_watch()`` callback commands. Other variable references keep their
|
|
existing behavior.
|
|
|
|
Mixed Policy Chains
|
|
^^^^^^^^^^^^^^^^^^^
|
|
|
|
Whether pre-escaping occurs is determined by the policy setting at each
|
|
call site. When a project and its dependencies use different ``CMP0219``
|
|
settings, each macro call in the chain follows the policy where that call
|
|
appears.
|
|
|
|
Consider a project (``CMP0219`` is ``OLD``) that calls a macro from
|
|
dependency A (upgraded to
|
|
:command:`cmake_minimum_required(VERSION 4.4) <cmake_minimum_required>`,
|
|
so ``CMP0219`` is ``NEW``), which in turn forwards arguments to a macro
|
|
from dependency B (not yet upgraded, so ``CMP0219`` is ``OLD``):
|
|
|
|
.. code-block:: cmake
|
|
|
|
# Dependency B: cmake_minimum_required(VERSION 3.24)
|
|
# CMP0219 is OLD inside dependency B.
|
|
macro(depB_store var_name)
|
|
set(${var_name} "${ARGN}")
|
|
endmacro()
|
|
|
|
# Dependency A: cmake_minimum_required(VERSION 4.4)
|
|
# CMP0219 is NEW inside dependency A.
|
|
macro(depA_forward var_name)
|
|
depB_store(${var_name} ${ARGN}) # call site is NEW -> pre-escapes
|
|
endmacro()
|
|
|
|
# Project: cmake_minimum_required(VERSION 3.24)
|
|
# CMP0219 is OLD in the project.
|
|
macro(my_wrapper var_name)
|
|
depA_forward(${var_name} ${ARGN}) # call site is OLD -> no pre-escaping
|
|
endmacro()
|
|
|
|
In a fully ``OLD`` chain, each macro boundary re-evaluates backslash
|
|
escapes, so callers must add extra escaping layers to compensate.
|
|
To pass the Windows path ``C:\build\new\temp`` through three ``OLD``
|
|
boundaries, the caller needs eight backslashes per separator:
|
|
|
|
.. code-block:: cmake
|
|
|
|
my_wrapper(result "C:\\\\\\\\build\\\\\\\\new\\\\\\\\temp")
|
|
message("${result}") # -> C:\build\new\temp
|
|
|
|
When dependency A upgrades and the middle boundary becomes ``NEW``,
|
|
that boundary preserves backslashes instead of consuming a level.
|
|
The same input now retains an extra layer:
|
|
|
|
.. code-block:: cmake
|
|
|
|
# Same 8x-escaped input through OLD -> NEW -> OLD:
|
|
my_wrapper(result "C:\\\\\\\\build\\\\\\\\new\\\\\\\\temp")
|
|
message("${result}") # -> C:\\build\\new\\temp (one extra layer)
|
|
|
|
The caller must then use half the escaping to reach the native path:
|
|
|
|
.. code-block:: cmake
|
|
|
|
# Only 4x-escaped input needed for OLD -> NEW -> OLD:
|
|
my_wrapper(result "C:\\\\build\\\\new\\\\temp")
|
|
message("${result}") # -> C:\build\new\temp
|
|
|
|
When a dependency updates its :command:`cmake_minimum_required` version
|
|
to 4.4 or above, call sites inside that dependency begin pre-escaping.
|
|
Callers that previously added extra backslash layers to compensate for
|
|
multiple levels of ``OLD`` re-evaluation may then need fewer escape
|
|
layers.
|
|
|
|
Where possible, converting paths to forward slashes with
|
|
:command:`cmake_path(CONVERT ... TO_CMAKE_PATH_LIST)` avoids the issue entirely, because
|
|
forward slashes require no escaping regardless of the policy setting.
|
|
|
|
.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.4
|
|
.. |WARNS_OR_DOES_NOT_WARN| replace:: warns when backslashes are present
|
|
.. include:: include/STANDARD_ADVICE.rst
|
|
|
|
.. include:: include/DEPRECATED.rst
|