| # Copyright (c) Monetra Technologies LLC |
| # SPDX-License-Identifier: MIT |
| |
| # EnableWarnings.cmake |
| # |
| # Checks for and turns on a large number of warning C flags. |
| # |
| # Adds the following helper functions: |
| # |
| # remove_warnings(... list of warnings ...) |
| # Turn off given list of individual warnings for all targets and subdirectories added after this. |
| # |
| # remove_all_warnings() |
| # Remove all warning flags, add -w to suppress built-in warnings. |
| # |
| # remove_all_warnings_from_targets(... list of targets ...) |
| # Suppress warnings for the given targets only. |
| # |
| # push_warnings() |
| # Save current warning flags by pushing them onto an internal stack. Note that modifications to the internal |
| # stack are only visible in the current CMakeLists.txt file and its children. |
| # |
| # Note: changing warning flags multiple times in the same directory only affects add_subdirectory() calls. |
| # Targets in the directory will always use the warning flags in effect at the end of the CMakeLists.txt |
| # file - this is due to really weird and annoying legacy behavior of CMAKE_C_FLAGS. |
| # |
| # pop_warnings() |
| # Restore the last set of flags that were saved with push_warnings(). Note that modifications to the internal |
| # stack are only visible in the current CMakeLists.txt file and its children. |
| # |
| |
| if (_internal_enable_warnings_already_run) |
| return() |
| endif () |
| set(_internal_enable_warnings_already_run TRUE) |
| |
| include(CheckCCompilerFlag) |
| include(CheckCXXCompilerFlag) |
| |
| get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) |
| |
| # internal helper: _int_enable_warnings_set_flags_ex(langs_var configs_var [warnings flags]) |
| function(_int_enable_warnings_set_flags_ex langs_var configs_var) |
| if (NOT ARGN) |
| return() |
| endif () |
| |
| if (NOT ${configs_var}) |
| set(${configs_var} "NONE") |
| endif () |
| string(TOUPPER "${${configs_var}}" ${configs_var}) |
| |
| foreach(_flag ${ARGN}) |
| string(MAKE_C_IDENTIFIER "HAVE_${_flag}" varname) |
| |
| if ("C" IN_LIST ${langs_var}) |
| check_c_compiler_flag(${_flag} ${varname}) |
| if (${varname}) |
| foreach (config IN LISTS ${configs_var}) |
| if (config STREQUAL "NONE") |
| set(config) |
| else () |
| set(config "_${config}") |
| endif () |
| string(APPEND CMAKE_C_FLAGS${config} " ${_flag}") |
| endforeach () |
| endif () |
| endif () |
| |
| if ("CXX" IN_LIST ${langs_var}) |
| string(APPEND varname "_CXX") |
| check_cxx_compiler_flag(${_flag} ${varname}) |
| if (${varname}) |
| foreach (config IN LISTS ${configs_var}) |
| if (config STREQUAL "NONE") |
| set(config) |
| else () |
| set(config "_${config}") |
| endif () |
| string(APPEND CMAKE_CXX_FLAGS${config} " ${_flag}") |
| endforeach () |
| endif () |
| endif () |
| endforeach() |
| |
| foreach(lang C CXX) |
| foreach (config IN LISTS ${configs_var}) |
| string(TOUPPER "${config}" config) |
| if (config STREQUAL "NONE") |
| set(config) |
| else () |
| set(config "_${config}") |
| endif () |
| string(STRIP "${CMAKE_${lang}_FLAGS${config}}" CMAKE_${lang}_FLAGS${config}) |
| set(CMAKE_${lang}_FLAGS${config} "${CMAKE_${lang}_FLAGS${config}}" PARENT_SCOPE) |
| endforeach () |
| endforeach() |
| endfunction() |
| |
| # internal helper: _int_enable_warnings_set_flags(langs_var [warnings flags]) |
| macro(_int_enable_warnings_set_flags langs_var) |
| set(configs "NONE") |
| _int_enable_warnings_set_flags_ex(${langs_var} configs ${ARGN}) |
| endmacro() |
| |
| set(_flags_C) |
| set(_flags_CXX) |
| set(_debug_flags_C) |
| set(_debug_flags_CXX) |
| |
| if (MSVC) |
| # Visual Studio uses a completely different nomenclature for warnings than gcc/mingw/clang, so none of the |
| # "-W[name]" warnings will work. |
| |
| # W4 would be better but it produces unnecessary warnings like: |
| # * warning C4706: assignment within conditional expression |
| # Triggered when doing "while(1)" |
| # * warning C4115: 'timeval' : named type definition in parentheses |
| # * warning C4201: nonstandard extension used : nameless struct/union |
| # Triggered by system includes (commctrl.h, shtypes.h, Shlobj.h) |
| set(_flags |
| /W3 |
| /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 |
| ) |
| |
| list(APPEND _flags_C ${_flags}) |
| list(APPEND _flags_CXX ${_flags}) |
| |
| elseif (CMAKE_C_COMPILER_ID MATCHES "Intel") |
| # Intel's compiler warning flags are more like Visual Studio than GCC, though the numbers aren't the same. |
| set(_flags |
| # Use warning level 3, quite wordy. |
| -w3 |
| # Disable warnings we don't care about (add more as they are encountered). |
| -wd383 # Spammy warning about initializing from a temporary object in C++ (which is done all the time ...). |
| -wd11074 # Diagnostic related to inlining. |
| -wd11076 # Diagnostic related to inlining. |
| ) |
| |
| list(APPEND _flags_C ${_flags}) |
| list(APPEND _flags_CXX ${_flags}) |
| |
| elseif (CMAKE_C_COMPILER_ID MATCHES "XL") |
| set (_flags |
| -qwarn64 |
| -qformat=all |
| -qflag=i:i |
| ) |
| list(APPEND _flags_C ${_flags}) |
| list(APPEND _flags_CXX ${_flags}) |
| |
| else () |
| # If we're compiling with GCC / Clang / MinGW (or anything else besides Visual Studio or Intel): |
| # C Flags: |
| list(APPEND _flags_C |
| -Wall |
| -Wextra |
| |
| # Enable additional warnings not covered by Wall and Wextra. |
| -Wcast-align |
| -Wconversion |
| -Wdeclaration-after-statement |
| -Wdouble-promotion |
| -Wfloat-equal |
| -Wformat-security |
| -Winit-self |
| -Wjump-misses-init |
| -Wlogical-op |
| -Wmissing-braces |
| -Wmissing-declarations |
| -Wmissing-format-attribute |
| -Wmissing-include-dirs |
| -Wmissing-prototypes |
| -Wnested-externs |
| -Wno-coverage-mismatch |
| -Wold-style-definition |
| -Wpacked |
| -Wpointer-arith |
| -Wredundant-decls |
| -Wshadow |
| -Wsign-conversion |
| -Wstrict-overflow |
| -Wstrict-prototypes |
| -Wtrampolines |
| -Wundef |
| -Wunused |
| -Wvariadic-macros |
| -Wvla |
| -Wwrite-strings |
| |
| # On Windows MinGW I think implicit fallthrough enabled by -Wextra must not default to 3 |
| -Wimplicit-fallthrough=3 |
| |
| # Treat implicit variable typing and implicit function declarations as errors. |
| -Werror=implicit-int |
| -Werror=implicit-function-declaration |
| |
| # Make MacOSX honor -mmacosx-version-min |
| -Werror=partial-availability |
| |
| # Some clang versions might warn if an argument like "-I/path/to/headers" is unused, |
| # silence these. |
| -Qunused-arguments |
| ) |
| |
| # C++ flags: |
| list(APPEND _flags_CXX |
| -Wall |
| -Wextra |
| |
| # Enable additional warnings not covered by Wall and Wextra. |
| -Wcast-align |
| -Wformat-security |
| -Wmissing-declarations |
| -Wmissing-format-attribute |
| -Wpacked-bitfield-compat |
| -Wredundant-decls |
| -Wvla |
| |
| # Turn off unused parameter warnings with C++ (they happen often in C++ and Qt). |
| -Wno-unused-parameter |
| |
| # Some clang versions might warn if an argument like "-I/path/to/headers" is unused, |
| # silence these. |
| -Qunused-arguments |
| ) |
| |
| # Note: when cross-compiling to Windows from Cygwin, the Qt Mingw packages have a bunch of |
| # noisy type-conversion warnings in headers. So, only enable those warnings if we're |
| # not building that configuration. |
| if (NOT (WIN32 AND (CMAKE_HOST_SYSTEM_NAME MATCHES "CYGWIN"))) |
| list(APPEND _flags_CXX |
| -Wconversion |
| -Wfloat-equal |
| -Wsign-conversion |
| ) |
| endif () |
| |
| # Add flags to force colored output even when output is redirected via pipe. |
| if (CMAKE_GENERATOR MATCHES "Ninja") |
| set(color_default TRUE) |
| else () |
| set(color_default FALSE) |
| endif () |
| option(FORCE_COLOR "Force compiler to always colorize, even when output is redirected." ${color_default}) |
| mark_as_advanced(FORCE FORCE_COLOR) |
| if (FORCE_COLOR) |
| set(_flags |
| -fdiagnostics-color=always # GCC |
| -fcolor-diagnostics # Clang |
| ) |
| list(APPEND _flags_C ${_flags}) |
| list(APPEND _flags_CXX ${_flags}) |
| endif () |
| |
| # Add -fno-omit-frame-pointer (and optionally -fno-inline) to make debugging and stack dumps nicer. |
| set(_flags |
| -fno-omit-frame-pointer |
| ) |
| option(M_NO_INLINE "Disable function inlining for RelWithDebInfo and Debug configurations?" FALSE) |
| if (M_NO_INLINE) |
| list(APPEND _flags |
| -fno-inline |
| ) |
| endif () |
| list(APPEND _debug_flags_C ${_flags}) |
| list(APPEND _debug_flags_CXX ${_flags}) |
| endif () |
| |
| # Check and set compiler flags. |
| set(_debug_configs |
| RelWithDebInfo |
| Debug |
| ) |
| foreach(_lang ${languages}) |
| _int_enable_warnings_set_flags(_lang ${_flags_${_lang}}) |
| _int_enable_warnings_set_flags_ex(_lang _debug_configs ${_debug_flags_${_lang}}) |
| |
| # Ensure pure Debug builds are NOT optimized (not possible on Visual Studio). |
| # Any optimization of a Debug build will prevent debuggers like lldb from |
| # fully displaying backtraces and stepping. |
| if (NOT MSVC) |
| set(_config Debug) |
| _int_enable_warnings_set_flags_ex(_lang _config -O0) |
| endif () |
| endforeach() |
| |
| |
| |
| # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| # Helper functions |
| |
| |
| # This function can be called in subdirectories, to prune out warnings that they don't want. |
| # vararg: warning flags to remove from list of enabled warnings. All "no" flags after EXPLICIT_DISABLE |
| # will be added to C flags. |
| # |
| # Ex.: remove_warnings(-Wall -Wdouble-promotion -Wcomment) prunes those warnings flags from the compile command. |
| function(remove_warnings) |
| get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) |
| set(langs C) |
| if ("CXX" IN_LIST languages) |
| list(APPEND langs CXX) |
| endif () |
| |
| foreach(lang ${langs}) |
| set(toadd) |
| set(in_explicit_disable FALSE) |
| foreach (flag ${ARGN}) |
| if (flag STREQUAL "EXPLICIT_DISABLE") |
| set(in_explicit_disable TRUE) |
| elseif (in_explicit_disable) |
| list(APPEND toadd "${flag}") |
| else () |
| string(REGEX REPLACE "${flag}([ \t]+|$)" "" CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}") |
| endif () |
| endforeach () |
| _int_enable_warnings_set_flags(lang ${toadd}) |
| string(STRIP "${CMAKE_${lang}_FLAGS}" CMAKE_${lang}_FLAGS) |
| set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}" PARENT_SCOPE) |
| endforeach() |
| endfunction() |
| |
| |
| # Explicitly suppress all warnings. As long as this flag is the last warning flag, warnings will be |
| # suppressed even if earlier flags enabled warnings. |
| function(remove_all_warnings) |
| get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) |
| set(langs C) |
| if ("CXX" IN_LIST languages) |
| list(APPEND langs CXX) |
| endif () |
| |
| foreach(lang ${langs}) |
| string(REGEX REPLACE "[-/][Ww][^ \t]*([ \t]+|$)" "" CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}") |
| if (MSVC) |
| string(APPEND CMAKE_${lang}_FLAGS " /w") |
| else () |
| string(APPEND CMAKE_${lang}_FLAGS " -w") |
| endif () |
| string(STRIP "${CMAKE_${lang}_FLAGS}" CMAKE_${lang}_FLAGS) |
| set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}" PARENT_SCOPE) |
| endforeach() |
| endfunction() |
| |
| |
| function(remove_all_warnings_from_targets) |
| foreach (target ${ARGN}) |
| if (MSVC) |
| target_compile_options(${target} PRIVATE "/w") |
| else () |
| target_compile_options(${target} PRIVATE "-w") |
| endif () |
| endforeach() |
| endfunction() |
| |
| |
| # Save the current warning settings to an internal variable. |
| function(push_warnings) |
| get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) |
| set(langs C) |
| if ("CXX" IN_LIST languages) |
| list(APPEND langs CXX) |
| endif () |
| |
| foreach(lang ${langs}) |
| if (CMAKE_${lang}_FLAGS MATCHES ";") |
| message(AUTHOR_WARNING "Cannot push warnings for ${lang}, CMAKE_${lang}_FLAGS contains semicolons") |
| continue() |
| endif () |
| # Add current flags to end of internal list. |
| list(APPEND _enable_warnings_internal_${lang}_flags_stack "${CMAKE_${lang}_FLAGS}") |
| # Propagate results up to caller's scope. |
| set(_enable_warnings_internal_${lang}_flags_stack "${_enable_warnings_internal_${lang}_flags_stack}" PARENT_SCOPE) |
| endforeach() |
| endfunction() |
| |
| |
| # Restore the current warning settings from an internal variable. |
| function(pop_warnings) |
| get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) |
| set(langs C) |
| if ("CXX" IN_LIST languages) |
| list(APPEND langs CXX) |
| endif () |
| |
| foreach(lang ${langs}) |
| if (NOT _enable_warnings_internal_${lang}_flags_stack) |
| continue() |
| endif () |
| # Pop flags off of end of list, overwrite current flags with whatever we popped off. |
| list(GET _enable_warnings_internal_${lang}_flags_stack -1 CMAKE_${lang}_FLAGS) |
| list(REMOVE_AT _enable_warnings_internal_${lang}_flags_stack -1) |
| # Propagate results up to caller's scope. |
| set(_enable_warnings_internal_${lang}_flags_stack "${_enable_warnings_internal_${lang}_flags_stack}" PARENT_SCOPE) |
| string(STRIP "${CMAKE_${lang}_FLAGS}" CMAKE_${lang}_FLAGS) |
| set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}" PARENT_SCOPE) |
| endforeach() |
| endfunction() |