不要扩展 CMake 列表变量

Do not expand CMake list variable

我有一个 CMake 脚本,它 运行 在 CMake 3.15 中通过 add_test()、运行ning 在 Windows(Server 2008,不要问)下进行一些测试.当调用这些测试时,它们 运行 所在环境中的 PYTHONPATH 环境变量似乎被重置为环境默认值,并且不包含它需要的一些路径。

因此,当测试是 运行 CMake 运行s 时 $ENV{PYTHONPATH} 变量的值时,我需要设置 PYTHONPATH。这有许多以分号分隔的路径,因此 CMake 认为它是一个列表并试图将其扩展为多个 space 分隔的字符串,这显然结束得很糟糕。

我不知道如何阻止 CMake 这样做。从我所看到的一切来看,你应该可以用引号括起来:

add_test(
  NAME mytest
  COMMAND cmake -E env PYTHONPATH="$ENV{PYTHONPATH}"
  run_test_here)

...但它总是进行扩展。我也尝试设置 set_tests_properties:

set_tests_properties(mytest PROPERTIES
    ENVIRONMENT PYTHONPATH="$ENV{PYTHONPATH}")

...但这似乎根本没有做任何事情 - 测试时的 PYTHONPATH 没有改变。我认为这是因为它是一个环境变量,但是通过 set() 使用常规 CMake 变量没有任何区别,所以我做错了什么。请帮忙!

以下应该有效:

COMMAND cmake -E env "PYTHONPATH=$ENV{PYTHONPATH}"

您需要引用命令行的完整部分,以正确扩展消息。

测试:

set(tmp "C:\Python27\Scripts;E:\JenkinsMIDEBLD\workspace\...;...")
add_test(NAME MYtest1 COMMAND cmake -S . -E env "tmp=${tmp}") 
add_test(NAME MYtest2 COMMAND cmake -S . -E env tmp="${tmp}") 

在 运行 ctest 之后我得到:

1: Test command: /bin/cmake "-S" "." "-E" "env" "tmp=C:\Python27\Scripts;E:\JenkinsMIDEBLD\workspace\...;..."
2: Test command: /bin/cmake "-S" "." "-E" "env" "tmp="C:\Python27\Scripts" "E:\JenkinsMIDEBLD\workspace\..." "...""

第一个测试正确 ; 传递给 var,而第二个测试通过 space 分隔列表。

这就是 cmake 解析的方式 quoted arguments。参数要么被完全引用,要么根本没有被引用 - 部分引号被解释为文字 "。所以假设:

set(var a;b;c)

以下:

var="$var"

不是引号,"是字面意思!它将$var列表扩展为space分隔列表和"保留,=a之间有一个",并且有最后添加 "var="$var" 等于:

var=\"a b c\"
    ^^     ^^    - the quotes stay!
^^^^^^^ ^ ^^^    - these are 3 arguments, the last one is `c"`

没有引号是:

var=$var

等于(注意遗漏的引号):

var=a c c

要引用参数,您必须将其全部引用,元素的第一个和最后一个字符为 ":

"var=$var"

将扩展为:

"var=a;b;c"

您可以使用 ENVIRONMENT 测试 属性 完成这项工作,但有一个问题:

分号分隔不同的环境变量进行设置;您需要在环境变量中转义分号。例如代替

set_tests_properties(mytest PROPERTIES
    ENVIRONMENT "PYTHONPATH=foo;bar")

你需要使用

set_tests_properties(mytest PROPERTIES
    ENVIRONMENT "PYTHONPATH=foo\;bar")

环境变量可能包含分号这一事实使得一些转换成为必要:因为 ; 用于分隔列表元素,您可以简单地使用 list(JOIN) 将它们替换为 "\;"

以下示例适用于 PATH,不适用于 PYTHONPATH,因为我没有安装 python:

CMakeLists.txt

cmake_minimum_required(VERSION 3.12.4) # required for list(JOIN)

project(TestProject)

# get a version of the PATH environment var that can be used in the ENVIRONMENT test property
set(_PATH $ENV{PATH})
list(JOIN _PATH "\;" _PATH_CLEAN)

# just use a cmake script so we don't need to require any program able to retrieve environment vars
add_test(NAME Test1 COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_SOURCE_DIR}/test_script.cmake")

# we add another simpler var to test in the cmake script
set_tests_properties(Test1 PROPERTIES ENVIRONMENT "PATH=${_PATH_CLEAN};FOO=foo")

enable_testing()

test_script.cmake

message(STATUS "PATH=$ENV{PATH}")

if (NOT "$ENV{FOO}" STREQUAL "foo")
    # the following command results in a non-0 exit code, if executed
    message(FATAL_ERROR "FOO environment var should contain \"foo\" but contains \"$ENV{FOO}\"")
endif()