Common Problems and Solutions
Overview
Teaching: 5 min
Exercises: 0 minQuestions
What could go possibly wrong?
Objectives
Identify some common mistakes
Avoid making common mistakes
Now let’s take a look at some common problems with CMake code and with builds.
1: Low minimum CMake version
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
Okay, I had to put this one in. But in some cases, just increasing this number fixes problems. 3.0 or less, for example, has a tendency to do the wrong thing when linking on macOS.
Solution: Either set a high minimum version or use the version range feature and CMake 3.12 or better. The lowest version you should ever choose is 3.4 even for an ultra-conservative project; several common issues were fixed by that version.
2: Building inplace
CMake should never be used to build in-place; but it’s easy to accidentally do so. And once it
happens, you have to manually clean the directory before you can do an out-of-source build again.
Because of this, while you can run cmake .
from the build directory after the initial run, it’s
best to avoid this form just in case you forget and run it from the source directory. Also, you can
add the following check to your CMakeLists.txt
:
### Require out-of-source builds
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH)
if(EXISTS "${LOC_PATH}")
message(FATAL_ERROR "You cannot build in a source directory (or any directory with "
"CMakeLists.txt file). Please make a build subdirectory. Feel free to "
"remove CMakeCache.txt and CMakeFiles.")
endif()
One or two generated files cannot be avoided, but if you put this near the top, you can avoid most of the generated files as well as immediately notifying the user (possibly you) that you’ve made a mistake.
3: Picking a compiler
CMake may pick the wrong compiler on systems with multiple compilers. You can use the environment
variables CC
and CXX
when you first configure, or CMake variables
CMAKE_CXX_COMPILER
, etc. - but you need to pick the compiler on the first run; you can’t
just reconfigure to get a new compiler.
4: Spaces in paths
CMake’s list and argument system is very crude (it is a macro language); you can use it to your
advantage, but it can cause issues. (This is also why there is no “splat” operator in CMake, like
f(*args)
in Python.) If you have multiple items, that’s a list (distinct arguments):
set(VAR a b v)
The value of VAR
is a list with three elements, or the string "a;b;c"
(the two things are exactly
the same). So, if you do:
set(MY_DIR "/path/with spaces/")
target_include_directories(target PRIVATE ${MY_DIR})
that is identical to:
target_include_directories(target PRIVATE /path/with spaces/)
which is two separate arguments, which is not at all what you wanted. The solution is to surround the original call with quotes:
set(MY_DIR "/path/with spaces/")
target_include_directories(target PRIVATE "${MY_DIR}")
Now you will correctly set a single include directory with spaces in it.
Key Points
Setting a CMake version too low.
Avoid building inplace.
How to select a compiler.
How to work with spaces in paths.