From 4ef333ab0b60ca86e9a44cae0b77d1f752892a94 Mon Sep 17 00:00:00 2001 From: Konstantin Tokarev Date: Tue, 27 Jun 2017 16:34:00 +0300 Subject: [PATCH 016/143] [cmake] Import ECMEnableSanitizers Change-Id: I1417511f0734e8d03bf8d55c5766b57388ed5504 --- Source/cmake/ECMEnableSanitizers.cmake | 173 +++++++++++++++++++++++++ Source/cmake/OptionsQt.cmake | 1 + 2 files changed, 174 insertions(+) create mode 100644 Source/cmake/ECMEnableSanitizers.cmake diff --git a/Source/cmake/ECMEnableSanitizers.cmake b/Source/cmake/ECMEnableSanitizers.cmake new file mode 100644 index 00000000000..06cc0b66d86 --- /dev/null +++ b/Source/cmake/ECMEnableSanitizers.cmake @@ -0,0 +1,173 @@ +#.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 +# supports the sanitizers that you want to enable +# +# Usage +# ===== +# +# Simply add:: +# +# include(ECMEnableSanitizers) +# +# to your ``CMakeLists.txt``. Note that this module is included in +# KDECompilerSettings, so projects using that module do not need to also +# include this one. +# +# The sanitizers are not enabled by default. Instead, you must set +# ``ECM_ENABLE_SANITIZERS`` (either in your ``CMakeLists.txt`` or on the +# command line) to a semicolon-separated list of sanitizers you wish to enable. +# The options are: +# +# - address +# - memory +# - thread +# - leak +# - undefined +# +# The sanitizers "address", "memory" and "thread" are mutually exclusive. You +# cannot enable two of them in the same build. +# +# "leak" requires the "address" sanitizer. +# +# .. note:: +# +# To reduce the overhead induced by the instrumentation of the sanitizers, it +# is advised to enable compiler optimizations (``-O1`` or higher). +# +# Example +# ======= +# +# This is an example of usage:: +# +# mkdir build +# cd build +# cmake -DECM_ENABLE_SANITIZERS='address;leak;undefined' .. +# +# .. note:: +# +# Most of the sanitizers will require Clang. To enable it, use:: +# +# -DCMAKE_CXX_COMPILER=clang++ +# +# Since 1.3.0. + +#============================================================================= +# Copyright 2014 Mathieu Tarral +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# 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("4.9" "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 () + +if (ECM_ENABLE_SANITIZERS) + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # 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} ) + # TODO: GCC will not link pthread library if enabled ASan + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${XSAN_COMPILE_FLAGS}" ) + endif() + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${XSAN_COMPILE_FLAGS}" ) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + link_libraries(${XSAN_LINKER_FLAGS}) + endif() + 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() + else() + message(STATUS "Tried to enable sanitizers (-DECM_ENABLE_SANITIZERS=${ECM_ENABLE_SANITIZERS}), \ +but compiler (${CMAKE_CXX_COMPILER_ID}) does not have sanitizer support") + endif() +endif() diff --git a/Source/cmake/OptionsQt.cmake b/Source/cmake/OptionsQt.cmake index 463a091c787..0835e47aa72 100644 --- a/Source/cmake/OptionsQt.cmake +++ b/Source/cmake/OptionsQt.cmake @@ -1,4 +1,5 @@ include(FeatureSummary) +include(ECMEnableSanitizers) include(ECMPackageConfigHelpers) set(ECM_MODULE_DIR ${CMAKE_MODULE_PATH}) -- 2.17.1