cmake build system.
A very small introduction to cmake and its application to configure, compile and execute a cpp program which requires linking with another library (openMP) in this case for parallel programming.
Typical hello world c++ program file (say main.cpp) using openMP for parallel execution.
#include <iostream>
#include <omp.h>
int main() {
#pragma omp parallel
{
std::cout << "Hello from thread " << omp_get_thread_num() << ", of nthreads " << omp_get_num_threads() << std::endl;
}
return 0;
}The program above can be compiled on the command line using the following command
g++ -fopenmp -o hello_omp main.cpp
So, why not just use g++?
When we ran g++ -fopenmp -o hello_omp main.cpp, we were directly telling the compiler (g++) three things:
- Use the
OpenMPflag (-fopenmp). - The output file should be named
hello_omp. - The input source file is
main.cpp.
This is fine for one file. But imagine a real project with:
- Dozens or hundreds of source files.
- Complex directory structures (
src/,include/,lib/). - Dependencies on multiple libraries (like
OpenMP,Boost, networking libraries, etc.). - The need to compile on different operating systems (Linux, Windows, macOS), which use different compilers and have libraries in different places.
Writing and maintaining the g++ command for a complicated project would become a nightmare.
The Solution: CMake, the Build System Generator.
CMake is not a compiler. It doesn’t build your code directly. Instead, CMake is a build system generator. You give it a simple text file with high-level instructions, and it generates the complex, platform-specific build files for you (like Makefiles on Linux, or Visual Studio .sln files on Windows).
Think of it like this:
- You: Write a simple recipe (
CMakeLists.txt). CMake: Reads your recipe and writes a very detailed, professional cookbook (Makefile) specifically for your kitchen (Linux).make(the build tool): Follows the detailed cookbook to actually cook the meal (compile your code).
The Core Components
Your project needs two key things for CMake to work:
main.cpp(Your Source Code): Thec++code you want to build.CMakeLists.txt(Your “Recipe”): A plain text file that tellsCMakeabout your project.
Let’s look at our CMakeLists.txt line by line:
1 # 1. Set the minimum required version of CMake.
2 cmake_minimum_required(VERSION 3.10)
3
4 # 2. Declare the project name. This is important for organization.
5 project(HelloWorld)
6
7 # 3. Find a required dependency. This is a key feature!
8 # CMake searches the system for the OpenMP library. If it can't be
9 # found, it will stop with an error because we said it's REQUIRED.
10 find_package(OpenMP REQUIRED)
11
12 # 4. Define an executable target.
13 # This says "create an executable program named 'HelloWorld'
14 # from the source file 'main.cpp'".
15 add_executable(HelloWorld main.cpp)
16
17 # 5. Link the executable to its dependencies.
18 # This says "the 'HelloWorld' target needs to be linked with the
19 # OpenMP C++ library that we found with find_package".
20 target_link_libraries(HelloWorld PUBLIC OpenMP::OpenMP_CXX)
The Two-Step CMake Workflow
This is the standard, cross-platform way to build any CMake project.
Step 1: Configuration and Generation
Command: cmake -S . -B build
- This is the “generate the cookbook” step.
cmakereads yourCMakeLists.txt.-S .tells CMake that your Source code directory (whereCMakeLists.txtis) is the current directory (.).-Bbuild tellsCMaketo put all the generated files and compiled output into a new build directory namedbuild(which means that abuilddirectory needs to be created within the source directory first).
Why the build directory? This is called an “out-of-source” build. It’s a best practice that keeps your clean source code separate from the messy temporary files and executables that the compiler generates. To clean up, you just delete the build folder.
After this step, the build directory contains Makefiles and other configuration files.
Step 2: Building the Code
Command: cmake --build build
- This is the “follow the cookbook” step.
--build buildtellsCMaketo run the actual build tool (in our case,make) inside the build directory.- This command reads the
Makefilesgenerated in Step 1 and runs the compiler to create your finalHelloWorldexecutable inside the build directory.
The beauty of this command is that it’s generic. On Windows, it would automatically call the Microsoft compiler instead of make, but the command you type is exactly the same.
Summary
| Phase | Your Action | What Happens |
|---|---|---|
| Setup | Write main.cpp and CMakeLists.txt |
You describe your project and its dependencies at a high level. |
| Configure | cmake -S . -B build |
CMake generates low-level, platform-specific Makefiles. |
| Build | cmake --build build |
make (or another tool) is called to compile the code into an executable. |
| Run | ./build/HelloWorld |
You run the final program. |