CMake là một hệ thống xây dựng mã nguồn mở, đa nền tảng, cho phép mô tả quy trình biên dịch, kiểm thử và đóng gói phần mềm bằng ngôn ngữ đơn giản. Từ đó, CMake tạo ra các tập tin Makefile hoặc project file phù hợp với hệ điều hành và trình biên dịch mục tiêu.
Các khái niệm cốt lõi
Trình biên dịch (gcc): Chuyển đổi mã nguồn thành tệp thực thi hoặc thư viện.
Make: Quản lý quá trình xây dựng (build) nhiều tệp nguồn, dựa trên định nghĩa trong Makefile.
CMake: Tự động sinh Makefile từ tập tin cấu hình CMakeLists.txt, giúp đơn giản hóa việc viết Makefile thủ công cho dự án lớn.
Quy trình sử dụng CMake cơ bản
- Tạo hệ thống build: Dùng lệnh
cmakeđể sinh Makefile.-S <source_dir>: Thư mục chứaCMakeLists.txt.-B <build_dir>: Thư mục chứa kết quả build trung gian.-D <var>=<value>: Gán giá trị cho biến CMake.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug - Thực thi build: Dùng
cmake --buildhoặc trực tiếp gọimaketrong thư mục build.cmake --build build # hoặc cd build && make
Ví dụ minh họa: Hello World
Cấu trúc dự án:
project/
├── CMakeLists.txt
└── src/
└── main.c
Nội dung src/main.c:
#include <stdio.h>
int main() {
printf("Hello from CMake!\n");
return 0;
}
Nội dung CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(hello_cmake VERSION 1.0 LANGUAGES C)
add_executable(app src/main.c)
Build và chạy:
cmake -B build
cmake --build build
./build/app
Cú pháp CMake cơ bản
Biến và chú thích
- Chú thích dòng:
# comment - Chú thích khối:
#[[ ... ]] - Đặt biến:
set(VAR_NAME value) - Danh sách:
set(LIST item1 item2)hoặcset(LIST "item1;item2") - Truy xuất biến:
${VAR_NAME}
Câu lệnh điều kiện
if(NOT VAR OR FLAG STREQUAL "ON")
message(STATUS "Condition met")
elseif(DEFINED OTHER_VAR)
# ...
endif()
Các lệnh phổ biến
message(STATUS "Info"): In thông báo.list(APPEND MY_LIST new_item): Thao tác danh sách.file(GLOB_RECURSE SOURCES "src/**/*.c"): Liệt kê tệp tin.configure_file(template.in output.h): Sinh tệp cấu hình.execute_process(COMMAND git rev-parse HEAD OUTPUT_VARIABLE COMMIT): Gọi lệnh hệ thống.
Xây dựng dự án đầy đủ với CMakeLists.txt
Cấu hình cơ bản
cmake_minimum_required(VERSION 3.12)
project(MyProject VERSION 2.1.0 LANGUAGES CXX)
# Chuẩn ngôn ngữ
set(CMAKE_CXX_STANDARD 17)
# Tùy chọn biên dịch
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
# Thư mục include
include_directories(include)
Tạo mục tiêu (targets)
# Thư viện tĩnh
add_library(core STATIC src/core.cpp)
# Thư viện động
add_library(utils SHARED src/utils.cpp)
# Tệp thực thi
add_executable(main_app src/main.cpp)
target_link_libraries(main_app core utils)
Cài đặt và đóng gói
# Cài đặt
install(TARGETS main_app core
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
# Đóng gói
include(CPack)
set(CPACK_GENERATOR "ZIP")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
Kiểm thử với Google Test
enable_testing()
add_subdirectory(third_party/googletest)
add_executable(test_core test/test_core.cpp)
target_link_libraries(test_core core gtest_main)
add_test(NAME core_tests COMMAND test_core)
Quản lý mô-đun và phụ thuộc
Sử dụng add_subdirectory() để chia nhỏ dự án:
# Thư mục gốc/CMakeLists.txt
add_subdirectory(src/math)
add_executable(app src/main.cpp)
target_link_libraries(app math_lib)
# src/math/CMakeLists.txt
add_library(math_lib STATIC add.cpp subtract.cpp)
Biểu thức sinh (Generator Expressions)
Cho phép cấu hình linh hoạt theo điều kiện:
# Tùy chọn biên dịch theo chế độ
add_compile_options("$<$<CONFIG:Debug>:-Wall;-Wextra>")
# Đường dẫn thư viện theo nền tảng
target_link_libraries(app "$<IF:$<PLATFORM_ID:Darwin>,lib_mac.a,lib_linux.a>")