22

I've got a CMakeLists where I want to build some targets using the dynamic version of the C runtime, and some other targets using the static version.

Because this needs to be set per target, the default method of setting CMAKE_CXX_FLAGS_<Config> does not work; this overrides for all targets.

To that end, I tried something like the following:

# @fn       set_target_dynamic_crt
# @brief    Sets the given target to use the dynamic version of the CRT (/MD or
#           /MDd)
# @param    ...  A list of targets to which this setting should be applied.
function( set_target_dynamic_crt )
    if ( MSVC )
        message (WARNING ${CMAKE_BUILD_TYPE})
        if (CMAKE_BUILD_TYPE STREQUAL "Debug")
            set_target_properties ( ${ARGN} PROPERTIES COMPILE_FLAGS "/MDd" )
        else()
            set_target_properties ( ${ARGN} PROPERTIES COMPILE_FLAGS "/MD" )
        endif()
    endif()
endfunction()

However, this always chooses the release version (/MD) and when I query for the build type (the message call above) I get the empty string. (I suspect this is because I'm using the Visual Studio generator; I've seen more than one reference that says CMAKE_BUILD_TYPE is for makefiles only...)

How can I set compile options like this per target?

TheBat
  • 1,006
  • 7
  • 25
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • There is now a better solution, than what's shown below, to fix this problem. I posted about it on so as well since I ran in the same problem and did not find your question first, see here: http://stackoverflow.com/questions/18065299/is-it-possible-in-the-same-cmakelists-txt-to-setup-projects-with-mt-and-other/18068420#18068420 – Alexis Wilke Aug 05 '13 at 21:53

4 Answers4

41

In CMake 2.8.12 I added a target_compile_options command to address this need:

http://public.kitware.com/Bug/view.php?id=6493

http://www.cmake.org/cmake/help/git-master/manual/cmake-generator-expressions.7.html

target_compile_options(tgt PRIVATE "/MD$<$<CONFIG:Debug>:d>")

See

http://www.cmake.org/cmake/help/git-next/manual/cmake-buildsystem.7.html#build-specification-with-generator-expressions

for more relating to CMAKE_BUILD_TYPE and several reasons why the generator expression is better (eg IMPORTED target config mapping).

steveire
  • 10,694
  • 1
  • 37
  • 48
  • The fact it took until 2.8.12 to implement this feature is one of the reasons I still don't use CMake to this day. To add to that, it wasn't until version _3.13_ that target specific _linker_ options were introduced! Before that, you had to hack-ily add options using `target_link_libraries`, which was never intended. – Benjamin Crawford Ctrl-Alt-Tut Jul 23 '20 at 17:24
2

The only option I know of for this scenario is to split your project into subdirectories on a per-target basis and use add_subdirectory.

Depending on how your project is currently set up, this could be a painful process I guess.

The result would be a top-level CMakeLists.txt that looked like e.g.

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
add_subdirectory(libB)
add_subdirectory(libA)
add_executable(main_exe "main.cpp")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
target_link_libraries(main_exe lib_a lib_b)

then libA/CMakeLists.txt could specify MD and MDd flags:

project(LibA)
add_library(lib_a a.cpp a.hpp)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")

and libB/CMakeLists.txt for MT and MTd flags:

project(LibB)
add_library(lib_b b.cpp b.hpp)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")

You can of course add all targets needing linked to the static CRT in the one subdirectory and CMakeLists.txt and all the dynamic CRT ones in the other if you have a lot of targets.

Fraser
  • 74,704
  • 20
  • 238
  • 215
  • Note that there is now a better solution with the target_compile_options() cmake function. It's brand new (June 2013) and only available in the daily compiles, but that's neat! See here: http://stackoverflow.com/questions/18065299/is-it-possible-in-the-same-cmakelists-txt-to-setup-projects-with-mt-and-other/18068420#18068420 – Alexis Wilke Aug 05 '13 at 21:56
0

CMAKE_BUILD_TYPE is only valid for single-configuration generators. The multi-configuration generators (MSVC and Xcode) can build for multiple configurations in one build-directory and as such the CMAKE_BUILD_TYPE flag wouldn't have a meaning.

The COMPILE_FLAGS target property does not distinguish different configurations (See kitware bugtracker for more information).

A workaround would be to have two build-directories, similar to how people use the Makefile generators, and define an additional flag when building binaries for distribution. (ie, the Release configuration)

phb
  • 691
  • 4
  • 7
  • The workaround doesn't work though -- you end up having to set that in a zillion different places. (Specifically, to change configurations, you have to go through all hundred or so projects and change them over, and then change it in the VS IDE when building, etc.) – Billy ONeal Apr 17 '12 at 22:23
  • No, I mean that you should use the exact code you posted in the question, but instead of using CMAKE_BUILD_TYPE, use MY_RELEASEBUILD, and only define that when you are about to create a build for distribution. (Assuming it's OK to use /MDd when you are running locally) – phb Apr 17 '12 at 22:36
  • but then you have to select the right thing inside VS to match, and it can't be set for each target. The whole point of doing this was to be able to use CMAke's build configuration support. – Billy ONeal Apr 17 '12 at 22:54
  • It's not possible. I don't think I'm understanding you correctly though. I'm proposing something like mkdir build; cd build; cmake ../ ; cd .. ; mkdir build-release; cd build-release; cmake -DRELEASE_BUILD=1. Yes, it would suck, but at least it would allow you to test the flags locally (and it would work for your buildservers etc as well) – phb Apr 17 '12 at 22:55
  • It results in something that is more difficult to maintain than maintaining separate platform specific make files. Yes, it "works" in a perverse sense of "working" -- but not in a manner that justifies the cost. – Billy ONeal Apr 17 '12 at 23:57
0

Assume that I want to add -On options to vmovq_n_u8.c and generate vmovq_O3.out and vmovq_O0.out. I had it done with target_compile_options by following:

add_executable(vmovq_O3.out vmovq_n_u8.c)
add_executable(vmovq_O0.out vmovq_n_u8.c)

target_compile_options(vmovq_O3.out PRIVATE -O3)
target_compile_options(vmovq_O0.out PRIVATE -O0)

kucer
  • 86
  • 1
  • 4