From fae88d1b70d5fdfec5ce8928460671014972a915 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 13 Aug 2016 10:47:28 +0100 Subject: [PATCH] Support static and dynamic C++ runtime linking Update libloadorder to 9.4.1 to support statically linking Boost libraries while dynamically-linking the runtime library, and update how CEF's default configuration is edited to also support dynamic linking. Dynamic linking is required for the API DLL, and static linking is required by the C API wrapper. As building both would double build times, CI will only build with dynamic linking, which means LOOT application users will now also need the MSVC 2015 x86 runtime. --- .travis.yml | 2 +- CMakeLists.txt | 45 +++++++++++++++++------------- README.md | 4 +-- scripts/appveyor/install_boost.ps1 | 26 ++++++++--------- scripts/cmake/CEF_CMakeLists.txt | 20 ------------- scripts/cmake/configure_cef.cmake | 24 ++++++++++++++++ 6 files changed, 66 insertions(+), 55 deletions(-) delete mode 100644 scripts/cmake/CEF_CMakeLists.txt create mode 100644 scripts/cmake/configure_cef.cmake diff --git a/.travis.yml b/.travis.yml index dd70952d..bc2b99b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ before_script: # Move into the cloned LOOT repo build path. - mkdir build && cd build # Link dynamically to the C++ standard library runtime. - - cmake .. -DPROJECT_STATIC_RUNTIME=OFF -DBOOST_ROOT=~/boost_1_61_0 + - cmake .. -DBOOST_ROOT=~/boost_1_61_0 script: - if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then npm test; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 163892f2..5989688a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,13 @@ project (LOOT) include(ExternalProject) option(BUILD_SHARED_LIBS "Build a shared library" ON) -option(PROJECT_STATIC_RUNTIME "Build with static runtime libs (/MT)" ON) +option(MSVC_STATIC_RUNTIME "Build with static runtime libs (/MT)" OFF) + +IF (${MSVC_STATIC_RUNTIME}) + set (MSVC_SHARED_RUNTIME OFF) +ELSE() + set (MSVC_SHARED_RUNTIME ON) +ENDIF() ############################## # Get Build Revision @@ -32,7 +38,12 @@ configure_file("${CMAKE_SOURCE_DIR}/src/backend/app/loot_version.cpp.in" "${CMAK set (Boost_USE_STATIC_LIBS ON) set (Boost_USE_MULTITHREADED ON) -set (Boost_USE_STATIC_RUNTIME ${PROJECT_STATIC_RUNTIME}) + +IF (MSVC) + set (Boost_USE_STATIC_RUNTIME ${MSVC_STATIC_RUNTIME}) +ELSE() + set (Boost_USE_STATIC_RUNTIME OFF) +ENDIF() IF (NOT Boost_USE_STATIC_LIBS) add_definitions(-DBOOST_LOG_DYN_LINK) @@ -43,6 +54,7 @@ find_package(Boost REQUIRED COMPONENTS atomic log log_setup regex locale thread ExternalProject_Add(GTest PREFIX "external" URL "https://github.com/google/googletest/archive/release-1.7.0.tar.gz" + CMAKE_ARGS -Dgtest_force_shared_crt=${MSVC_SHARED_RUNTIME} INSTALL_COMMAND "") ExternalProject_Get_Property(GTest SOURCE_DIR BINARY_DIR) set (GTEST_INCLUDE_DIRS "${SOURCE_DIR}/include") @@ -60,7 +72,7 @@ set (LIBESPM_INCLUDE_DIRS "${SOURCE_DIR}/include") ExternalProject_Add(libgit2 PREFIX "external" URL "https://github.com/libgit2/libgit2/archive/v0.24.1.tar.gz" - CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DBUILD_CLAR=OFF + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DBUILD_CLAR=OFF -DSTATIC_CRT=${MSVC_STATIC_RUNTIME} BUILD_COMMAND ${CMAKE_COMMAND} --build . --target git2 --config $(CONFIGURATION) INSTALL_COMMAND "") ExternalProject_Get_Property(libgit2 SOURCE_DIR BINARY_DIR) @@ -70,9 +82,9 @@ set(LIBGIT2_LIBRARIES "${BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_ ExternalProject_Add(libloadorder PREFIX "external" DEPENDS libespm - URL "https://github.com/WrinklyNinja/libloadorder/archive/9.4.0.tar.gz" - CMAKE_ARGS -DBOOST_INCLUDEDIR=${Boost_INCLUDE_DIR} -DPROJECT_STATIC_RUNTIME=${PROJECT_STATIC_RUNTIME} - # BUILD_COMMAND ${CMAKE_COMMAND} --build . --target loadorder --config $(CONFIGURATION) + URL "https://github.com/WrinklyNinja/libloadorder/archive/9.4.1.tar.gz" + CMAKE_ARGS -DBOOST_INCLUDEDIR=${Boost_INCLUDE_DIR} -DMSVC_STATIC_RUNTIME=${MSVC_STATIC_RUNTIME} + BUILD_COMMAND ${CMAKE_COMMAND} --build . --target loadorder --config $(CONFIGURATION) INSTALL_COMMAND "") ExternalProject_Get_Property(libloadorder SOURCE_DIR BINARY_DIR) set(LIBLOADORDER_INCLUDE_DIRS "${SOURCE_DIR}/include") @@ -104,7 +116,7 @@ ExternalProject_Add(testing-plugins ExternalProject_Add(yaml-cpp PREFIX "external" URL "https://github.com/WrinklyNinja/yaml-cpp/archive/patched-for-loot.tar.gz" - CMAKE_ARGS -DMSVC_SHARED_RT=OFF + CMAKE_ARGS -DMSVC_SHARED_RT=${MSVC_SHARED_RUNTIME} BUILD_COMMAND ${CMAKE_COMMAND} --build . --target yaml-cpp --config $(CONFIGURATION) INSTALL_COMMAND "") ExternalProject_Get_Property(yaml-cpp SOURCE_DIR BINARY_DIR) @@ -127,7 +139,7 @@ ExternalProject_Add(cef PREFIX "external" URL ${CEF_URL} URL_HASH SHA1=${CEF_URL_HASH} - PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/scripts/cmake/CEF_CMakeLists.txt" "${CMAKE_BINARY_DIR}/external/src/cef/CMakeLists.txt" + PATCH_COMMAND ${CMAKE_COMMAND} -DMSVC_STATIC_RUNTIME=${MSVC_STATIC_RUNTIME} -P "${CMAKE_SOURCE_DIR}/scripts/cmake/configure_cef.cmake" CMAKE_ARGS -DUSE_SANDBOX=OFF BUILD_COMMAND ${CMAKE_COMMAND} --build . --target libcef_dll_wrapper --config $(CONFIGURATION) INSTALL_COMMAND "") @@ -325,11 +337,6 @@ IF (CMAKE_COMPILER_IS_GNUCXX) set (CMAKE_BUILD_WITH_INSTALL_RPATH ON) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=c++14") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++14") - IF (PROJECT_STATIC_RUNTIME) - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libstdc++ -static-libgcc") - set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") - ENDIF () set (LOOT_LIBS ssl curl @@ -340,8 +347,11 @@ IF (CMAKE_COMPILER_IS_GNUCXX) ENDIF () IF (MSVC) - # Force static C++ runtime linkage. - IF (PROJECT_STATIC_RUNTIME) + # Set /bigobj to allow building Debug tests + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") + + # Update compiler flags. + IF (MSVC_STATIC_RUNTIME) FOREACH(flag CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_DEBUG_INIT @@ -352,9 +362,6 @@ IF (MSVC) ENDFOREACH() ENDIF () - # Set /bigobj to allow building Debug tests - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") - set (LOOT_LIBS version ws2_32 shlwapi @@ -378,7 +385,7 @@ target_link_libraries(loot_common ${Boost_LIBRARIES} ${LIBGIT2_LIBRARIES} ${LIBL # Build tests. add_executable (tests ${LOOT_TESTS_SRC} ${LOOT_TESTS_HEADERS}) add_dependencies (tests loot_common GTest testing-metadata testing-plugins) -target_link_libraries(tests loot_common ${GTEST_LIBRARIES}) +target_link_libraries(tests loot_common ${GTEST_LIBRARIES} ${LIBLOADORDER_LIBRARIES}) # Build API. add_library (loot_api ${LOOT_API_SRC} ${LOOT_API_HEADERS}) diff --git a/README.md b/README.md index d2759a79..ce05e51c 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ LOOT uses the following CMake variables to set build parameters: Parameter | Values | Default |Description ----------|--------|---------|----------- -`BUILD_SHARED_LIBS` | `ON`, `OFF` | `OFF` | Whether or not to build a shared LOOT API binary. -`PROJECT_STATIC_RUNTIME` | `ON`, `OFF` | `ON` | Whether to link the C++ runtime statically or not. +`BUILD_SHARED_LIBS` | `ON`, `OFF` | `ON` | Whether or not to build a shared LOOT API binary. +`MSVC_STATIC_RUNTIME` | `ON`, `OFF` | `OFF` | Whether to link the C++ runtime statically or not when building with MSVC. You may also need to set `BOOST_ROOT` if CMake cannot find Boost. diff --git a/scripts/appveyor/install_boost.ps1 b/scripts/appveyor/install_boost.ps1 index 60d2b8a9..9f67773c 100644 --- a/scripts/appveyor/install_boost.ps1 +++ b/scripts/appveyor/install_boost.ps1 @@ -4,17 +4,17 @@ $boostUrl = 'https://downloads.sourceforge.net/project/boost/boost/1.61.0/boost_ $boostArchive = 'C:\projects\boost_1_61_0.7z' $boostFolder = 'C:\projects\boost_1_61_0' $boostLibraries = @( - 'libboost_atomic-vc140-mt-s-1_61.lib' - 'libboost_chrono-vc140-mt-s-1_61.lib' - 'libboost_date_time-vc140-mt-s-1_61.lib' - 'libboost_filesystem-vc140-mt-s-1_61.lib' - 'libboost_iostreams-vc140-mt-s-1_61.lib' - 'libboost_locale-vc140-mt-s-1_61.lib' - 'libboost_log_setup-vc140-mt-s-1_61.lib' - 'libboost_log-vc140-mt-s-1_61.lib' - 'libboost_regex-vc140-mt-s-1_61.lib' - 'libboost_system-vc140-mt-s-1_61.lib' - 'libboost_thread-vc140-mt-s-1_61.lib' + 'libboost_atomic-vc140-mt-1_61.lib' + 'libboost_chrono-vc140-mt-1_61.lib' + 'libboost_date_time-vc140-mt-1_61.lib' + 'libboost_filesystem-vc140-mt-1_61.lib' + 'libboost_iostreams-vc140-mt-1_61.lib' + 'libboost_locale-vc140-mt-1_61.lib' + 'libboost_log_setup-vc140-mt-1_61.lib' + 'libboost_log-vc140-mt-1_61.lib' + 'libboost_regex-vc140-mt-1_61.lib' + 'libboost_system-vc140-mt-1_61.lib' + 'libboost_thread-vc140-mt-1_61.lib' ) function Is-LibraryMissing { @@ -37,10 +37,10 @@ if (Is-LibraryMissing) { Write-Output "Time taken: $((Get-Date).Subtract($start_time).Seconds) second(s)" Write-Output 'Extracting ' + $boostArchive + '...' - cd + cd 7z x $boostArchive -o"C:\projects" cd $boostFolder .\bootstrap.bat - .\b2 toolset=msvc threadapi=win32 link=static runtime-link=static variant=release address-model=32 --with-log --with-date_time --with-thread --with-filesystem --with-locale --with-regex --with-system --with-iostreams + .\b2 toolset=msvc threadapi=win32 link=static variant=release address-model=32 --with-log --with-date_time --with-thread --with-filesystem --with-locale --with-regex --with-system --with-iostreams } diff --git a/scripts/cmake/CEF_CMakeLists.txt b/scripts/cmake/CEF_CMakeLists.txt deleted file mode 100644 index 94fddfce..00000000 --- a/scripts/cmake/CEF_CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights -# reserved. Use of this source code is governed by a BSD-style license that -# can be found in the LICENSE file. - -cmake_minimum_required(VERSION 2.8.12.1) - -set(CMAKE_CONFIGURATION_TYPES Debug Release) - -project(cef) - -set_property(GLOBAL PROPERTY OS_FOLDERS ON) - -set(CEF_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CEF_ROOT}/cmake") - -find_package(CEF REQUIRED) - -add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper) - -PRINT_CEF_CONFIG() diff --git a/scripts/cmake/configure_cef.cmake b/scripts/cmake/configure_cef.cmake new file mode 100644 index 00000000..60eb57ad --- /dev/null +++ b/scripts/cmake/configure_cef.cmake @@ -0,0 +1,24 @@ +# Set CEF_PATH to the path to the root of the CEF folder that contains the +# files to be edited. + +# Remove the "add_subdirectory(cefclient)" and "add_subdirectory(cefsimple)" +# lines from CEF's CMakeLists.txt. +set(CEF_CMAKELISTS_PATH "CMakeLists.txt") +file(READ ${CEF_CMAKELISTS_PATH} CEF_CMAKELISTS) + +string(REPLACE "add_subdirectory(cefclient)" "" CEF_CMAKELISTS ${CEF_CMAKELISTS}) +string(REPLACE "add_subdirectory(cefsimple)" "" CEF_CMAKELISTS ${CEF_CMAKELISTS}) + +file(WRITE ${CEF_CMAKELISTS_PATH} ${CEF_CMAKELISTS}) + +message("MSVC_STATIC_RUNTIME: ${MSVC_STATIC_RUNTIME}") + +if (NOT MSVC_STATIC_RUNTIME) + # Replace the "/MT" and "/MTd" linker flags with "/MD" and "/MDd". + set(CEF_VARIABLES_PATH "cmake/cef_variables.cmake") + file(READ ${CEF_VARIABLES_PATH} CEF_VARIABLES) + + string(REPLACE "/MT" "/MD" CEF_VARIABLES ${CEF_VARIABLES}) + + file(WRITE ${CEF_VARIABLES_PATH} ${CEF_VARIABLES}) +endif ()