Since I have mentioned CMake in a handful of past blog posts, it is time to give a short introduction for those that don’t know it yet.

CMake is one of the most popular build systems for C++ out there. One of the main reasons probably is that it is cross-platform: It does not build the project itself but operates a platform-specific system. That means it can generate Makefiles, ninja-build files, or project files for Visual Studio or Xcode, to name just a few.

This post is the first of a series about CMake:

In this post, I’ll lay out the very first step to approach a CMake-based project. I use MSYS2/MINGW64 on Windows and let CMake generate Makefiles, but the principle is the same for other environments and generators.

Hello CMake!

We’ll start with a very small project: A typical hello world example. It only has a simple main.cpp:

#include <iostream> int main() { std::cout << "Hello CMake!

"; }

Let’s now add an equally simple CMakeLists.txt. That is the file CMake looks for, and it contains the information it needs to know what to build – or, more precisely, what build files to generate. Our CMakeLists.txt, for now, contains only a single line:

add_executable(prog main.cpp)

This line is simply telling CMake that we want to build an executable, named prog , and it consists of a single source file, main.cpp. You can see this minimal state of our project on GitHub.

Run CMake to generate the build files…

CMake generates a bunch of files in the place where we run it, so it’s good practice to have a separate directory for that. Assuming we’re in the directory where the source file and CMakeLists.txt are located, this is how we can prepare to build the project:

> mkdir _build && cd _build > cmake .. -G "Unix Makefiles"

The call to cmake has two parameters: .. is the path to the CMakeLists.txt, and -G "Unix Makefiles" tells it to generate a Makefile (try cmake --help for more generators). The latter will be located in the _build directory where we called cmake , among other things.

The first time we run cmake in this directory it will take a few seconds, detecting the C and C++ compilers to use and some information about them:

-- The C compiler identification is GNU 7.2.0 -- The CXX compiler identification is GNU 7.2.0 -- Check for working C compiler: C:/msys64/mingw64/bin/cc.exe -- Check for working C compiler: C:/msys64/mingw64/bin/cc.exe -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: C:/msys64/mingw64/bin/c++.exe -- Check for working CXX compiler: C:/msys64/mingw64/bin/c++.exe -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done

The information CMake finds about the compiler is stored in CMakeCache.txt, one of the generated files, so it does not have to do the chores again every time we run it. If the compiler CMake finds is not the one we want, we can set the environment variables CC and CXX to point to the correct C and C++ compilers, respectively. Without those variables, it simply looks for a number of known compilers in the PATH .

The last lines of the output are about the project itself and will be repeated every time we call cmake :

-- Configuring done -- Generating done -- Build files have been written to: C:/hello_cmake/_build

… and again to build our project

Now that we have generated a Makefile, the last thing to do ist to actually build our program and run it:

> cmake --build . Scanning dependencies of target prog [ 50%] Building CXX object CMakeFiles/prog.dir/main.cpp.obj [100%] Linking CXX executable prog.exe [100%] Built target prog > ./prog.exe Hello CMake!

This call to cmake directs it to the current directory, and the option --build tells it to use the generated files to do the actual build. In our example, that is the same as simply calling make , but it also works for other generators, e.g. Visual Studio project files.

Note that everything created by the build, including the Makefile, the executable, and other build artifacts, is located in our _build directory. That means we can cleanly separate them from our project sources.

Conclusion

This is only the very first step in getting started with CMake. I will add a few more posts about it in the next weeks. I am still learning CMake myself, so the more advanced stuff will come in later posts as I learn it. Come back to the list at the start of this post for a table of contents. The next post in this series is Another Target and the Project.

Please point out any mistakes you see, ask questions, and share your problems and discoveries you had with CMake. Maybe you’d like to write a guest post about it? Get in touch!