Bỏ qua điều hướng, tới nội dung chính
Học C
Bài 38.228 phút đọc

Build type, tùy chọn, phụ thuộc

Sau bài này bạn sẽ làm được

  • Cấu hình build type và cờ theo từng type
  • Thêm một option bật tắt sanitizer
  • Sinh compile_commands.json cho công cụ
  • Kéo một phụ thuộc bằng FetchContent

CMake không dùng biến theo mục tiêu như Make. Thay vào đó nó có build type, tuỳ chọn bật tắt, và một hệ quản lý phụ thuộc kéo được thư viện từ internet. Bài này lắp ba thứ đó vào dự án ở bài trước.

#Build type

Cấu hình cờ theo build type
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug)          # mac dinh Debug neu khong chon
endif()

set(CMAKE_C_FLAGS_DEBUG   "-g3 -O0 -DDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG")
set(CMAKE_C_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
terminal
# Chon build type luc CAU HINH, khong phai luc dung
cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug
cmake --build build
[100%] Built target app
Build typeCờ điển hìnhDùng khi
Debug-g3 -O0Phát triển, gỡ lỗi
Release-O2 -DNDEBUGPhát hành
RelWithDebInfo-O2 -g -DNDEBUGPhát hành nhưng vẫn gỡ lỗi được khi sập
MinSizeRel-Os -DNDEBUGHệ nhúng, tối ưu kích thước

#Tùy chọn

Một tuỳ chọn bật tắt sanitizer
option(ENABLE_ASAN "Bat AddressSanitizer" OFF)

if(ENABLE_ASAN)
    target_compile_options(app PRIVATE -fsanitize=address,undefined)
    target_link_options(app    PRIVATE -fsanitize=address,undefined)
endif()
terminal
# Bat tuy chon bang -D khi cau hinh
cmake -S . -B build-asan -G "MinGW Makefiles" -DENABLE_ASAN=ON
cmake --build build-asan --target app
ld.exe: cannot find -lasan
ld.exe: cannot find -lubsan
collect2.exe: error: ld returned 1 exit status

#compile_commands.json

terminal
# Mot dong, sinh co so du lieu bien dich cho cong cu
cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
head -8 build/compile_commands.json
[
{
  "directory": ".../build",
  "command": "gcc.exe ... -std=c17 -Wall -Wextra -o CMakeFiles/toan.dir/src/toan.c.obj -c .../src/toan.c",
  "file": ".../src/toan.c",
  "output": "CMakeFiles/toan.dir/src/toan.c.obj"
},

#FetchContent

Kéo một thư viện từ internet
include(FetchContent)

FetchContent_Declare(unity
    GIT_REPOSITORY https://github.com/ThrowTheSwitch/Unity.git
    GIT_TAG        v2.6.0        # GHIM phien ban cu the, khong dung nhanh
)
FetchContent_MakeAvailable(unity)

# Bay gio dung unity nhu mot target binh thuong:
target_link_libraries(test_toan PRIVATE unity)
FetchContent
Cơ chế của CMake để tải mã nguồn của một phụ thuộc lúc cấu hình, dựng nó cùng dự án của bạn. Khác với cài thư viện lên hệ thống: phụ thuộc nằm trong thư mục dựng, phiên bản ghim trong CMakeLists.txt, nên mọi người dựng cùng một phiên bản.

#Preset

CMakePresets.json, lưu cấu hình thành tên
{
  "version": 3,
  "configurePresets": [
    {
      "name": "debug",
      "generator": "Ninja",
      "binaryDir": "build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "ENABLE_ASAN": "ON"
      }
    },
    {
      "name": "release",
      "generator": "Ninja",
      "binaryDir": "build/release",
      "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
    }
  ]
}
terminal
# Thay vi go dong -D dai, dung ten preset
cmake --preset debug
cmake --build build/debug
cmake --preset release && cmake --build build/release

Tự làm thử

  1. Cấu hình dự án của bạn với Debug và Release vào hai thư mục khác nhau.
  2. Thêm một option bật LTO và kiểm tra cờ xuất hiện trong lệnh dịch.
  3. Sinh compile_commands.json và mở nó để đọc lệnh dịch một tệp.
  4. Xác nhận cờ -std là c17 chứ không gnu17 trong tệp đó.
  5. Trên máy có mạng, dùng FetchContent kéo một thư viện kiểm thử.
  6. Viết một CMakePresets.json với hai preset và dùng chúng.

Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.

Tóm tắt

  • Build type chọn cờ và chọn lúc cấu hình; một thư mục dựng cho mỗi type.
  • option cho người dùng bật tắt tính năng từ dòng lệnh bằng -D.
  • CMAKE_EXPORT_COMPILE_COMMANDS=ON sinh compile_commands.json cho clang-tidy, clangd, và các công cụ khác.
  • FetchContent tải mã phụ thuộc lúc cấu hình với phiên bản ghim; find_package dùng thư viện đã cài.
  • CMakePresets.json lưu cấu hình thành tên để cả đội và CI dùng giống nhau.