From 42e3add6a1a5e2a28b5e83389ebea7540606cb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E4=BF=8A=E5=98=89?= Date: Sun, 12 Sep 2021 05:55:53 +0800 Subject: [PATCH] BUILD: a couple of cmake msvc compile fixes (#10799) * cmake: a couple of msvc compile fixes Throw error when using multi-config generators. Add USE_MSVC_STATIC_CRT option for statically linking with CRT. Set curl's CURL_STATIC_CRT aligned with USE_MSVC_STATIC_CRT. Fix cmake configs of 7z and OpenAL in msvc build. Remove unecessary hard coded compiling and linking flags. Use debug option in windeployqt when configuring for a debug build. Search for windeployqt tool in configure time. Add vcpkg's Qt support. * Fix some typos --- 3rdparty/7z/CMakeLists.txt | 4 +- 3rdparty/OpenAL/CMakeLists.txt | 4 +- 3rdparty/curl/CMakeLists.txt | 3 ++ CMakeLists.txt | 53 ++++++++++++++++++++++-- buildfiles/cmake/ConfigureCompiler.cmake | 3 +- rpcs3/CMakeLists.txt | 43 ++++++++++++++++++- 6 files changed, 100 insertions(+), 10 deletions(-) diff --git a/3rdparty/7z/CMakeLists.txt b/3rdparty/7z/CMakeLists.txt index 80979cfafd..43fc3c77b2 100644 --- a/3rdparty/7z/CMakeLists.txt +++ b/3rdparty/7z/CMakeLists.txt @@ -45,7 +45,9 @@ if(WIN32) src/LzmaLib.c src/7zCrc.c src/MtDec.c) - target_include_directories(3rdparty_7z INTERFACE 7z) + target_include_directories(3rdparty_7z INTERFACE + $ + $) else() add_library(3rdparty_7z INTERFACE) endif() diff --git a/3rdparty/OpenAL/CMakeLists.txt b/3rdparty/OpenAL/CMakeLists.txt index 715534e5bf..3c897e7d81 100644 --- a/3rdparty/OpenAL/CMakeLists.txt +++ b/3rdparty/OpenAL/CMakeLists.txt @@ -1,7 +1,7 @@ # OpenAL if (MSVC) - find_path(OPENAL_INCLUDE_DIR al.h PATHS OpenAL/include) - find_library(OPENAL_LIBRARY OpenAL32 PATHS OpenAL/libs/Win64/) + find_path(OPENAL_INCLUDE_DIR al.h PATHS include/) + find_library(OPENAL_LIBRARY OpenAL32 PATHS libs/Win64/) else() find_package(OpenAL REQUIRED) endif() diff --git a/3rdparty/curl/CMakeLists.txt b/3rdparty/curl/CMakeLists.txt index f0cc526167..3cb67e6d20 100644 --- a/3rdparty/curl/CMakeLists.txt +++ b/3rdparty/curl/CMakeLists.txt @@ -12,5 +12,8 @@ else() option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON) option(CURL_ZLIB "Set to ON to enable building curl with zlib support." OFF) set(CURL_CA_PATH "none" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") + if(USE_MSVC_STATIC_CRT) + set(CURL_STATIC_CRT ON CACHE BOOL "Use static crt to build curl" FORCE) + endif() add_subdirectory(curl EXCLUDE_FROM_ALL) endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index f9b18ef691..c053e05be4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,17 +28,64 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/buildfiles/cmake") include(CheckCXXCompilerFlag) +# TODO(cjj19970505@live.cn) +# Currently cmake config scripts are single-config generator only. +get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTI_CONFIG) + message(FATAL_ERROR "Multi-config generators are not supported.") +endif() + if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to Release") set(CMAKE_BUILD_TYPE "Release") endif() -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - add_definitions(-DNDEBUG) -elseif(NOT MSVC) +if(CMAKE_BUILD_TYPE MATCHES "Debug" AND NOT MSVC) add_definitions(-D_DEBUG) endif() +if(MSVC) + option(USE_MSVC_STATIC_CRT "Use static MSVC C runtime" OFF) + + # TODO(cjj19970505@live.cno) + # DiscordRPC binary in 3rdparty is compiled /MT + # So theoretically we should enable DiscordRPC in Release and static CRT build + # since we might encounter some rumtime issues when more than one CRT version are presented. + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-160#what-problems-exist-if-an-application-uses-more-than-one-crt-version + # Add other DiscordRPC binaries(compiled with /MTd, /MD, /MDd) or compile it from source may address this issue. + if(NOT(CMAKE_BUILD_TYPE MATCHES "Release" AND USE_MSVC_STATIC_CRT)) + set(USE_DISCORD_RPC OFF CACHE BOOL "Discord RPC is only available in Release and static CRT build." FORCE) + endif() + + if(USE_MSVC_STATIC_CRT) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + else() + # though doc ( https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html ) + # says if that property is not set then CMake uses the default value MultiThreaded$<$:Debug>DLL + # to select a MSVC runtime library. + # But yaml-cpp set /MT(d) if CMAKE_MSVC_RUNTIME_LIBRARY is undefined + # So we have to define it explicitly + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + endif() + + # TODO(cjj19970505@live.cn) + # offical QT uses dynamic CRT. + # When building our lib with static CRT and debug build type + # and linking with Qt with dynmaic CRT and debug build, + # error is encountered in runtime (which is expected). + # But building our lib with static CRT and release build type, + # and linking with Qt with dynamic CRT and release build seems to be working, + # which is the same config with VS solution. + # (though technically it might still have some hidden errors). + # So we allow static CRT in both relase and debug build, but prompt warning in debug build. + # For more info: + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-160#what-problems-exist-if-an-application-uses-more-than-one-crt-version + # https://wiki.qt.io/Technical_FAQ#Why_does_a_statically_built_Qt_use_the_dynamic_Visual_Studio_runtime_libraries_.3F_Do_I_need_to_deploy_those_with_my_application_.3F + if(USE_MSVC_STATIC_CRT AND CMAKE_BUILD_TYPE MATCHES "Debug") + message(AUTHOR_WARNING "Debug build currently can not work with static CRT.") + endif() +endif() + if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." ) endif() diff --git a/buildfiles/cmake/ConfigureCompiler.cmake b/buildfiles/cmake/ConfigureCompiler.cmake index 49af51a61f..cbec6ef73c 100644 --- a/buildfiles/cmake/ConfigureCompiler.cmake +++ b/buildfiles/cmake/ConfigureCompiler.cmake @@ -2,8 +2,7 @@ if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew- /constexpr:steps16777216 /D _CRT_SECURE_NO_DEPRECATE=1 /D _CRT_NON_CONFORMING_SWPRINTFS=1 /D _SCL_SECURE_NO_WARNINGS=1") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D NOMINMAX /D _ENABLE_EXTENDED_ALIGNED_STORAGE=1 /D _HAS_EXCEPTIONS=0 /MT") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcd.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrtd.lib") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D NOMINMAX /D _ENABLE_EXTENDED_ALIGNED_STORAGE=1 /D _HAS_EXCEPTIONS=0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /DYNAMICBASE:NO /BASE:0x10000 /FIXED") #TODO: Some of these could be cleaned up diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 7a63931362..b52000a3f8 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -151,9 +151,48 @@ elseif(UNIX) COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $/git) elseif(WIN32) + # TODO(cjj19970505@live.cn) + # this is a single-config generator workaround + # multi-config generator will fail. + + # TODO(cjj19970505@live.cn) + # offical Qt binaries are built with -MD(d) only as stated in offical wiki + # https://wiki.qt.io/Technical_FAQ#Why_does_a_statically_built_Qt_use_the_dynamic_Visual_Studio_runtime_libraries_.3F_Do_I_need_to_deploy_those_with_my_application_.3F + # If we build our libs with /MT(d), we might encounter some issues. + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-160#what-problems-exist-if-an-application-uses-more-than-one-crt-version + + # Qt installed from Qt installer has following hierarchy: + # bin/ for release and debug dlls and windeployqt tools + # lib/cmake/Qt5/ for Qt5_Dir + # Qt installed from vcpkg has following hierarchy: + # bin/ for release dlls + # debug/bin/ for debug dlls + # tools/qt5/bin/ for tools including windeployqt + # tools/qt5/debug/bin/ for tools with debug build including windeployqt + # share/cmake/Qt5/ for Qt5_Dir + + # If Qt5 is installed from official Qt installer + list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../bin/") + + # If Qt5 is installed from vcpkg + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5/debug/bin/") + else() + list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5/bin/") + endif() + + find_program(_WINDEPLOYQT + NAMES windeployqt + PATHS ${_QT5_TOOLS_PATHS} + REQUIRED) + message("Use windeployqt in ${_WINDEPLOYQT}") + add_custom_command(TARGET rpcs3 POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$" - COMMAND "${Qt5_DIR}/../../../bin/windeployqt" --no-angle --no-compiler-runtime --no-opengl-sw --no-patchqt --no-svg --no-translations --no-quick --plugindir "$/qt/plugins" --release "$") + COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$" + # If Qt5 is installed from vcpkg, add binary path to PATH + # otherwise windeployqt tool won't be able to locate necessary dlls + COMMAND set PATH=${Qt5_DIR}/../../../$<$:debug/>bin/$%PATH% + COMMAND "${_WINDEPLOYQT}" --no-angle --no-compiler-runtime --no-opengl-sw --no-patchqt --no-svg --no-translations --no-quick --plugindir "$/qt/plugins" $<$:--debug> $<$:--release> "$") endif() # Unix installation