6

The Cmake FAQ and other places recommend to check CMAKE_CONFIGURATION_TYPES to recognize a multi-configuration generator. I have found several questions where this did not work (for example this one). The issue seems to be that the variable is not set the first time cmake is called.

I tested with the following file

cmake_minimum_required(VERSION 2.6)

if(CMAKE_CONFIGURATION_TYPES)
    message("Multi-configuration generator")
else()
    message("Single-configuration generator")
endif()

project(foo)

and called it like this

mkdir build
cd build
cmake -G "Visual Studio 12 2013" ..

and got Single-configuration generator.

How should I distinguish whether the current generator supports multiple configurations?

starball
  • 20,030
  • 7
  • 43
  • 238
Flogo
  • 1,673
  • 4
  • 20
  • 33
  • 1
    Any reason why you check `CMAKE_CONFIGURATION_TYPES` before the `project()` command? Because most variables are set with the `project()` call (see [here](http://stackoverflow.com/questions/30503631/cmake-in-which-order-are-files-parsed-cache-toolchain)). Please add a `message("CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}")` before and after `project()` to see the difference. – Florian Jul 27 '15 at 19:27

2 Answers2

6

EDITED: Added information on checking and changing CMAKE_CONFIGURATION_TYPES

Check and Changing CMAKE_CONFIGURATION_TYPES

Taking the suggestions from this question you could check and change CMAKE_CONFIGURATION_TYPES, but be aware that there was a bug 0015577: The 'project' command overwrites CMAKE_CONFIGURATION_TYPES in CMake 3.2.2 that did break this behaviour for the initial VS solution generation (fixed with CMake 3.3.0):

cmake_minimum_required(VERSION 3.3)

project(foo NONE)

if(CMAKE_CONFIGURATION_TYPES)
    message("Multi-configuration generator")
    set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "My multi config types" FORCE)
else()
    message("Single-configuration generator")
endif()

enable_language(C CXX)

Preset CMAKE_CONFIGURATION_TYPES

If you just need a certain set of configurations for multi-configuration environments you can do (thanks to @Tsyvarev for the suggestion):

cmake_minimum_required(VERSION 2.8)

# NOTE: Only used in multi-configuration environments
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "My multi config types" FORCE)

project(foo)

None multi-configuration environments will just ignore it. But be aware that other CMake modules like findBoost.cmake, findCUDA.cmake may rely on CMAKE_CONFIGURATION_TYPES being empty for single-configuration environments (thanks again @Tsyvarev for the hint).

So a better solution would be adding toolchain files for all your supported generators. They are generally useful, because there you can handle all the toolchain/generator specific parts.

Here is an extract of my VSToolchain.txt:

# Reduce the config types to only Debug and Release
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)

# Standard is a console app. If you need a windows app, use WIN32 define in add_executable
set(CMAKE_WIN32_EXECUTABLE 0 CACHE INTERNAL "")

CMAKE_WIN32_EXECUTABLE is just there to show what kind of settings I have put in my Visual Studio toolchain file.

Another CMake command line solution is suggested here: How to create cmake build configuration without debug symbols and without optimizations?

Only Checking CMAKE_CONFIGURATION_TYPES

If you only want do check what CMake does set in CMAKE_CONFIGURATION_TYPES:

I just tested your above code with Visual Studio 2013 and MinGW/GCC (both with empty build directories). You just need one small change and move the check after the project() command:

project(foo)

message("CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}")

if(CMAKE_CONFIGURATION_TYPES)
    message("Multi-configuration generator")
else()
    message("Single-configuration generator")
endif()

And I get for VS2013:

CMAKE_CONFIGURATION_TYPES Debug;Release;MinSizeRel;RelWithDebInfo
Multi-configuration generator

And for GCC:

CMAKE_CONFIGURATION_TYPES
Single-configuration generator

For more details about what CMake does see:

Community
  • 1
  • 1
Florian
  • 39,996
  • 9
  • 133
  • 149
  • The reason why I had the test before `project()` was that setting the variable after the project meant that the change did not propagate to the VS project file in the first cmake run. I can't test this right now (only Windows PC is in the office) but the question I linked (stackoverflow.com/questions/20638963) mentions the same problem and the answer was to set CMAKE_CONFIGURATION_TYPES before `ENABLE_LANGUAGE()`. – Flogo Jul 27 '15 at 20:57
  • @Flogo: Answer you refers states, that you can setup `CMAKE_CONFIGURATION_TYPES` before choosing language. Just set it unconditionally as cache value. BTW, the best place for config specific flags(`CMAKE__FLAGS_`) is also before language setup. – Tsyvarev Jul 27 '15 at 22:50
  • @Tsyvarev: I don't get it. Doesn't unconditionally setting this as a cache value circumvent the whole if statement? That is, if I set the value in the cache, will the language setup of a single config generator delete it again? Do I then even need the if statement after language setup, or can I just set up the types I want to have unconditionally before language setup. If so, why do all the examples use the if statement? In particular the example from the FAQ seems somewhat incomplete. – Flogo Jul 28 '15 at 08:03
  • @Flogo: You are right. If you only want to change the configuration types for your environment you can set them generally as cached values. If tested it and `CMAKE_CONFIGURATION_TYPES` is ignored in single configuration environments. Taking @Tsyvarev suggestion I updated my answer accordingly. – Florian Jul 28 '15 at 09:13
  • 1
    @Florian, thanks for testing. Actually, problem with unconditionally setting `CMAKE_CONFIGURATION_TYPES` is that some modules (e.g. `findBoost.cmake`, `findCUDA.cmake`) use it for recognize a multi-configuration generator. I am not sure, whether it is critical for them to found non-empty variable in case of single config. – Tsyvarev Jul 28 '15 at 10:04
  • Also, some CMake-peoples (e.g. http://www.cmake.org/pipermail/cmake/2012-January/048599.html) advice to check and set `CMAKE_CONFIGURATION_TYPES` variable *after* `project()` **without language** but before enabling language. @Florian, can you check this approach for the sake of completeness? None-languages project command is `project(foo NONE)`. – Tsyvarev Jul 28 '15 at 10:13
  • 1
    @Tsyvarev I tested this by adding `variable_watch(CMAKE_CONFIGURATION_TYPES)` and I didn't find any combination with `project(foo NONE)`/`enable_language()` that did work. What's weird here: for VS both commands do call `cmGlobalVisualStudio7Generator::EnableLanguage()` and do overwrite `CMAKE_CONFIGURATION_TYPES` again (which it shouldn't because the code checks if the variable is already set). And the behavior was changed several times between CMake 2.8.12 and 3.3 (see e.g. [here](https://github.com/Kitware/CMake/commit/42bb42d19723323e6e48346b1437e04a251addfa). I check again with 3.3 again. – Florian Jul 28 '15 at 11:33
  • I have seen that `EnableLanguage` implementation, and was just curious about how non-language-project approach works. So, it doesn't work at all. Thanks again for testing. As result, `CMAKE_CONFIGURATION_TYPES` can be either unconditionally writting before project() or checked-only after it. Conditional writting is possible only when two-pass configuration is acceptable. – Tsyvarev Jul 28 '15 at 11:55
  • @Tsyvarev With CMake 3.3 it does work. I checked BugTracker and found that [0015577: The 'project' command overwrites CMAKE_CONFIGURATION_TYPES](http://www.cmake.org/Bug/view.php?id=15577) did break the behavior and was fixed with CMake 3.3. So I updated the answer again. Thanks for your help with this. – Florian Jul 28 '15 at 12:03
1

I see you are on CMake v2.6, but for anyone who is on v3.9+, v3.9 introduced the global property called GENERATOR_IS_MULTI_CONFIG:

Read-only property that is true on multi-configuration generators.

You can load the value into a CMake variable like so:

get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)

This very approach is recommended in "Professional CMake" by Craig Scott, along with explanations of the shortcomings of other approaches- especially those involving CMAKE_CONFIGURATION_TYPES. The book is $30 but the section I'm referring to is in the sample chapters.

starball
  • 20,030
  • 7
  • 43
  • 238