CMake-作为构建过程的一部分运行测试并将stdout输出捕获到文件 [英] CMake - run test as part of the build process and capture stdout output to file

查看:112
本文介绍了CMake-作为构建过程的一部分运行测试并将stdout输出捕获到文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有几个单元测试,我们希望在构建过程中运行它们。

We have several unit tests which we would like to be run as part of our build process.

要实现这一点,我有一个帮助程序脚本,可创建自定义命令运行测试,如果成功,则创建文件 test_name.passed

To achieve this I have a helper script which creates a custom command that runs the test, and if successful, creates a file "test_name.passed".

我然后添加一个自定义目标 test_name.run 取决于 test_name.passed

I then add a custom target "test_name.run" which depends on "test_name.passed".

这个想法是,如果 test_name.passed 不存在或早于 test_name ,则将运行自定义命令。

The idea is that if "test_name.passed" doesn't exist or is older than "test_name", the custom command will be run.

内部版本将继续运行自定义命令,直到测试通过。一旦通过,后续的构建将不会调用自定义命令,因此该测试将在不需要时运行。

Builds will continue to run the custom command until the test passes. Once it passes, subsequent builds won't call the custom command, so the test won't be run when it doesn't need to.

到目前为止

以下是所有脚本的工作原理:

Here is the script:

# create command which runs the test and creates a sentinel file if it passes
add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND $<TARGET_FILE:${TEST_NAME}>
    COMMAND ${CMAKE_COMMAND} -E touch ${TEST_NAME}.passed
    DEPENDS ${TEST_NAME}
    )

# create test.run module which depends on test.passed
add_custom_target(${TEST_NAME}.run
    ALL
    DEPENDS ${TEST_NAME}.passed
    )

问题- stdout

The problem - noise on stdout

问题在于我们的测试通常会将一吨信息记录到 stdout 中,这会使构建过程非常嘈杂。

The problem is that our tests often log a tonne of information to stdout, and it makes for a very noisy build.

我正在尝试捕获 stdout 到文件,只有在失败的情况下,才显示测试输出。

I'm trying to now capture stdout to a file, and only in the event of a failure, display the test output.

我的第一次尝试是尝试使用Bash Shell脚本语法-将 stdout 捕获到文件中,然后在退出状态为错误时,将文件保存为空。

My first attempt was to try a Bash shell scripting syntax - capture stdout into a file and when the exit status is an error, cat the file.

add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND $<TARGET_FILE:${TEST_NAME}> > ${TEST_NAME}.output || cat ${TEST_NAME}.output
    COMMAND ${CMAKE_COMMAND} -E touch ${TEST_NAME}.passed
    DEPENDS ${TEST_NAME}
    )

这是行不通的,即使测试失败,我也会收到哨兵 test_name.passed 文件已创建,这意味着我下次尝试构建该文件时,它认为测试已通过。

This doesn't work, as even if the test fails I am getting the sentinal "test_name.passed" file created, which means the next time I try to build it thinks the test passed.

可能的不合标准的修补程序

通过与 ctest 集成,我可以通过ctest运行每个测试,并使用命令行选项-故障输出

By integrating with ctest, I can run each test through ctest and use the command-line option --output-on-failure

add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND ctest --build-config $<CONFIGURATION> --tests-regex ${TEST_NAME} --output-on-failure
    COMMAND ${CMAKE_COMMAND} -E touch ${TEST_NAME}.passed
    DEPENDS ${TEST_NAME}
    )

问题在于两倍。


  1. 极大地增加了构建时间。每个测试都必须通过单独的ctest流程执行,所有注册的测试名称都将根据正则表达式进行解析,依此类推。随着单个测试数量的增加,我们的额外时间大大增加了。

  2. ctest默认会输出很多噪音。指定-quiet 标志会抑制-failure-output 标志,因此您可以产生嘈杂的输出或没有输出-没有办法只能解决失败。

  1. It vastly increases the build time. Each and every test has to be executed through a separate ctest process, all the registered test names parsed against the regex, etc. With the number of individual tests we have the extra time adds up considerably.
  2. ctest outputs a lot of noise by default. Specifying the --quiet flag suppresses the --output-on-failure flag, so you can either have noisy output or no output - there is no way to only get the failures.

问题

有没有办法实现我想要的?

Is there a way to achieve what I want?

即:


  • 手动运行测试(即:不通过ctest)

  • 将输出捕获到文件中

  • 仅在测试退出状态指示失败时才输出该文件。

  • 如果测试退出状态指示成功,则触摸哨兵文件。

  • Run the test manually (ie: not through ctest)
  • Capture the output to a file
  • Only output that file in the event of the test exit status indicating failure.
  • Touch a sentinel file in the event of the test exit status indicating success.

奖金指向跨平台方法,但是如果必须仅是Linux,那就这样吧。

Bonus points for a cross-platform method, but if it has to be Linux only, then so be it.

推荐答案

回答我自己的问题问题,因为我找到了适合我的解决方案。

Answering my own question because I found a solution which works for me.

在下面的摘录中, $ {ARG_NAME} 是我们已经构建并要运行的测试二进制文件。

In the below excerpt, ${ARG_NAME} is the test binary which we've built and want to run.

运行测试时创建了2个文件

There are 2 files created whilst running the tests


  • $ {ARG_NAME} .output ,其中包含测试输出

  • $ {ARG_NAME} .passed 是通过测试成功创建的哨兵文件

  • ${ARG_NAME}.output which contains the test output
  • ${ARG_NAME}.passed which is a sentinel file created if the test is successful

custom_command 由几个命令组成,我们依靠的事实是,一旦其中一个失败,cmake就会停止执行。

The custom_command consists of several commands, and we rely on the fact that cmake will stop executing as soon as one of them fails.

我们运行测试:

${ARG_NAME}

所有测试输出都重定向到 $ {ARG_NAME} .output ,因此在测试通过时我们不会污染stdout

All test output is redirected to ${ARG_NAME}.output, so we don't pollute stdout when the tests pass

${ARG_NAME} >> ${OUTPUT_FILE} 2>&1

在失败的情况下使用测试的退出状态我们对文件进行分类:

Using the test's exit status, in the event of a failure we cat the file:

${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 || cat ${OUTPUT_FILE}

但是,只有在测试通过后,我们才想创建前哨文件,因此我们将文件放在目录中并运行 false

However, only when the test passes do we want to create the sentinel file, so we both cat the file and run false

${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 || (cat ${OUTPUT_FILE} && false)

如果测试通过(退出状态为0 ),那么我们就不会运行 cat输出&& false ,因此运行下一个cmake命令

If the test passes (exit status is 0), then we won't have run the cat output && false, so then the next cmake command is run

${CMAKE_COMMAND} -E touch ${PASSED_FILE}

最后,我们创建一个 custom_target 取决于 .passed 文件

Finally we create a custom_target which depends on the .passed file

set(OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}.output)
set(PASSED_FILE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}.passed)

# create test.passed command which runs this test and creates a sentinel file
# if it passes
add_custom_command(
    OUTPUT
        ${PASSED_FILE}

    COMMAND
        ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 
              || (cat ${OUTPUT_FILE} && false)

    COMMAND
        ${CMAKE_COMMAND} -E touch ${PASSED_FILE}

    COMMENT
        "Running ${ARG_NAME} tests"

    DEPENDS
        ${ARG_NAME}

    USES_TERMINAL
    )

# create test.run target which depends on test.passed
add_custom_target(${ARG_NAME}.run
    ALL
    DEPENDS ${PASSED_FILE}
    )

这篇关于CMake-作为构建过程的一部分运行测试并将stdout输出捕获到文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆