EnableWarnings.cmake (14203B)
1 # Copyright (c) Monetra Technologies LLC 2 # SPDX-License-Identifier: MIT 3 4 # EnableWarnings.cmake 5 # 6 # Checks for and turns on a large number of warning C flags. 7 # 8 # Adds the following helper functions: 9 # 10 # remove_warnings(... list of warnings ...) 11 # Turn off given list of individual warnings for all targets and subdirectories added after this. 12 # 13 # remove_all_warnings() 14 # Remove all warning flags, add -w to suppress built-in warnings. 15 # 16 # remove_all_warnings_from_targets(... list of targets ...) 17 # Suppress warnings for the given targets only. 18 # 19 # push_warnings() 20 # Save current warning flags by pushing them onto an internal stack. Note that modifications to the internal 21 # stack are only visible in the current CMakeLists.txt file and its children. 22 # 23 # Note: changing warning flags multiple times in the same directory only affects add_subdirectory() calls. 24 # Targets in the directory will always use the warning flags in effect at the end of the CMakeLists.txt 25 # file - this is due to really weird and annoying legacy behavior of CMAKE_C_FLAGS. 26 # 27 # pop_warnings() 28 # Restore the last set of flags that were saved with push_warnings(). Note that modifications to the internal 29 # stack are only visible in the current CMakeLists.txt file and its children. 30 # 31 32 if (_internal_enable_warnings_already_run) 33 return() 34 endif () 35 set(_internal_enable_warnings_already_run TRUE) 36 37 include(CheckCCompilerFlag) 38 include(CheckCXXCompilerFlag) 39 40 get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 41 42 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 43 # Helper functions 44 45 46 # This function can be called in subdirectories, to prune out warnings that they don't want. 47 # vararg: warning flags to remove from list of enabled warnings. All "no" flags after EXPLICIT_DISABLE 48 # will be added to C flags. 49 # 50 # Ex.: remove_warnings(-Wall -Wdouble-promotion -Wcomment) prunes those warnings flags from the compile command. 51 function(remove_warnings) 52 get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 53 set(langs C) 54 if ("CXX" IN_LIST languages) 55 list(APPEND langs CXX) 56 endif () 57 58 foreach(lang ${langs}) 59 set(toadd) 60 set(in_explicit_disable FALSE) 61 foreach (flag ${ARGN}) 62 if (flag STREQUAL "EXPLICIT_DISABLE") 63 set(in_explicit_disable TRUE) 64 elseif (in_explicit_disable) 65 list(APPEND toadd "${flag}") 66 else () 67 string(REGEX REPLACE "${flag}([ \t]+|$)" "" CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}") 68 endif () 69 endforeach () 70 _int_enable_warnings_set_flags(lang ${toadd}) 71 string(STRIP "${CMAKE_${lang}_FLAGS}" CMAKE_${lang}_FLAGS) 72 set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}" PARENT_SCOPE) 73 endforeach() 74 endfunction() 75 76 77 # Explicitly suppress all warnings. As long as this flag is the last warning flag, warnings will be 78 # suppressed even if earlier flags enabled warnings. 79 function(remove_all_warnings) 80 get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 81 set(langs C) 82 if ("CXX" IN_LIST languages) 83 list(APPEND langs CXX) 84 endif () 85 86 foreach(lang ${langs}) 87 string(REGEX REPLACE "[-/][Ww][^ \t]*([ \t]+|$)" "" CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}") 88 if (MSVC) 89 string(APPEND CMAKE_${lang}_FLAGS " /w") 90 else () 91 string(APPEND CMAKE_${lang}_FLAGS " -w") 92 endif () 93 string(STRIP "${CMAKE_${lang}_FLAGS}" CMAKE_${lang}_FLAGS) 94 set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}" PARENT_SCOPE) 95 endforeach() 96 endfunction() 97 98 99 function(remove_all_warnings_from_targets) 100 foreach (target ${ARGN}) 101 if (MSVC) 102 target_compile_options(${target} PRIVATE "/w") 103 else () 104 target_compile_options(${target} PRIVATE "-w") 105 endif () 106 endforeach() 107 endfunction() 108 109 110 # Save the current warning settings to an internal variable. 111 function(push_warnings) 112 get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 113 set(langs C) 114 if ("CXX" IN_LIST languages) 115 list(APPEND langs CXX) 116 endif () 117 118 foreach(lang ${langs}) 119 if (CMAKE_${lang}_FLAGS MATCHES ";") 120 message(AUTHOR_WARNING "Cannot push warnings for ${lang}, CMAKE_${lang}_FLAGS contains semicolons") 121 continue() 122 endif () 123 # Add current flags to end of internal list. 124 list(APPEND _enable_warnings_internal_${lang}_flags_stack "${CMAKE_${lang}_FLAGS}") 125 # Propagate results up to caller's scope. 126 set(_enable_warnings_internal_${lang}_flags_stack "${_enable_warnings_internal_${lang}_flags_stack}" PARENT_SCOPE) 127 endforeach() 128 endfunction() 129 130 131 # Restore the current warning settings from an internal variable. 132 function(pop_warnings) 133 get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 134 set(langs C) 135 if ("CXX" IN_LIST languages) 136 list(APPEND langs CXX) 137 endif () 138 139 foreach(lang ${langs}) 140 if (NOT _enable_warnings_internal_${lang}_flags_stack) 141 continue() 142 endif () 143 # Pop flags off of end of list, overwrite current flags with whatever we popped off. 144 list(GET _enable_warnings_internal_${lang}_flags_stack -1 CMAKE_${lang}_FLAGS) 145 list(REMOVE_AT _enable_warnings_internal_${lang}_flags_stack -1) 146 # Propagate results up to caller's scope. 147 set(_enable_warnings_internal_${lang}_flags_stack "${_enable_warnings_internal_${lang}_flags_stack}" PARENT_SCOPE) 148 string(STRIP "${CMAKE_${lang}_FLAGS}" CMAKE_${lang}_FLAGS) 149 set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}" PARENT_SCOPE) 150 endforeach() 151 endfunction() 152 153 154 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 155 # Runs when included automatically 156 157 # internal helper: _int_enable_warnings_set_flags_ex(langs_var configs_var [warnings flags]) 158 function(_int_enable_warnings_set_flags_ex langs_var configs_var) 159 if (NOT ARGN) 160 return() 161 endif () 162 163 if (NOT ${configs_var}) 164 set(${configs_var} "NONE") 165 endif () 166 string(TOUPPER "${${configs_var}}" ${configs_var}) 167 168 foreach(_flag ${ARGN}) 169 string(MAKE_C_IDENTIFIER "HAVE_${_flag}" varname) 170 171 if ("C" IN_LIST ${langs_var}) 172 check_c_compiler_flag(${_flag} ${varname}) 173 if (${varname}) 174 foreach (config IN LISTS ${configs_var}) 175 if (config STREQUAL "NONE") 176 set(config) 177 else () 178 set(config "_${config}") 179 endif () 180 string(APPEND CMAKE_C_FLAGS${config} " ${_flag}") 181 endforeach () 182 endif () 183 endif () 184 185 if ("CXX" IN_LIST ${langs_var}) 186 string(APPEND varname "_CXX") 187 check_cxx_compiler_flag(${_flag} ${varname}) 188 if (${varname}) 189 foreach (config IN LISTS ${configs_var}) 190 if (config STREQUAL "NONE") 191 set(config) 192 else () 193 set(config "_${config}") 194 endif () 195 string(APPEND CMAKE_CXX_FLAGS${config} " ${_flag}") 196 endforeach () 197 endif () 198 endif () 199 endforeach() 200 201 foreach(lang C CXX) 202 foreach (config IN LISTS ${configs_var}) 203 string(TOUPPER "${config}" config) 204 if (config STREQUAL "NONE") 205 set(config) 206 else () 207 set(config "_${config}") 208 endif () 209 string(STRIP "${CMAKE_${lang}_FLAGS${config}}" CMAKE_${lang}_FLAGS${config}) 210 set(CMAKE_${lang}_FLAGS${config} "${CMAKE_${lang}_FLAGS${config}}" PARENT_SCOPE) 211 endforeach () 212 endforeach() 213 endfunction() 214 215 # internal helper: _int_enable_warnings_set_flags(langs_var [warnings flags]) 216 macro(_int_enable_warnings_set_flags langs_var) 217 set(configs "NONE") 218 _int_enable_warnings_set_flags_ex(${langs_var} configs ${ARGN}) 219 endmacro() 220 221 set(_flags_C) 222 set(_flags_CXX) 223 set(_debug_flags_C) 224 set(_debug_flags_CXX) 225 226 if (MSVC) 227 # Don't automatically set /W3 228 CMAKE_POLICY (SET CMP0092 NEW) 229 230 # Visual Studio uses a completely different nomenclature for warnings than gcc/mingw/clang, so none of the 231 # "-W[name]" warnings will work. 232 233 set(_flags 234 # Enable warnings 235 /W4 # Baseline reasonable warnings 236 /w14242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 237 /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 238 /w14263 # 'function': member function does not override any base class virtual member function 239 /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may 240 # not be destructed correctly 241 /w14287 # 'operator': unsigned/negative constant mismatch 242 /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside 243 # the for-loop scope 244 /w14296 # 'operator': expression is always 'boolean_value' 245 /w14311 # 'variable': pointer truncation from 'type1' to 'type2' 246 /w14545 # expression before comma evaluates to a function which is missing an argument list 247 /w14546 # function call before comma missing argument list 248 /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect 249 /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? 250 /w14555 # expression has no effect; expected expression with side- effect 251 /w14619 # pragma warning: there is no warning number 'number' 252 /w14640 # Enable warning on thread un-safe static member initialization 253 /w14826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. 254 /w14905 # wide string literal cast to 'LPSTR' 255 /w14906 # string literal cast to 'LPWSTR' 256 /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied 257 258 # Disable some warnings 259 /wd4201 # nonstandard extension used: nameless struct/union. Used in some windows headers, e.g. IO_STATUS_BLOCK, 260 # disable. 261 262 # Turn some warnings into errors 263 /we4013 # Treat "function undefined, assuming extern returning int" warning as an error. https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4013 264 ) 265 266 list(APPEND _flags_C ${_flags}) 267 list(APPEND _flags_CXX ${_flags}) 268 269 elseif (CMAKE_C_COMPILER_ID MATCHES "Intel") 270 # Intel's compiler warning flags are more like Visual Studio than GCC, though the numbers aren't the same. 271 set(_flags 272 # Use warning level 3, quite wordy. 273 -w3 274 # Disable warnings we don't care about (add more as they are encountered). 275 -wd383 # Spammy warning about initializing from a temporary object in C++ (which is done all the time ...). 276 -wd11074 # Diagnostic related to inlining. 277 -wd11076 # Diagnostic related to inlining. 278 ) 279 280 list(APPEND _flags_C ${_flags}) 281 list(APPEND _flags_CXX ${_flags}) 282 283 elseif (CMAKE_C_COMPILER_ID MATCHES "XL") 284 set (_flags 285 -qwarn64 286 -qformat=all 287 -qflag=i:i 288 ) 289 list(APPEND _flags_C ${_flags}) 290 list(APPEND _flags_CXX ${_flags}) 291 292 else () 293 # If we're compiling with GCC / Clang / MinGW (or anything else besides Visual Studio or Intel): 294 # C Flags: 295 list(APPEND _flags_C 296 -Wall 297 -Wextra 298 299 # Enable additional warnings not covered by Wall and Wextra. 300 -Waggregate-return 301 -Wcast-align 302 -Wcast-qual 303 -Wconversion 304 -Wdeclaration-after-statement 305 -Wdouble-promotion 306 -Wfloat-equal 307 -Wformat-security 308 -Winit-self 309 -Wjump-misses-init 310 -Wlogical-op 311 -Wmissing-braces 312 -Wmissing-declarations 313 -Wmissing-format-attribute 314 -Wmissing-include-dirs 315 -Wmissing-prototypes 316 -Wnested-externs 317 -Wno-coverage-mismatch 318 -Wold-style-definition 319 -Wpacked 320 -Wpedantic 321 -Wpointer-arith 322 -Wredundant-decls 323 -Wshadow 324 -Wsign-conversion 325 -Wstrict-overflow 326 -Wstrict-prototypes 327 -Wtrampolines 328 -Wundef 329 -Wunreachable-code 330 -Wunused 331 -Wvariadic-macros 332 -Wvla 333 -Wwrite-strings 334 335 # On Windows MinGW I think implicit fallthrough enabled by -Wextra must not default to 3 336 -Wimplicit-fallthrough=3 337 338 # Treat implicit variable typing and implicit function declarations as errors. 339 -Werror=implicit-int 340 -Werror=implicit-function-declaration 341 342 # Make MacOSX honor -mmacosx-version-min 343 -Werror=partial-availability 344 345 # Some clang versions might warn if an argument like "-I/path/to/headers" is unused, 346 # silence these. 347 -Qunused-arguments 348 349 -Wno-long-long 350 ) 351 352 # C++ flags: 353 list(APPEND _flags_CXX 354 -Wall 355 -Wextra 356 357 # Enable additional warnings not covered by Wall and Wextra. 358 -Wcast-align 359 -Wformat-security 360 -Wmissing-declarations 361 -Wmissing-format-attribute 362 -Wpacked-bitfield-compat 363 -Wredundant-decls 364 -Wvla 365 366 # Turn off unused parameter warnings with C++ (they happen often in C++ and Qt). 367 -Wno-unused-parameter 368 369 # Some clang versions might warn if an argument like "-I/path/to/headers" is unused, 370 # silence these. 371 -Qunused-arguments 372 ) 373 374 # Note: when cross-compiling to Windows from Cygwin, the Qt Mingw packages have a bunch of 375 # noisy type-conversion warnings in headers. So, only enable those warnings if we're 376 # not building that configuration. 377 if (NOT (WIN32 AND (CMAKE_HOST_SYSTEM_NAME MATCHES "CYGWIN"))) 378 list(APPEND _flags_CXX 379 -Wconversion 380 -Wfloat-equal 381 -Wsign-conversion 382 ) 383 endif () 384 385 # Add flags to force colored output even when output is redirected via pipe. 386 if (CMAKE_GENERATOR MATCHES "Ninja") 387 set(color_default TRUE) 388 else () 389 set(color_default FALSE) 390 endif () 391 option(FORCE_COLOR "Force compiler to always colorize, even when output is redirected." ${color_default}) 392 mark_as_advanced(FORCE FORCE_COLOR) 393 if (FORCE_COLOR) 394 set(_flags 395 -fdiagnostics-color=always # GCC 396 -fcolor-diagnostics # Clang 397 ) 398 list(APPEND _flags_C ${_flags}) 399 list(APPEND _flags_CXX ${_flags}) 400 endif () 401 402 # Add -fno-omit-frame-pointer (and optionally -fno-inline) to make debugging and stack dumps nicer. 403 set(_flags 404 -fno-omit-frame-pointer 405 ) 406 option(M_NO_INLINE "Disable function inlining for RelWithDebInfo and Debug configurations?" FALSE) 407 if (M_NO_INLINE) 408 list(APPEND _flags 409 -fno-inline 410 ) 411 endif () 412 list(APPEND _debug_flags_C ${_flags}) 413 list(APPEND _debug_flags_CXX ${_flags}) 414 endif () 415 416 # Check and set compiler flags. 417 set(_debug_configs 418 RelWithDebInfo 419 Debug 420 ) 421 foreach(_lang ${languages}) 422 _int_enable_warnings_set_flags(_lang ${_flags_${_lang}}) 423 _int_enable_warnings_set_flags_ex(_lang _debug_configs ${_debug_flags_${_lang}}) 424 425 # Ensure pure Debug builds are NOT optimized (not possible on Visual Studio). 426 # Any optimization of a Debug build will prevent debuggers like lldb from 427 # fully displaying backtraces and stepping. 428 if (NOT MSVC) 429 set(_config Debug) 430 _int_enable_warnings_set_flags_ex(_lang _config -O0) 431 endif () 432 endforeach() 433 434 # CMP0092 doesn't appear to really work, really remove the /W3 here. 435 if (MSVC) 436 remove_warnings(/W3) 437 endif ()