Table of Contents
构建C应用程序,可以可靠地在Windows,macOS,和Linux之间编译和运行,需要的不仅仅是便携式源代码,它需要一个适应每个平台本土工具的构建系统. CMake,一个开源构建系统生成器,通过让你在简单的配置文件中定义一次项目,然后生成平台专用构建文件(Makefiles,Visual Studio溶液文件,Xcode项目等)来解决这个问题. 文章为C项目创建跨平台构建系统提供了透彻,实用的指南,涵盖了从基本设置到依赖管理,测试,交叉编译等先进技术的所有内容.
什么是CMake(美国电影)?
CMake是一个元构建系统: 它不直接编译代码,而是生成其他构建系统的输入文件。 您使用特定域语言在 [[FLT: 0] 文件中描述您的工程。 CMake 然后读取这些文件, 并为目标平台输出适当的构建指令 。
CMake的主要特征包括:
- 平面-不可知语法:[] 相同的在Unix,Windows,和macOS上工作.
- 多倍发电机:支持 Make,忍者,Visual Studio,Xcode等.
- 出源建筑:[ 保持建筑文物与源代码分离.
- 扩展性:[]模块,函数,和宏允许可重复使用的构建逻辑.
- 包件发现:[ 定位已安装的库和信头.
- 与CI/CD的结合:在自动化管道中无缝工作.
CMake已经成为C和C++生态系统中跨平台开发的事实上的标准,被LLVM,MySQL等不同项目以及整个 KDE 桌面环境所使用.
利用CMake促进跨平台C发展的益处
采用CMake不仅能简单携带,还带来若干具体好处:
- 单一的真理源:[ 写一个构建逻辑,并为每个平台生成文件,消除脆弱的 shell脚本或平台特有的 Makefile.
- IDE集成: 团队可以在Visual Studio,CLion,Xcode,或VS代码中工作,同时共享相同的.
- 模块工程结构:使用将大型项目分成具有自身依赖性的可管理组件.
- 条件逻辑:[ 仅在需要时应用平台专用旗帜,源文件,或库,而无需复制整个配置.
- 自动依赖处理:和 简化使用第三方库。
- 测试和包装:[]CTest和CPack紧密结合,使得添加测试和创建安装器变得微不足道.
- 构建性能:[] 忍者生成器与CCACHE结合,大幅缩短重建时间.
- 活动社区:[] 扫荡 官方文献[ 和模块与教程的蓬勃生态系统.
开始: 为 C 项目设置 CMake
本节从安装到三个主要平台上编译的可执行文件,贯穿整个工作流程.
1. 安装CMake
从 cmake.org 下载最新的二进制,或使用您的系统软件包管理器:
- 林努(德比安/乌本图):]
- macOS(客家话:]]]
- Windows: 运行安装器,并确保选择“添加CMake to the system PATH”。
以 验证安装。建议为本文讨论的特性提供3.10 或更高版本。
2. 写一个最小的 CMakeLists.txt
在您的工程根中创建一个名为 [[FLT: 10] ] 的文件。 下面是单个源 C 项目的最小示例 :
cmake_minimum_required(VERSION 3.10)
project(HelloWorld C)
add_executable(hello main.c)
细分 :
- ] 设定最小的 CMake 版本。这也允许对政策进行更新,从而改进行为。
- 定义工程名称和语言。指定],防止CMake扫描C++编译器。
- 告诉CMake,目标]应该从]中构建.
一个略为现实的例子增加了编译器旗和只以页眉为主的依赖:
cmake_minimum_required(VERSION 3.15)
project(Calculator C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
add_executable(calc main.c parser.c)
target_include_directories(calc PRIVATE include)
在此 ] 添加 ] 给编译器头搜索路径,只用于目标.
3. 生成构建文件
创建构建目录并运行 CMake :
mkdir build
cd build
cmake ..
在 Linux/macOS 上,它默认生成一个 Makefile。在安装了 Visual Studio 的 Windows 上,它生成一个 ] 文件。要请求不同的生成器,请使用 。
生成后,您可以在配置时间通过选项 :
cmake .. -DCMAKE_BUILD_TYPE=Release -DMY_FEATURE=ON
这些变量存储在中,并在后续运行中再使用.
4. 建设项目
一旦生成构建文件, 将编译 :
- make/Ninja:](所有平台和发电机的工作)
- 视觉工作室:[]]
- Xcode:[]]]
]命令是跨平台的,并避免平台特定引用. 使用[]加速构建.
用于真实世界项目的高级 CMake 技术
除了基本内容, CMake 提供了精简更大或更复杂的建筑的功能。 掌握这些功能将节省时间并减少错误 。
管理带有 find package 的依赖关系
命令 定位已安装的库, 并为其中包含路径和库文件设置变量。 现代 CMake 鼓励使用 [[FLT: 0]] 导入的目标 [[[FLT: 1]] 来进行清洁依赖性传播 :
find_package(SDL2 REQUIRED)
target_link_libraries(my_app PRIVATE SDL2::SDL2)
导入的目标自动携带包括目录、 汇编定义和链接标记。 如果库不提供 CMake 配置文件, 您可能需要一个查找模块。 请在 [[FLT: 0]] cmake- developer [[[FLT: 1] 上写入您自己或依赖社区模块 。
对于没有全系统安装的依赖性,在配置时间下载和整合源代码: :
include(FetchContent)
FetchContent_Declare(
zlib
GIT_REPOSITORY https://github.com/madler/zlib.git
GIT_TAG v1.3
)
FetchContent_MakeAvailable(zlib)
target_link_libraries(my_app PRIVATE zlib)
这种方法通过固定特定版本来确保可复制的构建。
加入测试
CMake 通过 CMT 整合测试。 启用测试并在您的 [[FLT: 36] ] 中定义测试 :
enable_testing()
add_executable(test_parser test_parser.c)
target_link_libraries(test_parser PRIVATE parser_lib)
add_test(NAME ParserTest COMMAND test_parser)
运行测试方式 :
ctest --output-on-failure
CTest 支持测试定点,标签,超时,以及并行执行. 对于更全面的测试,考虑与单位测试框架结合,如 cmocka [],方法是连接其库并使用 ].
交叉汇编
CMake通过 工具链文件简化了交叉汇编。工具链文件设置了编译器、sysroot和目标架构。创建类似 的文件:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_SYSROOT /path/to/sysroot)
然后用工具链引用 CMake :
cmake -DCMAKE_TOOLCHAIN_FILE=arm-cross.cmake ..
CMake 将自动使用指定的交叉编译器, 并搜索库的系统。 此技术适用于嵌入式系统、 移动平台, 以及任何与目标机不同的构建机器。 请参考官方 [[FLT: 0]] 与 CMake [[[FLT: 1] 指南进行校正 。
安装和包装
使用 [[FLT: 43]] ] 命令来定义您的工程应如何部署:
install(TARGETS my_app DESTINATION bin)
install(FILES config.ini DESTINATION etc)
CPack 然后生成安装器: DEB, RPM, NSIS, DMG 等。 在您的 ] 结尾添加 :
include(CPack)
运行 [[FLT: 47]] 以生成 Debian 软件包. CPack 继承所有安装规则,并允许通过 等变量定制.
常见的陷阱和最佳做法
即使是有经验的开发者也遇到麻烦。这里经常出现问题以及如何避免它们:
坑:硬编码路径
绝对路径 : [FLT: 49] 。 相对于源树使用 [[FLT: 50] 和 ]。 对于运行时文件位置, 请使用 嵌入路径或依赖安装目录 。
陷阱: 忽略生成器表达式
生成器表达式()在构建时评价,而不是配置时间。这些表达式对于每个配置设置都是必不可少的:
target_compile_definitions(my_app PRIVATE
$<$<CONFIG:Debug>:_DEBUG>
)
仅为调试构建添加 [[FLT: 55] 。 避免使用 [[FLT: 56] ] ], 因为多配置生成器( Visual Studio, Xcode) 在配置时间时没有设置 [[FLT: 57] ] 。
陷阱: 过度使用全局命令
命令,如、和],会影响所有目标。
陷阱: 找不到合适的范围
适当设置 范围。如果现代 CMake , 则选择 , 然后链接目标。 除非绝对必要, 不要使用 , 手动设置链接目录 。
结论
CMake将多平台 C 开发的挑战转化为可管理、可重复的过程。 通过编写一套单一的构建指令,您可以获得本地性能、IDE支持和所有主要操作系统的强力依赖管理。从简单的开始,随着您的项目的增长,逐步采用高级特性——测试、交叉汇编、包装。学习 CMake的投资每次在不重写单一构建代码的情况下,都会在不同的平台上进行补偿。