diff options
-rw-r--r-- | kde-modules/KDECompilerSettings.cmake | 1 | ||||
-rw-r--r-- | modules/ECMEnableSanitizers.cmake | 140 |
2 files changed, 141 insertions, 0 deletions
diff --git a/kde-modules/KDECompilerSettings.cmake b/kde-modules/KDECompilerSettings.cmake index f0d1aefe..728bb413 100644 --- a/kde-modules/KDECompilerSettings.cmake +++ b/kde-modules/KDECompilerSettings.cmake @@ -420,3 +420,4 @@ if (MINGW AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--export-all-symbols") endif() +include ( ECMEnableSanitizers ) diff --git a/modules/ECMEnableSanitizers.cmake b/modules/ECMEnableSanitizers.cmake new file mode 100644 index 00000000..d1de532e --- /dev/null +++ b/modules/ECMEnableSanitizers.cmake @@ -0,0 +1,140 @@ +#.rst: +# ECMEnableSanitizers +# ------------------- +# +# Enable compiler sanitizer flags +# +# The following sanitizers are supported : +# - Address Sanitizer +# - Memory Sanitizer +# - Thread Sanitizer +# - Leak Sanitizer +# - Undefined Behaviour Sanitizer +# +# All of them are implemented in Clang, depending on your version, and +# there is an work in progress in GCC, where some of them are currently +# implemented. +# This module will check your current compiler version to see if it support +# the sanitizers that you want to enable +# +# How to use it ? +# --------------- +# This module is included in KDECompilerSettings. Therefore you don't have +# to change your CMakeLists.txt +# +# It introduce a new cached variable : +# ECM_ENABLE_SANITIZERS +# +# which can take the following values : +# - address +# - memory +# - thread +# - leak +# - undefined +# +# You can enable two sanitizers in the same build, depending on their +# compatibility by separating each one with a semicolon : +# ECM_ENABLE_SANITIZERS='address;undefined' +# +# +# The sanitizers `address`, `memory` and `thread` are mutually exclusive. +# You cannot enable two of them in the same build. +# +# `undefined` can be used with every other sanitizers +# +# `leak` can be enable with the `address` sanitizer. +# +# Finally, to reduce the overhead induced by the instrumentation of the +# sanitizers, it is advised to use -O1, or higher to improve the performances. +# +# Example +# ------- +# This is an example of usage : +# mkdir _build +# cd _build +# cmake -DECM_ENABLE_SANITIZERS='address' .. +# +# If you want to use multiple sanitizers +# +# cmake -DECM_ENABLE_SANITIZERS='address;leak;undefined' .. +# +# => Most of the sanitizers will require Clang. To enable it, use : +# -DCMAKE_CXX_COMPILR=clang++ +# +#============================================================================= +# Copyright 2014 Mathieu Tarral <mathieu.tarral@gmail.com> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING-CMAKE-SCRIPTS for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of extra-cmake-modules, substitute the full +# License text for the above reference.) + +# MACRO check_compiler_version +#----------------------------- +macro (check_compiler_version gcc_required_version clang_required_version) + if ( + ( + CMAKE_CXX_COMPILER_ID MATCHES "GNU" + AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${gcc_required_version} + ) + OR + ( + CMAKE_CXX_COMPILER_ID MATCHES "Clang" + AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${clang_required_version} + ) + ) + # error ! + message(FATAL_ERROR "You ask to enable the sanitizer ${CUR_SANITIZER}, + but your compiler ${CMAKE_CXX_COMPILER_ID} version ${CMAKE_CXX_COMPILER_VERSION} + does not support it ! + You should use at least GCC ${gcc_required_version} or Clang ${clang_required_version} + (99.99 means not implemented yet)") + endif () +endmacro () + +# MACRO check_compiler_support +#------------------------------ +macro (enable_sanitizer_flags sanitize_option) + if (${sanitize_option} MATCHES "address") + check_compiler_version("4.8" "3.1") + set(XSAN_COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls") + set(XSAN_LINKER_FLAGS "asan") + elseif (${sanitize_option} MATCHES "thread") + check_compiler_version("4.8" "3.1") + set(XSAN_COMPILE_FLAGS "-fsanitize=thread") + set(XSAN_LINKER_FLAGS "tsan") + elseif (${sanitize_option} MATCHES "memory") + check_compiler_version("99.99" "3.1") + set(XSAN_COMPILE_FLAGS "-fsanitize=memory") + elseif (${sanitize_option} MATCHES "leak") + check_compiler_version("4.9" "3.4") + set(XSAN_COMPILE_FLAGS "-fsanitize=leak") + set(XSAN_LINKER_FLAGS "lsan") + elseif (${sanitize_option} MATCHES "undefined") + check_compiler_version("99.99" "3.1") + set(XSAN_COMPILE_FLAGS "-fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls") + else () + message(FATAL_ERROR "Compiler sanitizer option \"${sanitize_option}\" not supported.") + endif () +endmacro () + +# for each element of the ECM_ENABLE_SANITIZERS list +foreach ( CUR_SANITIZER ${ECM_ENABLE_SANITIZERS} ) + # lowercase filter + string(TOLOWER ${CUR_SANITIZER} CUR_SANITIZER) + # check option and enable appropriate flags + enable_sanitizer_flags ( ${CUR_SANITIZER} ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${XSAN_COMPILE_FLAGS}" ) + link_libraries(${XSAN_LINKER_FLAGS}) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + string(REPLACE "-Wl,--no-undefined" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") + endif () +endforeach () |