2016-04-18 43 views
3

我想通过测试构建过程的一部分。cmake:使测试成功通过构建过程的一部分

这里我使用add_custom_command作为POST_BUILD步骤运行测试。

function(register_test NAME) 

    add_test(${NAME} ${NAME}) 

    # make the test run as part of the build process 
    add_custom_command(TARGET ${NAME} POST_BUILD COMMAND ${NAME}) 

endfunction() 

这种方法的问题是,当目标是建立测试只运行:

$ make 
[ 50%] Built target lib1 
Linking CXX executable ../../Debug/bin/lib1_test 
Running 1 test case... 
main.cpp(8): fatal error: in "lib1_test": 
    critical check lib1() == "lib1" has failed [error != lib1] 

*** 1 failure is detected in the test module "Master Test Suite" 

make[2]: *** [lib1/test/lib1_test] Error 201 
make[1]: *** [lib1/test/CMakeFiles/lib1_test.dir/all] Error 2 
make: *** [all] Error 2 

如果目标不需要被建立,然后测试不运行,并且构建通过。

在这里我不作任何改动,只需重新运行构建过程

$ make 
[ 50%] Built target lib1 
[100%] Built target lib1_test 

但是,如果lib1_test实际运行,测试失败。

$ ./lib1/test/lib1_test 
Running 1 test case... 
main.cpp(8): fatal error: in "lib1_test": 
    critical check lib1() == "lib1" has failed [error != lib1] 

*** 1 failure is detected in the test module "Master Test Suite" 

一个更好的办法来做到这一点是使一个lib1_test.passed目标取决于lib1_test,运行测试,如果测试通过,才会创建。

我曾尝试:

我一直在使用add_custom_target创建目标lib1_test.passed取决于lib1_test尝试,如果成功,将创建一个文件lib1_test.passed

add_custom_target(${NAME}.passed 
    DEPENDS ${NAME} 
    COMMAND ${NAME} 
    COMMAND ${CMAKE_COMMAND} -E touch ${NAME}.passed) 

有2个缺口与我目前取得的成果:

  • 测试的运行不是正常构建过程的一部分。
    也就是说,make不会“build”lib1_test.passed;
    我要明确说明make lib1_test.passed
  • make lib1_test.passed总会执行lib1_test,无论lib1_test.passed较新,lib1_test1或不

问:

怎样才能让测试部分的运行的构建,一个失败的测试总是会重新运行?

+1

拿不到你的愿望,你希望运行'lib1_test'甚至如果没有改变?它会得到不同的输入数据或什么,为什么需要重新运行,如果它没有改变? – fghj

+0

否 - 与此相反 - 我希望'lib1_test'作为'make'的一部分运行,如果它通过,再次输入'make'将不会运行测试。但是,如果失败,请再次键入'make' **必须**再次运行测试。 –

+0

然后你只需要'add_custom_target',这取决于二进制文件'lib1_test',并删除这个二进制(可执行)文件,如果失败,为什么你不尝试这样的变种? – fghj

回答

2

在这里,我到目前为止。这个实现非常快而且很脏,但它仍然有效。请检查并告诉它是否满足您的需求。

的CMakeLists.txt:

lib.c:

#include "lib.h" 

#include <time.h> 

int lib_func() { 
    return time(NULL) % 2; 
} 

lib.h:

#pragma once 

int lib_func(); 

测试

cmake_minimum_required(VERSION 2.8.12) 

project(test) 

enable_testing() 

set(lib1_SRC lib.c) 

add_library(lib1 ${lib1_SRC}) 

set(test_SRC test.c) 

add_executable(libtest ${test_SRC}) 
target_link_libraries(libtest lib1) 

add_test(NAME libtest COMMAND libtest) 

add_custom_command(
    OUTPUT _libtest_completed 
    COMMAND ctest -C $<CONFIGURATION> --output-on-failure 
    COMMAND cmake -E touch _libtest_completed 
    DEPENDS libtest 
) 

add_custom_target(
    libtest_force ALL 
    DEPENDS _libtest_completed 
) 

为完整起见源文件.c:

#include "lib.h" 

int main() { 
    return lib_func(); 
} 

不幸的是,这是不可能直接在test目标取决于由于CMake bug,所以我们必须手动进行日落。

+0

有没有办法在编译'lib1'时建立'libtest_force'?也就是说,如果我输入'make lib1',它会建立'lib1','libtest'和'libtest_force'(从而运行测试)。 –

+0

这三者是“顶级目标”,所以你可以使用'add_dependencies'。但是我会避免循环依赖,它会带来更多的问题而不是解决问题。 – user3159253

+0

我想出了一些或多或少的作品。如果你愿意,请看看[我的答案](http://stackoverflow.com/a/36702886/955273)[我的问题](http://stackoverflow.com/questions/36701286/cmake-replicate- boost-builds-build-everything-in-jamfile-behavior/36702886)以及评论(如果有的话)。谢谢! –

0

如@ user3159253答案所示,您需要生成环境的输出文件(带时间戳)以检查是否必须再次“构建”有问题的目标。因此,如果您的可执行文件成功构建 - 即使后续调用运行失败 - 也不会再次构建。

我想添加一个解决方案,只有一个目标。这将重命名测试可执行输出,运行它, - 如果成功 - 重新命名文件到其原来的名字之类的标记为“已通过”:

function(register_test NAME) 

    add_test(NAME ${NAME} COMMAND ${NAME}) 

    set(TMP "$<TARGET_FILE_DIR:${NAME}>/tmp_$<TARGET_FILE_NAME:${NAME}>") 
    set(ORG "$<TARGET_FILE:${NAME}>") 

    # make the test run as part of the build process 
    add_custom_command(
     TARGET ${NAME} 
     POST_BUILD 
     COMMAND ${CMAKE_COMMAND} -E rename "${ORG}" "${TMP}" 
     COMMAND ${TMP} 
     COMMAND ${CMAKE_COMMAND} -E rename "${TMP}" "${ORG}" 
    ) 

endfunction() 
相关问题