diff --git a/CMakeLists.txt b/CMakeLists.txt index 445f0334b..1cc439403 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,7 @@ option(USE_UBSAN "Enable Undefined Behavior Sanitizer." FALSE) option(USE_LSAN "Enable LeakSanitizer." FALSE) option(USE_MSAN "Enable MemorySanitizer." FALSE) -set(ENABLED_SANITIZER CACHE INTERNAL BOOL FALSE) +set(ENABLED_SANITIZER FALSE CACHE INTERNAL BOOL "Am i using a sanitizer?") if(USE_ASAN OR USE_MSAN OR USE_LSAN OR USE_MSAN) set(ENABLED_SANITIZER TRUE) endif() @@ -197,6 +197,11 @@ if(SINGLE_TARGET) #set_target_properties(spheresvr_release PROPERTIES CXX_EXTENSIONS OFF) #target_compile_features(spheresvr_release PUBLIC cxx_std_20) target_precompile_headers(spheresvr_release ${pch_options}) + + add_custom_command(TARGET spheresvr_release POST_BUILD + COMMAND ${CMAKE_STRIP} $ + COMMENT "Stripping executable" + ) endif() if(("${CMAKE_BUILD_TYPE}" STREQUAL "") OR (${CMAKE_BUILD_TYPE} MATCHES "(N|n?)ightly")) set(TARGETS ${TARGETS} spheresvr_nightly) @@ -210,6 +215,11 @@ if(SINGLE_TARGET) #set_target_properties(spheresvr_nightly PROPERTIES CXX_EXTENSIONS OFF) #target_compile_features(spheresvr_nightly PUBLIC cxx_std_20) target_precompile_headers(spheresvr_nightly ${pch_options}) + + add_custom_command(TARGET spheresvr_nightly POST_BUILD + COMMAND ${CMAKE_STRIP} $ + COMMENT "Stripping executable" + ) endif() if(("${CMAKE_BUILD_TYPE}" STREQUAL "") OR (${CMAKE_BUILD_TYPE} MATCHES "(D|d?)ebug")) set(TARGETS ${TARGETS} spheresvr_debug) @@ -233,30 +243,19 @@ else(SINGLE_TARGET) #set_target_properties(spheresvr PROPERTIES CXX_EXTENSIONS OFF) #target_compile_features(spheresvr PUBLIC cxx_std_20) target_precompile_headers(spheresvr ${pch_options}) + + # To be tested + #add_custom_command(TARGET spheresvr POST_BUILD + # $<$:COMMAND ${CMAKE_STRIP} $> + # $<$:COMMAND ${CMAKE_STRIP} $> + # COMMENT "Stripping executable" + #) endif(SINGLE_TARGET) # -------------------- message(STATUS) -include("${CMAKE_SOURCE_DIR}/cmake/CompilerFlagsChecker.cmake") - -# -------------------- - -if(USE_ASAN) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) -endif() -if(USE_UBSAN) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) -endif() -if(USE_LSAN) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) -endif() -if(USE_MSAN) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) -endif() -if(ENABLED_SANITIZER) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) -endif() +include("${CMAKE_SOURCE_DIR}/cmake/CommonCompilerFlags.cmake") # -------------------- diff --git a/cmake/CommonCompilerFlags.cmake b/cmake/CommonCompilerFlags.cmake new file mode 100644 index 000000000..2fae79e31 --- /dev/null +++ b/cmake/CommonCompilerFlags.cmake @@ -0,0 +1,22 @@ +set(list_explicit_compiler_options_all CACHE INTERNAL STRING) +set(list_explicit_linker_options_all CACHE INTERNAL STRING) +include("${CMAKE_SOURCE_DIR}/cmake/CompilerFlagsBase.cmake") +include("${CMAKE_SOURCE_DIR}/cmake/CompilerFlagsChecker.cmake") + +# -------------------- + +if(USE_ASAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) +endif() +if(USE_UBSAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) +endif() +if(USE_LSAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) +endif() +if(USE_MSAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) +endif() +if(ENABLED_SANITIZER) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) +endif() diff --git a/cmake/CompilerFlagsBase.cmake b/cmake/CompilerFlagsBase.cmake new file mode 100644 index 000000000..fddb2c124 --- /dev/null +++ b/cmake/CompilerFlagsBase.cmake @@ -0,0 +1,98 @@ +message(STATUS "Setting base compiler flags...") + +if(NOT MSVC) + # Compiler option flags (minimum). + list( + APPEND + compiler_options_base + -pthread + -fexceptions + -fnon-call-exceptions + -pipe + -ffast-math + # Place each function and variable into its own section, allowing the linker to remove unused ones. + #-ffunction-sections + #-fdata-sections + #-flto # Supported even by ancient compilers... also needed to benefit the most from the two flags above. + ) + list( + APPEND + compiler_options_warning_base + -Werror + -Wall + -Wextra + -Wpedantic + ) + + # Linker option flags (minimum). + list( + APPEND + linker_options_base + -pthread + -dynamic + #-flto + ) + + message(STATUS "Adding the following base compiler options: ${compiler_options_base}.") + message(STATUS "Adding the following base compiler warning options: ${compiler_options_warning_base}.") + message(STATUS "Adding the following base linker options: ${linker_options_base}.") + + #-- Store once the compiler flags, only the ones specific per build type. + + if("${ENABLED_SANITIZER}" STREQUAL "TRUE") + # -fno-omit-frame-pointer disables a good optimization which might corrupt the debugger stack trace. + set(local_compile_options_nondebug -ggdb3 -Og -fno-omit-frame-pointer -fno-inline) + set(local_link_options_nondebug) + else() + # If using ThinLTO: -flto=thin -fsplit-lto-unit + # If using classic/monolithic LTO: -flto=full -fvirtual-function-elimination + # Probably useful when using lto: -ffunction-sections -fdata-sections + set(local_compile_options_nondebug -O3)# -flto) + set(local_link_options_nondebug)#-flto) + endif() + + set(custom_compile_options_release + ${local_compile_options_nondebug} + -flto=full + -fvirtual-function-elimination + -ffunction-sections + -fdata-sections + CACHE INTERNAL STRING + ) + set(custom_compile_options_nightly + ${local_compile_options_nondebug} + CACHE INTERNAL STRING + ) + set(custom_compile_options_debug + -ggdb3 -O0 -fno-omit-frame-pointer -fno-inline + CACHE INTERNAL STRING + ) + + set(custom_link_options_release + ${local_link_options_nondebug} + -flto=full + CACHE INTERNAL STRING + ) + set(custom_link_options_nightly + ${local_link_options_nondebug} + CACHE INTERNAL STRING + ) + set(custom_link_options_debug + "" + CACHE INTERNAL STRING + ) + + if(TARGET spheresvr_release) + message(STATUS "Adding the following compiler options specific to 'Release' build: ${custom_compile_options_release}.") + message(STATUS "Adding the following linker options specific to 'Release' build: ${custom_link_options_release}.") + endif() + if(TARGET spheresvr_nightly) + message(STATUS "Adding the following compiler options specific to 'Nightly' build: ${custom_compile_options_nightly}.") + message(STATUS "Adding the following linker options specific to 'Nightly' build: ${custom_link_options_nightly}.") + endif() + if(TARGET spheresvr_debug) + message(STATUS "Adding the following compiler options specific to 'Debug' build: ${custom_compile_options_debug}.") + message(STATUS "Adding the following linker options specific to 'Debug' build: ${custom_link_options_debug}.") + endif() + +endif() diff --git a/cmake/CompilerFlagsChecker.cmake b/cmake/CompilerFlagsChecker.cmake index b0e183dc0..768b6a9da 100644 --- a/cmake/CompilerFlagsChecker.cmake +++ b/cmake/CompilerFlagsChecker.cmake @@ -4,19 +4,7 @@ message(STATUS "Checking available compiler flags...") if(NOT MSVC) message(STATUS "-- Compilation options:") - # Compiler option flags. - list( - APPEND - compiler_options_base - -pthread - -fexceptions - -fnon-call-exceptions - -pipe - -ffast-math - ) - list(APPEND base_compiler_options_warning -Werror;-Wall;-Wextra;-Wpedantic) - - # Linker flags (warnings) + # Linker flags (warnings). #check_cxx_compiler_flag("-Wl,--fatal-warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V1) #check_cxx_compiler_flag("-Wl,-fatal_warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V2) if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") @@ -213,6 +201,10 @@ if(NOT MSVC) list(APPEND checked_linker_options_all "-Wl,-fatal_warnings") endif() + #if(COMP_HAS_LTO) + # list(APPEND checked_compiler_options "-flto") + #endif() + if(COMP_HAS_FNO_EXPENSIVE_OPTIMIZATIONS) list(APPEND checked_compiler_options "-fno-expensive-optimizations") endif() @@ -456,8 +448,6 @@ if(NOT MSVC) list( APPEND list_explicit_compiler_options_all - ${compiler_options_base} - ${base_compiler_options_warning} ${checked_compiler_options} ${checked_compiler_options_asan} ${checked_compiler_options_ubsan} @@ -468,18 +458,14 @@ if(NOT MSVC) ${checked_compiler_warnings_disabled} ) - list(APPEND list_explicit_linker_options_all ${checked_linker_options_all};-pthread;-dynamic) - - #string(JOIN " " string_checked_compiler_options_all ${list_checked_compiler_options_all}) - #set(string_checked_compiler_options_all CACHE INTERNAL STRING) - set(list_explicit_compiler_options_all CACHE INTERNAL STRING) - set(list_explicit_linker_options_all CACHE INTERNAL STRING) + list( + APPEND + list_explicit_linker_options_all + ${checked_linker_options_all} + ) # -- - message(STATUS "Adding the following base compiler options: ${compiler_options_base}") - message(STATUS "Adding the following base compiler warning options: ${base_compiler_options_warning}") - message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options}.") if(COMP_HAS_ASAN) message(STATUS "Adding the following conditional compiler options for ASan: ${checked_compiler_options_asan}.") @@ -507,13 +493,12 @@ if(NOT MSVC) STATUS "Adding the following conditional compiler warnings ignore options: ${checked_compiler_warnings_disabled}." ) - message(STATUS "Adding the following linker options: ${list_explicit_linker_options_all}.") + message(STATUS "Adding the following conditional linker options: ${checked_linker_options_all}.") elseif(MSVC) list( APPEND list_explicit_compiler_options_all - ${base_compiler_options_msvc} ${checked_compiler_options_msvc} ) diff --git a/cmake/toolchains/include/Linux-Clang_common.inc.cmake b/cmake/toolchains/include/Linux-Clang_common.inc.cmake index a7304c79c..bb1bf34a7 100644 --- a/cmake/toolchains/include/Linux-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Linux-Clang_common.inc.cmake @@ -18,7 +18,7 @@ function(toolchain_exe_stuff_common) #-- Validate sanitizers options and store them between the common compiler flags. # From https://clang.llvm.org/docs/ClangCommandLineReference.html - # -static-libsan Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin) + # -static-libsan Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on Darwin) #string(REPLACE ";" " " CXX_FLAGS_EXTRA "${CXX_FLAGS_EXTRA}") @@ -27,29 +27,14 @@ function(toolchain_exe_stuff_common) #-- Apply compiler flags, only the ones specific per build type. - # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(local_compile_options_extra) - if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) - endif() if(TARGET spheresvr_release) - target_compile_options( - spheresvr_release - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} - ) + target_compile_options(spheresvr_release PUBLIC ${custom_compile_options_release}) endif() if(TARGET spheresvr_nightly) - if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) - else() - target_compile_options( - spheresvr_nightly - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} - ) - endif() + target_compile_options(spheresvr_nightly PUBLIC ${custom_compile_options_nightly}) endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) + target_compile_options(spheresvr_debug PUBLIC ${custom_compile_options_debug}) endif() #-- Store common linker flags. @@ -62,6 +47,19 @@ function(toolchain_exe_stuff_common) -static-libgcc> # no way to safely statically link against libc ) + #-- Apply linker flags, only the ones specific per build type. + + if(TARGET spheresvr_release) + target_link_options(spheresvr_release PUBLIC ${custom_link_options_release}) + endif() + if(TARGET spheresvr_nightly) + target_link_options(spheresvr_nightly PUBLIC ${custom_link_options_nightly}) + endif() + if(TARGET spheresvr_debug) + target_link_options(spheresvr_debug PUBLIC ${custom_link_options_debug}) + endif() + + #-- Store common define macros. set(cxx_compiler_definitions_common diff --git a/cmake/toolchains/include/Linux-GNU_common.inc.cmake b/cmake/toolchains/include/Linux-GNU_common.inc.cmake index 19e8c3a71..b890cf8d2 100644 --- a/cmake/toolchains/include/Linux-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Linux-GNU_common.inc.cmake @@ -21,23 +21,14 @@ function(toolchain_exe_stuff_common) #-- Apply compiler flags, only the ones specific per build type. - # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(local_compile_options_extra) - if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) - endif() if(TARGET spheresvr_release) - target_compile_options(spheresvr_release PUBLIC -s -O3 ${local_compile_options_extra}) + target_compile_options(spheresvr_release PUBLIC ${custom_compile_options_release}) endif() if(TARGET spheresvr_nightly) - if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) - else() - target_compile_options(spheresvr_nightly PUBLIC -O3 ${local_compile_options_extra}) - endif() + target_compile_options(spheresvr_nightly PUBLIC ${custom_compile_options_nightly}) endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) + target_compile_options(spheresvr_debug PUBLIC ${custom_compile_options_debug}) endif() #-- Store common linker flags. @@ -52,6 +43,18 @@ function(toolchain_exe_stuff_common) > ) + #-- Apply linker flags, only the ones specific per build type. + + if(TARGET spheresvr_release) + target_link_options(spheresvr_release PUBLIC ${custom_link_options_release}) + endif() + if(TARGET spheresvr_nightly) + target_link_options(spheresvr_nightly PUBLIC ${custom_link_options_nightly}) + endif() + if(TARGET spheresvr_debug) + target_link_options(spheresvr_debug PUBLIC ${custom_link_options_debug}) + endif() + #-- Store common define macros. set(cxx_compiler_definitions_common diff --git a/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake b/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake index efc752811..0103c0e61 100644 --- a/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake +++ b/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake @@ -30,23 +30,14 @@ function(toolchain_exe_stuff_common) #-- Apply compiler flags, only the ones specific per build type. - # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(local_compile_options_extra) - if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) - endif() if(TARGET spheresvr_release) - target_compile_options(spheresvr_release PUBLIC -O3 ${local_compile_options_extra}) + target_compile_options(spheresvr_release PUBLIC ${custom_compile_options_release}) endif() if(TARGET spheresvr_nightly) - if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) - else() - target_compile_options(spheresvr_nightly PUBLIC -O3 ${local_compile_options_extra}) - endif() + target_compile_options(spheresvr_nightly PUBLIC ${custom_compile_options_nightly}) endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) + target_compile_options(spheresvr_debug PUBLIC ${custom_compile_options_debug}) endif() #-- Store common linker flags. @@ -60,13 +51,16 @@ function(toolchain_exe_stuff_common) ) #-- Apply linker flags, only the ones specific per build type. - # -s got deprecated, we could directly call 'strip' - #IF (TARGET spheresvr_release) - # target_link_options (spheresvr_release PRIVATE -s) - #ENDIF () - #IF (TARGET spheresvr_nightly AND NOT ${ENABLED_SANITIZER}) - # target_link_options (spheresvr_nightly PRIVATE -s) - #ENDIF () + + if(TARGET spheresvr_release) + target_link_options(spheresvr_release PUBLIC ${custom_link_options_release}) + endif() + if(TARGET spheresvr_nightly) + target_link_options(spheresvr_nightly PUBLIC ${custom_link_options_nightly}) + endif() + if(TARGET spheresvr_debug) + target_link_options(spheresvr_debug PUBLIC ${custom_link_options_debug}) + endif() #-- Store common define macros. diff --git a/cmake/toolchains/include/Windows-Clang_common.inc.cmake b/cmake/toolchains/include/Windows-Clang_common.inc.cmake index bf2094af3..3d399b54a 100644 --- a/cmake/toolchains/include/Windows-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Windows-Clang_common.inc.cmake @@ -35,16 +35,8 @@ function(toolchain_exe_stuff_common) #-- Apply compiler flags, only the ones specific per build type. - # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(local_compile_options_extra) - if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) - endif() if(TARGET spheresvr_release) - target_compile_options( - spheresvr_release - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} - ) + if(TARGET spheresvr_release) #[[ IF (NOT ${CLANG_USE_GCC_LINKER}) if (${RUNTIME_STATIC_LINK}) @@ -56,14 +48,7 @@ function(toolchain_exe_stuff_common) ]] endif() if(TARGET spheresvr_nightly) - if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) - else() - target_compile_options( - spheresvr_nightly - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} - ) - endif() + target_compile_options(spheresvr_nightly PUBLIC ${custom_compile_options_nightly}) #[[ IF (NOT ${CLANG_USE_GCC_LINKER}) if (${RUNTIME_STATIC_LINK}) @@ -75,7 +60,7 @@ function(toolchain_exe_stuff_common) ]] endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0) + target_compile_options(spheresvr_debug PUBLIC ${custom_compile_options_debug}) #[[ IF (NOT ${CLANG_USE_GCC_LINKER}) if (${RUNTIME_STATIC_LINK}) @@ -95,16 +80,40 @@ function(toolchain_exe_stuff_common) if(${RUNTIME_STATIC_LINK}) set(cxx_linker_options_common ${cxx_linker_options_common} -static-libstdc++ -static-libgcc) # no way to statically link against libc? maybe we can on windows? endif() -#[[ + #[[ else () if (${RUNTIME_STATIC_LINK}) set (cxx_linker_options_common ${cxx_linker_options_common} /MTd ) else () set (cxx_linker_options_common ${cxx_linker_options_common} /MDd ) endif () -]] + ]] endif() + #-- Apply linker flags, only the ones specific per build type. + + if(TARGET spheresvr_release) + target_link_options(spheresvr_release PUBLIC ${custom_link_options_release}) + endif() + if(TARGET spheresvr_nightly) + target_link_options(spheresvr_nightly PUBLIC ${custom_link_options_nightly}) + endif() + if(TARGET spheresvr_debug) + target_link_options(spheresvr_debug PUBLIC ${custom_link_options_debug}) + endif() + #if (NOT ${CLANG_USE_GCC_LINKER}) + # IF (TARGET spheresvr_release) + # target_link_options ( spheresvr_release PUBLIC "LINKER:SHELL:" ) + # ENDIF () + # IF (TARGET spheresvr_nightly) + # target_link_options ( spheresvr_nightly PUBLIC "LINKER:SHELL:" ) + # ENDIF () + # IF (TARGET spheresvr_debug) + # target_link_options ( spheresvr_debug PUBLIC "LINKER:/DEBUG" ) + # ENDIF () + #endif () + + #-- Store common define macros. set(cxx_compiler_definitions_common @@ -136,20 +145,6 @@ function(toolchain_exe_stuff_common) endif() endif() - #-- Apply linker options, only the ones specific per build type. - - #if (NOT ${CLANG_USE_GCC_LINKER}) - # IF (TARGET spheresvr_release) - # target_link_options ( spheresvr_release PUBLIC "LINKER:SHELL:" ) - # ENDIF () - # IF (TARGET spheresvr_nightly) - # target_link_options ( spheresvr_nightly PUBLIC "LINKER:SHELL:" ) - # ENDIF () - # IF (TARGET spheresvr_debug) - # target_link_options ( spheresvr_debug PUBLIC "LINKER:/DEBUG" ) - # ENDIF () - #endif () - #-- Now add back the common compiler options, preprocessor macros, linker targets and options. if(NOT ${CLANG_USE_GCC_LINKER}) diff --git a/cmake/toolchains/include/Windows-GNU_common.inc.cmake b/cmake/toolchains/include/Windows-GNU_common.inc.cmake index c2a90d51f..018e0dbc3 100644 --- a/cmake/toolchains/include/Windows-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Windows-GNU_common.inc.cmake @@ -24,23 +24,14 @@ function(toolchain_exe_stuff_common) #-- Apply compiler flags, only the ones specific per build type. - # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(local_compile_options_extra) - if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) - endif() if(TARGET spheresvr_release) - target_compile_options(spheresvr_release PUBLIC -s -O3 ${local_compile_options_extra}) + target_compile_options(spheresvr_release PUBLIC ${custom_compile_options_release}) endif() if(TARGET spheresvr_nightly) - if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) - else() - target_compile_options(spheresvr_nightly PUBLIC -O3 ${local_compile_options_extra}) - endif() + target_compile_options(spheresvr_nightly PUBLIC ${custom_compile_options_nightly}) endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) + target_compile_options(spheresvr_debug PUBLIC ${custom_compile_options_debug}) endif() #-- Store common linker flags. @@ -53,6 +44,18 @@ function(toolchain_exe_stuff_common) -static-libgcc> # no way to statically link against libc? maybe we can on windows? ) + #-- Apply linker flags, only the ones specific per build type. + + if(TARGET spheresvr_release) + target_link_options(spheresvr_release PUBLIC ${custom_link_options_release}) + endif() + if(TARGET spheresvr_nightly) + target_link_options(spheresvr_nightly PUBLIC ${custom_link_options_nightly}) + endif() + if(TARGET spheresvr_debug) + target_link_options(spheresvr_debug PUBLIC ${custom_link_options_debug}) + endif() + #-- Store common define macros. set(cxx_compiler_definitions_common diff --git a/lib/lib_build_flags_common_c.cmake b/lib/lib_build_flags_common_c.cmake index 2d3cc4734..33bc76815 100644 --- a/lib/lib_build_flags_common_c.cmake +++ b/lib/lib_build_flags_common_c.cmake @@ -23,7 +23,11 @@ elseif(NOT MSVC) -pipe -fexceptions -fnon-call-exceptions - -O3 + -O3 # -Os saves ~200 kb, probably not worth losing some performance for that amount... + # Place each function and variable into its own section, allowing the linker to remove unused ones. + #-ffunction-sections + #-fdata-sections + #-flto # Also needed to benefit the most from the two flags above. $<$:-ggdb3> ) diff --git a/src/common/sphere_library/CSString.cpp b/src/common/sphere_library/CSString.cpp index a0cc3b665..009bf68bb 100644 --- a/src/common/sphere_library/CSString.cpp +++ b/src/common/sphere_library/CSString.cpp @@ -9,7 +9,7 @@ #include // for vsnprintf #endif -#define STRING_DEFAULT_SIZE 42 +#define CSTRING_DEFAULT_SIZE 42 //#define DEBUG_STRINGS #ifdef DEBUG_STRINGS @@ -67,7 +67,7 @@ CSString::CSString(const CSString& s) : // private void CSString::Init() { - m_iMaxLength = STRING_DEFAULT_SIZE; + m_iMaxLength = CSTRING_DEFAULT_SIZE; #ifdef DEBUG_STRINGS gMemAmount += m_iMaxLength; #endif @@ -117,7 +117,7 @@ int CSString::Resize(int iNewLength, bool fPreciseSize) } else { - //m_iMaxLength = iNewLength + (STRING_DEFAULT_SIZE >> 1); // Probably too much... + //m_iMaxLength = iNewLength + (CSTRING_DEFAULT_SIZE >> 1); // Probably too much... m_iMaxLength = (iNewLength * 3) >> 1; // >> 2 is equal to doing / 2 } diff --git a/src/common/sphere_library/CSString.h b/src/common/sphere_library/CSString.h index 26aedb428..8c7bb0dc9 100644 --- a/src/common/sphere_library/CSString.h +++ b/src/common/sphere_library/CSString.h @@ -30,7 +30,7 @@ class CSString /** * @brief Initializes internal data. * - * Allocs STRING_DEFAULT_SIZE by default. If DEBUG_STRINGS setted, updates statistical information (total memory allocated). + * Allocs CSTRING_DEFAULT_SIZE by default. If DEBUG_STRINGS setted, updates statistical information (total memory allocated). */ void Init(); diff --git a/src/common/sphere_library/sstringobjs.cpp b/src/common/sphere_library/sstringobjs.cpp index 765aeb009..e07785026 100644 --- a/src/common/sphere_library/sstringobjs.cpp +++ b/src/common/sphere_library/sstringobjs.cpp @@ -3,28 +3,35 @@ #include "sstringobjs.h" -#define MAX_TEMP_LINES_NO_CONTEXT 512 -#define STRING_DEFAULT_SIZE 40 - +// temporary string storage +#define NO_CONTEXT_TEMPSTRING_MAX_LINES 256 +//#define STRINGOBJ_DEFAULT_SIZE 48 struct TemporaryStringUnsafeStateHolder { // NOT thread safe size_t m_tempPosition; - char m_tempStrings[MAX_TEMP_LINES_NO_CONTEXT][THREAD_STRING_LENGTH]; + std::unique_ptr m_tempStrings; static TemporaryStringUnsafeStateHolder& get() { static TemporaryStringUnsafeStateHolder instance; return instance; } -}; +private: + TemporaryStringUnsafeStateHolder() + { + m_tempStrings = std::make_unique(NO_CONTEXT_TEMPSTRING_MAX_LINES * THREAD_STRING_LENGTH); + } +}; +[[nodiscard]] static tchar* getUnsafeStringBuffer() noexcept { auto& unsafe_state_holder = TemporaryStringUnsafeStateHolder::get(); - tchar* unsafe_buffer = unsafe_state_holder.m_tempStrings[unsafe_state_holder.m_tempPosition++]; - if (unsafe_state_holder.m_tempPosition >= MAX_TEMP_LINES_NO_CONTEXT) + tchar* unsafe_buffer = &(unsafe_state_holder.m_tempStrings[unsafe_state_holder.m_tempPosition * THREAD_STRING_LENGTH]); + unsafe_state_holder.m_tempPosition += 1; + if (unsafe_state_holder.m_tempPosition >= NO_CONTEXT_TEMPSTRING_MAX_LINES) { unsafe_state_holder.m_tempPosition = 0; } @@ -32,6 +39,7 @@ static tchar* getUnsafeStringBuffer() noexcept } +[[nodiscard]] tchar* Str_GetTemp() noexcept { AbstractThread *pThreadState = ThreadHolder::get().current(); @@ -184,17 +192,17 @@ size_t AbstractString::lastIndexOf(char c) const noexcept /* HeapString::HeapString() { - resize(STRING_DEFAULT_SIZE); + resize(STRINGOBJ_DEFAULT_SIZE); } HeapString::~HeapString() { - destroyHeap(); + destroyHeap(); } void HeapString::resize(size_t newLength) { - ensureLengthHeap(newLength); + ensureLengthHeap(newLength); } */ diff --git a/src/common/sphere_library/sstringobjs.h b/src/common/sphere_library/sstringobjs.h index fddd7e55e..86e591715 100644 --- a/src/common/sphere_library/sstringobjs.h +++ b/src/common/sphere_library/sstringobjs.h @@ -8,26 +8,21 @@ #include "../common.h" -// temporary string storage -#define THREAD_STRING_STORAGE 4096 -#define THREAD_TSTRING_STORAGE 2048 -#define THREAD_STRING_LENGTH 4096 - //-- -tchar* Str_GetTemp() noexcept; +#define THREAD_STRING_LENGTH 4096 -#if __cplusplus >= 202002L -// C++20 (and later) code +[[nodiscard]] consteval -#else -constexpr -#endif -size_t Str_TempLength() noexcept { +size_t Str_TempLength() noexcept +{ return (size_t)(THREAD_STRING_LENGTH); } +[[nodiscard]] +tchar* Str_GetTemp() noexcept; + //-- // Base abstract class for strings, provides basic information of what should be available diff --git a/src/game/CWorld.cpp b/src/game/CWorld.cpp index fe7ba2d57..b7b4996b5 100644 --- a/src/game/CWorld.cpp +++ b/src/game/CWorld.cpp @@ -184,6 +184,9 @@ static lpctstr GetReasonForGarbageCode(int iCode = -1) noexcept break; case 0x4226: pStr = "Old Spawn memory item conversion"; + break; + case 0x4227: + pStr = "Old Spawn memory item conversion (mislinked)"; break; case 0xFFFF: @@ -408,9 +411,12 @@ void CWorldThread::AddIdleObj(CSObjContRec* obj) void CWorldThread::ScheduleObjDeletion(CSObjContRec* obj) { - const auto servMode = g_Serv.GetServerMode(); - const bool fDestroy = (servMode == SERVMODE_Exiting || servMode == SERVMODE_Loading); // If the world is being destroyed, do not schedule the object for deletion but delete it right away. + const auto servMode = g_Serv.GetServerMode(); + // I can't destroy it while SERVMODE_Loading, because the script parser can't know (without creating a global state holder, TODO) that this + // object was deleted/destroyed. The object pointer will become invalid, and if something uses it, even for calling a method, Sphere will crash. + //const bool fDestroy = (servMode == SERVMODE_Exiting || servMode == SERVMODE_Loading); + const bool fDestroy = (servMode == SERVMODE_Exiting); if (fDestroy) { diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index cdd22b0a0..d06988321 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -4921,7 +4921,7 @@ TRIGRET_TYPE CChar::CheckLocationEffects(bool fStanding) { if (_uiRecursingItemStep >= _kuiRecursingItemStepLimit) { - g_Log.EventError("Calling recursively @ITEMSTEP for more than %u times. Skipping trigger call.\n", _kuiRecursingStepLimit); + g_Log.EventError("Calling recursively @ITEMSTEP for more than %u times. Skipping trigger call.\n", _kuiRecursingItemStepLimit); } else { diff --git a/src/game/chars/CCharNPCAct.cpp b/src/game/chars/CCharNPCAct.cpp index 27f573784..84d51e238 100644 --- a/src/game/chars/CCharNPCAct.cpp +++ b/src/game/chars/CCharNPCAct.cpp @@ -577,8 +577,7 @@ int CChar::NPC_WalkToPoint( bool fRun ) CheckRevealOnMove(); EXC_SET_BLOCK("MoveToChar"); - //if (!MoveToChar(pMe, false, true)) - if (!MoveToChar(pMe, false, false)) + if (!MoveToChar(pMe, false, true)) return 2; EXC_SET_BLOCK("Move Update"); diff --git a/src/game/clients/CAccount.cpp b/src/game/clients/CAccount.cpp index 7e2027853..6e292947e 100644 --- a/src/game/clients/CAccount.cpp +++ b/src/game/clients/CAccount.cpp @@ -1062,7 +1062,7 @@ void CAccount::SetNewPassword( lpctstr pszPassword ) ADDTOCALLSTACK("CAccount::SetNewPassword"); if ( !pszPassword || !pszPassword[0] ) // no password given, auto-generate password { - static tchar const passwdChars[] = "ABCDEFGHJKLMNPQRTUVWXYZ2346789"; + static constexpr tchar passwdChars[] = "ABCDEFGHJKLMNPQRTUVWXYZ2346789"; int len = (int)strlen(passwdChars); int charsCnt = g_Rand.GetVal(4) + 6; // 6 - 10 chars if ( charsCnt > (MAX_ACCOUNT_PASSWORD_ENTER - 1) ) diff --git a/src/game/items/CItemMemory.cpp b/src/game/items/CItemMemory.cpp index 5ef7ea9a5..2df3f81fe 100644 --- a/src/game/items/CItemMemory.cpp +++ b/src/game/items/CItemMemory.cpp @@ -104,8 +104,16 @@ int CItemMemory::FixWeirdness() dword dwFlags = GetHue(); if (dwFlags & MEMORY_LEGACY_ISPAWNED) { - CCSpawn *pSpawn = static_cast(m_uidLink.ItemFind()->GetComponent(COMP_SPAWN)); - if (pSpawn && pChar) + CItem *pSpawnItem = m_uidLink.ItemFind(); + if (!pSpawnItem) + { + iResultCode = 0x4227; + return iResultCode; + } + + CCSpawn *pSpawn = static_cast(pSpawnItem->GetComponent(COMP_SPAWN)); + ASSERT(pSpawn); + if (pSpawn) { pSpawn->AddObj(pChar->GetUID()); } diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index aacad6db1..096b03f99 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -1,5 +1,7 @@ -// this thing is somehow required to be able to initialise OLE -#define _WIN32_DCOM +#ifdef _WIN32 + // this thing is somehow required to be able to initialise OLE + #define _WIN32_DCOM +#endif #include "../common/basic_threading.h" #include "../common/CException.h" @@ -12,7 +14,7 @@ #include #include #elif !defined(_BSD) && !defined(__APPLE__) - #include + #include // to set thread name #endif #include @@ -26,32 +28,42 @@ // number of milliseconds to wait for a thread to close #define THREADJOIN_TIMEOUT 60000 +// temporary string storage +#define THREAD_TEMPSTRING_C_STORAGE 2048 +#define THREAD_TEMPSTRING_OBJ_STORAGE 1024 + struct TemporaryStringThreadSafeStateHolder { - // Normal Buffer + // C-style string Buffer (char array) SimpleMutex g_tmpStringMutex; - std::atomic g_tmpStringIndex = 0; - char g_tmpStrings[THREAD_TSTRING_STORAGE][THREAD_STRING_LENGTH]; + std::atomic g_tmpStringIndex; + std::unique_ptr g_tmpStrings; // TemporaryString Buffer SimpleMutex g_tmpTemporaryStringMutex; - std::atomic g_tmpTemporaryStringIndex = 0; - - + std::atomic g_tmpTemporaryStringIndex; struct TemporaryStringStorage { char m_buffer[THREAD_STRING_LENGTH]; char m_state; - } g_tmpTemporaryStringStorage[THREAD_STRING_STORAGE]; + }; + std::unique_ptr g_tmpTemporaryStringStorage; +private: + TemporaryStringThreadSafeStateHolder() : + g_tmpStringIndex(0), g_tmpTemporaryStringIndex(0) + { + g_tmpStrings = std::make_unique(THREAD_TEMPSTRING_C_STORAGE * THREAD_STRING_LENGTH); + g_tmpTemporaryStringStorage = std::make_unique(THREAD_TEMPSTRING_OBJ_STORAGE); + } public: - static TemporaryStringThreadSafeStateHolder* get() noexcept - { - static TemporaryStringThreadSafeStateHolder instance{}; - return &instance; - } + static TemporaryStringThreadSafeStateHolder& get() noexcept + { + static TemporaryStringThreadSafeStateHolder instance; + return instance; + } }; @@ -786,18 +798,19 @@ AbstractSphereThread::~AbstractSphereThread() char *AbstractSphereThread::allocateBuffer() noexcept { - auto* tsholder = TemporaryStringThreadSafeStateHolder::get(); - SimpleThreadLock stlBuffer(tsholder->g_tmpStringMutex); + auto& tsholder = TemporaryStringThreadSafeStateHolder::get(); + SimpleThreadLock stlBuffer(tsholder.g_tmpStringMutex); char * buffer = nullptr; - tsholder->g_tmpStringIndex += 1; + tsholder.g_tmpStringIndex += 1; - if (tsholder->g_tmpStringIndex >= THREAD_TSTRING_STORAGE ) + if (tsholder.g_tmpStringIndex >= THREAD_TEMPSTRING_C_STORAGE ) { - tsholder->g_tmpStringIndex = tsholder->g_tmpStringIndex % THREAD_TSTRING_STORAGE; + tsholder.g_tmpStringIndex = tsholder.g_tmpStringIndex % THREAD_TEMPSTRING_C_STORAGE; } - buffer = tsholder->g_tmpStrings[tsholder->g_tmpStringIndex]; + //buffer = tsholder->g_tmpStrings.get() + (tsholder->g_tmpStringIndex * THREAD_STRING_LENGTH); + buffer = &(tsholder.g_tmpStrings[tsholder.g_tmpStringIndex * THREAD_TEMPSTRING_C_STORAGE]); *buffer = '\0'; return buffer; @@ -807,24 +820,24 @@ static TemporaryStringThreadSafeStateHolder::TemporaryStringStorage * getThreadRawStringBuffer() { - auto* tsholder = TemporaryStringThreadSafeStateHolder::get(); - SimpleThreadLock stlBuffer(tsholder->g_tmpStringMutex); + auto& tsholder = TemporaryStringThreadSafeStateHolder::get(); + SimpleThreadLock stlBuffer(tsholder.g_tmpStringMutex); - int initialPosition = tsholder->g_tmpTemporaryStringIndex; + int initialPosition = tsholder.g_tmpTemporaryStringIndex; int index; for (;;) { - index = tsholder->g_tmpTemporaryStringIndex += 1; - if(tsholder->g_tmpTemporaryStringIndex >= THREAD_STRING_STORAGE ) + index = tsholder.g_tmpTemporaryStringIndex += 1; + if(tsholder.g_tmpTemporaryStringIndex >= THREAD_TEMPSTRING_OBJ_STORAGE ) { - const int inc = tsholder->g_tmpTemporaryStringIndex % THREAD_STRING_STORAGE; - tsholder->g_tmpTemporaryStringIndex = inc; + const int inc = tsholder.g_tmpTemporaryStringIndex % THREAD_TEMPSTRING_OBJ_STORAGE; + tsholder.g_tmpTemporaryStringIndex = inc; index = inc; } - if(tsholder->g_tmpTemporaryStringStorage[index].m_state == 0 ) + if(tsholder.g_tmpTemporaryStringStorage[index].m_state == 0 ) { - auto* store = &tsholder->g_tmpTemporaryStringStorage[index]; + auto* store = &(tsholder.g_tmpTemporaryStringStorage[index]); *store->m_buffer = '\0'; return store; } @@ -846,8 +859,8 @@ getThreadRawStringBuffer() void AbstractSphereThread::getStringBuffer(TemporaryString &string) noexcept { ADDTOCALLSTACK("alloc"); - auto* tsholder = TemporaryStringThreadSafeStateHolder::get(); - SimpleThreadLock stlBuffer(tsholder->g_tmpTemporaryStringMutex); + auto& tsholder = TemporaryStringThreadSafeStateHolder::get(); + SimpleThreadLock stlBuffer(tsholder.g_tmpTemporaryStringMutex); auto* store = getThreadRawStringBuffer(); string.init(store->m_buffer, &store->m_state);