28

I want to write a CMakeLists.txt so that I can run my tests normally or with valgrind. I have seen much on integrating ctest with valgrind but all with the assumption that you want to set up a server to submit test results to a dart dashboard. I just want to run the tests on my machine and see the results on the command line.

If I have to do a cmake -D VALGRIND=ON thats fine, but I'd rather generate tests named "foo" and "valgrind_foo" if possible.

leif
  • 1,987
  • 4
  • 19
  • 22

4 Answers4

28

I use valgrind for my memory check. To configure valgrind, I define the following variables in my build system:

find_program( MEMORYCHECK_COMMAND valgrind )
set( MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full" )

Also, in there is my valgrind suppression file:

set( MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/valgrind_suppress.txt" )

After you write your CMakeLists.txt files and configure valgrind correctly in them, you can run the following command:

cmake -G ... (to configure your build)
ctest -D ExperimentalBuild (this will build your code)
ctest -R testName -D ExperimentalTest (just runs the test)
ctest -R testName -D ExperimentalMemCheck (to run the test under valgrind)

This will trick your build system to run the test automation locally. It expects you to run:

ctest -R testName -D ExperimentalSubmit

next, to submit to the (default or your) Dashboard, but you don't need to go through this step to run what you want. The results will be stored in the Testing/Temporary/ directory.

quant
  • 21,507
  • 32
  • 115
  • 211
KlingonJoe
  • 815
  • 8
  • 17
8

It seems the following is sufficient. I wasn't using separate_arguments before, that was my stupidity.

function(add_memcheck_test name binary)
  set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}")
  separate_arguments(memcheck_command)
  add_test(${name} ${binary} ${ARGN})
  add_test(memcheck_${name} ${memcheck_command} ./${binary} ${ARGN})
endfunction(add_memcheck_test)

function(set_memcheck_test_properties name)
  set_tests_properties(${name} ${ARGN})
  set_tests_properties(memcheck_${name} ${ARGN})
endfunction(set_memcheck_test_properties)
leif
  • 1,987
  • 4
  • 19
  • 22
1

My case was simple enough that I just used a custom target:

project(bftest)

add_executable(bftest main.c)

target_link_libraries(bftest LINK_PUBLIC bf)

find_program(VALGRIND "valgrind")
if(VALGRIND)
    add_custom_target(valgrind
        COMMAND "${VALGRIND}" --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes $<TARGET_FILE:bftest>)
endif()
Ben
  • 5,952
  • 4
  • 33
  • 44
0

You can generate a minimal 'DartConfiguration.tcl' configuration file using add_custom_target(). Then you can add a valgrind custom target that calls ctest with the appropriate args. This is how I usually do it:

find_program(VALGRIND "valgrind")
if (VALGRIND)
    set(DART_CONFIG DartConfiguration.tcl)
    add_custom_target(${DART_CONFIG}
        COMMAND echo "MemoryCheckCommand: ${VALGRIND}" >> ${DART_CONFIG}
        COMMENT "Generating ${DART_CONFIG}"
    )
    set(VALGRIND_ARGS
        --leak-check=full
        --error-exitcode=255
    )
    set(LOGFILE memcheck.log)
    add_custom_target(valgrind        
        COMMAND ctest -O ${LOGFILE} -D ExperimentalMemCheck --overwrite MemoryCheckCommandOptions="${VALGRIND_ARGS}"
        COMMAND tail -n1 ${LOGFILE} | grep 'Memory checking results:' > /dev/null
        COMMAND rm -f ${LOGFILE}
        DEPENDS ${DART_CONFIG}
    )
endif()

Hope this helps! :-)

Credit: https://github.com/ARMmbed/mbedtls/blob/development/CMakeLists.txt#L237

Cédric
  • 156
  • 1
  • 6