release 0.1.7
[liba.git] / cmake / TargetSanitize.cmake
blob825b362c2e68ee983cfe4c9f1f5d425fb11e79b1
1 get_cmake_property(ENABLED_LANGUAGES ENABLED_LANGUAGES)
2 include(CheckCXXCompilerFlag)
3 include(CheckCCompilerFlag)
5 function(list_append var)
6   foreach(arg ${ARGN})
7     list(FIND ${var} ${arg} index)
8     if(${index} EQUAL -1)
9       list(APPEND ${var} ${arg})
10     endif()
11   endforeach()
12   set(${var} ${${var}} PARENT_SCOPE)
13 endfunction()
15 macro(sanitize_flag)
16   foreach(arg ${ARGN})
17     list_append(SANITIZE_CC ${arg})
18     list_append(SANITIZE_XX ${arg})
19   endforeach()
20 endmacro()
22 macro(sanitize_flag_cx)
23   foreach(arg ${ARGN})
24     string(REPLACE "+" "x" var ${arg})
25     string(REGEX REPLACE "[^A-Za-z0-9_-]+" "-" var ${var})
26     list(FIND ENABLED_LANGUAGES C index)
27     if(${index} GREATER -1)
28       check_c_compiler_flag(${arg} cc${var})
29       if(cc${var})
30         list_append(SANITIZE_CC ${arg})
31       endif()
32     endif()
33     list(FIND ENABLED_LANGUAGES CXX index)
34     if(${index} GREATER -1)
35       check_cxx_compiler_flag(${arg} xx${var})
36       if(xx${var})
37         list_append(SANITIZE_XX ${arg})
38       endif()
39     endif()
40     set(var)
41   endforeach()
42   set(index)
43 endmacro()
45 macro(sanitize_flag_ld)
46   foreach(arg ${ARGN})
47     string(REPLACE "+" "x" var ${arg})
48     string(REGEX REPLACE "[^A-Za-z0-9_-]+" "-" var ${var})
49     list(FIND ENABLED_LANGUAGES CXX index)
50     if(${index} GREATER -1)
51       check_cxx_compiler_flag(${arg} ld${var})
52       if(ld${var})
53         list_append(SANITIZE_LD ${arg})
54       endif()
55     endif()
56     list(FIND ENABLED_LANGUAGES C index)
57     if(${index} GREATER -1)
58       check_c_compiler_flag(${arg} ld${var})
59       if(ld${var})
60         list_append(SANITIZE_LD ${arg})
61       endif()
62     endif()
63     set(var)
64   endforeach()
65   set(index)
66 endmacro()
68 if(
69   CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" OR
70   CMAKE_C_COMPILER_ID MATCHES "IntelLLVM" OR
71   CMAKE_C_COMPILER_ID MATCHES "GNU" OR
72   CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang" OR
73   CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM" OR
74   CMAKE_CXX_COMPILER_ID MATCHES "GNU"
76   sanitize_flag(-fsanitize=address)
77   sanitize_flag_cx(-fsanitize=undefined)
78   sanitize_flag_cx(-fno-omit-frame-pointer)
79   sanitize_flag_cx(-fsanitize-recover=address)
80   if(NOT(
81     CMAKE_C_COMPILER_ID MATCHES "Apple[Cc]lang" OR
82     CMAKE_CXX_COMPILER_ID MATCHES "Apple[Cc]lang"
83     ))
84     sanitize_flag_cx(-fsanitize=leak)
85   endif()
86   if(
87     CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" OR
88     CMAKE_C_COMPILER_ID MATCHES "IntelLLVM" OR
89     CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang" OR
90     CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM"
91   )
92     sanitize_flag_ld(-static-libsan)
93   endif()
94 elseif(
95   CMAKE_C_COMPILER_ID MATCHES "MSVC" OR
96   CMAKE_CXX_COMPILER_ID MATCHES "MSVC"
98   sanitize_flag_cx(/fsanitize=address)
99 endif()
101 function(target_compile_sanitize_3_3)
102   foreach(target ${ARGN})
103     if(TARGET ${target})
104       target_compile_options(${target} ${scope} ${SANITIZE_CC} ${SANITIZE_XX})
105     endif()
106   endforeach()
107 endfunction()
109 function(target_compile_sanitize)
110   set(scope PRIVATE)
111   if(CMAKE_VERSION VERSION_LESS 3.3)
112     target_compile_sanitize_3_3(${ARGN})
113     return()
114   endif()
115   foreach(target ${ARGN})
116     if(target MATCHES "^INTERFACE|PUBLIC|PRIVATE")
117       set(scope ${target})
118       continue()
119     endif()
120     target_compile_options(${target} ${scope}
121       $<$<COMPILE_LANGUAGE:C>:${SANITIZE_CC}>
122       $<$<COMPILE_LANGUAGE:CXX>:${SANITIZE_XX}>
123     )
124   endforeach()
125 endfunction()
127 function(target_link_sanitize_3_13)
128   foreach(target ${ARGN})
129     if(TARGET ${target})
130       get_property(LINK_FLAGS TARGET ${target} PROPERTY LINK_FLAGS)
131       string_append(LINK_FLAGS ${SANITIZE_CC} ${SANITIZE_XX} ${SANITIZE_LD})
132       set_property(TARGET ${target} PROPERTY LINK_FLAGS "${LINK_FLAGS}")
133     endif()
134   endforeach()
135 endfunction()
137 function(target_link_sanitize)
138   if(MSVC)
139     return()
140   endif()
141   if(CMAKE_VERSION VERSION_LESS 3.13)
142     target_link_sanitize_3_13(${ARGN})
143     return()
144   endif()
145   set(scope PRIVATE)
146   foreach(target ${ARGN})
147     if(target MATCHES "^INTERFACE|PUBLIC|PRIVATE")
148       set(scope ${target})
149       continue()
150     endif()
151     target_link_options(${target} ${scope}
152       $<$<COMPILE_LANGUAGE:C>:${SANITIZE_CC}>
153       $<$<COMPILE_LANGUAGE:CXX>:${SANITIZE_XX}>
154       ${SANITIZE_LD}
155     )
156   endforeach()
157 endfunction()