CMP0219

Added in version 4.4.

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 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 cmake_minimum_required(VERSION 4.4), so CMP0219 is NEW), which in turn forwards arguments to a macro from dependency B (not yet upgraded, so CMP0219 is OLD):

# 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:

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:

# 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:

# 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 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 cmake_path(CONVERT ... TO_CMAKE_PATH_LIST) avoids the issue entirely, because forward slashes require no escaping regardless of the policy setting.

This policy was introduced in CMake version 4.4. It may be set by cmake_policy() or cmake_minimum_required(). If it is not set, CMake warns when backslashes are present, and uses OLD behavior.

Note

The OLD behavior of a policy is deprecated by definition and may be removed in a future version of CMake.