CMake 实战案例一:简单命令行工具
这一篇用一个“命令行工具”贯穿最常见的 CMake 用法:从单文件到多文件,从最小可用到可安装、可发布。
目标
- 构建一个可执行程序
hello - 支持 Debug/Release
- 给出最小可复制的目录结构、CMakeLists、构建命令
场景 A:单文件项目(最小可用)
目录结构:
hello/
├── CMakeLists.txt
└── main.c
main.c:
#include <stdio.h>
int main(void) {
puts("Hello, CMake!");
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(hello C)
add_executable(hello main.c)
构建:
cmake -S . -B build
cmake --build build -j
./build/hello
场景 B:多文件 + include 目录(更贴近真实项目)
目录结构:
hello/
├── CMakeLists.txt
├── include/
│ └── greet.h
└── src/
├─ ─ greet.c
└── main.c
include/greet.h:
#pragma once
const char* greet(void);
src/greet.c:
#include "greet.h"
const char* greet(void) {
return "Hello, CMake (multi-file)!";
}
src/main.c:
#include <stdio.h>
#include "greet.h"
int main(void) {
puts(greet());
return 0;
}
CMakeLists.txt(用 target-based 写法,不污染全局):
cmake_minimum_required(VERSION 3.15)
project(hello C)
add_executable(hello
src/main.c
src/greet.c
)
target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
构建命令同上。
场景 C:加上版本号、编译选项与构建类型
你可以在顶层声明版本与标准,并按配置添加编译选项:
cmake_minimum_required(VERSION 3.15)
project(hello VERSION 1.0.0 LANGUAGES C)
add_executable(hello src/main.c src/greet.c)
target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_options(hello PRIVATE
$<$<CONFIG:Debug>:-O0 -g>
$<$<CONFIG:Release>:-O3>
)
配置 Debug/Release:
cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build-debug -j
cmake -S . -B build-release -DCMAKE_BUILD_TYPE=Release
cmake --build build-release -j
场景 D:安装(可选,但很实用)
给可执行文件加安装规则:
include(GNUInstallDirs)
install(TARGETS hello RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
安装到系统或自定义前缀:
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local
cmake --build build -j
cmake --install build
~/.local/bin/hello
常见坑
- 忘了用
-S/-B分离源代码与构建目录:推荐统一用cmake -S . -B build。 - 头文件找不到:优先用
target_include_directories()绑定到目标,不要用全局include_directories()。 - Debug/Release 没生效:单配置生成器(Makefiles/Ninja)要设置
CMAKE_BUILD_TYPE;多配置生成器(VS/Xcode)要用--config。
小结
这个案例覆盖了“可执行程序”的核心骨架。下一篇可以把可复用逻辑提取成库,并演示 PUBLIC/PRIVATE/INTERFACE 的传播规则。