From 7b72b3d4eaaf4a22c303a2b7b446d6c454053574 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Tue, 7 Apr 2020 02:41:14 +0100 Subject: [PATCH] CMake: Use generator expressions more Generator expressions are the only way to distinguish between build types in multi-configuration builds (Visual Studio). This adds generator expressions for some of build type dependent values as a starting point. See a more detailed explanation at: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-specification-with-generator-expressions Notably: > Some buildsystems generated by cmake(1) have a predetermined build-configuration set in the CMAKE_BUILD_TYPE variable. The buildsystem for the IDEs such as Visual Studio and Xcode are generated independent of the build-configuration, and the actual build configuration is not known until build-time. Therefore, code such as > > string(TOLOWER ${CMAKE_BUILD_TYPE} _type) > if (_type STREQUAL debug) > target_compile_definitions(exe1 PRIVATE DEBUG_BUILD) > endif() > > may appear to work for Makefile Generators and Ninja generators, but is not portable to IDE generators. --- CMake/genex.cmake | 34 ++++++++++++++ CMake/git.cmake | 2 +- CMakeLists.txt | 109 ++++++++++++++++++++++---------------------- SourceS/config.h.in | 4 -- build/.gitignore | 1 - build/.gitkeep | 0 6 files changed, 90 insertions(+), 60 deletions(-) create mode 100644 CMake/genex.cmake delete mode 100644 SourceS/config.h.in delete mode 100644 build/.gitignore create mode 100644 build/.gitkeep diff --git a/CMake/genex.cmake b/CMake/genex.cmake new file mode 100644 index 000000000..09ba1dd37 --- /dev/null +++ b/CMake/genex.cmake @@ -0,0 +1,34 @@ +# Generator expression helpers + +macro(GENEX_OPTION name default description) + set(${name} ${default} CACHE STRING ${description}) + set_property(CACHE ${name} PROPERTY STRINGS FOR_DEBUG FOR_RELEASE ON OFF) +endmacro() + +# Provide an option that defaults to ON in debug builds. +macro(DEBUG_OPTION name description) + GENEX_OPTION(${name} FOR_DEBUG ${description}) +endmacro() + +# Provide an option that defaults to ON in non-debug builds. +# Note that this applies to Release, RelWithDebInfo, and MinSizeRel. +macro(RELEASE_OPTION name description) + GENEX_OPTION(${name} FOR_RELEASE ${description}) +endmacro() + +# Generate a generator expression for the given variable's current value. +# +# Supported variable values and what the resulting generator expression will evaluate to: +# * FOR_DEBUG - 1 in Debug config. +# * FOR_RELEASE - 1 in non-Debug config (Release, RelWithDebInfo). +# * Boolean value (TRUE, FALSE, ON, 1, etc) - that value as 0 or 1. +# +# Result is set on ${option}_GENEX in the calling scope. +function(genex_for_option name) + set(value ${${name}}) + set( + ${name}_GENEX + $,$,$,$>,$>> + PARENT_SCOPE + ) +endfunction() diff --git a/CMake/git.cmake b/CMake/git.cmake index d205b5bda..97def8904 100644 --- a/CMake/git.cmake +++ b/CMake/git.cmake @@ -9,7 +9,7 @@ endfunction(get_git_tag) function(get_git_commit_hash output_var) execute_process( - COMMAND git log -1 --format=-%h + COMMAND git log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/CMakeLists.txt b/CMakeLists.txt index 685266146..ab42c8b9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,64 +1,56 @@ cmake_minimum_required(VERSION 3.10) # CMP0083 NEW include(CMake/out_of_tree.cmake) +include(CMake/genex.cmake) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -option(ASAN "Enable address sanitizer" ON) -option(UBSAN "Enable undefined behaviour sanitizer" ON) -option(DEBUG "Enable debug mode in engine" ON) +DEBUG_OPTION(ASAN "Enable address sanitizer") +DEBUG_OPTION(UBSAN "Enable undefined behaviour sanitizer") +DEBUG_OPTION(DEBUG "Enable debug mode in engine") +option(DISABLE_LTO "Disable link-time optimization (by default enabled in release mode)" OFF) option(PIE "Generate position-independent code" OFF) -option(LTO "Enable link-time optimization (if supported by the toolchain)" OFF) option(SPAWN "Build the shareware version" OFF) option(DIST "Dynamically link only glibc and SDL2" OFF) -option(FASTER "Enable FASTER in engine" ON) option(BINARY_RELEASE "Enable options for binary release" OFF) option(NIGHTLY_BUILD "Enable options for nightly build" OFF) option(USE_SDL1 "Use SDL1.2 instead of SDL2" OFF) option(NONET "Disable network" OFF) option(RUN_TESTS "Build and run tests" OFF) -if(BINARY_RELEASE) +if(BINARY_RELEASE OR CMAKE_BUILD_TYPE STREQUAL "Release") + set(BINARY_RELEASE ON) set(CMAKE_BUILD_TYPE "Release") - set(ASAN OFF) - set(UBSAN OFF) - set(DEBUG OFF) - set(LTO ON) set(DIST ON) - set(FASTER OFF) endif() -if(NIGHTLY_BUILD) +if(NIGHTLY_BUILD OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + set(NIGHTLY_BUILD ON) set(CMAKE_BUILD_TYPE "RelWithDebInfo") - set(ASAN OFF) - set(UBSAN OFF) - set(DEBUG ON) - set(LTO ON) set(DIST ON) - set(FASTER OFF) endif() -include(CMake/git.cmake) -get_git_tag(GIT_TAG) -if(NOT CMAKE_BUILD_TYPE MATCHES "Release") +if(NOT VERSION_NUM) + include(CMake/git.cmake) + get_git_tag(VERSION_NUM) get_git_commit_hash(GIT_COMMIT_HASH) + if(NOT VERSION_SUFFIX) + set(VERSION_SUFFIX "$<$>:-${GIT_COMMIT_HASH}>") + endif() endif() project(DevilutionX - VERSION ${GIT_TAG} + VERSION ${VERSION_NUM} LANGUAGES C CXX) -if(LTO) - # Use LTO on compilers where it is supported. +# Not a genexp because CMake doesn't support it +# https://gitlab.kitware.com/cmake/cmake/-/issues/20546 +if(NOT DISABLE_LTO) + # LTO if supported: include(CheckIPOSupported) - check_ipo_supported(RESULT result OUTPUT lto_error) - if(result) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) - else() - message(WARNING "LTO not supported by this compiler and/or CMake version:") - message(WARNING ${lto_error}) + check_ipo_supported(RESULT is_ipo_supported OUTPUT lto_error) + if(is_ipo_supported) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL ON) endif() endif() @@ -327,6 +319,22 @@ endif() add_executable(${BIN_TARGET} WIN32 MACOSX_BUNDLE ${devilutionx_SRCS}) +# Use file GENERATE instead of configure_file because configure_file +# does not support generator expressions. +get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(is_multi_config) + set(CONFIG_PATH $/config.h) + target_include_directories(devilution PRIVATE ${CMAKE_BINARY_DIR}/$) + target_include_directories(${BIN_TARGET} PRIVATE ${CMAKE_BINARY_DIR}/$) +else() + set(CONFIG_PATH config.h) +endif() +file(GENERATE OUTPUT ${CONFIG_PATH} CONTENT +"#pragma once +#define PROJECT_NAME \"${PROJECT_NAME}\" +#define PROJECT_VERSION \"${PROJECT_VERSION}${VERSION_SUFFIX}\" +") + if(RUN_TESTS) include(CTest) include(GoogleTest) @@ -337,7 +345,6 @@ if(RUN_TESTS) gtest_add_tests(${BIN_TARGET} "" AUTO) endif() -configure_file(SourceS/config.h.in config.h @ONLY) target_include_directories(devilution PUBLIC Source SourceS ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(${BIN_TARGET} PRIVATE SourceX @@ -358,10 +365,8 @@ if(NOT NONET) endif() target_compile_definitions(devilution PRIVATE DEVILUTION_ENGINE) -target_compile_definitions(devilution PUBLIC - "$<$:_DEBUG>" - # Skip fades and other fluff - "$<$:FASTER>") +genex_for_option(DEBUG) +target_compile_definitions(devilution PUBLIC "$<${DEBUG_GENEX}:_DEBUG>") target_compile_definitions(${BIN_TARGET} PRIVATE ASIO_STANDALONE) # Defines without value @@ -434,7 +439,14 @@ foreach( endif() endforeach(def_name) +genex_for_option(ASAN) +genex_for_option(UBSAN) foreach(target devilution ${BIN_TARGET}) + target_compile_options(${target} PUBLIC "$<${ASAN_GENEX}:-fsanitize=address;-fsanitize-recover=address>") + target_link_libraries(${target} PUBLIC "$<${ASAN_GENEX}:-fsanitize=address;-fsanitize-recover=address>") + target_compile_options(${target} PUBLIC $<${UBSAN_GENEX}:-fsanitize=undefined>) + target_link_libraries(${target} PUBLIC $<${UBSAN_GENEX}:-fsanitize=undefined>) + if(USE_SDL1) target_link_libraries(${target} PRIVATE ${SDL_TTF_LIBRARY} @@ -448,16 +460,6 @@ foreach(target devilution ${BIN_TARGET}) SDL2::SDL2_mixer) endif() - if(ASAN) - target_compile_options(${target} PUBLIC -fsanitize=address -fsanitize-recover=address) - target_link_libraries(${target} PUBLIC -fsanitize=address -fsanitize-recover=address) - endif() - - if(UBSAN) - target_compile_options(${target} PUBLIC -fsanitize=undefined) - target_link_libraries(${target} PUBLIC -fsanitize=undefined) - endif() - if(SWITCH) target_link_libraries(${target} PRIVATE switch::libnx -lfreetype -lvorbisfile -lvorbis -logg -lmodplug -lmpg123 -lSDL2 -lopusfile -lopus -lEGL -lglapi -ldrm_nouveau -lpng -lbz2 -lz -lnx) @@ -475,8 +477,8 @@ foreach(target devilution ${BIN_TARGET}) target_compile_definitions(${target} PRIVATE ${def_list}) endforeach(target) -if(DIST AND CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT HAIKU) - target_link_libraries(${BIN_TARGET} PUBLIC -static-libgcc -static-libstdc++) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT HAIKU) + target_link_libraries(${BIN_TARGET} PUBLIC "$<$>:-static-libgcc;-static-libstdc++>") endif() if(WIN32) @@ -507,10 +509,9 @@ if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined") - if(DEBUG) - # Note: For Valgrind suppor. - target_compile_options(devilution PUBLIC -fno-omit-frame-pointer) - endif() + # Note: For Valgrind support. + genex_for_option(DEBUG) + target_compile_options(devilution PUBLIC $<${DEBUG_GENEX}:-fno-omit-frame-pointer>) # Ignore serious warnings due to "quality" of decompiled code # Currently, disable ignore all warnings (-w), to be removed later target_compile_options(devilution PRIVATE -fpermissive -w) diff --git a/SourceS/config.h.in b/SourceS/config.h.in deleted file mode 100644 index 989672a8c..000000000 --- a/SourceS/config.h.in +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#define PROJECT_NAME "@PROJECT_NAME@" -#define PROJECT_VERSION "@PROJECT_VERSION@@GIT_COMMIT_HASH@" diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100644 index 72e8ffc0d..000000000 --- a/build/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/build/.gitkeep b/build/.gitkeep new file mode 100644 index 000000000..e69de29bb