2016-04-18 75 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() 
相關問題