# Specifying allowed configuration types

**URL:** https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677
**Category:** Development
**Created:** [October 3, 2024, 8:49pm UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677 "2024-10-03T20:49:47Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![purpleKarrot](https://discourse.cmake.org/user_avatar/discourse.cmake.org/purplekarrot/32/4821_2.png) [@purpleKarrot](https://discourse.cmake.org/u/purpleKarrot)
#### Post date: [October 3, 2024, 8:49pm UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/1 "2024-10-03T20:49:47Z")

</div>

Specifying the allowed configuration types is tricky. People are confused by the variables `CMAKE_CONFIGURATION_TYPES` and `CMAKE_BUILD_TYPE`. Many don’t know about the usefulness of the `STRINGS` cache property.

One approach for reusable code is presented at [https://www.kitware.com/cmake-and-the-default-build-type/](https://www.kitware.com/cmake-and-the-default-build-type/)

Another approach is the function I wrote:

```cmake
function(allow_configurations)
  set(configs ${ARGN})
  
  if(DEFINED ENV{CMAKE_CONFIGURATION_TYPES})
    set(configs $ENV{CMAKE_CONFIGURATION_TYPES})
  endif()

  if(NOT configs)
    message(FATAL_ERROR "No configuratons given.")
  endif()

  get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
  if(is_multi_config)
    set(CMAKE_CONFIGURATION_TYPES ${configs})
    return()
  endif()

  set(default "") # list(GET configs 0 default) ?
  list(JOIN configs ", " help)

  if(DEFINED ENV{CMAKE_BUILD_TYPE})
    set(default $ENV{CMAKE_BUILD_TYPE})
  endif()

  set(CMAKE_BUILD_TYPE "${default}" CACHE STRING "Choose the type of build (${help}).")
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${configs}")

  if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE IN_LIST configs)
    message(FATAL_ERROR "CMAKE_BUILD_TYPE must be one of ${help}")
  endif()
endfunction()

```

I think it would be desirable that CMake provides a way to set the allowed configuration types.  
Since both `CMAKE_CONFIGURATION_TYPES` and `CMAKE_BUILD_TYPE` are initialized in the `project()` command, why not integrate this logic there?

This would allow project authors to write:

```cmake
project(MyProject
  CONFIGURATIONS Debug Release
  LANGUAGES CXX Swift
  VERSION 1.0
  )

```

And integrators would still be able to override the configurations with the `CMAKE_CONFIGURATION_TYPES` environment variable.

Thoughts?

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [October 3, 2024, 9:36pm UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/2 "2024-10-03T21:36:14Z")

</div>

I used to show how to restrict the configuration types in my Professional CMake book, but I now consider that to be an anti-pattern. Users should have the freedom to define and use whatever configurations they want. There are use cases where a user might want to create their own custom configuration, and if a project tries to restrict them to only a predefined set of configurations, it can be an annoying and unnecessary thing to work around.

It _might_ make sense to _initialize_ a pre-defined set of configurations for a multi-config generator if `CMAKE_CONFIGURATION_TYPES` isn’t set yet. This could be useful in company settings, for example. The case for single-config generators is much weaker, since you have to select a configuration by the time you hit the first `project()` call on the first run. There’s little point offering initialization of initial configurations for this because the user will always have to have made a choice before the first run. With multi-config generators, they don’t make that choice until build time, so that use case still makes sense.

The `STRINGS` cache variable property initially looks interesting, but in practice, I’m finding it increasingly less useful. If a project wants to make it easy for users to switch the configuration used, then they’re better off supporting multi-config generators. That’s a much better end user experience. It avoids having to re-run CMake each time you want to switch, you keep built artefacts for each config, so switching configs doesn’t rebuild the world, etc. Getting a bit off in the weeds, but I’m trying to highlight that we’re better off spending effort moving people to multi-config generators than on adding support for config selection logic for single-config generators.

---

<div class="post-metadata">

### Author: ![benthevining](https://discourse.cmake.org/user_avatar/discourse.cmake.org/benthevining/32/1924_2.png) [@benthevining](https://discourse.cmake.org/u/benthevining)
#### Post date: [October 4, 2024, 12:26am UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/3 "2024-10-04T00:26:48Z")

</div>

Just to nitpick: in your function you’re using regular `set()`, which will just set that variable in the scope of the function. You probably want to use `set(CACHE)` and/or `PARENT_SCOPE`.

---

<div class="post-metadata">

### Author: ![neundorf](https://discourse.cmake.org/user_avatar/discourse.cmake.org/neundorf/32/2075_2.png) [@neundorf](https://discourse.cmake.org/u/neundorf)
#### Post date: [October 6, 2024, 8:56pm UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/4 "2024-10-06T20:56:25Z")

</div>

> [@craig.scott](#):
>
> Users should have the freedom to define and use whatever configurations they want.

Can you please elaborate ?  
The buildsystem may be tweaked to work for a known set of buildtypes, e.g. by setting compile flags or definitions for them, so with other buildtypes it may not work correctly.

How should “users” use whatever configuration they want ?

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [October 6, 2024, 9:07pm UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/5 "2024-10-06T21:07:54Z")

</div>

> [@neundorf](#):
>
> The buildsystem may be tweaked to work for a known set of buildtypes, e.g. by setting compile flags or definitions for them, so with other buildtypes it may not work correctly.

In such cases, it would then be up to the user to sort out any issues with their own custom build type. They might want a special type of debug build, for example, or maybe they want to use a particular sort of profiling method. Maybe they want to build with a very specific set of warning and optimisation flags. All of this could be done in a variety of ways, not just with a custom configuration, but an advantage of a custom configuration is that with a multi-config generator, they can easily switch between different configurations when they need to do different things with the same project. It makes doing comparisons between option sets easier.

---

<div class="post-metadata">

### Author: ![hsattler](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/h/59ef9b/32.png) [@hsattler](https://discourse.cmake.org/u/hsattler)
#### Post date: [October 7, 2024, 7:56am UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/6 "2024-10-07T07:56:10Z")

</div>

If they extend the build system in such a way, it should be no problem for them to update the list of selectable configuration types.

Currently, the predefined list is questionable anyway:

- getting debug symbols for a release build is more like an option, not a build type. Yes, they also use different optimization levels but that’s also a bit weird.
- does anyone actually use the minsizerel build type?

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [October 7, 2024, 12:10pm UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/7 "2024-10-07T12:10:54Z")

</div>

> [@hsattler](#):
>
> If they extend the build system in such a way, it should be no problem for them to update the list of selectable configuration types.

Not always. They might be pulling in third party dependencies and want to use their custom configuration with those too. Trying to modify third party code just to use a custom configuration would be much less straightforward and would frequently be enough to make developers give up.

> [@hsattler](#):
>
> does anyone actually use the minsizerel build type?

It’s definitely used by embedded folks (I have at least one consulting client where this is the case). The binary size requirements can be quite stringent, and MinSizeRel is squarely aimed at that scenario. That’s not to say that it couldn’t be handled by a different abstraction, but you could argue that for pretty much everything that would be different between different configuration types.

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [March 18, 2026, 11:15am UTC](https://discourse.cmake.org/t/specifying-allowed-configuration-types/12677/8 "2026-03-18T11:15:25Z")

</div>

So would this recommended or not:

```bash
cmake_minimum_required(VERSION 3.30...4.4)

if(NOT ENV{CMAKE_CONFIGURATION_TYPES})
    set(ENV{CMAKE_CONFIGURATION_TYPES} "Debug;Release")
endif()

project(dep LANGUAGES CXX)

# FIXME: seems to late! list(REMOVE_ITEM CMAKE_CONFIGURATIONS RelWithDebInfo)

set(CMAKE_DEBUG_POSTFIX d)

add_library(a STATIC)
target_sources(a PUBLIC FILE_SET CXX_MODULES FILES a.cpp)
target_compile_features(a PUBLIC cxx_std_20)

add_library(b STATIC)
target_sources(b PUBLIC FILE_SET CXX_MODULES FILES b.cpp)
target_link_libraries(b PUBLIC a)

set(_config_install_dir lib/cmake/dep)
install(
    TARGETS a b
    EXPORT dep
    FILE_SET CXX_MODULES DESTINATION ${_config_install_dir}/cxx-modules
    CXX_MODULES_BMI
        DESTINATION
            ${_config_install_dir}/bmi-${CMAKE_CXX_COMPILER_ID}_$<CONFIG>
)
install(
    EXPORT dep
    NAMESPACE dep::
    DESTINATION ${_config_install_dir}
    FILE dep-targets.cmake
    CXX_MODULES_DIRECTORY
    cxx-modules
)
install(FILES dep-config.cmake DESTINATION ${_config_install_dir})

```
