如何将Valgrind测试添加到我的CMake“test”目标中

38

我通过使用ninja构建,然后从我的构建目录中运行ninja test来运行单元测试:

cmake -G Ninja /source/tree
ninja
ninja test

然而,要运行valgrind,我需要手动运行它:

valgrind rel/path/to/test

我希望能在运行ninja test时自动运行valgrind。根据"设置[valgrind测试]非常容易"cmake文档的说明,但是当我运行时。

ctest -D NightlyMemoryCheck

我刚刚遇到了这个错误:
Cannot find file: /home/arman/tinman/deb/DartConfiguration.tcl
   Site: 
   Build name: (empty)
WARNING: No nightly start time found please set in CTestConfig.cmake or DartConfig.cmake
Problem initializing the dashboard.

当我按照这个Stack Overflow问题的说明进行操作时,我遇到了类似的错误:

如何在不使用Dart的情况下使ctest运行带有valgrind的程序?

我不知道dart是什么,但根据网站上的信息,它是一种在线测试工具。

显然,“极其简单”对我来说还不够简单。是否有人知道一种解决方案,它非常简单,以至于只有IT巫师才能使其无法工作?


我认为你需要使用ctest_memcheck命令,参考链接:https://cmake.org/cmake/help/v3.7/command/ctest_memcheck.html#command:ctest_memcheck 和 https://cmake.org/cmake/help/v3.7/manual/ctest.1.html?highlight=valgrind#ctest-memcheck-step。 - usr1234567
1个回答

64

这里有一个自包含的示例,展示了如何将valgrind测试添加到CMake项目中。该示例由单个C++源文件main.cpp组成:

#include <iostream>

int main()
{
    double* leak = new double[10];
    std::cout << "Hello!" << std::endl;
}

代码中包含了一个有意的泄漏,应该被valgrind检测到。我们还需要一个 CMakeLists.txt 文件,它需要 CMake >= 2.8:

cmake_minimum_required(VERSION 2.8)

project (ValgrindExample)

include (CTest)
add_executable(example main.cpp)
add_test(example_test example)

这里重要的是使用 include 包含 CTest 模块,而不仅仅是使用 enable_testing() 启用测试。CTest 模块可以设置运行测试时的内存检查工具(例如定位 valgrind 可执行文件)。

现在我们可以在项目文件夹中打开一个 shell 会话,并创建一个 Ninja 构建树:

$ mkdir build; cd build
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..

我们可以以常规方式构建和运行测试,无需使用valgrind:

$ ninja
[2/2] Linking CXX executable example
$ ninja test
[0/1] Running tests...
...
100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.01 sec

要使用 Valgrind 运行测试,我们必须使用 CMake 的 ctest 可执行文件,并使用测试操作 memcheck

$ ctest -T memcheck
...
1/1 MemCheck #1: example_test .....................   Passed    0.77 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.77 sec
-- Processing memory checking output: 
Memory checking results:
Memory Leak - 2

ctest会打印出内存检查结果的摘要。valgrind的详细输出位于构建树中的临时目录中:

$ cat ./Testing/Temporary/MemoryChecker.*.log
==4565== 80 bytes in 1 blocks are definitely lost in loss record 37 of 64
==4565==    at 0x10000B681: malloc (in /usr/local/Cellar/valgrind/3.12.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==4565==    by 0x1000507DD: operator new(unsigned long) (in /usr/lib/libc++.1.dylib)
==4565==    by 0x100000F93: main (main.cpp:5)
...

当你运行ninja test时,无法自动运行valgrind,因为CMake的内置测试目标无法修改,并且始终以常规方式运行测试。但是,我们可以添加一个自定义的CMake目标,该目标使用-T memcheck选项调用ctest,然后打印详细的valgrind报告:

add_custom_target(test_memcheck
    COMMAND ${CMAKE_CTEST_COMMAND} 
        --force-new-ctest-process --test-action memcheck
    COMMAND ${CMAKE_COMMAND} -E cat "${CMAKE_BINARY_DIR}/Testing/Temporary/MemoryChecker.*.log"
    WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")

--test-action 是开关 -T 的冗长版本。

然后我们可以通过 Ninja 调用 valgrind 进行测试:

$ ninja test_memcheck

并且以我们手动运行valgrind的方式获取结果。


1
所以在这个例子中使用了一个默认命令test-action memcheck。如果我想要指定一个自定义的抑制文件,或者使用自定义参数来传递给valgrind(比如运行完整的泄漏检查),该怎么做呢? - Dwight
设置变量 CTEST_MEMORYCHECK_SUPPRESSIONS_FILE。请参阅 https://cmake.org/cmake/help/v3.7/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.html。 - sakra
2
如何仅在valgrind检查失败时cat valgrind日志?如何使用-1退出? - johnsam
4
如何设置 CTEST_MEMORYCHECK_SUPPRESSIONS_FILE 变量?我尝试使用 ctest 的 -D 选项,但好像没有任何作用。你有什么想法吗?我真的希望能够在运行 ctest 时从命令行设置 suppressions 文件和 memcheck 选项。 - dcmm88
1
自定义目标缺少 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - Peter
1
@dcmm88,我通过使用MEMORYCHECK_SUPPRESSIONS_FILE解决了这个问题。 - jyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接