CMake

CMake is a cross-platform build system generator that is widely used in C++ projects to manage the build process. It generates native makefiles or project files for IDEs (like Visual Studio, Xcode, etc.), allowing you to build your project on different platforms in a standardized way.

🔹 1. CMake Basics: What is CMake?

CMake is a tool that helps manage the build process of a project in a platform-independent manner. It doesn’t directly compile the code but generates the necessary build scripts (e.g., Makefile, Visual Studio project files, etc.) based on CMakeLists.txt files, which describe the project structure and build instructions.

🔹 2. Basic Structure of a CMake Project

A simple CMake project typically consists of:

  1. CMakeLists.txt: The main configuration file that specifies the project’s build instructions.
  2. Source files: The actual code files that need to be compiled.
  3. Build directory: Where CMake generates the necessary build files.

Example Directory Structure:

/your_project
├── CMakeLists.txt
├── src/
├── main.cpp
├── my_class.cpp
└── my_class.h

🔹 3. A Simple CMakeLists.txt File

Here’s a basic CMakeLists.txt file for a simple C++ project:

CMakeLists.txt (Simple Project)

# Set the minimum required version of CMake
cmake_minimum_required(VERSION 3.10)

# Define the project name and version
project(MyProject VERSION 1.0)

# Add the executable to be built (specify source files)
add_executable(MyProject src/main.cpp src/my_class.cpp)

# Optionally link libraries (e.g., Boost, pthread, etc.)
# target_link_libraries(MyProject Boost::Boost pthread)

Explanation:

  • cmake_minimum_required(VERSION 3.10): Ensures that CMake version 3.10 or higher is used.
  • project(MyProject VERSION 1.0): Defines the project name and version.
  • add_executable(MyProject src/main.cpp src/my_class.cpp): Specifies the source files for the executable.

🔹 4. Running CMake

Step 1: Create a Build Directory

It’s recommended to create a separate directory to store the build files.

mkdir build
cd build

Step 2: Run CMake

To configure the project and generate the build files:

cmake ..

This command tells CMake to look for the CMakeLists.txt in the parent directory (..) and generate the necessary build system files (e.g., Makefile, Visual Studio project).

Step 3: Build the Project

Once the build system files are generated, you can use make (on Unix-like systems) or other tools (e.g., Visual Studio, Xcode) to build the project:

make

🔹 5. Advanced CMake Features

1. Adding Libraries

You can add libraries (both static and dynamic) using add_library() and link them with your target using target_link_libraries().

Example: Adding Static Library

# Create a static library
add_library(MyLibrary STATIC src/my_class.cpp)

# Link the library to the executable
add_executable(MyProject src/main.cpp)
target_link_libraries(MyProject MyLibrary)

2. Defining Compiler Options

You can specify compiler flags or options to control how your code is compiled:

# Set the C++ standard
set(CMAKE_CXX_STANDARD 17)

# Add compiler flags (e.g., optimization level)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")

3. Find and Link External Libraries

For libraries like Boost, CMake can find and link them automatically using find_package().

find_package(Boost 1.70 REQUIRED)

# Link Boost libraries
target_link_libraries(MyProject Boost::Boost)

4. Conditional Compilation

You can use if() statements to compile parts of the code conditionally based on platform, architecture, or other conditions.

if(WIN32)
# Code for Windows platform
elseif(APPLE)
# Code for macOS platform
else()
# Code for Linux or other platforms
endif()

5. Adding Custom Commands

You can specify custom build commands using add_custom_command().

add_custom_command(TARGET MyProject POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/data/some_file.txt
${CMAKE_BINARY_DIR}/some_file.txt)

🔹 6. CMake for Multiple Directories (Subdirectories)

For larger projects, you may want to organize the project into multiple directories (e.g., separate folders for src, include, etc.). You can use add_subdirectory() to include subdirectories.

Example project structure:

/your_project
├── CMakeLists.txt
├── src/
├── include/
├── lib/

Root CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(MyProject)

# Add subdirectories
add_subdirectory(src)
add_subdirectory(lib)

Subdirectory CMakeLists.txt (src/):

add_executable(MyProject src/main.cpp)

🔹 7. Building and Testing with CMake

Unit Testing with CMake

CMake has built-in support for unit testing using CTest. Here’s how you can add Google Test to your project for testing.

Add Google Test:

git clone https://github.com/google/googletest.git

Modify CMakeLists.txt to include tests:

# Add Google Test
add_subdirectory(googletest)

# Create a test executable
add_executable(MyTests test/main_test.cpp)

# Link Google Test libraries
target_link_libraries(MyTests gtest gtest_main)

# Add CTest for testing
enable_testing()
add_test(NAME MyTests COMMAND MyTests)

Now you can run tests with:

ctest

🔹 8. Common CMake Commands

  • cmake –version: Check the installed CMake version.
  • cmake –build .: Build the project (equivalent to make).
  • cmake –install .: Install the built project.
  • cmake –help: Show CMake help documentation.

🔹 9. Conclusion

CMake is a powerful and flexible build system generator that helps simplify the process of building C++ projects across different platforms. It abstracts away platform-specific details and helps in managing complex projects with dependencies, libraries, and multiple configurations.

Key Points to Remember:

  • Use CMakeLists.txt to define your project.
  • Keep your source files in separate directories for better organization.
  • Use find_package() to link external libraries like Boost or Google Test.
  • For large projects, split them into multiple directories and manage them using add_subdirectory().
  • Use CTest for integrating unit tests in your build system.