如何在 cmake 中使用重定向 add_test
How to use redirection in cmake add_test
我有一个名为 "foo" 的控制台应用程序,它将参考文本文件作为输入 (in.txt) 并在标准输出中生成文本(我想保持这种行为)。
在 make(不是 cmake)中,我使用了一个测试目标,它调用 foo 并将输出重定向到一个文件 (out.txt),如下所示。然后,我使用 diff 将文件 out.txt 与预期的引用 (ref.txt)
进行比较
test:
./foo -a test/in.txt > test/out.txt
diff test/out.txt test/ref.txt
使用 make 效果很好。现在我的问题是; 如何使用cmake创建类似的Makefile?
我尝试从名为 build 的子目录中
project(foo)
...
add_test(NAME test1 COMMAND ./foo ../test/in.txt > ../test/out.txt)
enable_testing()
使用 cmake 版本 3.5,我得到了一个没有错误的 Makefile,但是当我调用 make test
时,测试本身失败了。似乎 cmake 命令 add_test
支持命令行参数,但不支持重定向。我尝试了引号并成功逃脱。由于我无法通过这部分,所以我没有尝试使用diff。我只是想象我可以使用 & 将 foo 和 diff 打包在一行中,就像使用 bash 一样。那将是第二步。
They say 你不能:
There is no redirection of output using add_test arguments.
不同于 add_custom_command
中的命令,它们作为 makefile 收据的一部分执行(即,在某些 shell 的上下文中),测试由 CTest 直接执行,没有任何 shell 参与 。因此,shell 机制不适用于测试。
您可以创建包装器脚本,它调用作为参数给定的程序,并执行重定向,进一步 diff
等等。然后使用此脚本(带有适当的参数)作为 COMMAND
for add_test
.
将我的评论变成答案
正如@Tsyvarev 所说,CTest 命令在shell 的上下文中不是运行。但是您可以自己添加 shell 并使用例如sh
作为要用 add_test()
.
调用的命令
我已经 运行 使用您的示例代码进行了一些测试,以下确实成功运行:
add_test(NAME test1 COMMAND sh -c "$<TARGET_FILE:foo> ../test/in.txt > ../test/out.txt")
此解决方案与平台无关(它取决于 sh
在搜索路径中是否可用)。
因此,如果您想更加灵活,可以执行以下操作:
include(FindUnixCommands)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/test/in.txt" _in)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/test/out.txt" _out)
if (BASH)
add_test(
NAME test1
COMMAND ${BASH} -c "$<TARGET_FILE:foo> ${_in} > ${_out}"
)
else()
if (WIN32)
add_test(
NAME test1
COMMAND ${CMAKE_COMMAND} -E chdir $<TARGET_FILE_DIR:foo> $ENV{ComSpec} /c "$<TARGET_FILE_NAME:foo> ${_in} > ${_out}"
)
else()
message(FATAL_ERROR "Unknown shell command for ${CMAKE_HOST_SYSTEM_NAME}")
endif()
endif()
此外,还可以使用 ${CMAKE_COMMAND} -E compare_files <file1> <file2>
执行更独立于平台的 diff
。因此,您可以在 CMake 中简化基于 makefile 的完整示例:
add_custom_command(
TARGET foo
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Running $<TARGET_FILE_NAME:foo> ..."
COMMAND foo in.txt > out.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
)
add_test(
NAME test1
COMMAND ${CMAKE_COMMAND} -E compare_files in.txt out.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
)
参考资料
- Integrate bash test scripts in cmake
- CMake: piping commands to executable
我有一个名为 "foo" 的控制台应用程序,它将参考文本文件作为输入 (in.txt) 并在标准输出中生成文本(我想保持这种行为)。
在 make(不是 cmake)中,我使用了一个测试目标,它调用 foo 并将输出重定向到一个文件 (out.txt),如下所示。然后,我使用 diff 将文件 out.txt 与预期的引用 (ref.txt)
进行比较test:
./foo -a test/in.txt > test/out.txt
diff test/out.txt test/ref.txt
使用 make 效果很好。现在我的问题是; 如何使用cmake创建类似的Makefile?
我尝试从名为 build 的子目录中
project(foo)
...
add_test(NAME test1 COMMAND ./foo ../test/in.txt > ../test/out.txt)
enable_testing()
使用 cmake 版本 3.5,我得到了一个没有错误的 Makefile,但是当我调用 make test
时,测试本身失败了。似乎 cmake 命令 add_test
支持命令行参数,但不支持重定向。我尝试了引号并成功逃脱。由于我无法通过这部分,所以我没有尝试使用diff。我只是想象我可以使用 & 将 foo 和 diff 打包在一行中,就像使用 bash 一样。那将是第二步。
They say 你不能:
There is no redirection of output using add_test arguments.
不同于 add_custom_command
中的命令,它们作为 makefile 收据的一部分执行(即,在某些 shell 的上下文中),测试由 CTest 直接执行,没有任何 shell 参与 。因此,shell 机制不适用于测试。
您可以创建包装器脚本,它调用作为参数给定的程序,并执行重定向,进一步 diff
等等。然后使用此脚本(带有适当的参数)作为 COMMAND
for add_test
.
将我的评论变成答案
正如@Tsyvarev 所说,CTest 命令在shell 的上下文中不是运行。但是您可以自己添加 shell 并使用例如sh
作为要用 add_test()
.
我已经 运行 使用您的示例代码进行了一些测试,以下确实成功运行:
add_test(NAME test1 COMMAND sh -c "$<TARGET_FILE:foo> ../test/in.txt > ../test/out.txt")
此解决方案与平台无关(它取决于 sh
在搜索路径中是否可用)。
因此,如果您想更加灵活,可以执行以下操作:
include(FindUnixCommands)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/test/in.txt" _in)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/test/out.txt" _out)
if (BASH)
add_test(
NAME test1
COMMAND ${BASH} -c "$<TARGET_FILE:foo> ${_in} > ${_out}"
)
else()
if (WIN32)
add_test(
NAME test1
COMMAND ${CMAKE_COMMAND} -E chdir $<TARGET_FILE_DIR:foo> $ENV{ComSpec} /c "$<TARGET_FILE_NAME:foo> ${_in} > ${_out}"
)
else()
message(FATAL_ERROR "Unknown shell command for ${CMAKE_HOST_SYSTEM_NAME}")
endif()
endif()
此外,还可以使用 ${CMAKE_COMMAND} -E compare_files <file1> <file2>
执行更独立于平台的 diff
。因此,您可以在 CMake 中简化基于 makefile 的完整示例:
add_custom_command(
TARGET foo
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Running $<TARGET_FILE_NAME:foo> ..."
COMMAND foo in.txt > out.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
)
add_test(
NAME test1
COMMAND ${CMAKE_COMMAND} -E compare_files in.txt out.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
)
参考资料
- Integrate bash test scripts in cmake
- CMake: piping commands to executable