1# The MIT License (MIT) 2# 3# Copyright (c) 4# 2013 Matthew Arsenault 5# 2015-2016 RWTH Aachen University, Federal Republic of Germany 6# 7# Permission is hereby granted, free of charge, to any person obtaining a copy 8# of this software and associated documentation files (the "Software"), to deal 9# in the Software without restriction, including without limitation the rights 10# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11# copies of the Software, and to permit persons to whom the Software is 12# furnished to do so, subject to the following conditions: 13# 14# The above copyright notice and this permission notice shall be included in all 15# copies or substantial portions of the Software. 16# 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23# SOFTWARE. 24 25# Helper function to get the language of a source file. 26function (sanitizer_lang_of_source FILE RETURN_VAR) 27 get_filename_component(LONGEST_EXT "${FILE}" EXT) 28 # If extension is empty return. This can happen for extensionless headers 29 if("${LONGEST_EXT}" STREQUAL "") 30 set(${RETURN_VAR} "" PARENT_SCOPE) 31 return() 32 endif() 33 # Get shortest extension as some files can have dot in their names 34 string(REGEX REPLACE "^.*(\\.[^.]+)$" "\\1" FILE_EXT ${LONGEST_EXT}) 35 string(TOLOWER "${FILE_EXT}" FILE_EXT) 36 string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) 37 38 get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 39 foreach (LANG ${ENABLED_LANGUAGES}) 40 list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) 41 if (NOT ${TEMP} EQUAL -1) 42 set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) 43 return() 44 endif () 45 endforeach() 46 47 set(${RETURN_VAR} "" PARENT_SCOPE) 48endfunction () 49 50 51# Helper function to get compilers used by a target. 52function (sanitizer_target_compilers TARGET RETURN_VAR) 53 # Check if all sources for target use the same compiler. If a target uses 54 # e.g. C and Fortran mixed and uses different compilers (e.g. clang and 55 # gfortran) this can trigger huge problems, because different compilers may 56 # use different implementations for sanitizers. 57 set(BUFFER "") 58 get_target_property(TSOURCES ${TARGET} SOURCES) 59 foreach (FILE ${TSOURCES}) 60 # If expression was found, FILE is a generator-expression for an object 61 # library. Object libraries will be ignored. 62 string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) 63 if ("${_file}" STREQUAL "") 64 sanitizer_lang_of_source(${FILE} LANG) 65 if (LANG) 66 list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID}) 67 endif () 68 endif () 69 endforeach () 70 71 list(REMOVE_DUPLICATES BUFFER) 72 set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) 73endfunction () 74 75 76# Helper function to check compiler flags for language compiler. 77function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) 78 if (${LANG} STREQUAL "C") 79 include(CheckCCompilerFlag) 80 check_c_compiler_flag("${FLAG}" ${VARIABLE}) 81 82 elseif (${LANG} STREQUAL "CXX") 83 include(CheckCXXCompilerFlag) 84 check_cxx_compiler_flag("${FLAG}" ${VARIABLE}) 85 86 elseif (${LANG} STREQUAL "Fortran") 87 # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible 88 # with older Cmake versions, we will check if this module is present 89 # before we use it. Otherwise we will define Fortran coverage support as 90 # not available. 91 include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) 92 if (INCLUDED) 93 check_fortran_compiler_flag("${FLAG}" ${VARIABLE}) 94 elseif (NOT CMAKE_REQUIRED_QUIET) 95 message(STATUS "Performing Test ${VARIABLE}") 96 message(STATUS "Performing Test ${VARIABLE}" 97 " - Failed (Check not supported)") 98 endif () 99 endif() 100endfunction () 101 102 103# Helper function to test compiler flags. 104function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) 105 set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) 106 107 get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 108 foreach (LANG ${ENABLED_LANGUAGES}) 109 # Sanitizer flags are not dependend on language, but the used compiler. 110 # So instead of searching flags foreach language, search flags foreach 111 # compiler used. 112 set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) 113 if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) 114 foreach (FLAG ${FLAG_CANDIDATES}) 115 if(NOT CMAKE_REQUIRED_QUIET) 116 message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") 117 endif() 118 119 set(CMAKE_REQUIRED_FLAGS "${FLAG}") 120 unset(${PREFIX}_FLAG_DETECTED CACHE) 121 sanitizer_check_compiler_flag("${FLAG}" ${LANG} 122 ${PREFIX}_FLAG_DETECTED) 123 124 if (${PREFIX}_FLAG_DETECTED) 125 # If compiler is a GNU compiler, search for static flag, if 126 # SANITIZE_LINK_STATIC is enabled. 127 if (SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU")) 128 string(TOLOWER ${PREFIX} PREFIX_lower) 129 sanitizer_check_compiler_flag( 130 "-static-lib${PREFIX_lower}" ${LANG} 131 ${PREFIX}_STATIC_FLAG_DETECTED) 132 133 if (${PREFIX}_STATIC_FLAG_DETECTED) 134 set(FLAG "-static-lib${PREFIX_lower} ${FLAG}") 135 endif () 136 endif () 137 138 set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING 139 "${NAME} flags for ${COMPILER} compiler.") 140 mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) 141 break() 142 endif () 143 endforeach () 144 145 if (NOT ${PREFIX}_FLAG_DETECTED) 146 set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING 147 "${NAME} flags for ${COMPILER} compiler.") 148 mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) 149 150 message(WARNING "${NAME} is not available for ${COMPILER} " 151 "compiler. Targets using this compiler will be " 152 "compiled without ${NAME}.") 153 endif () 154 endif () 155 endforeach () 156endfunction () 157 158 159# Helper to assign sanitizer flags for TARGET. 160function (sanitizer_add_flags TARGET NAME PREFIX) 161 # Get list of compilers used by target and check, if sanitizer is available 162 # for this target. Other compiler checks like check for conflicting 163 # compilers will be done in add_sanitizers function. 164 sanitizer_target_compilers(${TARGET} TARGET_COMPILER) 165 list(LENGTH TARGET_COMPILER NUM_COMPILERS) 166 if ("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "") 167 return() 168 endif() 169 170 # Set compile- and link-flags for target. 171 set_property(TARGET ${TARGET} APPEND_STRING 172 PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") 173 set_property(TARGET ${TARGET} APPEND_STRING 174 PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}") 175 set_property(TARGET ${TARGET} APPEND_STRING 176 PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") 177endfunction () 178