release 0.1.15
[liba.git] / cmake / TargetSanitize.cmake
blob7b1e2815a72bf14d92614472c4d072dbbfd4087a
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} found)
8     if(${found} EQUAL -1)
9       list(APPEND ${var} ${arg})
10     endif()
11   endforeach()
12   set(${var} ${${var}} PARENT_SCOPE)
13 endfunction()
15 macro(sanitize_flag_cx)
16   foreach(arg ${ARGN})
17     string(REPLACE "+" "x" var ${arg})
18     string(REGEX REPLACE "[^A-Za-z0-9_-]+" "-" var ${var})
19     string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${SANITIZE_CX} ${arg}")
20     list(FIND ENABLED_LANGUAGES C found)
21     if(${found} GREATER -1)
22       check_c_compiler_flag(${arg} cx${var})
23       if(cx${var})
24         list_append(SANITIZE_CX ${arg})
25       endif()
26     endif()
27     list(FIND ENABLED_LANGUAGES CXX found)
28     if(${found} GREATER -1)
29       check_cxx_compiler_flag(${arg} cx${var})
30       if(cx${var})
31         list_append(SANITIZE_CX ${arg})
32       endif()
33     endif()
34     set(CMAKE_REQUIRED_FLAGS)
35   endforeach()
36 endmacro()
38 macro(sanitize_flag_ld)
39   foreach(arg ${ARGN})
40     string(REPLACE "+" "x" var ${arg})
41     string(REGEX REPLACE "[^A-Za-z0-9_-]+" "-" var ${var})
42     string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${SANITIZE_CX} ${SANITIZE_LD} ${arg}")
43     list(FIND ENABLED_LANGUAGES C found)
44     if(${found} GREATER -1)
45       check_c_compiler_flag(${arg} ld${var})
46       if(ld${var})
47         list_append(SANITIZE_LD ${arg})
48       endif()
49     endif()
50     list(FIND ENABLED_LANGUAGES CXX found)
51     if(${found} GREATER -1)
52       check_cxx_compiler_flag(${arg} ld${var})
53       if(ld${var})
54         list_append(SANITIZE_LD ${arg})
55       endif()
56     endif()
57     set(CMAKE_REQUIRED_FLAGS)
58   endforeach()
59 endmacro()
61 if(
62   CMAKE_C_COMPILER_ID MATCHES "GNU|[Cc]lang|LLVM" OR
63   CMAKE_CXX_COMPILER_ID MATCHES "GNU|[Cc]lang|LLVM"
65   sanitize_flag_cx(-fsanitize=address)
66   sanitize_flag_cx(-fsanitize=leak)
67   sanitize_flag_cx(-fsanitize=undefined)
68   sanitize_flag_cx(-fsanitize-recover=all)
69   sanitize_flag_cx(-fno-omit-frame-pointer)
70   if(
71     CMAKE_C_COMPILER_ID MATCHES "GNU" OR
72     CMAKE_CXX_COMPILER_ID MATCHES "GNU"
73   )
74     sanitize_flag_ld(-static-libasan)
75     sanitize_flag_ld(-static-liblsan)
76     sanitize_flag_ld(-static-libubsan)
77   else()
78     sanitize_flag_ld(-static-libsan)
79   endif()
80 elseif(
81   CMAKE_C_COMPILER_ID MATCHES "MSVC" OR
82   CMAKE_CXX_COMPILER_ID MATCHES "MSVC"
84   list_append(SANITIZE_LD /INCREMENTAL:NO)
85   sanitize_flag_cx(/fsanitize=address)
86 endif()
88 function(target_compile_sanitize)
89   set(scope PRIVATE)
90   foreach(target ${ARGN})
91     if(target MATCHES "^INTERFACE|PUBLIC|PRIVATE")
92       set(scope ${target})
93     else()
94       target_compile_options(${target} ${scope} ${SANITIZE_CX})
95     endif()
96   endforeach()
97 endfunction()
99 function(target_link_sanitize_3_13)
100   function(string_append var)
101     foreach(arg ${ARGN})
102       string(FIND "${${var}}" "${arg}" found)
103       if(${found} EQUAL -1)
104         string(STRIP "${${var}} ${arg}" ${var})
105       endif()
106     endforeach()
107     set(${var} "${${var}}" PARENT_SCOPE)
108   endfunction()
109   foreach(target ${ARGN})
110     if(TARGET ${target})
111       get_property(LINK_FLAGS TARGET ${target} PROPERTY LINK_FLAGS)
112       if(MSVC)
113         string_append(LINK_FLAGS ${SANITIZE_LD})
114       else()
115         string_append(LINK_FLAGS ${SANITIZE_CX} ${SANITIZE_LD})
116       endif()
117       set_property(TARGET ${target} PROPERTY LINK_FLAGS "${LINK_FLAGS}")
118     endif()
119   endforeach()
120 endfunction()
122 function(target_link_sanitize)
123   if(CMAKE_VERSION VERSION_LESS 3.13)
124     target_link_sanitize_3_13(${ARGN})
125     return()
126   endif()
127   set(scope PRIVATE)
128   foreach(target ${ARGN})
129     if(target MATCHES "^INTERFACE|PUBLIC|PRIVATE")
130       set(scope ${target})
131     elseif(MSVC)
132       target_link_options(${target} ${scope} ${SANITIZE_LD})
133     else()
134       target_link_options(${target} ${scope} ${SANITIZE_CX} ${SANITIZE_LD})
135     endif()
136   endforeach()
137 endfunction()