Back to Cmake

CMP0219

Help/policy/CMP0219.rst

4.4.03.9 KB
Original Source

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