【问题标题】:Do not expand CMake list variable不要展开 CMake 列表变量
【发布时间】:2019-11-01 10:40:40
【问题描述】:

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

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

我不知道如何阻止 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 变量没有任何区别,所以我做错了。请帮忙!

【问题讨论】:

  • 你的意思是你想要\$ENV{PYTHONPATH}
  • 我想要:cmake COMMAND cmake -E env PYTHONPATH="C:\part\of\pythonpath;C:\another\part" ...但显然不是硬编码的。
  • PYTHONPATH 不应该用: 分隔吗?它不应该是分号分隔的路径,它应该是冒号分隔的路径。运行命令前COMMAND echo "$ENV{PYTHONPATH}"message(STATUS "ENV{PYTHONPATH} = $ENV{PYTHONPATH}") 的输出是什么?
  • 在 Linux 上确实如此。可悲的是,我坚持使用使用分号的 Windows。
  • message(STATUS "ENV{PYTHONPATH} = $ENV{PYTHONPATH}") 返回它应该返回的内容(冒号分隔的路径列表,看起来像 C:\Python27\Scripts;E:\JenkinsMIDEBLD\workspace\...;...COMMAND echo "$ENV{PYTHONPATH}" 返回相同的内容,但带有空格:"C:\Python27\Scripts" "E:\JenkinsMIDEBLD\workspace\..." "..."

标签: cmake ctest


【解决方案1】:

以下应该有效:

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,而第二个测试通过空格分隔列表。

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

set(var a;b;c)

以下内容:

var="$var"

不是引用的参数," 是字面意思!它将$var列表扩展为空格分隔列表,"留在,=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"

【讨论】:

  • 万岁,它有效!我没有尝试过的报价和事情的一种配置。非常感谢!
【解决方案2】:

您可以使用 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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-22
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多