CMake and the Default Build Type
One thing that can be a little confusing when you first start using CMake to build your project is the default build type – specified in the CMAKE_BUILD_TYPE variable. CMake has several default build types, but if nothing is specified when configuring your project it defaults to an empty string and no optimization flags are used. A few years ago I wrote some CMake code to set a default if one was not specified, and also populate a list of available options so that it would show up in cmake-gui as a drop down list.
# Set a default build type if none was specified set(default_build_type "Release") if(EXISTS "${CMAKE_SOURCE_DIR}/.git") set(default_build_type "Debug") endif() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${default_build_type}' as none was specified.") set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif()
The code snippet above shows a slightly modified version, that I put in a file called BuildType.cmake, and use it to ensure the build type defaults to something reasonable for generators that use it. If you add the directory containing this file to the CMAKE_MODULE_PATH in your project you can then include it somewhere near the top of your CMakeLists.txt. It will now default to using a debug build if the source directory is a git clone, or a release build if not. It is also quite easy to customize its behavior according to the preferences of your project.
If a build type is supplied on the command line that will be respected, and for multi configuration generators (such as Visual Studio) this doesn’t apply (indicated by the presence of the CMAKE_CONFIGURATION_TYPES variable). I have found it useful to develop a few files like this that can easily be dropped into a CMake-based project to provide default settings.
Great idea. Thanks for sharing these lines of code. I think other projects (such as Slicer) have a similar approach. Maybe it would make sense to consolidate everything into one file (directly included in CMake?)
Yeah, there is similar stuff in several projects. I wanted something easy to add across several distinct projects, and thought this would be easy to drop in independently of anything else. What else would you want to do for setting the default build type, I thought this was about as fancy as it needed to get 🙂
My idea was not on improving the code you wrote but where it could be shared and if it should directly be included in CMake since many projects such as Slicer (https://github.com/Slicer/Slicer/blob/master/CMakeLists.txt#L114-L127) use it or something similar.
Good point, I am not sure how they would feel about it. On the one hand it is a simple snippet, and I would never mark that variable as advanced, and some people want to change the default for source check outs whereas others would not.
Happy to see it adopted, I said to a colleague that I would try and write some posts documenting some of what I did as best practice in CMake projects at a recent meeting. This was hopefully my first in a series as I find time – if there is interest in integrating any code snippets that would be great.
Well done.
The version found in Slicer was copied from you did few year ago 🙂 And yes, it would be great to add it as a CMake module.
(and I am not particularly attached to advanced vs non-advanced variable.)
Why the FORCE is needed?
In case the cache variable already exists, but is set to empty, the use of FORCE ensures the new setting will show up in ccmake/cmake-gui. Otherwise it could confuse, it is possible it is not strictly necessary but if we are setting the build type I wanted to ensure we did it in a way that was visible in the GUIs.
Shouldn’t you use CMAKE_BUILD_TYPE_INIT before project instead of overriding CMAKE_BUILD_TYPE
CMAKE_BUILD_TYPE_INIT is internal only.
see https://gitlab.kitware.com/cmake/cmake/issues/17944
Good to know, I thought it was fair game to use that variable too. Thanks for pointing this out!
The default CMake build type is the “empty” build type, which is used in combination with the environment variables CFLAGS and CXXFLAGS.
This build type is targeted at Linux distributions which want to use the same compiler flags for multiple packages.
I think one needs to check if $ENV{CFLAGS} and $ENV{CXXFLAGS} are defined, before changing the empty build type.
Is it reasonable to use set_property() to avoid updating the docstring for CMAKE_BUILD_TYPE?
Something like:
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE “${default_build_type}”)
I would say so, I reached the same conclusion independently 😀
Can you clarify what exactly you’re suggesting? That is, should the line you wrote down be inserted somewhere? Should it replace the existing
set()
command?Is it not the CMAKE_CONFIGURATION_TYPES that you need to set for cmake-gui? That is the information in I got on IRC at least.