From 7d454e054aa280371c8e474f7e2f5fa3ff99e13c Mon Sep 17 00:00:00 2001 From: Rafael Kitover Date: Wed, 2 Feb 2022 22:27:39 +0000 Subject: [PATCH] Fix MSVC compiler/linker flags. Turn off ccache for vcpkg builds (this is only relevant to MSVC, where ccache does not work yet.) Throw an error if CMAKE_BUILD_TYPE is not valid or does not match case exactly (to make comparisons simple.) Add SetCompilerLinkerFlags.cmake lib with the functions: add_compiler_flags() For each flag passed in, add it to CMAKE_CXX_FLAGS and CMAKE_C_FLAGS if not already present. Also clears all build-specific flag variables on every call, if using this functions you must set build-specific flags yourself. add_linker_flags() For each flag passed in, add it to CMAKE_(EXE|SHARED|MODULE|STATIC)_LINKER_FLAGS if not already present. Add remove_dupes() function to VbamFunctions.cmake from: https://stackoverflow.com/a/41416298/262458 This is used to remove duplicate flags in SetCompilerLinkerFlags.cmake described above. Use the new functions to set compiler and linker flags for MSVC. Signed-off-by: Rafael Kitover --- CMakeLists.txt | 83 +++++++++++++----------------- cmake/SetCompilerLinkerFlags.cmake | 44 ++++++++++++++++ cmake/VbamFunctions.cmake | 10 ++++ 3 files changed, 91 insertions(+), 46 deletions(-) create mode 100644 cmake/SetCompilerLinkerFlags.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eb2de53..1605e028 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,20 +58,16 @@ endif() # Use ccache if available and not already enabled on the command line. # This has to be done before the project() call. -if(NOT (CMAKE_CXX_COMPILER_LAUNCHER OR CMAKE_CXX_COMPILER MATCHES ccache)) + +if(NOT (VCPKG_TARGET_TRIPLET OR CMAKE_CXX_COMPILER_LAUNCHER OR CMAKE_CXX_COMPILER MATCHES ccache)) find_program(CCACHE_EXECUTABLE ccache) if(CCACHE_EXECUTABLE) message(STATUS "Enabling ccache") - if(CMAKE_VERSION VERSION_LESS 3.4.0) - # FIXME: This method currently breaks for native ccache on windows - # with the visual studio resource compiler. - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_EXECUTABLE}) - else() - set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "C compiler launcher" FORCE) - set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "C++ compiler launcher" FORCE) - set(CMAKE_ASM_NASM_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "nasm assembler launcher" FORCE) - endif() + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_EXECUTABLE}) + set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "C compiler launcher" FORCE) + set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "C++ compiler launcher" FORCE) + set(CMAKE_ASM_NASM_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "nasm assembler launcher" FORCE) endif() endif() @@ -85,6 +81,8 @@ endif() if(CMAKE_BUILD_TYPE STREQUAL "") set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE) +elseif(NOT CMAKE_BUILD_TYPE MATCHES "^(Release|Debug|RelWithDebInfo|MinSizeRel)$") + message(FATAL_ERROR "Invalid CMAKE_BUILD_TYPE: '${CMAKE_BUILD_TYPE}', must be one of: 'Release', 'Debug', 'RelWithDebInfo' or 'MinSizeRel'") endif() include(CTest) @@ -547,6 +545,8 @@ ProcessorCount(num_cpus) option(UPSTREAM_RELEASE "do some optimizations and release automation tasks" OFF) +include(SetCompilerLinkerFlags) + if(CMAKE_C_COMPILER_ID STREQUAL Clang AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) include(LLVMToolchain) endif() @@ -770,47 +770,38 @@ elseif(MSVC) string(REGEX REPLACE "/[Ww][^ ]+" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) string(REGEX REPLACE "/[Ww][^ ]+" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - add_compile_options(/std:c++17 -D__STDC_LIMIT_MACROS /fp:fast /Oi) - - if(CMAKE_BUILD_TYPE STREQUAL Debug) - add_compile_options(/W4) - else() - add_compile_options(/w) - - if(X86_32) - add_compile_options(/Ot /Oy /Ob3 /GF /Gy) - else() - add_compile_options(/O2 /Ob3) - endif() - - - if(ENABLE_LTO) - add_compile_options(/GL) - - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /LTCG") - set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /LTCG") - endif() - endif() + add_compiler_flags(/std:c++17 -D__STDC_LIMIT_MACROS /fp:fast /Oi) if(VBAM_STATIC) - string(REGEX REPLACE "/MDd?" "" CMAKE_C_FLAGS ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS}) + set(runtime "/MT") + else() + set(runtime "/MD") + endif() - string(REGEX REPLACE "/MDd?" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS}) - string(REGEX REPLACE "/MDd?" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS}) + if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(runtime "${runtime}d") - if(CMAKE_BUILD_TYPE MATCHES "Debug|RelWithDebInfo") - add_compile_options(/MTd) + add_compiler_flags(${runtime} /W4 /Ob0 /Od /RTC1 /DDEBUG) + else() + add_compiler_flags(/w /DNDEBUG) + + if(CMAKE_BUILD_TYPE STREQUAL Release) + if(X86_32) + add_compiler_flags(${runtime} /Ot /Oy /GF /Gy /Ob3) + else() + add_compiler_flags(${runtime} /O2 /Ob3) + endif() + elseif(CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo) + add_compiler_flags(${runtime} /Zi /Ob1) + elseif(CMAKE_BUILD_TYPE STREQUAL MinSizeRel) + add_compiler_flags(${runtime} /O1 /Ob1) else() - add_compile_options(/MT) + message(FATAL_ERROR "Unknown CMAKE_BUILD_TYPE: '${CMAKE_BUILD_TYPE}'") + endif() + + if(ENABLE_LTO) + add_compiler_flags(/GL) + add_linker_flags(/LTCG) endif() endif() endif() diff --git a/cmake/SetCompilerLinkerFlags.cmake b/cmake/SetCompilerLinkerFlags.cmake new file mode 100644 index 00000000..1cf291bf --- /dev/null +++ b/cmake/SetCompilerLinkerFlags.cmake @@ -0,0 +1,44 @@ +include(VbamFunctions) + +function(add_compiler_flags) + foreach(var RELEASE DEBUG RELWITHDEBINFO MINSIZEREL) + set("CMAKE_CXX_FLAGS_${var}" "" CACHE STRING "MUST BE UNSET" FORCE) + set("CMAKE_CXX_FLAGS_${var}" "" PARENT_SCOPE) + set("CMAKE_C_FLAGS_${var}" "" CACHE STRING "MUST BE UNSET" FORCE) + set("CMAKE_C_FLAGS_${var}" "" PARENT_SCOPE) + endforeach() + + # Set C and CXX flags if not already set. + foreach(flag ${ARGV}) + foreach(var CMAKE_CXX_FLAGS CMAKE_C_FLAGS) + # Remove any duplicates first. + remove_dupes("${${var}}" "${var}") + + string(FIND "${${var}}" "${flag}" found) + + if(found EQUAL -1) + set("${var}" "${${var}} ${flag}" CACHE STRING "Compiler Flags" FORCE) + set("${var}" "${${var}} ${flag}" PARENT_SCOPE) + endif() + endforeach() + endforeach() +endfunction() + +function(add_linker_flags) + # Set linker flags if not already set. + foreach(flag ${ARGV}) + foreach(var EXE SHARED MODULE STATIC) + set(var "CMAKE_${var}_LINKER_FLAGS") + + # Remove any duplicates first. + remove_dupes("${${var}}" "${var}") + + string(FIND "${${var}}" "${flag}" found) + + if(found EQUAL -1) + set("${var}" "${${var}} ${flag}" CACHE STRING "Linker Flags" FORCE) + set("${var}" "${${var}} ${flag}" PARENT_SCOPE) + endif() + endforeach() + endforeach() +endfunction() diff --git a/cmake/VbamFunctions.cmake b/cmake/VbamFunctions.cmake index e048787d..ce866cc8 100644 --- a/cmake/VbamFunctions.cmake +++ b/cmake/VbamFunctions.cmake @@ -1,3 +1,13 @@ +# From: https://stackoverflow.com/a/41416298/262458 +function(REMOVE_DUPES ARG_STR OUTPUT) + set(ARG_LIST ${ARG_STR}) + separate_arguments(ARG_LIST) + list(REMOVE_DUPLICATES ARG_LIST) + string (REGEX REPLACE "([^\\]|^);" "\\1 " _TMP_STR "${ARG_LIST}") + string (REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping + set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE) +endfunction() + # From: https://stackoverflow.com/a/7216542 function(JOIN VALUES GLUE OUTPUT) string (REGEX REPLACE "([^\\]|^);" "\\1${GLUE}" _TMP_STR "${VALUES}")