Changeset View
Changeset View
Standalone View
Standalone View
cmake/modules/sanitize-helpers.cmake
- This file was added.
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. | ||||
26 | function (sanitizer_lang_of_source FILE RETURN_VAR) | ||||
27 | get_filename_component(FILE_EXT "${FILE}" EXT) | ||||
28 | string(TOLOWER "${FILE_EXT}" FILE_EXT) | ||||
29 | string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) | ||||
30 | | ||||
31 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | ||||
32 | foreach (LANG ${ENABLED_LANGUAGES}) | ||||
33 | list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) | ||||
34 | if (NOT ${TEMP} EQUAL -1) | ||||
35 | set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) | ||||
36 | return() | ||||
37 | endif () | ||||
38 | endforeach() | ||||
39 | | ||||
40 | set(${RETURN_VAR} "" PARENT_SCOPE) | ||||
41 | endfunction () | ||||
42 | | ||||
43 | | ||||
44 | # Helper function to get compilers used by a target. | ||||
45 | function (sanitizer_target_compilers TARGET RETURN_VAR) | ||||
46 | # Check if all sources for target use the same compiler. If a target uses | ||||
47 | # e.g. C and Fortran mixed and uses different compilers (e.g. clang and | ||||
48 | # gfortran) this can trigger huge problems, because different compilers may | ||||
49 | # use different implementations for sanitizers. | ||||
50 | set(BUFFER "") | ||||
51 | get_target_property(TSOURCES ${TARGET} SOURCES) | ||||
52 | foreach (FILE ${TSOURCES}) | ||||
53 | # If expression was found, FILE is a generator-expression for an object | ||||
54 | # library. Object libraries will be ignored. | ||||
55 | string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) | ||||
56 | if ("${_file}" STREQUAL "") | ||||
57 | sanitizer_lang_of_source(${FILE} LANG) | ||||
58 | if (LANG) | ||||
59 | list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
60 | endif () | ||||
61 | endif () | ||||
62 | endforeach () | ||||
63 | | ||||
64 | list(REMOVE_DUPLICATES BUFFER) | ||||
65 | set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) | ||||
66 | endfunction () | ||||
67 | | ||||
68 | | ||||
69 | # Helper function to check compiler flags for language compiler. | ||||
70 | function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) | ||||
71 | if (${LANG} STREQUAL "C") | ||||
72 | include(CheckCCompilerFlag) | ||||
73 | check_c_compiler_flag("${FLAG}" ${VARIABLE}) | ||||
74 | | ||||
75 | elseif (${LANG} STREQUAL "CXX") | ||||
76 | include(CheckCXXCompilerFlag) | ||||
77 | check_cxx_compiler_flag("${FLAG}" ${VARIABLE}) | ||||
78 | | ||||
79 | elseif (${LANG} STREQUAL "Fortran") | ||||
80 | # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible | ||||
81 | # with older Cmake versions, we will check if this module is present | ||||
82 | # before we use it. Otherwise we will define Fortran coverage support as | ||||
83 | # not available. | ||||
84 | include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) | ||||
85 | if (INCLUDED) | ||||
86 | check_fortran_compiler_flag("${FLAG}" ${VARIABLE}) | ||||
87 | elseif (NOT CMAKE_REQUIRED_QUIET) | ||||
88 | message(STATUS "Performing Test ${VARIABLE}") | ||||
89 | message(STATUS "Performing Test ${VARIABLE}" | ||||
90 | " - Failed (Check not supported)") | ||||
91 | endif () | ||||
92 | endif() | ||||
93 | endfunction () | ||||
94 | | ||||
95 | | ||||
96 | # Helper function to test compiler flags. | ||||
97 | function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) | ||||
98 | set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) | ||||
99 | | ||||
100 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | ||||
101 | foreach (LANG ${ENABLED_LANGUAGES}) | ||||
102 | # Sanitizer flags are not dependend on language, but the used compiler. | ||||
103 | # So instead of searching flags foreach language, search flags foreach | ||||
104 | # compiler used. | ||||
105 | set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
106 | if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) | ||||
107 | foreach (FLAG ${FLAG_CANDIDATES}) | ||||
108 | if(NOT CMAKE_REQUIRED_QUIET) | ||||
109 | message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") | ||||
110 | endif() | ||||
111 | | ||||
112 | set(CMAKE_REQUIRED_FLAGS "${FLAG}") | ||||
113 | unset(${PREFIX}_FLAG_DETECTED CACHE) | ||||
114 | sanitizer_check_compiler_flag("${FLAG}" ${LANG} | ||||
115 | ${PREFIX}_FLAG_DETECTED) | ||||
116 | | ||||
117 | if (${PREFIX}_FLAG_DETECTED) | ||||
118 | # If compiler is a GNU compiler, search for static flag, if | ||||
119 | # SANITIZE_LINK_STATIC is enabled. | ||||
120 | if (SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU")) | ||||
121 | string(TOLOWER ${PREFIX} PREFIX_lower) | ||||
122 | sanitizer_check_compiler_flag( | ||||
123 | "-static-lib${PREFIX_lower}" ${LANG} | ||||
124 | ${PREFIX}_STATIC_FLAG_DETECTED) | ||||
125 | | ||||
126 | if (${PREFIX}_STATIC_FLAG_DETECTED) | ||||
127 | set(FLAG "-static-lib${PREFIX_lower} ${FLAG}") | ||||
128 | endif () | ||||
129 | endif () | ||||
130 | | ||||
131 | set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING | ||||
132 | "${NAME} flags for ${COMPILER} compiler.") | ||||
133 | mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) | ||||
134 | break() | ||||
135 | endif () | ||||
136 | endforeach () | ||||
137 | | ||||
138 | if (NOT ${PREFIX}_FLAG_DETECTED) | ||||
139 | set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING | ||||
140 | "${NAME} flags for ${COMPILER} compiler.") | ||||
141 | mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) | ||||
142 | | ||||
143 | message(WARNING "${NAME} is not available for ${COMPILER} " | ||||
144 | "compiler. Targets using this compiler will be " | ||||
145 | "compiled without ${NAME}.") | ||||
146 | endif () | ||||
147 | endif () | ||||
148 | endforeach () | ||||
149 | endfunction () | ||||
150 | | ||||
151 | | ||||
152 | # Helper to assign sanitizer flags for TARGET. | ||||
153 | function (sanitizer_add_flags TARGET NAME PREFIX) | ||||
154 | # Get list of compilers used by target and check, if sanitizer is available | ||||
155 | # for this target. Other compiler checks like check for conflicting | ||||
156 | # compilers will be done in add_sanitizers function. | ||||
157 | sanitizer_target_compilers(${TARGET} TARGET_COMPILER) | ||||
158 | list(LENGTH TARGET_COMPILER NUM_COMPILERS) | ||||
159 | if ("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "") | ||||
160 | return() | ||||
161 | endif() | ||||
162 | | ||||
163 | # Set compile- and link-flags for target. | ||||
164 | set_property(TARGET ${TARGET} APPEND_STRING | ||||
165 | PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") | ||||
166 | set_property(TARGET ${TARGET} APPEND_STRING | ||||
167 | PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}") | ||||
168 | set_property(TARGET ${TARGET} APPEND_STRING | ||||
169 | PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") | ||||
170 | endfunction () |