Empty (Qt Creator wrongly refers to this as “Default”)
Debug
Release
RelWithDebInfo – Release with debug information, needed for profiling / post mortem debugging
MinSizeRel – Release optimized for size, and not for speed.
If we have a look at CMake’s Modules/Compiler/GNU.cmake we can see:
The empty build type usually contains the common build flags for all build types. It is generated from
the CMAKE_C_FLAGS_INIT / CMAKE_CXX_FLAGS_INIT variables, and the CFLAGS / CXXFLAGS system environment variables.
But in the case of an IDE like Qt Creator makes no sense to have, you will end up for GCC with a
-O0 (Debug) build. I’ve opened QTCREATORBUG-22013 in this regard.
CMake uses the CMAKE_<LANG>_FLAGS_<CONFIG>_INIT
variables which will be used to populate the CMAKE_CMAKE_<LANG>_FLAGS_<CONFIG> variables.
There are cases when you might want to change the default build types:
Want to have -g1 for RelWithDebInfo, because your binaries are becoming too big
Want to enable all possible warnings from the compiler
Lastly, we want to do all this without putting if clauses in the code, and manually changing the CMAKE_<LANG>_FLAGS variables.
The rule of thumb is: if you have to change compiler flags, you should do it in a toolchain file!
Writing a CMake toolchain file
If we read the CMake documentation about writing a toolchain,
we can see how easy is to write such a toolchain file. You pass the path to the compiler, while CMake will do autodetection for you.
This works fine for GNU GCC / Clang / Visual C++ compilers.
Here is what you have to set for using clang as a cross compiler for Arm platform:
There is nothing about CMAKE_<LANG>_FLAGS_<CONFIG>, because it is assumed we are using the defaults. If one needs to add something
special to CMAKE_<LANG>_FLAGS_<CONFIG> variable, you are supposed to use the CMAKE_<LANG>_FLAGS_<CONFIG>_INIT variables.
Android NDK Toolchain
The Android NDK CMake toolchain wants to have for Release build type debugging information enabled, and the -O2 compilation flag,
while the default CMake Release build type is using -O3. Basically having the default CMake RelWithDebInfo build type.
Which is then followed by (edited a bit for brevity):
The comment in the above code shows some problems one might have while editing CMAKE_<LANG>_FLAGS_<CONFIG> variables.
Static linking to CRT with Visual C++
On Windows CMake has selected dynamic linking to the CRT for its build types, namely the /MD compiler flag.
But what if we want to link statically to the CRT with the /MT compiler flag, thus avoiding the need of
deploying the CRT runtime on older Windows versions?
Here is what Google Test is doing in its googletest/cmake/internal_utils.cmake:
This means that you need to call this macro in your CMake code, and that it will affect
the compilation of all subsequent targets.
We can avoid this by having a toolchain file:
This unfortunately only works starting with CMake version 3.11, released in March 2018!
CMake 3.11 has gathered the generation of all config variable generation in one function.
This is an internal function, and it’s functionality has not been documented in the 3.11 release notes.
We have the variable CMAKE_NOT_USING_CONFIG_FLAGS
documented, variable which is used in the cmake_initialize_per_config_variable function.
cmake_initialize_per_config_variable will be called at the point of generating the CMAKE_<LANG>_FLAGS_<CONFIG>, which is done after the toolchain code has been
processed.
CMake versions lower than 3.11
The CMAKE_<LANG>_FLAGS_<CONFIG>_INIT variables are defined in different places, for Clang / GCC you have them in Modules/Compiler/GNU.cxx, for Visual C++ they
are in Modules/Platform/Windows-MSVC.cmake. They are also defined with string(APPEND, which means that they will overpower your toolchain versions.
I am mentioning this because you might get something like this working for GNU like compilers for CMake versions lower than 3.11:
But this will partially work for Visual C++. Compiler feature detection won’t be working, etc.
With cmake_initialize_per_config_variable you can replace / modify the CMAKE_<LANG>_FLAGS_<CONFIG>_INIT values at will.
Android NDK toolchain patch
Armed with this information, I decided to hack the Android NDK toolchain. Below you have the patch:
The new code involves a bit more time to figure out what it does, but you have the benefit of having
in the CMakeCache.txt the CMAKE_<LANG>_FLAGS_<CONFIG> values, as opposed to having empty values as
you get with the default toolchain.
Roundup
As a conclusion to this article is that you should never touch CMAKE_<LANG>_FLAGS_<CONFIG> variables directly.
All the compiler build flags should be set in a toolchain, even if you don’t do cross compiling.
This way you can have a consistent build, with the same compiler flags used for all targets / subprojects!