iT邦幫忙

2025 iThome 鐵人賽

DAY 30
0
Software Development

30 天精通 C 語言建置與除錯:從 Makefile 到 CMake 跨平台實戰系列 第 30

[Day 30] [專案實戰] 一次走完 0 到 1 Cmake建置流程

  • 分享至 

  • xImage
  •  

今天會學到的
30 天走到這裡,我們已經學了:

  • 用 gcc 編譯第一支程式
  • 用 makefile 自動化
  • 用 cmake 抽象化 + 多平台支援
  • 加上 CTest 測試、CPack 打包
  • 用 CMakePresets.json 分享設定

今天就把這些全部串起來,實際做一次完整專案實戰:
從寫程式、建置、測試、打包、安裝,到 CI/CD 自動化。

步驟

  1. 專案結構
C_final_proj/
├─ inc/
│  └─ dog_meme.h
├─ src/
│  ├─ dog_meme.c
│  └─ main.c
├─ tests/
│  └─ test_dog.c
├─ CMakeLists.txt
└─ CMakePresets.json
  1. 程式碼
  • inc/dog_meme.h
#pragma once

int dog_add(int a, int b);
  • src/dog_meme.c
#include "dog_meme.h"

int dog_add(int a, int b) {
    return a + b;
}

  • src/main.c
#include <stdio.h>
#include "dog_meme.h"

int main() {
    int result = dog_add(2, 40);
    printf("dog_add(2,40) = %d\n", result);
    return 0;
}

  • tests/test_dog.c
#include <assert.h>
#include "dog_meme.h"

int main() {
    assert(dog_add(2, 40) == 42);
    return 0;
}
  1. CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(C_FINAL_PROJ VERSION 1.0.0 LANGUAGES C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 建立靜態函式庫
add_library(dog_meme STATIC src/dog_meme.c)
target_include_directories(dog_meme PUBLIC ${CMAKE_SOURCE_DIR}/inc)

# 建立執行檔
add_executable(app src/main.c)
target_link_libraries(app PRIVATE dog_meme)
target_compile_options(app PRIVATE -Wall -Wextra -Wpedantic)
target_compile_definitions(app PRIVATE APP_VERSION="1.0.0")

# 測試
include(CTest)
enable_testing()
add_executable(test_dog tests/test_dog.c)
target_link_libraries(test_dog PRIVATE dog_meme)
add_test(NAME dog_meme_add_test COMMAND test_dog)

# 安裝與打包
install(TARGETS app RUNTIME DESTINATION bin)
install(DIRECTORY inc/ DESTINATION include)

include(CPack)
set(CPACK_PACKAGE_NAME "dog_meme_proj")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_GENERATOR "TGZ")
  1. CMakePresets.json
{
  "version": 6,
  "configurePresets": [
    {
      "name": "debug-ninja",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
      }
    },
    {
      "name": "release-ninja",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    },
    {
      "name": "asan",
      "inherits": "debug-ninja",
      "cacheVariables": {
        "CMAKE_C_FLAGS": "-fsanitize=address -g",
        "CMAKE_CXX_FLAGS": "-fsanitize=address -g"
      }
    }
  ],
  "buildPresets": [
    { "name": "debug", "configurePreset": "debug-ninja", "jobs": 8 },
    { "name": "release", "configurePreset": "release-ninja", "jobs": 8 },
    { "name": "asan", "configurePreset": "asan", "jobs": 8 }
  ],
  "testPresets": [
    { "name": "ctest-debug", "configurePreset": "debug-ninja", "output": { "outputOnFailure": true } }
  ]
}
  1. 編譯與測試
cmake --preset debug-ninja
cmake --build --preset debug
ctest --preset ctest-debug --output-on-failure
  1. 打包與安裝
cpack --config build/debug/CPackConfig.cmake
cmake --install build/debug --prefix ./dist

安裝後的結構:

dist/
├─ bin/app
└─ include/dog_meme.h
  1. 串接 CI/CD(GitHub Actions 範例)

.github/workflows/cmake.yml

name: CMake CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Configure
        run: cmake --preset release-ninja
      - name: Build
        run: cmake --build --preset release
      - name: Test
        run: ctest --preset ctest-debug --output-on-failure
      - name: Package
        run: cpack --config build/release/CPackConfig.cmake

小結

到這裡,挖已經30天的,真是辛苦大家也辛苦自己了!
在這30天的鐵人中,我們總共學會

  • 用 gcc 手動編譯
  • 用 makefile 自動化
  • 用 cmake 管理跨平台專案
  • 用 gdb 增加建置除錯效率
  • 加上測試(CTest)、打包(CPack)、共享設定(Presets)
  • 串進 CI/CD pipeline

上一篇
[Day 29] [cmake] 用CMakePresets.json 與團隊合作
系列文
30 天精通 C 語言建置與除錯:從 Makefile 到 CMake 跨平台實戰30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言