mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
macro: Add policy to preserve backslashes in arguments
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
This commit is contained in:
@@ -100,6 +100,7 @@ Policies Introduced by CMake 4.4
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
CMP0219: Macro invocations preserve backslashes in arguments. </policy/CMP0219>
|
||||
CMP0218: The CMAKE_WARN_DEPRECATED and CMAKE_ERROR_DEPRECATED variables are ignored. </policy/CMP0218>
|
||||
CMP0217: The MACROS directory property does not exist anymore. </policy/CMP0217>
|
||||
CMP0216: Swift targets have a default project name. </policy/CMP0216>
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
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
|
||||
@@ -0,0 +1,7 @@
|
||||
macro-argument-escape
|
||||
---------------------
|
||||
|
||||
* :command:`macro` invocations now preserve backslashes in arguments.
|
||||
See policy :policy:`CMP0219`.
|
||||
* :command:`variable_watch` callback command arguments preserve backslashes.
|
||||
See policy :policy:`CMP0219`.
|
||||
@@ -63,9 +63,6 @@ bool cmMacroHelperCommand::operator()(
|
||||
return false;
|
||||
}
|
||||
|
||||
cmMakefile::MacroPushPop macroScope(&makefile, this->FilePath,
|
||||
this->Policies, this->Diagnostics);
|
||||
|
||||
// set the value of argc
|
||||
std::string argcDef = std::to_string(expandedArgs.size());
|
||||
|
||||
@@ -73,6 +70,21 @@ bool cmMacroHelperCommand::operator()(
|
||||
std::string expandedArgn =
|
||||
cmList::to_string(cmMakeRange(expIt, expandedArgs.end()));
|
||||
std::string expandedArgv = cmList::to_string(expandedArgs);
|
||||
{
|
||||
cmPolicies::PolicyStatus cmp0219 =
|
||||
makefile.CheckCMP0219(this->Args[0], expandedArgs);
|
||||
if (cmp0219 == cmPolicies::NEW) {
|
||||
// Escape macro argument backslashes so that callees receive the same
|
||||
// values the caller had.
|
||||
for (std::string& expandedArg : expandedArgs) {
|
||||
cmSystemTools::ReplaceString(expandedArg, "\\", "\\\\");
|
||||
}
|
||||
cmSystemTools::ReplaceString(expandedArgn, "\\", "\\\\");
|
||||
cmSystemTools::ReplaceString(expandedArgv, "\\", "\\\\");
|
||||
} else if (cmp0219 == cmPolicies::WARN) {
|
||||
makefile.IssueCMP0219Warning(this->Args[0], expandedArgs);
|
||||
}
|
||||
}
|
||||
std::vector<std::string> variables;
|
||||
variables.reserve(this->Args.size() - 1);
|
||||
for (unsigned int j = 1; j < this->Args.size(); ++j) {
|
||||
@@ -83,6 +95,10 @@ bool cmMacroHelperCommand::operator()(
|
||||
for (unsigned int j = 0; j < expandedArgs.size(); ++j) {
|
||||
argVs.emplace_back(cmStrCat("${ARGV", j, '}'));
|
||||
}
|
||||
|
||||
cmMakefile::MacroPushPop macroScope(&makefile, this->FilePath,
|
||||
this->Policies, this->Diagnostics);
|
||||
|
||||
// Invoke all the functions that were collected in the block.
|
||||
// for each function
|
||||
for (cmListFileFunction const& func : this->Functions) {
|
||||
|
||||
@@ -2625,6 +2625,83 @@ cm::optional<std::string> cmMakefile::DeferGetCall(std::string const& id) const
|
||||
return call;
|
||||
}
|
||||
|
||||
namespace {
|
||||
cmPolicies::PolicyStatus CheckCMP0219Impl(cmPolicies::PolicyStatus status,
|
||||
std::string const& calleeName,
|
||||
bool hasBackslashes,
|
||||
std::set<std::string>& warned)
|
||||
{
|
||||
if (status == cmPolicies::WARN && hasBackslashes &&
|
||||
warned.insert(calleeName).second) {
|
||||
return cmPolicies::WARN;
|
||||
}
|
||||
// Suppress WARN when there are no backslashes or already warned.
|
||||
return status == cmPolicies::NEW ? cmPolicies::NEW : cmPolicies::OLD;
|
||||
}
|
||||
}
|
||||
|
||||
cmPolicies::PolicyStatus cmMakefile::CheckCMP0219(
|
||||
std::string const& calleeName, std::vector<std::string> const& args)
|
||||
{
|
||||
bool const hasBackslashes =
|
||||
std::any_of(args.begin(), args.end(), [](std::string const& s) {
|
||||
return s.find('\\') != std::string::npos;
|
||||
});
|
||||
return CheckCMP0219Impl(GetPolicyStatus(cmPolicies::CMP0219), calleeName,
|
||||
hasBackslashes, WarnedCMP0219);
|
||||
}
|
||||
|
||||
cmPolicies::PolicyStatus cmMakefile::CheckCMP0219(
|
||||
std::string const& calleeName, std::vector<cmListFileArgument> const& args)
|
||||
{
|
||||
bool const hasBackslashes =
|
||||
std::any_of(args.begin(), args.end(), [](cmListFileArgument const& s) {
|
||||
return s.Value.find('\\') != std::string::npos;
|
||||
});
|
||||
return CheckCMP0219Impl(GetPolicyStatus(cmPolicies::CMP0219), calleeName,
|
||||
hasBackslashes, WarnedCMP0219);
|
||||
}
|
||||
|
||||
void cmMakefile::IssueCMP0219Warning(
|
||||
std::string const& calleeName, std::vector<std::string> const& args) const
|
||||
{
|
||||
std::string oldArgs;
|
||||
for (std::string const& arg : args) {
|
||||
if (arg.find('\\') == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (!oldArgs.empty()) {
|
||||
oldArgs += '\n';
|
||||
}
|
||||
oldArgs += cmStrCat(" \"", arg, '"');
|
||||
}
|
||||
|
||||
std::string newArgs = oldArgs;
|
||||
cmSystemTools::ReplaceString(newArgs, "\\", "\\\\");
|
||||
|
||||
this->IssueDiagnostic(
|
||||
cmDiagnostics::CMD_POLICY,
|
||||
cmStrCat(
|
||||
cmPolicies::GetPolicyWarning(cmPolicies::CMP0219), '\n', "Command \"",
|
||||
calleeName, "\" called with arguments containing backslashes.\n",
|
||||
"Since the policy is not set, backslashes in the arguments:\n", oldArgs,
|
||||
"\n", "will be interpreted as escape sequences for compatibility.\n",
|
||||
"Set the policy to NEW to instead pass\n", newArgs, "\n",
|
||||
"so that argument parsing will preserve the original values."));
|
||||
}
|
||||
|
||||
void cmMakefile::IssueCMP0219Warning(
|
||||
std::string const& calleeName,
|
||||
std::vector<cmListFileArgument> const& args) const
|
||||
{
|
||||
std::vector<std::string> stringArgs;
|
||||
stringArgs.reserve(args.size());
|
||||
for (cmListFileArgument const& arg : args) {
|
||||
stringArgs.push_back(arg.Value);
|
||||
}
|
||||
this->IssueCMP0219Warning(calleeName, stringArgs);
|
||||
}
|
||||
|
||||
MessageType cmMakefile::ExpandVariablesInStringImpl(
|
||||
std::string& errorstr, std::string& source, bool escapeQuotes,
|
||||
bool noEscapes, bool atOnly, char const* filename, long line,
|
||||
|
||||
@@ -1186,6 +1186,20 @@ public:
|
||||
cm::optional<std::string> DeferGetCallIds() const;
|
||||
cm::optional<std::string> DeferGetCall(std::string const& id) const;
|
||||
|
||||
//! Check CMP0219 policy status for the given callee and arguments.
|
||||
//! Returns the effective policy status: OLD, NEW, or WARN (only on
|
||||
//! first occurrence of calleeName with backslashes present). The
|
||||
//! caller is responsible for issuing any warning when WARN is returned.
|
||||
cmPolicies::PolicyStatus CheckCMP0219(std::string const& calleeName,
|
||||
std::vector<std::string> const& args);
|
||||
cmPolicies::PolicyStatus CheckCMP0219(
|
||||
std::string const& calleeName,
|
||||
std::vector<cmListFileArgument> const& args);
|
||||
void IssueCMP0219Warning(std::string const& calleeName,
|
||||
std::vector<std::string> const& args) const;
|
||||
void IssueCMP0219Warning(std::string const& calleeName,
|
||||
std::vector<cmListFileArgument> const& args) const;
|
||||
|
||||
protected:
|
||||
// add link libraries and directories to the target
|
||||
void AddGlobalLinkInformation(cmTarget& target);
|
||||
@@ -1350,6 +1364,7 @@ private:
|
||||
bool CheckCMP0000;
|
||||
std::set<std::string> WarnedCMP0074;
|
||||
std::set<std::string> WarnedCMP0144;
|
||||
std::set<std::string> WarnedCMP0219;
|
||||
bool IsSourceFileTryCompile;
|
||||
ImportedTargetScope CurrentImportedTargetScope = ImportedTargetScope::Local;
|
||||
};
|
||||
|
||||
+4
-1
@@ -654,7 +654,10 @@ class cmMakefile;
|
||||
SELECT(POLICY, CMP0218, \
|
||||
"The CMAKE_WARN_DEPRECATED and CMAKE_ERROR_DEPRECATED variables " \
|
||||
"are ignored.", \
|
||||
4, 4, 0, WARN)
|
||||
4, 4, 0, WARN) \
|
||||
SELECT(POLICY, CMP0219, \
|
||||
"Macro invocations preserve backslashes in arguments.", 4, 4, 0, \
|
||||
WARN)
|
||||
|
||||
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
|
||||
#define CM_FOR_EACH_POLICY_ID(POLICY) \
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmValue.h"
|
||||
@@ -56,6 +57,17 @@ void cmVariableWatchCommandVariableAccessed(
|
||||
{ *currentListFile, cmListFileArgument::Quoted, fakeLineNo },
|
||||
{ stack, cmListFileArgument::Quoted, fakeLineNo }
|
||||
};
|
||||
{
|
||||
cmPolicies::PolicyStatus cmp0219 =
|
||||
makefile->CheckCMP0219(data->Command, newLFFArgs);
|
||||
if (cmp0219 == cmPolicies::NEW) {
|
||||
for (cmListFileArgument& arg : newLFFArgs) {
|
||||
cmSystemTools::ReplaceString(arg.Value, "\\", "\\\\");
|
||||
}
|
||||
} else if (cmp0219 == cmPolicies::WARN) {
|
||||
makefile->IssueCMP0219Warning(data->Command, newLFFArgs);
|
||||
}
|
||||
}
|
||||
|
||||
cmListFileFunction newLFF{ data->Command, fakeLineNo, fakeLineNo,
|
||||
std::move(newLFFArgs) };
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_inner)
|
||||
set(cmp0219_inner_argn "${ARGN}")
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_middle)
|
||||
cmp0219_inner(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_outer)
|
||||
cmp0219_middle(${ARGN})
|
||||
endmacro()
|
||||
|
||||
cmp0219_outer(HINTS "${cmp0219_path_native}")
|
||||
cmp0219_assert_equal("${cmp0219_inner_argn}" "HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1,18 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_capture package_name first_named)
|
||||
set(cmp0219_named "${first_named}")
|
||||
set(cmp0219_argn "${ARGN}")
|
||||
set(cmp0219_argv "${ARGV}")
|
||||
set(cmp0219_argv0 "${ARGV0}")
|
||||
set(cmp0219_argv1 "${ARGV1}")
|
||||
endmacro()
|
||||
|
||||
cmp0219_capture(pybind11 HINTS "${cmp0219_path_native}")
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_named}" "HINTS")
|
||||
cmp0219_assert_equal("${cmp0219_argn}" "${cmp0219_path_native}")
|
||||
cmp0219_assert_equal("${cmp0219_argv}" "pybind11;HINTS;${cmp0219_path_native}")
|
||||
cmp0219_assert_equal("${cmp0219_argv0}" "pybind11")
|
||||
cmp0219_assert_equal("${cmp0219_argv1}" "HINTS")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
Invalid character escape '\\b'\.
|
||||
@@ -0,0 +1,8 @@
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_capture_old)
|
||||
set(cmp0219_old_argn "${ARGN}")
|
||||
endmacro()
|
||||
|
||||
cmp0219_capture_old(HINTS "${cmp0219_path_native}")
|
||||
@@ -0,0 +1,20 @@
|
||||
function(cmp0219_assert_equal actual expected)
|
||||
if(NOT "${actual}" STREQUAL "${expected}")
|
||||
message(FATAL_ERROR
|
||||
"Assertion failed:\n"
|
||||
" expected=[${expected}]\n"
|
||||
" actual=[${actual}]")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(cmp0219_assert_undefined variable_name)
|
||||
if(DEFINED ${variable_name})
|
||||
message(FATAL_ERROR
|
||||
"Assertion failed:\n"
|
||||
" ${variable_name} should be undefined\n"
|
||||
" actual=[${${variable_name}}]")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(cmp0219_path_fwd "C:/build_bot/new/temp/vendor")
|
||||
string(REPLACE "/" "\\" cmp0219_path_native "${cmp0219_path_fwd}")
|
||||
@@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
|
||||
@@ -0,0 +1,8 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
|
||||
enable_language(C)
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("int main() { return '\\0'; }" RESULT)
|
||||
if(NOT RESULT)
|
||||
message(FATAL_ERROR "check_c_source_compiles failed for escaped NUL character source")
|
||||
endif()
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
Invalid character escape '\\0'\.
|
||||
@@ -0,0 +1,5 @@
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
|
||||
enable_language(C)
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("int main() { return '\\0'; }" RESULT)
|
||||
@@ -0,0 +1,30 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_defer_capture var_name)
|
||||
set(${var_name} "${ARGN}")
|
||||
endmacro()
|
||||
|
||||
# Deferred call is scheduled with OLD at the call site,
|
||||
# but executed with NEW at end-of-file.
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
cmake_language(
|
||||
DEFER CALL
|
||||
cmp0219_defer_capture cmp0219_defer_old_callsite
|
||||
HINTS "${cmp0219_path_native}")
|
||||
|
||||
# Deferred call is scheduled with NEW at the call site,
|
||||
# and executed with NEW at end-of-file.
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
cmake_language(
|
||||
DEFER CALL
|
||||
cmp0219_defer_capture cmp0219_defer_new_callsite
|
||||
HINTS "${cmp0219_path_native}")
|
||||
|
||||
cmake_language(
|
||||
DEFER CALL
|
||||
cmp0219_assert_equal "${cmp0219_defer_old_callsite}"
|
||||
"HINTS;${cmp0219_path_native}")
|
||||
cmake_language(
|
||||
DEFER CALL
|
||||
cmp0219_assert_equal "${cmp0219_defer_new_callsite}"
|
||||
"HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
Invalid character escape '\\b'\.
|
||||
@@ -0,0 +1,15 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_defer_capture var_name)
|
||||
set(${var_name} "${ARGN}")
|
||||
endmacro()
|
||||
|
||||
# Deferred call is scheduled with NEW at the call site,
|
||||
# but executed with OLD at end-of-file.
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
cmake_language(
|
||||
DEFER CALL
|
||||
cmp0219_defer_capture cmp0219_defer_new_callsite
|
||||
HINTS "${cmp0219_path_native}")
|
||||
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
@@ -0,0 +1,7 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
find_package(pybind11 HINTS "${cmp0219_path_native}")
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_provider_method}" "FIND_PACKAGE")
|
||||
cmp0219_assert_equal("${cmp0219_provider_package}" "pybind11")
|
||||
cmp0219_assert_equal("${cmp0219_provider_argn}" "HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
Invalid character escape '\\b'\.
|
||||
@@ -0,0 +1,3 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
find_package(pybind11 HINTS "${cmp0219_path_native}")
|
||||
@@ -0,0 +1,11 @@
|
||||
macro(cmp0219_provider method package_name)
|
||||
set(cmp0219_provider_method "${method}")
|
||||
set(cmp0219_provider_package "${package_name}")
|
||||
set(cmp0219_provider_argn "${ARGN}")
|
||||
set(${package_name}_FOUND TRUE)
|
||||
endmacro()
|
||||
|
||||
cmake_language(
|
||||
SET_DEPENDENCY_PROVIDER cmp0219_provider
|
||||
SUPPORTED_METHODS FIND_PACKAGE
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_dispatch)
|
||||
set(cmp0219_dispatch_argn "${ARGN}")
|
||||
endmacro()
|
||||
|
||||
cmake_language(CALL cmp0219_dispatch HINTS "${cmp0219_path_native}")
|
||||
cmp0219_assert_equal("${cmp0219_dispatch_argn}" "HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1,8 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
macro(cmp0219_escape str)
|
||||
cmp0219_assert_equal("${str}" "\\")
|
||||
endmacro()
|
||||
|
||||
cmp0219_escape("\\")
|
||||
@@ -0,0 +1,48 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
# Build progressively escaped variants to model callers that added extra
|
||||
# backslashes to make an OLD-only macro chain work.
|
||||
string(REPLACE "\\" "\\\\" cmp0219_path_2 "${cmp0219_path_native}")
|
||||
string(REPLACE "\\" "\\\\" cmp0219_path_4 "${cmp0219_path_2}")
|
||||
string(REPLACE "\\" "\\\\" cmp0219_path_8 "${cmp0219_path_4}")
|
||||
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
|
||||
macro(cmp0219_leaf var_name)
|
||||
set(${var_name} "${ARGN}")
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_middle_old)
|
||||
cmp0219_leaf(cmp0219_old_chain_capture ${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_middle_new)
|
||||
# Simulate a dependency update opting this middle forwarding layer into NEW.
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
cmp0219_leaf(cmp0219_mixed_chain_capture ${ARGN})
|
||||
cmake_policy(POP)
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_outer_to_old)
|
||||
cmp0219_middle_old(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_outer_to_new_middle)
|
||||
cmp0219_middle_new(${ARGN})
|
||||
endmacro()
|
||||
|
||||
# OLD->OLD->OLD requires heavily escaped input and produces a native path.
|
||||
cmp0219_outer_to_old(HINTS "${cmp0219_path_8}")
|
||||
cmp0219_assert_equal(
|
||||
"${cmp0219_old_chain_capture}" "HINTS;${cmp0219_path_native}")
|
||||
|
||||
# OLD->NEW->OLD with the same input preserves one extra layer.
|
||||
cmp0219_outer_to_new_middle(HINTS "${cmp0219_path_8}")
|
||||
cmp0219_assert_equal(
|
||||
"${cmp0219_mixed_chain_capture}" "HINTS;${cmp0219_path_2}")
|
||||
|
||||
# OLD->NEW->OLD needs fewer escape layers to reach a native path.
|
||||
cmp0219_outer_to_new_middle(HINTS "${cmp0219_path_4}")
|
||||
cmp0219_assert_equal(
|
||||
"${cmp0219_mixed_chain_capture}" "HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1,12 @@
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
macro(cmp0219_old_capture)
|
||||
set(cmp0219_old_argn "${ARGN}")
|
||||
endmacro()
|
||||
cmake_policy(POP)
|
||||
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
cmp0219_old_capture(HINTS "${cmp0219_path_native}")
|
||||
cmp0219_assert_equal("${cmp0219_old_argn}" "HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
Invalid character escape '\\b'\.
|
||||
@@ -0,0 +1,11 @@
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
macro(cmp0219_new_capture)
|
||||
set(cmp0219_new_argn "${ARGN}")
|
||||
endmacro()
|
||||
cmake_policy(POP)
|
||||
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
cmp0219_new_capture(HINTS "${cmp0219_path_native}")
|
||||
@@ -0,0 +1,46 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
|
||||
macro(cmp0219_parse_corner_case)
|
||||
set(_options)
|
||||
set(_one_value_args FOO)
|
||||
set(_multi_value_args)
|
||||
cmake_parse_arguments(cmp0219_q
|
||||
"${_options}"
|
||||
"${_one_value_args}"
|
||||
"${_multi_value_args}"
|
||||
"${ARGN}")
|
||||
cmake_parse_arguments(cmp0219_u
|
||||
"${_options}"
|
||||
"${_one_value_args}"
|
||||
"${_multi_value_args}"
|
||||
${ARGN})
|
||||
endmacro()
|
||||
|
||||
cmp0219_parse_corner_case(FOO "foo\\;bar")
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_q_FOO}" "foo;bar")
|
||||
cmp0219_assert_undefined(cmp0219_q_UNPARSED_ARGUMENTS)
|
||||
cmp0219_assert_equal("${cmp0219_u_FOO}" "foo")
|
||||
cmp0219_assert_equal("${cmp0219_u_UNPARSED_ARGUMENTS}" "bar")
|
||||
|
||||
cmp0219_parse_corner_case(FOO "foo\;bar")
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_q_FOO}" "foo;bar")
|
||||
cmp0219_assert_undefined(cmp0219_q_UNPARSED_ARGUMENTS)
|
||||
cmp0219_assert_equal("${cmp0219_u_FOO}" "foo")
|
||||
cmp0219_assert_equal("${cmp0219_u_UNPARSED_ARGUMENTS}" "bar")
|
||||
|
||||
cmp0219_parse_corner_case(FOO "foo;bar")
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_q_FOO}" "foo")
|
||||
cmp0219_assert_equal("${cmp0219_u_UNPARSED_ARGUMENTS}" "bar")
|
||||
cmp0219_assert_equal("${cmp0219_u_FOO}" "foo")
|
||||
cmp0219_assert_equal("${cmp0219_u_UNPARSED_ARGUMENTS}" "bar")
|
||||
|
||||
cmp0219_parse_corner_case(FOO foo;bar)
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_q_FOO}" "foo")
|
||||
cmp0219_assert_equal("${cmp0219_u_UNPARSED_ARGUMENTS}" "bar")
|
||||
cmp0219_assert_equal("${cmp0219_u_FOO}" "foo")
|
||||
cmp0219_assert_equal("${cmp0219_u_UNPARSED_ARGUMENTS}" "bar")
|
||||
@@ -0,0 +1,32 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
macro(cmp0219_old_return)
|
||||
set(cmp0219_old_return_argn "${ARGN}" PARENT_SCOPE)
|
||||
return()
|
||||
endmacro()
|
||||
|
||||
macro(cmp0219_old_set_policy)
|
||||
set(cmp0219_old_set_policy_argn "${ARGN}")
|
||||
cmake_policy(SET CMP0210 OLD)
|
||||
endmacro()
|
||||
cmake_policy(POP)
|
||||
|
||||
function(cmp0219_test_return)
|
||||
set(cmp0219_return_state "before" PARENT_SCOPE)
|
||||
cmp0219_old_return(HINTS "${cmp0219_path_native}")
|
||||
set(cmp0219_return_state "after" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
cmp0219_test_return()
|
||||
cmp0219_assert_equal("${cmp0219_return_state}" "before")
|
||||
cmp0219_assert_equal(
|
||||
"${cmp0219_old_return_argn}" "HINTS;${cmp0219_path_native}")
|
||||
|
||||
cmp0219_old_set_policy(HINTS "${cmp0219_path_native}")
|
||||
cmake_policy(GET CMP0210 cmp0219_cmp0210_status)
|
||||
cmp0219_assert_equal("${cmp0219_cmp0210_status}" "OLD")
|
||||
cmp0219_assert_equal(
|
||||
"${cmp0219_old_set_policy_argn}" "HINTS;${cmp0219_path_native}")
|
||||
@@ -0,0 +1,30 @@
|
||||
include(RunCMake)
|
||||
|
||||
run_cmake_script(Basic-NEW)
|
||||
run_cmake_script(Basic-OLD)
|
||||
run_cmake_script(Escape2-NEW)
|
||||
run_cmake_script(AllNEW-Forward)
|
||||
run_cmake_script(NEW-calls-OLD)
|
||||
run_cmake_script(OLD-calls-NEW)
|
||||
run_cmake_script(MixedChain-OLD-NEWMiddle)
|
||||
run_cmake_script(DynamicDispatch-NEW)
|
||||
run_cmake_script(ParseArguments-Semicolon)
|
||||
run_cmake_script(SemicolonEscape-QuotedUnquoted)
|
||||
run_cmake_script(ReturnAndPolicyPropagation)
|
||||
run_cmake_script(Warn-Unset-Macro)
|
||||
run_cmake_script(Warn-Unset-Macro-Multi)
|
||||
run_cmake_script(Warn-Unset-VariableWatch)
|
||||
run_cmake_script(VariableWatch-OLD)
|
||||
run_cmake_script(VariableWatch-NEW)
|
||||
run_cmake(CheckCSourceCompiles-OLD)
|
||||
run_cmake(CheckCSourceCompiles-NEW)
|
||||
run_cmake_with_options(DependencyProviderMacro-OLD
|
||||
-D "CMAKE_PROJECT_TOP_LEVEL_INCLUDES=${RunCMake_SOURCE_DIR}/DependencyProviderMacro-TopInclude.cmake"
|
||||
-D "CMAKE_POLICY_DEFAULT_CMP0219=OLD"
|
||||
)
|
||||
run_cmake_with_options(DependencyProviderMacro-NEW
|
||||
-D "CMAKE_PROJECT_TOP_LEVEL_INCLUDES=${RunCMake_SOURCE_DIR}/DependencyProviderMacro-TopInclude.cmake"
|
||||
-D "CMAKE_POLICY_DEFAULT_CMP0219=NEW"
|
||||
)
|
||||
run_cmake(Defer-EndPolicy-NEW)
|
||||
run_cmake(Defer-EndPolicy-OLD)
|
||||
@@ -0,0 +1,62 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
function(cmp0219_assert_encoded actual expected)
|
||||
string(REPLACE "\\" "<BS>" cmp0219_encoded "${actual}")
|
||||
string(REPLACE ";" "<SC>" cmp0219_encoded "${cmp0219_encoded}")
|
||||
cmp0219_assert_equal("${cmp0219_encoded}" "${expected}")
|
||||
endfunction()
|
||||
|
||||
function(cmp0219_sink out_prefix)
|
||||
math(EXPR cmp0219_sink_argc "${ARGC} - 1")
|
||||
set(${out_prefix}_argc "${cmp0219_sink_argc}" PARENT_SCOPE)
|
||||
if(cmp0219_sink_argc GREATER 0)
|
||||
set(${out_prefix}_arg0 "${ARGV1}" PARENT_SCOPE)
|
||||
endif()
|
||||
if(cmp0219_sink_argc GREATER 1)
|
||||
set(${out_prefix}_arg1 "${ARGV2}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(cmp0219_semicolon_probe prefix value)
|
||||
set(${prefix}_named_q "${value}")
|
||||
set(${prefix}_named_u ${value})
|
||||
set(${prefix}_argv1_q "${ARGV1}")
|
||||
set(${prefix}_argv1_u ${ARGV1})
|
||||
set(${prefix}_argn_q "${ARGN}")
|
||||
set(${prefix}_argn_u ${ARGN})
|
||||
|
||||
cmp0219_sink("${prefix}_sink_named_q" "${value}")
|
||||
cmp0219_sink("${prefix}_sink_named_u" ${value})
|
||||
cmp0219_sink("${prefix}_sink_argn_q" "${ARGN}")
|
||||
cmp0219_sink("${prefix}_sink_argn_u" ${ARGN})
|
||||
endmacro()
|
||||
|
||||
function(cmp0219_run_semicolon_escape_mode mode)
|
||||
cmake_policy(SET CMP0219 "${mode}")
|
||||
|
||||
# Value passed with a quoted argument keeps '\;' in textual substitutions
|
||||
# until an unquoted use decodes it.
|
||||
cmp0219_semicolon_probe("${mode}_quoted" "foo\\;bar" "foo\\;bar")
|
||||
cmp0219_assert_encoded("${${mode}_quoted_named_q}" "foo<BS><SC>bar")
|
||||
cmp0219_assert_encoded("${${mode}_quoted_named_u}" "foo<SC>bar")
|
||||
cmp0219_assert_equal("${${mode}_quoted_sink_named_q_argc}" "1")
|
||||
cmp0219_assert_equal("${${mode}_quoted_sink_named_u_argc}" "1")
|
||||
cmp0219_assert_equal("${${mode}_quoted_sink_argn_q_argc}" "1")
|
||||
cmp0219_assert_equal("${${mode}_quoted_sink_argn_u_argc}" "1")
|
||||
|
||||
# Value passed with an unquoted argument uses '\;' to keep one argument at
|
||||
# the call site, but unquoted forwarding splits at ';' in the macro body.
|
||||
cmp0219_semicolon_probe("${mode}_unquoted" foo\;bar foo\;bar)
|
||||
cmp0219_assert_encoded("${${mode}_unquoted_named_q}" "foo<SC>bar")
|
||||
cmp0219_assert_equal("${${mode}_unquoted_sink_named_q_argc}" "1")
|
||||
cmp0219_assert_equal("${${mode}_unquoted_sink_named_u_argc}" "2")
|
||||
cmp0219_assert_encoded("${${mode}_unquoted_sink_named_u_arg0}" "foo")
|
||||
cmp0219_assert_encoded("${${mode}_unquoted_sink_named_u_arg1}" "bar")
|
||||
cmp0219_assert_equal("${${mode}_unquoted_sink_argn_q_argc}" "1")
|
||||
cmp0219_assert_equal("${${mode}_unquoted_sink_argn_u_argc}" "2")
|
||||
cmp0219_assert_encoded("${${mode}_unquoted_sink_argn_u_arg0}" "foo")
|
||||
cmp0219_assert_encoded("${${mode}_unquoted_sink_argn_u_arg1}" "bar")
|
||||
endfunction()
|
||||
|
||||
cmp0219_run_semicolon_escape_mode(OLD)
|
||||
cmp0219_run_semicolon_escape_mode(NEW)
|
||||
@@ -0,0 +1,11 @@
|
||||
cmake_policy(SET CMP0219 NEW)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
function(cmp0219_watch_callback variable access value current_list_file stack)
|
||||
set(cmp0219_watch_value "${value}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
variable_watch(cmp0219_watched cmp0219_watch_callback)
|
||||
set(cmp0219_watched "${cmp0219_path_native}")
|
||||
|
||||
cmp0219_assert_equal("${cmp0219_watch_value}" "${cmp0219_path_native}")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
Invalid character escape '\\b'\.
|
||||
@@ -0,0 +1,9 @@
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0219-helpers.cmake")
|
||||
|
||||
function(cmp0219_watch_callback variable access value current_list_file stack)
|
||||
set(cmp0219_watch_value "${value}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
variable_watch(cmp0219_watched cmp0219_watch_callback)
|
||||
set(cmp0219_watched "${cmp0219_path_native}")
|
||||
@@ -0,0 +1,22 @@
|
||||
CMake Warning \(policy\) at .*/Warn-Unset-Macro-Multi\.cmake:[0-9]+ \(cmp0219_warn_macro\):
|
||||
Policy CMP0219 is not set: Macro invocations preserve backslashes in
|
||||
arguments\. Run "cmake --help-policy CMP0219" for policy details\. Use the
|
||||
cmake_policy command to set the policy and suppress this warning\.
|
||||
|
||||
Command "cmp0219_warn_macro" called with arguments containing backslashes\.
|
||||
|
||||
Since the policy is not set, backslashes in the arguments:
|
||||
|
||||
"prefix\\tsuffix"
|
||||
"left\\;right"
|
||||
|
||||
will be interpreted as escape sequences for compatibility\.
|
||||
|
||||
Set the policy to NEW to instead pass
|
||||
|
||||
"prefix\\\\tsuffix"
|
||||
"left\\\\;right"
|
||||
|
||||
so that argument parsing will preserve the original values\.
|
||||
This warning is for project developers\. Use -Wno-author or -Wno-policy to
|
||||
suppress it\.
|
||||
@@ -0,0 +1,9 @@
|
||||
set(cmp0219_warn_value1 "prefix\\tsuffix")
|
||||
set(cmp0219_warn_value2 "left\\;right")
|
||||
|
||||
macro(cmp0219_warn_macro arg1 arg2)
|
||||
set(cmp0219_warn_seen1 "${arg1}")
|
||||
set(cmp0219_warn_seen2 "${arg2}")
|
||||
endmacro()
|
||||
|
||||
cmp0219_warn_macro("${cmp0219_warn_value1}" "${cmp0219_warn_value2}")
|
||||
@@ -0,0 +1,20 @@
|
||||
CMake Warning \(policy\) at .*/Warn-Unset-Macro\.cmake:[0-9]+ \(cmp0219_warn_macro\):
|
||||
Policy CMP0219 is not set: Macro invocations preserve backslashes in
|
||||
arguments\. Run "cmake --help-policy CMP0219" for policy details\. Use the
|
||||
cmake_policy command to set the policy and suppress this warning\.
|
||||
|
||||
Command "cmp0219_warn_macro" called with arguments containing backslashes\.
|
||||
|
||||
Since the policy is not set, backslashes in the arguments:
|
||||
|
||||
"prefix\\tsuffix"
|
||||
|
||||
will be interpreted as escape sequences for compatibility\.
|
||||
|
||||
Set the policy to NEW to instead pass
|
||||
|
||||
"prefix\\\\tsuffix"
|
||||
|
||||
so that argument parsing will preserve the original values\.
|
||||
This warning is for project developers\. Use -Wno-author or -Wno-policy to
|
||||
suppress it\.
|
||||
@@ -0,0 +1,8 @@
|
||||
set(cmp0219_warn_value "prefix\\tsuffix")
|
||||
|
||||
macro(cmp0219_warn_macro value)
|
||||
set(cmp0219_warn_seen "${value}")
|
||||
endmacro()
|
||||
|
||||
cmp0219_warn_macro("${cmp0219_warn_value}")
|
||||
cmp0219_warn_macro("${cmp0219_warn_value}")
|
||||
@@ -0,0 +1,20 @@
|
||||
CMake Warning \(policy\) at .*/Warn-Unset-VariableWatch\.cmake:[0-9]+ \(set\):
|
||||
Policy CMP0219 is not set: Macro invocations preserve backslashes in
|
||||
arguments\. Run "cmake --help-policy CMP0219" for policy details\. Use the
|
||||
cmake_policy command to set the policy and suppress this warning\.
|
||||
|
||||
Command "cmp0219_warn_watch" called with arguments containing backslashes\.
|
||||
|
||||
Since the policy is not set, backslashes in the arguments:
|
||||
|
||||
"prefix\\tsuffix"
|
||||
|
||||
will be interpreted as escape sequences for compatibility\.
|
||||
|
||||
Set the policy to NEW to instead pass
|
||||
|
||||
"prefix\\\\tsuffix"
|
||||
|
||||
so that argument parsing will preserve the original values\.
|
||||
This warning is for project developers\. Use -Wno-author or -Wno-policy to
|
||||
suppress it\.
|
||||
@@ -0,0 +1,6 @@
|
||||
function(cmp0219_warn_watch variable access value current_list_file stack)
|
||||
endfunction()
|
||||
|
||||
variable_watch(cmp0219_warned cmp0219_warn_watch)
|
||||
set(cmp0219_warned "prefix\\tsuffix")
|
||||
set(cmp0219_warned "prefix\\tsuffix")
|
||||
@@ -185,6 +185,7 @@ if(WIN32)
|
||||
add_RunCMake_test(CMP0212)
|
||||
endif()
|
||||
add_RunCMake_test(CMP0217)
|
||||
add_RunCMake_test(CMP0219)
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
add_RunCMake_test(CMP0194 -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if(POLICY CMP0219)
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
endif()
|
||||
|
||||
project(${RunCMake_TEST} LANGUAGES NONE)
|
||||
|
||||
include(${RunCMake_TEST}.cmake)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
CMake Error at Escape2\.cmake:2 \(message\):
|
||||
CMake Error at Escape2\.cmake:[0-9]+ \(message\):
|
||||
Syntax error in cmake code at
|
||||
|
||||
.*/Tests/RunCMake/Syntax/Escape2\.cmake:2
|
||||
.*/Tests/RunCMake/Syntax/Escape2\.cmake:[0-9]+
|
||||
|
||||
when parsing string
|
||||
|
||||
@@ -9,5 +9,5 @@ CMake Error at Escape2\.cmake:2 \(message\):
|
||||
|
||||
Invalid character escape '\\' \(at end of input\)\.
|
||||
Call Stack \(most recent call first\):
|
||||
Escape2\.cmake:5 \(escape\)
|
||||
Escape2\.cmake:[0-9]+ \(escape\)
|
||||
CMakeLists\.txt:3 \(include\)
|
||||
|
||||
@@ -2,4 +2,8 @@ macro (escape str)
|
||||
message("${str}")
|
||||
endmacro ()
|
||||
|
||||
if(POLICY CMP0219)
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
endif()
|
||||
|
||||
escape("\\")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/test_utils.cmake)
|
||||
cmake_policy(SET CMP0219 OLD)
|
||||
|
||||
# example from the documentation
|
||||
# OPTIONAL is a keyword and therefore terminates the definition of
|
||||
|
||||
Reference in New Issue
Block a user