# # Copyright (c) 2022 Maxime Pinard # # Distributed under the MIT license # See accompanying file LICENSE or copy at # https://opensource.org/licenses/MIT # cmake_minimum_required(VERSION 3.18) # For check_linker_flag message(CHECK_START "Compiler flags configuration") list(APPEND CMAKE_MESSAGE_INDENT " ") # MSVC debug flags set(MSVC_DEBUG_FLAGS /utf-8 # Set source and execution character sets to UTF-8. /validate-charset # Validate UTF-8 files for only compatible characters. # /analyse # Enables code analysis. /diagnostics:caret # Diagnostics format: prints column and the indicated line of source. /W4 # Warning level /sdl # Enable Additional Security Checks # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default # /w44061 # enumerator 'identifier' in a switch of enum 'enumeration' is not explicitly handled by a case label # /w44062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled # /w14165 # 'HRESULT' is being converted to 'bool'; are you sure this is what you want? # /w34191 # 'operator': unsafe conversion from 'type_of_expression' to 'type_required' # /w44242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data # /w44254 # 'operator': conversion from 'type1' to 'type2', possible loss of data # /w44255 # 'function': no function prototype given: converting '()' to '(void)' /w44263 # 'function': member function does not override any base class virtual member function /w14264 # 'virtual_function': no override available for virtual member function from base 'class'; function is hidden /w34265 # 'class': class has virtual functions, but destructor is not virtual # /w44266 # 'function': no override available for virtual member function from base 'type'; function is hidden /w34287 # 'operator': unsigned/negative constant mismatch /w44289 # nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope /w44296 # 'operator': expression is always false # /w44339 # 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception # /w14342 # behavior change: 'function' called, but a member operator was called in previous versions # /w14350 # behavior change: 'member1' called instead of 'member2' /w44355 # 'this' : used in base member initializer list /w44365 # 'action': conversion from 'type_1' to 'type_2', signed/unsigned mismatch # /w34370 # layout of class has changed from a previous version of the compiler due to better packing # /w34371 # 'classname': layout of class may have changed from a previous version of the compiler due to better packing of member 'member' # /w44388 # signed/unsigned mismatch /w24412 # 'function': function signature contains type 'type'; C++ objects are unsafe to pass between pure code and mixed or native # /w14426 # optimization flags changed after including header, may be due to #pragma optimize() 14.1 # /w44435 # 'class1' : Object layout under /vd2 will change due to virtual base 'class2' # /w44437 # dynamic_cast from virtual base 'class1' to 'class2' could fail in some contexts # /w34444 # top level '__unaligned' is not implemented in this context /w44464 # relative include path contains '..' # /w44471 # a forward declaration of an unscoped enumeration must have an underlying type (int assumed) Perm # /w14472 # 'identifier' is a native enum: add an access specifier (private/public) to declare a managed enum # /w44514 # 'function': unreferenced inline function has been removed # /w44536 # 'type name': type-name exceeds meta-data limit of 'limit' characters /w14545 # expression before comma evaluates to a function which is missing an argument list /w14546 # function call before comma missing argument list /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect /w14548 # expression before comma has no effect; expected expression with side-effect /w14549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? /w14555 # expression has no effect; expected expression with side-effect /w34557 # '__assume' contains effect 'effect' # /w44571 # informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught # /w44574 # 'identifier' is defined to be '0': did you mean to use '#if identifier'? # /w14577 # 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc # /w44582 # 'type': constructor is not implicitly called # /w44583 # 'type': destructor is not implicitly called # /w14587 # 'anonymous_structure': behavior change: constructor is no longer implicitly called # /w14588 # 'anonymous_structure': behavior change: destructor is no longer implicitly called /w44596 # 'identifier': illegal qualified name in member declaration 14.3 Perm # /w33598 # '#include "header"': header number header-number in the precompiled header does not match current compilation at that position 14.3 # /w34599 # 'option path': command-line argument number number does not match pre-compiled header 14.3 # /w14605 # '/Dmacro' specified on current command line, but was not specified when precompiled header was built /w34608 # 'union_member' has already been initialized by another union member in the initializer list, 'union_member' Perm # /w34619 # #pragma warning: there is no warning number 'number' # /w44623 # 'derived class': default constructor could not be generated because a base class default constructor is inaccessible # /w44625 # 'derived class': copy constructor could not be generated because a base class copy constructor is inaccessible # /w44626 # 'derived class': assignment operator could not be generated because a base class assignment operator is inaccessible /w14628 # digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char' # /w34640 # 'instance': construction of local static object is not thread-safe /w44643 # Forward declaring 'identifier' in namespace std is not permitted by the C++ Standard. 15.8 # /w34647 # behavior change: __is_pod(type) has different value in previous versions /w44654 # Code placed before include of precompiled header line will be ignored. Add code to precompiled header. 14.1 /w44668 # 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' # /w44682 # 'symbol' : no directional parameter attribute specified, defaulting to [in] # /w34686 # 'user-defined type': possible change in behavior, change in UDT return calling convention # /w14692 # 'function': signature of non-private member contains assembly private native type 'native_type' # /w44710 # 'function': function not inlined # /w34738 # storing 32-bit float result in memory, possible loss of performance # /w44746 # volatile access of 'expression' is subject to /volatile: setting; consider using __iso_volatile_load/store intrinsic functions # /w44749 # conditionally supported: offsetof applied to non-standard-layout type 'type' # /w44767 # section name 'symbol' is longer than 8 characters and will be truncated by the linker # /w44774 # 'string' : format string expected in argument number is not a string literal /w44777 # 'function' : format string 'string' requires an argument of type 'type1', but variadic argument number has type 'type2' # /w34786 # 'symbol' : object name was truncated to 'number' characters in the debug information # /w44800 # Implicit conversion from 'type' to bool. Possible information loss 16.0 # /w44820 # 'bytes' bytes padding added after construct 'member_name' /w14822 # 'member': local class member function does not have a body # /w24826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. /w44837 # trigraph detected: '??character' replaced by 'character' /w44841 # non-standard extension used: compound member designator used in offsetof # /w44842 # the result of 'offsetof' applied to a type using multiple inheritance is not guaranteed to be consistent between compiler releases # /w44866 # 'file(line-number)' compiler may not enforce left-to-right evaluation order for call to operator # /w44868 # 'file(line_number)' compiler may not enforce left-to-right evaluation order in braced initialization list # /w14905 # wide string literal cast to 'LPSTR' # /w14906 # string literal cast to 'LPWSTR' /w14917 # 'declarator': a GUID can only be associated with a class, interface, or namespace /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied # /w44931 # we are assuming the type library was built for number-bit pointers /w14946 # reinterpret_cast used between related classes: 'class1' and 'class2' # /w44962 # 'function': profile-guided optimizations disabled because optimizations caused profile data to become inconsistent /w44986 # 'symbol': exception specification does not match previous declaration /w44987 # nonstandard extension used: 'throw (...)' # /w44988 # 'symbol': variable declared outside class/function scope # /w45022 # 'type': multiple move constructors specified # /w45023 # 'type': multiple move assignment operators specified # /w45024 # 'type': move constructor was implicitly defined as deleted # /w45025 # 'type': move assignment operator was implicitly defined as deleted # /w45026 # 'type': move constructor was implicitly defined as deleted # /w45027 # 'type': move assignment operator was implicitly defined as deleted /w45029 # nonstandard extension used: alignment attributes in C++ apply to variables, data members and tag types only /w45031 # #pragma warning(pop): likely mismatch, popping warning state pushed in different file 14.1 /w45032 # detected #pragma warning(push) with no corresponding #pragma warning(pop) 14.1 # /w45034 # use of intrinsic 'intrinsic' causes function function-name to be compiled as guest code 15.3 # /w45035 # use of feature 'feature' causes function function-name to be compiled as guest code 15.3 # /w15036 # varargs function pointer conversion when compiling with /hybrid:x86arm64 'type1' to 'type2' 15.3 /w45038 # data member 'member1' will be initialized after data member 'member2' 15.3 # /w45039 # 'function': pointer or reference to potentially throwing function passed to extern C function under -EHc. Undefined behavior may occur if this function throws an exception. 15.5 /w45041 # 'member-name': out-of-line definition for constexpr static data member is not needed and is deprecated in C++17. 15.2 /w35042 # 'function': function declarations at block scope cannot be specified 'inline' in standard C++; remove 'inline' specifier 15.5 # /w45045 # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 15.7 # /w35052 # Keyword 'keyword-name' was introduced in C++version and requires use of the 'option' command-line option` 16.1 /w35204 # A class with virtual functions has non-virtual trivial destructor. 16.5 /w45214 # applying 'keyword' to an operand with a volatile qualified type is deprecated in C++20 16.7 /w45215 # 'function-parameter' a function parameter with a volatile qualified type is deprecated in C++20 16.7 /w45216 # 'return-type' a volatile qualified return type is deprecated in C++20 16.7 /w45217 # a structured binding declaration that includes volatile is deprecated in C++20 16.7 # /w25219 # implicit conversion from 'type-1' to 'type-2', possible loss of data 16.7 # /w45220 # 'member': a non-static data member with a volatile qualified type no longer implies that compiler generated copy/move constructors and copy/move assignment operators are not trivial 16.7 /w45233 # explicit lambda capture 'identifier' is not used 16.10 /w45240 # 'attribute-name': attribute is ignored in this syntactic position 16.10 /w15243 # 'type-name': using incomplete class 'class-name' can cause potential one definition rule violation due to ABI limitation 16.10 # /w45245 # 'function': unreferenced function with internal linkage has been removed /w15246 # 'member': the initialization of a subobject should be wrapped in braces 16.10 /w15247 # Section 'section-name' is reserved for C++ dynamic initialization. Manually creating the section will interfere with C++ dynamic initialization and may lead to undefined behavior 16.11 /w15248 # Section 'section-name' is reserved for C++ dynamic initialization. Variable manually put into the section may be optimized out and its order relative to compiler generated dynamic initializers is unspecified 16.11 /w15249 # 'bitfield' of type 'enumeration_name' has named enumerators with values that cannot be represented in the given bit field width of 'bitfield_width'. 17.0 /w35250 # 'function_name': intrinsic function not declared. 17.0 # /w45251 # segment-name changed after including header 17.1 # /w45254 # language feature 'terse static assert' requires compiler flag '/std:c++17' 17.1 ## Explicitly disabled warnings /wd4702 # unreachable code ) # GCC debug flags set(GCC_DEBUG_FLAGS # General: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html -Wfatal-errors # -fanalyzer -Wlifetime -pedantic -pedantic-errors -Wall -Wextra -Wdouble-promotion -Wformat=2 -Wformat-signedness -Wnull-dereference -Wimplicit-fallthrough -Wif-not-aligned -Wmissing-include-dirs # -Wswitch-default # -Wswitch-enum -Wswitch-bool -Wswitch-unreachable # -Wunused-parameter -Wuninitialized -Wstrict-overflow=5 -Walloc-zero -Wduplicated-branches -Wduplicated-cond -Wfloat-equal -Wshadow -Wundef -Wcast-qual -Wcast-align -Wconversion -Wsign-conversion -Wdate-time -Wlogical-op -Wmissing-declarations -Wredundant-decls -Wrestrict -Winterference-size -Winvalid-pch -Wvla -Woverlength-strings # C++ specific: https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html -Wcomma-subscript -Wctad-maybe-unsupported -Wctor-dtor-privacy -Wnoexcept -Wnon-virtual-dtor -Wregister -Wredundant-tags -Wstrict-null-sentinel -Wold-style-cast # -Woverloaded-virtual -Wmismatched-tags -Wvolatile -Wzero-as-null-pointer-constant -Wextra-semi # -Wuseless-cast -Wsubobject-linkage -Wdelete-incomplete # Suggest -Weffc++ -Wsuggest-override #-Wsuggest-final-types #-Wsuggest-final-methods #-Wsuggest-attribute=pure #-Wsuggest-attribute=const #-Wsuggest-attribute=noreturn #-Wsuggest-attribute=format ) # CLANG debug flags set(CLANG_DEBUG_FLAGS # https://clang.llvm.org/docs/DiagnosticsReference.html -Wfatal-errors -Wlifetime -pedantic -pedantic-errors -Wall -Wextra -Wbad-function-cast -Wcomma -Wcomment -Wcomplex-component-init -Wconditional-uninitialized -Wcovered-switch-default -Wcstring-format-directive -Wdelete-non-virtual-dtor -Wdeprecated -Wdollar-in-identifier-extension -Wdouble-promotion -Wduplicate-enum -Wduplicate-method-arg -Wembedded-directive -Wexpansion-to-defined -Wfloat-conversion -Wfloat-equal -Wfor-loop-analysis -Wformat-pedantic -Wgnu -Wimplicit-fallthrough -Winfinite-recursion -Winvalid-or-nonexistent-directory -Wkeyword-macro -Wmain -Wmethod-signatures -Wmicrosoft -Wmismatched-tags -Wmissing-field-initializers -Wmissing-method-return-type -Wmissing-prototypes -Wmissing-variable-declarations -Wnested-anon-types -Wnon-virtual-dtor -Wnonportable-system-include-path -Wnull-pointer-arithmetic -Wnullability-extension -Wold-style-cast -Woverriding-method-mismatch -Wpacked -Wpedantic -Wpessimizing-move -Wredundant-move -Wreserved-id-macro -Wself-assign -Wself-move -Wsemicolon-before-method-body -Wshadow -Wshadow-field -Wshadow-field-in-constructor -Wshadow-uncaptured-local -Wshift-sign-overflow -Wshorten-64-to-32 -Wconversion -Wsigned-enum-bitfield -Wstatic-in-inline -Wtautological-compare -Wtautological-overlap-compare -Wthread-safety -Wundefined-reinterpret-cast -Wuninitialized -Wunreachable-code -Wunreachable-code-aggressive -Wunused-const-variable -Wunused-lambda-capture -Wunused-local-typedef -Wunused-parameter -Wunused-private-field -Wunused-template -Wunused-variable -Wused-but-marked-unused -Wzero-as-null-pointer-constant -Wzero-length-array ) # Asan flags set(GCC_GLANG_ASAN_FLAGS -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls ) set(MSVC_ASAN_FLAGS /fsanitize=address) # UBsan flags set(GCC_GLANG_UBSAN_FLAGS -fsanitize=undefined -fsanitize=shift -fsanitize=shift-exponent -fsanitize=shift-base -fsanitize=integer-divide-by-zero -fsanitize=unreachable -fsanitize=vla-bound -fsanitize=null -fsanitize=return -fsanitize=bounds -fsanitize=bounds-strict -fsanitize=alignment -fsanitize=object-size -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow # detect floating-point division by zero which can be legitimate to get infinity and NaN -fsanitize=nonnull-attribute -fsanitize=returns-nonnull-attribute -fsanitize=bool -fsanitize=enum -fsanitize=pointer-overflow -fsanitize=builtin # -fno-sanitize=vptr # linking problems on buster ) set(MSVC_UBSAN_FLAGS) # Tsan flags set(GCC_GLANG_TSAN_FLAGS -fsanitize=thread ) set(MSVC_TSAN_FLAGS) # Identify compiler set(DEGUG_FLAGS) # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") message(STATUS "C++ compiler is MSVC-like Clang") set(DEGUG_FLAGS ${MSVC_DEBUG_FLAGS}) set(ASAN_FLAGS ${MSVC_ASAN_FLAGS}) set(UBSAN_FLAGS ${MSVC_UBSAN_FLAGS}) set(TSAN_FLAGS ${MSVC_TSAN_FLAGS}) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") message(STATUS "C++ compiler is Microsoft Visual Studio") set(DEGUG_FLAGS ${MSVC_DEBUG_FLAGS}) set(ASAN_FLAGS ${MSVC_ASAN_FLAGS}) set(UBSAN_FLAGS ${MSVC_UBSAN_FLAGS}) set(TSAN_FLAGS ${MSVC_TSAN_FLAGS}) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") message(STATUS "C++ compiler is LLVM Clang") set(DEGUG_FLAGS ${CLANG_DEBUG_FLAGS}) set(ASAN_FLAGS ${GCC_GLANG_ASAN_FLAGS}) set(UBSAN_FLAGS ${GCC_GLANG_UBSAN_FLAGS}) set(TSAN_FLAGS ${GCC_GLANG_TSAN_FLAGS}) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") message(STATUS "C++ compiler is Apple Clang") set(DEGUG_FLAGS ${CLANG_DEBUG_FLAGS}) set(ASAN_FLAGS ${GCC_GLANG_ASAN_FLAGS}) set(UBSAN_FLAGS ${GCC_GLANG_UBSAN_FLAGS}) set(TSAN_FLAGS ${GCC_GLANG_TSAN_FLAGS}) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") message(STATUS "C++ compiler is GNU Compiler Collection") set(DEGUG_FLAGS ${GCC_DEBUG_FLAGS}) set(ASAN_FLAGS ${GCC_GLANG_ASAN_FLAGS}) set(UBSAN_FLAGS ${GCC_GLANG_UBSAN_FLAGS}) set(TSAN_FLAGS ${GCC_GLANG_TSAN_FLAGS}) else() message(STATUS "Unknown compiler ID: ${CMAKE_CXX_COMPILER_ID}") endif() # Initialize sanitizers build type flags from debug foreach(build_type ASAN UBSAN TSAN SANITIZE) #set(CMAKE_C_FLAGS_${build_type} "${CMAKE_C_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_DEBUG}") set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") endforeach() # Set sanitizers flags include(CheckLinkerFlag) message(CHECK_START "Adding Asan flags reported as supported by the C++ compiler") list(APPEND CMAKE_MESSAGE_INDENT " ") foreach(flag ${ASAN_FLAGS}) string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") check_linker_flag(CXX "${flag}" ${flag_supported}) if(${flag_supported}) foreach(build_type ASAN SANITIZE) #set(CMAKE_C_FLAGS_${build_type} "${CMAKE_C_FLAGS_${build_type}} ${flag}") set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}} ${flag}") set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_${build_type}} ${flag}") set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_${build_type}} ${flag}") endforeach() message(STATUS "[O] ${flag}") else() message(STATUS "[X] ${flag}") endif() endforeach() list(POP_BACK CMAKE_MESSAGE_INDENT) message(CHECK_PASS "done") message(CHECK_START "Adding UBsan flags reported as supported by the C++ compiler") list(APPEND CMAKE_MESSAGE_INDENT " ") foreach(flag ${UBSAN_FLAGS}) string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") check_linker_flag(CXX "${flag}" ${flag_supported}) if(${flag_supported}) foreach(build_type UBSAN SANITIZE) #set(CMAKE_C_FLAGS_${build_type} "${CMAKE_C_FLAGS_${build_type}} ${flag}") set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}} ${flag}") set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_${build_type}} ${flag}") set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_${build_type}} ${flag}") endforeach() message(STATUS "[O] ${flag}") else() message(STATUS "[X] ${flag}") endif() endforeach() list(POP_BACK CMAKE_MESSAGE_INDENT) message(CHECK_PASS "done") message(CHECK_START "Adding Tsan flags reported as supported by the C++ compiler") list(APPEND CMAKE_MESSAGE_INDENT " ") foreach(flag ${TSAN_FLAGS}) string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") check_linker_flag(CXX "${flag}" ${flag_supported}) if(${flag_supported}) #set(CMAKE_C_FLAGS_TSAN "${CMAKE_C_FLAGS_TSAN} ${flag}") set(CMAKE_CXX_FLAGS_TSAN "${CMAKE_CXX_FLAGS_TSAN} ${flag}") set(CMAKE_EXE_LINKER_FLAGS_TSAN "${CMAKE_EXE_LINKER_FLAGS_TSAN} ${flag}") set(CMAKE_SHARED_LINKER_FLAGS_TSAN "${CMAKE_SHARED_LINKER_FLAGS_TSAN} ${flag}") message(STATUS "[O] ${flag}") else() message(STATUS "[X] ${flag}") endif() endforeach() list(POP_BACK CMAKE_MESSAGE_INDENT) message(CHECK_PASS "done") # Put sanitizers build type base flags in cache, thus used by projects added by add_subdirectory(...) foreach(build_type ASAN UBSAN TSAN SANITIZE) #set(CMAKE_C_FLAGS_${build_type} # "${CMAKE_C_FLAGS_${build_type}}" # CACHE STRING "Flags used by the C compiler during ${build_type} builds." # FORCE #) set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}}" CACHE STRING "Flags used by the CXX compiler during ${build_type} builds." FORCE ) set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_${build_type}}" CACHE STRING "Flags used by the linker during ${build_type} builds." FORCE ) set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_${build_type}}" CACHE STRING "Flags used by the linker during the creation of shared libraries during ${build_type} builds." FORCE ) mark_as_advanced( #CMAKE_C_FLAGS_${build_type} CMAKE_CXX_FLAGS_${build_type} CMAKE_EXE_LINKER_FLAGS_${build_type} CMAKE_SHARED_LINKER_FLAGS_${build_type} ) endforeach() # Set debug flags include(CheckCXXCompilerFlag) message(CHECK_START "Adding debug flags reported as supported by the C++ compiler") list(APPEND CMAKE_MESSAGE_INDENT " ") foreach(flag ${DEGUG_FLAGS}) string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") check_cxx_compiler_flag("${flag}" ${flag_supported}) if(${flag_supported}) foreach(build_type DEBUG RELWITHDEBINFO ASAN UBSAN TSAN SANITIZE) set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}} ${flag}") endforeach() message(STATUS "[O] ${flag}") else() message(STATUS "[X] ${flag}") endif() endforeach() list(POP_BACK CMAKE_MESSAGE_INDENT) message(CHECK_PASS "done") list(POP_BACK CMAKE_MESSAGE_INDENT) message(CHECK_PASS "done")