如何在 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
)

参考资料