You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
442 lines
15 KiB
442 lines
15 KiB
|
|
include(CompileCheck) |
|
|
|
if(NOT MSVC AND NOT CMAKE_VERSION VERSION_LESS 2.8.6) |
|
include(CheckCXXSymbolExists) |
|
check_cxx_symbol_exists(_LIBCPP_VERSION "cstddef" IS_LIBCXX) |
|
if(IS_LIBCXX AND (DEBUG OR DEBUG_EXTRA)) |
|
check_cxx_symbol_exists(_LIBCPP_HARDENING_MODE "version" ARX_HAVE_LIBCPP_HARDENING_MODE) |
|
if(NOT ARX_HAVE_LIBCPP_HARDENING_MODE) |
|
check_cxx_symbol_exists(_LIBCPP_ENABLE_HARDENED_MODE "version" ARX_HAVE_LIBCPP_ENABLE_HARDENED_MODE) |
|
if(NOT ARX_HAVE_LIBCPP_ENABLE_HARDENED_MODE) |
|
check_cxx_symbol_exists(_LIBCPP_ENABLE_ASSERTIONS "version" ARX_HAVE_LIBCPP_ENABLE_ASSERTIONS) |
|
endif() |
|
endif() |
|
endif() |
|
else() |
|
set(IS_LIBCXX OFF) |
|
endif() |
|
|
|
|
|
option(DEBUG_EXTRA "Expensive debug options" OFF) |
|
option(SET_WARNING_FLAGS "Adjust compiler warning flags" ON) |
|
option(SET_NOISY_WARNING_FLAGS "Enable noisy compiler warnings" OFF) |
|
option(SET_OPTIMIZATION_FLAGS "Adjust compiler optimization flags" ON) |
|
|
|
if(MSVC) |
|
|
|
if(USE_LTO) |
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") |
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") |
|
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") |
|
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") |
|
endif() |
|
|
|
if(FASTLINK) |
|
|
|
# Optimize for link speed in developer builds |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DEBUG:FASTLINK") |
|
|
|
elseif(SET_OPTIMIZATION_FLAGS) |
|
|
|
# Merge symbols and discard unused symbols |
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF") |
|
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF") |
|
|
|
endif() |
|
|
|
if(SET_WARNING_FLAGS AND NOT SET_NOISY_WARNING_FLAGS) |
|
|
|
# TODO TEMP - disable very noisy warning |
|
# Conversion from 'A' to 'B', possible loss of data |
|
add_definitions(/wd4244) |
|
# warning C4245: 'return': conversion from 'A' to 'B', signed/unsigned mismatch |
|
add_definitions(/wd4245) |
|
# warning C4456: declaration of 'xxx' hides previous local declaration |
|
add_definitions(/wd4456) # triggers on nested BOOST_FOREACH |
|
# warning C4457: declaration of 'xxx' hides function parameter |
|
add_definitions(/wd4457) |
|
# warning C4458: declaration of 'xxx' hides class member |
|
add_definitions(/wd4458) |
|
# warning C4459: declaration of 'xxx' hides global declaration |
|
add_definitions(/wd4459) |
|
|
|
# warning C4127: conditional expression is constant |
|
add_definitions(/wd4127) |
|
if(MSVC_VERSION LESS 1900) |
|
# warning C4250: 'xxx': inherits 'std::basic_{i,o}stream::...' via dominance |
|
add_definitions(/wd4250) # harasses you when inheriting from std::basic_{i,o}stream |
|
# warning C4510: 'enum_names<const char *>' : default constructor could not be generated |
|
add_definitions(/wd4510) |
|
# warning C4512: 'xxx' : assignment operator could not be generated |
|
add_definitions(/wd4512) # not all classes need an assignment operator... |
|
# warning C4610: struct 'xxx' can never be instantiated - user defined constructor required |
|
add_definitions(/wd4610) |
|
endif() |
|
add_definitions(/wd4702) # warns in Boost |
|
add_definitions(/wd4706) # warns in Boost |
|
add_definitions(/wd4996) # 'unsafe' stdlib functions used by Boost |
|
|
|
endif() |
|
|
|
if(WERROR) |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") |
|
endif() |
|
|
|
if(SET_OPTIMIZATION_FLAGS) |
|
|
|
# Enable exceptions |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") |
|
|
|
# Enable linker optimization in release |
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Oi /Os") |
|
|
|
endif() |
|
|
|
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE) |
|
|
|
# Disable Run time checks |
|
if(NOT DEBUG_EXTRA) |
|
string(REGEX REPLACE "(^| )/RTC1( |$)" "\\1" ${flag_var} "${${flag_var}}") |
|
endif() |
|
|
|
# Remove definition of _DEBUG as it might conflict with libs we're linking with |
|
string(REGEX REPLACE "(^| )/D_DEBUG( |$)" "\\1" ${flag_var} "${${flag_var}}") |
|
set(${flag_var} "${${flag_var}} /DNDEBUG") |
|
|
|
# Force compiler warning level |
|
if(SET_WARNING_FLAGS) |
|
string(REGEX REPLACE "(^| )/W[0-4]( |$)" "\\1" ${flag_var} "${${flag_var}}") |
|
set(${flag_var} "${${flag_var}} /W4") |
|
endif() |
|
|
|
endforeach(flag_var) |
|
|
|
if(NOT MSVC_VERSION LESS 1900) |
|
add_definitions(/utf-8) |
|
endif() |
|
|
|
# Turn on standards compliant mode |
|
# /Za is not compatible with /fp:fast, leave it off |
|
if(NOT MSVC_VERSION LESS 1910) |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /permissive-") |
|
# /permissive- enables /Zc:twoPhase wich would be good if two phase lookup wasn't still broken in VS 2017 |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:twoPhase-") |
|
endif() |
|
if(NOT MSVC_VERSION LESS 1900) |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:inline") |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew") |
|
endif() |
|
if(NOT MSVC_VERSION LESS 1914) |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus") |
|
endif() |
|
|
|
# Always build with debug information |
|
if(NOT MSVC_VERSION LESS 1700) |
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") |
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG") |
|
endif() |
|
|
|
else(MSVC) |
|
|
|
set(linker_used) |
|
if(NOT linker_used AND (USE_LD STREQUAL "mold" OR USE_LD STREQUAL "best")) |
|
# Old versions are unstable or don't support LTO |
|
if(USE_LD STREQUAL "best") |
|
execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-fuse-ld=mold" "-Wl,-version" |
|
OUTPUT_VARIABLE _Mold_Version ERROR_QUIET) |
|
endif() |
|
if(USE_LD STREQUAL "best" AND _Mold_Version MATCHES "mold [0-1]\\.*") |
|
message(STATUS "Not using ancient ${CMAKE_MATCH_0}") |
|
else() |
|
add_ldflag("-fuse-ld=mold") |
|
if(FLAG_FOUND) |
|
set(linker_used "mold") |
|
elseif(STRICT_USE AND NOT USE_LD STREQUAL "best") |
|
message(FATAL_ERROR "Requested linker is not available") |
|
endif() |
|
endif() |
|
endif() |
|
if(NOT linker_used AND (USE_LD STREQUAL "lld" OR |
|
(USE_LD STREQUAL "best" AND (NOT USE_LTO OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")))) |
|
# Only supports LTO with LLVM-based compilers and old versions are unstable |
|
if(USE_LD STREQUAL "best") |
|
execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-fuse-ld=lld" "-Wl,-version" |
|
OUTPUT_VARIABLE _LLD_Version ERROR_QUIET) |
|
endif() |
|
if(USE_LD STREQUAL "best" AND _LLD_Version MATCHES "LLD [0-8]\\.[0-9\\.]*") |
|
message(STATUS "Not using ancient ${CMAKE_MATCH_0}") |
|
elseif(USE_LD STREQUAL "best" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND |
|
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9) |
|
message(STATUS "Not using ancient Clang ${CMAKE_CXX_COMPILER_VERSION}") |
|
else() |
|
add_ldflag("-fuse-ld=lld") |
|
if(FLAG_FOUND) |
|
set(linker_used "lld") |
|
elseif(STRICT_USE AND NOT USE_LD STREQUAL "best") |
|
message(FATAL_ERROR "Requested linker is not available") |
|
endif() |
|
endif() |
|
endif() |
|
if(NOT linker_used AND (USE_LD STREQUAL "gold" OR USE_LD STREQUAL "best")) |
|
add_ldflag("-fuse-ld=gold") |
|
if(FLAG_FOUND) |
|
set(linker_used "gold") |
|
elseif(STRICT_USE AND NOT USE_LD STREQUAL "best") |
|
message(FATAL_ERROR "Requested linker is not available") |
|
endif() |
|
endif() |
|
if(NOT linker_used AND (USE_LD STREQUAL "bfd")) |
|
add_ldflag("-fuse-ld=bfd") |
|
if(FLAG_FOUND) |
|
set(linker_used "bfd") |
|
elseif(STRICT_USE AND NOT USE_LD STREQUAL "best") |
|
message(FATAL_ERROR "Requested linker is not available") |
|
endif() |
|
endif() |
|
|
|
if(USE_LTO) |
|
add_cxxflag("-flto=auto") |
|
if(NOT FLAG_FOUND) |
|
add_cxxflag("-flto") |
|
endif() |
|
# TODO set CMAKE_INTERPROCEDURAL_OPTIMIZATION instead |
|
add_ldflag("-fuse-linker-plugin") |
|
endif() |
|
|
|
if(FASTLINK) |
|
|
|
# Optimize for link speed in developer builds |
|
if(linker_used STREQUAL "mold" OR linker_used STREQUAL "lld") |
|
# mold and lld are fast enough without -gsplit-dwarf that we don't need to deal with its issues |
|
else() |
|
add_cxxflag("-gsplit-dwarf") |
|
add_cxxflag("-gdwarf-4") # -gsplit-dwarf is broken with DWARF 5 |
|
endif() |
|
|
|
elseif(SET_OPTIMIZATION_FLAGS) |
|
|
|
# Merge symbols and discard unused symbols |
|
add_ldflag("-Wl,--gc-sections") |
|
add_ldflag("-Wl,--icf=all") |
|
add_cxxflag("-fmerge-all-constants") |
|
|
|
endif() |
|
|
|
if(SET_WARNING_FLAGS) |
|
|
|
# GCC or Clang (and compatible) |
|
|
|
add_cxxflag("-Wall") |
|
add_cxxflag("-Wextra") |
|
|
|
add_cxxflag("-Warray-bounds=2") |
|
add_cxxflag("-Wbool-conversions") |
|
add_cxxflag("-Wcast-qual") |
|
add_cxxflag("-Wcatch-value=3") |
|
add_cxxflag("-Wconversion") |
|
add_cxxflag("-Wdocumentation") |
|
add_cxxflag("-Wdouble-promotion") |
|
add_cxxflag("-Wduplicated-cond") |
|
add_cxxflag("-Wextra-semi") |
|
add_cxxflag("-Wformat=2") |
|
add_cxxflag("-Wheader-guard") |
|
add_cxxflag("-Wheader-hygiene") |
|
add_cxxflag("-Winit-self") |
|
add_cxxflag("-Wkeyword-macro") |
|
add_cxxflag("-Wliteral-conversion") |
|
add_cxxflag("-Wlogical-op") |
|
add_cxxflag("-Wmissing-declarations") |
|
add_cxxflag("-Wnoexcept") |
|
add_cxxflag("-Woverflow") |
|
add_cxxflag("-Woverloaded-virtual") |
|
add_cxxflag("-Wpessimizing-move") |
|
add_cxxflag("-Wpointer-arith") |
|
add_cxxflag("-Wredundant-decls") |
|
add_cxxflag("-Wreserved-id-macro") |
|
add_cxxflag("-Wshift-overflow") |
|
add_cxxflag("-Wsign-conversion") |
|
add_cxxflag("-Wstrict-null-sentinel") |
|
add_cxxflag("-Wstringop-overflow=4") |
|
add_cxxflag("-Wundef") |
|
add_cxxflag("-Wunused-const-variable=1") |
|
add_cxxflag("-Wunused-macros") |
|
add_cxxflag("-Wvla") |
|
|
|
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) |
|
add_cxxflag("-Wold-style-cast") |
|
endif() |
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5 |
|
AND NOT SET_NOISY_WARNING_FLAGS) |
|
# In older GCC versions this warning is too strict |
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5 |
|
AND NOT SET_NOISY_WARNING_FLAGS) |
|
# In older Clang verstions this warns on BOOST_SCOPE_EXIT |
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT SET_NOISY_WARNING_FLAGS) |
|
# For icc this warning is too strict |
|
else() |
|
add_cxxflag("-Wshadow") |
|
endif() |
|
|
|
add_ldflag("-Wl,--no-undefined") |
|
|
|
if(SET_NOISY_WARNING_FLAGS) |
|
|
|
# These are too noisy to enable right now but we still want to track new warnings. |
|
# TODO enable by default as soon as most are silenced |
|
add_cxxflag("-Wconditionally-supported") # warns on casting from pointer to function pointer |
|
add_cxxflag("-Wduplicated-branches") |
|
add_cxxflag("-Wstrict-aliasing=1") # has false positives |
|
add_cxxflag("-Wuseless-cast") # has false positives |
|
add_cxxflag("-Wsign-promo") |
|
# add_cxxflag("-Wnull-dereference") not that useful without deduction path |
|
|
|
# Possible optimization opportunities |
|
add_cxxflag("-Wdisabled-optimization") |
|
add_cxxflag("-Wpadded") |
|
add_cxxflag("-Wunsafe-loop-optimizations") |
|
|
|
if(NOT DEBUG_EXTRA OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") |
|
add_ldflag("-Wl,--detect-odr-violations") |
|
endif() |
|
|
|
else() |
|
|
|
# icc |
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") |
|
# '... was declared but never referenced' |
|
# While normally a sensible warning, it also fires when a member isn't used for |
|
# *all* instantiations of a template class, making the warning too annoying to |
|
# be useful |
|
add_cxxflag("-wd177") |
|
# 'external function definition with no prior declaration' |
|
# This gets annoying fast with small inline/template functions. |
|
add_cxxflag("-wd1418") |
|
# 'non-pointer conversion from "int" to "…" may lose significant bits' |
|
add_cxxflag("-wd2259") |
|
endif() |
|
|
|
# -Wuninitialized causes too many false positives in older gcc versions |
|
if(CMAKE_COMPILER_IS_GNUCXX) |
|
# GCC is 'clever' and silently accepts -Wno-* - check for the non-negated variant |
|
check_compiler_flag(FLAG_FOUND "-Wmaybe-uninitialized") |
|
if(FLAG_FOUND) |
|
add_cxxflag("-Wno-maybe-uninitialized") |
|
else() |
|
add_cxxflag("-Wno-uninitialized") |
|
endif() |
|
endif() |
|
|
|
# Xcode does not support -isystem yet |
|
if(MACOS) |
|
add_cxxflag("-Wno-undef") |
|
endif() |
|
|
|
endif() |
|
|
|
if(IS_LIBCXX) |
|
add_definitions(-D_LIBCPP_ENABLE_NODISCARD) |
|
add_definitions(-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) |
|
endif() |
|
|
|
endif(SET_WARNING_FLAGS) |
|
|
|
if(WERROR) |
|
add_cxxflag("-Werror") |
|
endif() |
|
|
|
if(DEBUG_EXTRA) |
|
add_cxxflag("-ftrapv") # to add checks for (undefined) signed integer overflow |
|
add_cxxflag("-fbounds-checking") |
|
add_cxxflag("-fcatch-undefined-behavior") |
|
add_cxxflag("-fstack-protector-all") |
|
add_cxxflag("-fsanitize=address") |
|
# add_cxxflag("-fsanitize=thread") does not work together with -fsanitize=address |
|
add_cxxflag("-fsanitize=leak") |
|
add_cxxflag("-fsanitize=undefined") |
|
if(ARX_HAVE_LIBCPP_HARDENING_MODE) |
|
# libc++ 18+ |
|
add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG) |
|
elseif(ARX_HAVE_LIBCPP_ENABLE_HARDENED_MODE) |
|
# libc++ 17 - Full debug mode is now a compile-time option and all -D_LIBCPP_DEBUG=1 does is |
|
# generate an #error if the library was not built in debug mode :| |
|
add_definitions(-D_LIBCPP_ENABLE_HARDENED_MODE=1) |
|
elseif(ARX_HAVE_LIBCPP_ENABLE_ASSERTIONS) |
|
# libc++ 15-16 - Full debug mode is now a compile-time option and all -D_LIBCPP_DEBUG=1 does is |
|
# generate an #error if the library was not built in debug mode :| |
|
add_definitions(-D_LIBCPP_ENABLE_ASSERTIONS=1) |
|
elseif(IS_LIBCXX) |
|
# older libc++ |
|
add_definitions(-D_LIBCPP_DEBUG=1) |
|
else() |
|
# libstdc++ |
|
add_definitions(-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_GLIBCXX_SANITIZE_VECTOR) |
|
set(disable_libstdcxx_debug "-U_GLIBCXX_DEBUG -U_GLIBCXX_DEBUG_PEDANTIC") |
|
endif() |
|
elseif(DEBUG) |
|
if(ARX_HAVE_LIBCPP_HARDENING_MODE) |
|
#libc++ 18+ |
|
add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE) |
|
elseif(ARX_HAVE_LIBCPP_ENABLE_HARDENED_MODE) |
|
# libc++ 17 |
|
add_definitions(-D_LIBCPP_ENABLE_HARDENED_MODE=1) |
|
elseif(ARX_HAVE_LIBCPP_ENABLE_ASSERTIONS) |
|
# libc++ 15-16 |
|
add_definitions(-D_LIBCPP_ENABLE_ASSERTIONS=1) |
|
elseif(IS_LIBCXX) |
|
# older libc++ - 0 means light checks only, it does not mean no checks |
|
add_definitions(-D_LIBCPP_DEBUG=0) |
|
else() |
|
# libstdc++ |
|
add_definitions(-D_GLIBCXX_ASSERTIONS=1) |
|
endif() |
|
endif() |
|
|
|
if(CMAKE_BUILD_TYPE STREQUAL "") |
|
set(CMAKE_BUILD_TYPE "Release") |
|
endif() |
|
|
|
if(SET_OPTIMIZATION_FLAGS) |
|
|
|
if(MACOS) |
|
# TODO For some reason this check succeeds on macOS, but then |
|
# flag causes the actual build to fail :( |
|
else() |
|
# Link as few libraries as possible |
|
# This is much easier than trying to decide which libraries are needed for each |
|
# system |
|
add_ldflag("-Wl,--as-needed") |
|
endif() |
|
|
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug") |
|
|
|
# set debug symbol level to -g3 |
|
check_compiler_flag(RESULT "-g3") |
|
if(NOT RESULT STREQUAL "") |
|
string(REGEX REPLACE "(^| )-g(|[0-9]|gdb)" "\\1" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") |
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${RESULT}") |
|
endif() |
|
|
|
# disable optimizations |
|
check_compiler_flag(RESULT "-Og") |
|
if(NOT RESULT) |
|
check_compiler_flag(RESULT "-O0") |
|
endif() |
|
string(REGEX REPLACE "-O[0-9]" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") |
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${RESULT}") |
|
|
|
elseif(CMAKE_BUILD_TYPE STREQUAL "Release") |
|
|
|
if((NOT CMAKE_CXX_FLAGS MATCHES "-g(|[0-9]|gdb)") |
|
AND (NOT CMAKE_CXX_FLAGS_RELEASE MATCHES "-g(|[0-9]|gdb)")) |
|
add_cxxflag("-g2") |
|
endif() |
|
|
|
add_cxxflag("-ffast-math") |
|
|
|
endif() |
|
|
|
endif(SET_OPTIMIZATION_FLAGS) |
|
|
|
endif(MSVC)
|
|
|