#[=======================================================================[.rst: SanitizerBuildTypes -------- Add the compiler and linker flags for the sanitizer build types. Currently, only Clang and GCC are supported. Support for MSVC has yet to be added. Arguments ~~~~~~~~ Provide the names for the build types through the following variables: ASAN LSAN MSAN TSAN UBSAN It is possible to only provide a subset of these variables to only create build types for specific sanitizers. #]=======================================================================] function(sanitizer_build_types) if(ARGC EQUAL 0) message(FATAL_ERROR "No arguments were given.") endif() set(prefix ARG) set(no_values "") set(single_values ASAN LSAN MSAN TSAN UBSAN) set(multi_values "") include(CMakeParseArguments) cmake_parse_arguments(${prefix} "${no_values}" "${single_values}" "${multi_values}" ${ARGN}) if(ARG_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unexpected arguments: ${ARG_UNPARSED_ARGUMENTS}") endif() if(ARG_KEYWORDS_MISSING_VALUES) message(FATAL_ERROR "Keywords missing values: ${ARG_KEYWORDS_MISSING_VALUES}") endif() set(_bitness 32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_bitness 64) endif() # todo Add support for the AddressSanitizer for MSVC / 32-bit builds. if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") foreach(arg IN LISTS single_values) if(${prefix}_${arg}) set_property(GLOBAL APPEND PROPERTY DEBUG_CONFIGURATIONS ${${prefix}_${arg}}) endif() endforeach() set(_asan_platforms Darwin FreeBSD Linux NetBSD Windows) if(ARG_ASAN) if(CMAKE_SYSTEM_NAME IN_LIST _asan_platforms) set(CMAKE_C_FLAGS_${ARG_ASAN} "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the C compiler during Address Sanitizer builds.") set(CMAKE_CXX_FLAGS_${ARG_ASAN} "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the C++ compiler during Address Sanitizer builds.") set(CMAKE_EXE_LINKER_FLAGS_${ARG_ASAN} "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the linker during Address Sanitizer builds.") else() message("The address sanitizer is only available on ${_asan_platforms}") endif() endif() set(_lsan_platforms Darwin Linux) if(ARG_LSAN) if(_bitness EQUAL 32) message("The leak sanitizer is only available for 64-bit systems") elseif(CMAKE_SYSTEM_NAME IN_LIST _lsan_platforms) set(CMAKE_C_FLAGS_${ARG_LSAN} "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fsanitize=leak -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the C compiler during Leak Sanitizer builds.") set(CMAKE_CXX_FLAGS_${ARG_LSAN} "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=leak -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the C++ compiler during Leak Sanitizer builds.") set(CMAKE_EXE_LINKER_FLAGS_${ARG_LSAN} "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -fsanitize=leak -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the linker during Leak Sanitizer builds.") else() message("The leak sanitizer is only available on ${_lsan_platforms}") endif() endif() set(_msan_platforms FreeBSD Linux NetBSD) if(ARG_MSAN) if(CMAKE_SYSTEM_NAME IN_LIST _msan_platforms) set(CMAKE_C_FLAGS_${ARG_MSAN} "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the C compiler during Memory Sanitizer builds.") set(CMAKE_CXX_FLAGS_${ARG_MSAN} "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the C++ compiler during Memory Sanitizer builds.") set(CMAKE_EXE_LINKER_FLAGS_${ARG_MSAN} "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g" CACHE STRING "Flags used by the linker during Memory Sanitizer builds.") else() message("The memory sanitizer is only available on ${_msan_platforms}") endif() endif() set(_tsan_platforms Darwin FreeBSD Linux NetBSD) if(ARG_TSAN) if(_bitness EQUAL 32) message("The thread sanitizer is only available for 64-bit systems") elseif(CMAKE_SYSTEM_NAME IN_LIST _tsan_platforms) set(CMAKE_C_FLAGS_${ARG_TSAN} "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fsanitize=thread -g" CACHE STRING "Flags used by the C compiler during Thread Sanitizer builds.") set(CMAKE_CXX_FLAGS_${ARG_TSAN} "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=thread -g" CACHE STRING "Flags used by the C++ compiler during Thread Sanitizer builds.") set(CMAKE_EXE_LINKER_FLAGS_${ARG_TSAN} "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -fsanitize=thread -g" CACHE STRING "Flags used by the linker during Thread Sanitizer builds.") else() message("The thread sanitizer is only available on ${_tsan_platforms}") endif() endif() set(_ubsan_platforms Darwin FreeBSD Linux NetBSD OpenBSD Windows) if(ARG_UBSAN) if(CMAKE_SYSTEM_NAME IN_LIST _ubsan_platforms) set(CMAKE_C_FLAGS_${UBSAN} "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fsanitize=undefined -g" CACHE STRING "Flags used by the C compiler during Undefined Behaviour Sanitizer builds.") set(CMAKE_CXX_FLAGS_${UBSAN} "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=undefined -g" CACHE STRING "Flags used by the C++ compiler during Undefined Behaviour Sanitizer builds.") set(CMAKE_EXE_LINKER_FLAGS_${UBSAN} "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -fsanitize=undefined -g" CACHE STRING "Flags used by the linker during Undefined Behavior Sanitizer builds.") else() message("The undefined behavior sanitizer is only available on ${_ubsan_platforms}") endif() endif() else() message("Sanitizers not supported for the current compiler: ${CMAKE_CXX_COMPILER_ID}.") endif() endfunction()