Click the blue text to follow us
CMake From Beginner to Expert: A Modern C++ Build System Guide
Hello everyone, I am an old coder! Today we will discuss the complex issue of building C++ projects. Are you still troubled by tedious compilation and linking? Still manually managing dependencies? Come on, let me introduce you to CMake, this powerful build system tool, which will surely make your project builds simple and elegant!
1
What is CMake?
CMake is like the blueprint for building a house. You can’t let the workers build the house without any plan, right? Similarly, we need to tell the compiler how to build our C++ project. CMake generates build files for various platforms (like Visual Studio project files on Windows and Makefiles on Linux) by writing a CMakeLists.txt
file.
2
Your First CMake Project
Let’s start with the simplest example:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(hello_world main.cpp)
// main.cpp
#include <iostream>
int main() {
std::cout << "Hello, CMake!" << std::endl;
return 0;
}
Tip: CMake commands are case insensitive, but I recommend developing the habit of using lowercase, as it looks cleaner.
3
Project Structure Organization
In actual projects, we usually have multiple source files and header files. CMake provides many convenient commands to organize the project structure:
# Add subdirectory
add_subdirectory(src)
# Find source files
file(GLOB SOURCES "src/*.cpp")
# Create library
add_library(mylib STATIC ${SOURCES})
# Set include directories
target_include_directories(mylib PUBLIC include)
Note: While file(GLOB ...)
is convenient, it’s better to explicitly list source files in actual projects to better control the build process.
4
Dependency Management
Modern C++ projects cannot do without third-party libraries, and CMake excels in this area:
# Find package
find_package(Boost REQUIRED COMPONENTS system filesystem)
# Link library
target_link_libraries(myapp PRIVATE mylib Boost::system Boost::filesystem)
Tip: Using PRIVATE
, PUBLIC
, and INTERFACE
keywords can control the transitivity of dependencies, avoiding unnecessary dependency spread.
5
Conditional Compilation and Configuration
CMake can also generate different code based on different platforms and configurations:
if(WIN32) target_compile_definitions(myapp PRIVATE WIN32_LEAN_AND_MEAN)endif()
# Configuration file
configure_file( "${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/config.h")
6
Build and Install
Once the project is written, the final steps are building and installing:
mkdir build && cd build
cmake ..
cmake --build .
# Install rules
install(TARGETS myapp RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
7
Practical Exercise
Try to complete this small task:
- Create a calculator library that includes functions for addition, subtraction, multiplication, and division.
- Create an executable program that uses this library.
- Add unit test support (Tip: you can use GTest).
8
Common Pitfalls Reminder
- Use forward slashes
/
for paths, not backslashes\
. - Remember to set the C++ standard:
set(CMAKE_CXX_STANDARD 17)
. - When using the MSVC compiler on Windows, pay attention to character set settings.
9
Summary
Today we learned:
- The basic concepts and uses of CMake.
- How to create and organize CMake projects.
- Methods of dependency management.
- Conditional compilation and configuration.
- The building and installation of projects.
That’s all from the old coder! Today’s C++ practice ends here. Writing is not easy, so don’t forget to like! Everyone is welcome to share their experiences using CMake in the comments. Wishing all programmer friends thick hair and plenty of job offers! See you next time!
Light up the 【like and watch】, let money and love flow to you.