Setting a default `CMAKE_BUILD_TYPE` per project

Splitting this discussion from this issue comment.

Basically I am considering how to allow a project to set its default custom build type without affecting other project’s build type.

Setup:

  • Project A: fetches Project B
  • Project A: sets default CMAKE_BUILD_TYPE to CustomReleaseA as local variable (maybe with an if-guard before/after project)
  • Project B: sets default CMAKE_BUILD_TYPE to CustomReleaseB as local variable (maybe with and if-guard before/after project)

Case1: user does not set CMAKE_BUILD_TYPE as -D option

  • Expectation: Project A and B are built against a default that they wish to implement
  • Users: Default behavior for (end-)users
  • CustomReleaseA and CustomReleaseB are expected to be used, but probably that would not happen because CMAKE_BUILD_TYPE is set as a local variable by Project A and propagated to Project B. I don’t think there is a clean way to get such an outcome right now.
  • The above behavior could be fixed if within project the cache variable is always set to set(CMAKE_BUILD_TYPE "" CACHE STRING ...) by project(), the local variable is reset to the cache variable, and the projects use:
    project(...)
    if (NOT CMAKE_BUILD_TYPE)
      set(CMAKE_BUILD_TYPE CustomReleaseA)
    endif()
    

Case2: user provides CMAKE_BUILD_TYPE as -D option

  • Expectation: Both project A and B are built against a configuration that they both recognize RelWithDebInfo/Debug
  • Users: Packagers where typically RelWithDebInfo is set, or developers who would require Debug
  • Would always work as intended if the project use an if-guard as above

Why have such a design?

This allows the project to define their own default configuration that builds on top of Release which they would want the typical user to use as a default, e.g. adding native build flags, compiler specific fixes or optimizations, etc. But if the packager like spack always uses Release as their CMAKE_BUILD_TYPE, this will ensure that the packager can overwrite those defaults and use the CMake specific defaults to build on top of.

I think I came up to thinking about this issue when seeing a project (ab)use CMAKE_<LANG>_FLAGS_<CONFIG> and appending flags manually to those. For the most cases that project can change to using target-scoped compile flags, but there could be some merit of putting the project’s default flags into CMAKE_<LANG>_FLAGS_<CustomRelease> so that they can be overwritten individually for each project.