cmake:让测试成功通过部分构建过程

时间:2016-04-18 14:42:00

标签: c++ 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的{​​{1}}目标,运行测试,并且仅在测试通过时创建。

我尝试了什么:

我尝试使用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) 不会"构建" make;
    我必须明确说明lib1_test.passed
  • make lib1_test.passed将始终执行make lib1_test.passed,无论lib1_test是否比lib1_test.passed更新

问题:

如何使测试的运行成为构建的一部分,在哪里将始终重新运行失败的测试?

2 个答案:

答案 0 :(得分:2)

这是我到目前为止所得到的。实施非常快速和肮脏,但它仍然有效。请检查并告知它是否满足您的需求。

的CMakeLists.txt:

        $search_course = "
    SELECT title, id, wyl, overview, module, course, careers
    FROM course
    LEFT JOIN cm
    ON course.id=cm.course
    WHERE id LIKE '%".$_POST['submitcourseselection']."%'";

    $result = $mysqli->query($search_course) or die($mysqli->error);
    $display_course = $result->fetch_assoc();

    //Searches the module table in the DB for modules within the course
    $Search_Module = "
    SELECT id, title, level, credits
    FROM module
    WHERE id LIKE '".$search_course['module']."'";

    $M_Results = $mysqli->query($Search_Module) or die($mysqli->error);


    $ModuleList = '';
    while ($MResults = $M_Results->fetch_assoc()) {
        $ID = $MResults['id'];
        $Title = $MResults['title'];
        $Level = $MResults['level'];
        $Credits = $MResults['credits'];
        $ModuleList.='<div><h2>'.$Title.'</h2></div>'; 
    }

为了完整起见,源文件:

lib.c:

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
)

lib.h:

#include "lib.h"

#include <time.h>

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

test.c的:

#pragma once

int lib_func();

不幸的是,由于CMake bug而无法直接依赖#include "lib.h" int main() { return lib_func(); } 目标,所以我们必须手动执行日落。

答案 1 :(得分:0)

如@ user3159253中所示,您需要一个输出文件(带有时间戳),以便构建环境检查是否必须构建&#34;构建&#34;有问题的目标再次出现。因此,如果您的可执行文件已成功构建 - 即使后续运行它的调用失败 - 也不会再次构建。

我想添加一个只有一个目标的解决方案。它将重命名测试可执行输出,运行它 - 如果成功 - 再次将其重命名为其原始名称,以便将其标记为&#34;传递&#34;:

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()