|
| 1 | +# run like: |
| 2 | +# |
| 3 | +# ctest -S memcheck.cmake |
| 4 | +# |
| 5 | +# optionally, tell path to memory checker like: |
| 6 | +# |
| 7 | +# ctest -DMEMCHECK_ROOT=/path/to/bin/valgrind -S memcheck.cmake |
| 8 | + |
| 9 | +list(APPEND opts -DCMAKE_BUILD_TYPE=Debug) |
| 10 | + |
| 11 | +set(CTEST_TEST_TIMEOUT 60) |
| 12 | +# takes effect only if test property TIMEOUT is not set |
| 13 | + |
| 14 | +if(NOT DEFINED CTEST_MEMORYCHECK_TYPE) |
| 15 | + set(CTEST_MEMORYCHECK_TYPE "Valgrind") |
| 16 | +endif() |
| 17 | + |
| 18 | +if(CTEST_MEMORYCHECK_TYPE STREQUAL "Valgrind") |
| 19 | + # https://www.cprogramming.com/debugging/valgrind.html |
| 20 | + find_program(exe NAMES valgrind HINTS ${MEMCHECK_ROOT} PATH_SUFFIXES bin REQUIRED) |
| 21 | + set(CTEST_MEMORYCHECK_COMMAND ${exe}) |
| 22 | + set(supp ${CMAKE_CURRENT_LIST_DIR}/valgrind.supp) |
| 23 | + if(EXISTS ${supp}) |
| 24 | + set(CTEST_MEMORYCHECK_COMMAND_OPTIONS --suppressions=${supp}) |
| 25 | + endif() |
| 26 | +elseif(CTEST_MEMORYCHECK_TYPE STREQUAL "DrMemory") |
| 27 | + find_program(exe NAMES drmemory HINTS ${MEMCHECK_ROOT} PATH_SUFFIXES bin64 bin REQUIRED) |
| 28 | + set(CTEST_MEMORYCHECK_COMMAND ${exe}) |
| 29 | + set(CTEST_MEMORYCHECK_COMMAND_OPTIONS "-light -count_leaks") |
| 30 | +elseif(CTEST_MEMORYCHECK_TYPE STREQUAL "AddressSanitizer") |
| 31 | + set(check_flags -fsanitize=address) |
| 32 | +elseif(CTEST_MEMORYCHECK_TYPE STREQUAL "LeakSanitizer") |
| 33 | + set(check_flags -fsanitize=leak) |
| 34 | +elseif(CTEST_MEMORYCHECK_TYPE STREQUAL "MemorySanitizer") |
| 35 | + set(check_flags -fsanitize=memory) |
| 36 | +elseif(CTEST_MEMORYCHECK_TYPE STREQUAL "ThreadSanitizer") |
| 37 | + set(check_flags -fsanitize=thread) |
| 38 | +elseif(CTEST_MEMORYCHECK_TYPE STREQUAL "UndefinedBehaviorSanitizer") |
| 39 | + set(check_flags -fsanitize=undefined) |
| 40 | +else() |
| 41 | + message(FATAL_ERROR "Unknown memory checker type: ${CTEST_MEMORYCHECK_TYPE}") |
| 42 | +endif() |
| 43 | + |
| 44 | +if(check_flags) |
| 45 | + list(APPEND opts |
| 46 | + -DCMAKE_C_FLAGS_DEBUG=${check_flags} |
| 47 | + -DCMAKE_CXX_FLAGS_DEBUG=${check_flags} |
| 48 | + -DCMAKE_EXE_LINKER_FLAGS_INIT=${check_flags} |
| 49 | + ) |
| 50 | +endif() |
| 51 | + |
| 52 | +set(CTEST_SOURCE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) |
| 53 | +set(CTEST_BINARY_DIRECTORY ${CTEST_SOURCE_DIRECTORY}/build-${CTEST_MEMORYCHECK_TYPE}) |
| 54 | +set(CTEST_BUILD_CONFIGURATION Debug) |
| 55 | + |
| 56 | +if(WIN32) |
| 57 | + set(CTEST_CMAKE_GENERATOR "MinGW Makefiles") |
| 58 | +else() |
| 59 | + set(CTEST_CMAKE_GENERATOR "Unix Makefiles") |
| 60 | +endif() |
| 61 | +set(CTEST_BUILD_FLAGS -j) |
| 62 | + |
| 63 | +message(STATUS "Checker ${CTEST_MEMORYCHECK_TYPE}: ${CTEST_MEMORYCHECK_COMMAND}") |
| 64 | + |
| 65 | +ctest_start(Experimental) |
| 66 | + |
| 67 | +ctest_configure( |
| 68 | +OPTIONS "${opts}" |
| 69 | +RETURN_VALUE ret |
| 70 | +CAPTURE_CMAKE_ERROR err |
| 71 | +) |
| 72 | +if(NOT (ret EQUAL 0 AND err EQUAL 0)) |
| 73 | + message(FATAL_ERROR "CMake configure failed: ${ret} ${err}") |
| 74 | +endif() |
| 75 | + |
| 76 | +cmake_host_system_information(RESULT Ncpu QUERY NUMBER_OF_PHYSICAL_CORES) |
| 77 | + |
| 78 | +ctest_build( |
| 79 | +PARALLEL_LEVEL ${Ncpu} |
| 80 | +RETURN_VALUE ret |
| 81 | +CAPTURE_CMAKE_ERROR err |
| 82 | +) |
| 83 | +if(NOT (ret EQUAL 0 AND err EQUAL 0)) |
| 84 | + message(FATAL_ERROR "CMake build failed: ${ret} ${err}") |
| 85 | +endif() |
| 86 | + |
| 87 | +ctest_memcheck( |
| 88 | +INCLUDE ${include} |
| 89 | +INCLUDE_LABEL ${include_label} |
| 90 | +EXCLUDE ${exclude} |
| 91 | +EXCLUDE_LABEL ${exclude_label} |
| 92 | +RETURN_VALUE ret |
| 93 | +CAPTURE_CMAKE_ERROR err |
| 94 | +DEFECT_COUNT count |
| 95 | +) |
| 96 | + |
| 97 | +if(NOT (ret EQUAL 0 AND err EQUAL 0)) |
| 98 | + message(FATAL_ERROR "Memory check failed: ${ret} ${err}") |
| 99 | +endif() |
| 100 | + |
| 101 | +if(NOT count EQUAL 0) |
| 102 | + message(FATAL_ERROR "Memory check found ${count} defects") |
| 103 | +endif() |
0 commit comments