cpp-pm / hunter

CMake driven cross-platform package manager for C/C++.
BSD 2-Clause "Simplified" License
601 stars 179 forks source link

specifying msvc runtime #349

Open fentanyluser opened 3 years ago

fentanyluser commented 3 years ago

You can set runtime in cmake in your main CMakeLists.txt

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")

So your project will use static runtime but everything built with hunter will still be dynamic and unlinkable. Was not able to find a way to change this.

rbsheth commented 3 years ago

Just guessing, but that's probably a setting you'd want to put in your toolchain. So that it is propagated to all your dependencies.

thomassuckow commented 3 years ago

I've been trying to do this same thing today. Setting the runtime in the toolchain doesn't seem to alter how Boost gets compiled resulting in messages like:

libboost_program_options-mt-gd-x32.lib(value_semantic.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MTd_StaticDebug'

The boost build seems to set it based on the _DLL #define.

if(MSVC)
  hunter_check_toolchain_definition(NAME "_DLL" DEFINED _hunter_vs_md)
  hunter_cmake_args(
    Boost
    CMAKE_ARGS
      BOOST_BUILD_DYNAMIC_VSRUNTIME=${_hunter_vs_md}
  )
endif()

But this doesn't seem to be working as intended. I set the compiler option in the toolchain and see that my code is being compiled with /MTd but _DLL in the toolchain id is 1 implying that its /MDd

Yet it is unset when I build my code

Value of _DLL: _DLL
Value of _MT: 1
fentanyluser commented 3 years ago

Yeah I ended up just disabling hunter and compiling each lib manually, kind of a pain, would be nice to have this feature.

thomassuckow commented 3 years ago

I have the cmake_policy(SET CMP0091 NEW) in my toolchain file but I kinda feel like it is ignoring the setting. I noticed the toolchain CMakeLists.txt is set to 3.0 as the minimum cmake version.

thomassuckow commented 3 years ago

Just confirmed cmake_policy has no effect in a toolchain file.

(╯°□°)╯︵ ┻━┻

thomassuckow commented 3 years ago

Here be 🐉🐉🐉

Hunter only propagates the Toolchain file, but you can't change the MSVC flags CMAKE generates in pre-3.15 versioned configs until after it has loaded the MSVC toolchain info which happens AFTER the toolchain file is processed.

So... h4ck5

3.15 also introduced CMAKE_PROJECT_INCLUDE which includes a cmake file after the toolchain is loaded but before anything in the project is processed. This is done regardless of what minimum version is specified in CMakeLists.txt.

We can specify a default toolchain in our CMakeLists.txt

cmake_minimum_required(VERSION 3.15 FATAL_ERROR)

set(
    CMAKE_TOOLCHAIN_FILE
    "cmake/toolchain.cmake"
    CACHE
    FILEPATH
    "Default toolchain used for both hunter and our code"
)

That in turn configures an after project include

set(
    CMAKE_PROJECT_INCLUDE
    "${CMAKE_CURRENT_LIST_DIR}/project_after.cmake"
    CACHE
    FILEPATH
    "Project after include"
)

That performs the hacks on the flags when running msvc

#This has to happen after the toolchain is done loading.
IF(MSVC)
    #Static build
     #cmake_policy(SET CMP0091 NEW) #This doesn't work in a toolchain, nor in project_after
    #But we still need to set this for the root Cmake which requires cmake 3.15 for the project_include rule...
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
   #This is for cmake_minimum_version less than 3.15 (AKA the Hunter builds)
    set(variables
      CMAKE_C_FLAGS_DEBUG
      CMAKE_C_FLAGS_MINSIZEREL
      CMAKE_C_FLAGS_RELEASE
      CMAKE_C_FLAGS_RELWITHDEBINFO
      CMAKE_CXX_FLAGS_DEBUG
      CMAKE_CXX_FLAGS_MINSIZEREL
      CMAKE_CXX_FLAGS_RELEASE
      CMAKE_CXX_FLAGS_RELWITHDEBINFO
    )
    message(STATUS "MSVC -> forcing use of statically-linked runtime.")
    foreach(variable ${variables})
    if(${variable} MATCHES "/MD")
        string(REGEX REPLACE "/MD" "/MT" ${variable} "${${variable}}")
    endif()
    endforeach()
ENDIF(MSVC)

The toolchain id does indeed reflect this modification, boost believes it is being compiled with a static runtime. I'll let you know in a few hours if it worked once it is done compiling boost. For the 20th time... 😭😭😭😭

thomassuckow commented 3 years ago

Did appear to work, I don't see the runtime dlls in dependency walker anymore. Sent it off to someone without the runtime for testing.

rbsheth commented 3 years ago

@thomassuckow yay hax! lol

Did it work in your testing?

thomassuckow commented 3 years ago

@rbsheth Ya, I did end up having to add set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded") as well to the after project include script because I went ahead and updated the minimum cmake version in our main project and because of that the string replacement doesn't work on our project, just on the HUNTER builds.

I edited the script above to reflect having to do it both ways.

hjmallon commented 3 years ago

To set policies in cmake toolchain you could try e.g. https://cmake.org/cmake/help/latest/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.html?highlight=cmake_policy_default#variable:CMAKE_POLICY_DEFAULT_CMP%3CNNNN%3E

CMAKE_POLICY_DEFAULT_CMP0114=NEW 
NeroBurner commented 2 years ago

I think I found a less hacky way, create a local hunter config file with the following to get a statically linked runtime for boost

hunter_config(
    Boost
    VERSION ${HUNTER_Boost_VERSION}
    CMAKE_ARGS
    BUILD_SHARED_LIBS=OFF
    BOOST_BUILD_DYNAMIC_VSRUNTIME=OFF
    USE_CONFIG_FROM_BOOST=ON
)

When searching for this boost version I use the following, because I like to be able to still build with system-boost, when not using Hunter:

if(HUNTER_ENABLED)
    find_package(Boost 1.64.0 CONFIG REQUIRED system filesystem)
else()
    find_package(Boost 1.64.0 REQUIRED system filesystem)
endif()

I think updating the documentation with the BOOST_BUILD_DYNAMIC_VSRUNTIME variable would be a great idea