8、CMake生成器:Unix Makefiles、Ninja、Visual Studio、Xcode生成器对比
说到CMake,有个概念你早晚得搞明白——生成器(Generator)。
说白了,CMake本身不负责编译代码。它是个“元构建系统”。它的工作,是读取你的CMakeLists.txt,然后生成一份让其他构建工具能看懂的文件。这个“其他构建工具”,就是生成器。
我刚开始用CMake时,以为它跟Make是一回事。后来发现,CMake只是个“翻译官”,真正的“包工头”是Make、Ninja这些家伙。嗯,这个认知很重要,搞错了后面会走弯路。
8.1 生成器是什么?
生成器,就是CMake用来生成底层构建文件的后端。你运行cmake -G "Ninja",CMake就会生成Ninja能识别的build.ninja文件。你换成-G "Unix Makefiles",它就生成一堆Makefile。
我个人习惯把生成器分成两类:
- 单配置生成器:一次只能生成一种配置(Debug、Release等)。比如Unix Makefiles、Ninja。
- 多配置生成器:一次生成所有配置,构建时再选。比如Visual Studio、Xcode。
这个区别很关键。你想想看,如果你在Linux上用Makefiles,想切Debug/Release,得重新跑一遍cmake。但在Windows上用Visual Studio,一次生成,IDE里下拉菜单直接选配置就行。
核心理解:生成器决定了CMake的输出格式,也决定了你的工作流。选对了,事半功倍;选错了,天天跟配置打架。
8.2 主流生成器对比
我这些年用过的生成器不少,挑四个最主流的说说。
| 生成器 | 平台 | 配置类型 | 构建速度 | 适用场景 |
|---|---|---|---|---|
| Unix Makefiles | Linux/macOS | 单配置 | 中等 | 通用、兼容性好 |
| Ninja | 跨平台 | 单配置 | 快 | 大型项目、增量编译 |
| Visual Studio | Windows | 多配置 | 中等 | Windows生态、IDE集成 |
| Xcode | macOS | 多配置 | 中等 | Apple生态、iOS/macOS开发 |
8.3 Unix Makefiles:老牌选手
这是CMake的默认生成器(在Linux/macOS上)。它生成标准的Makefile,你用make命令构建。
优点很明显:几乎任何Unix系统都支持,不需要额外安装工具。缺点嘛,构建速度一般,尤其是大型项目,增量编译不够聪明。
我记得有一次,一个同事的项目有上千个源文件,用Makefiles构建,改一行代码要等半分钟。后来换成Ninja,直接降到几秒。嗯,这就是差距。
小技巧:如果你用Unix Makefiles,可以试试make -j$(nproc)并行构建,能快不少。
8.4 Ninja:速度之王
Ninja的设计哲学很简单——快。它没有Make那么多花哨功能,就是专注于“把构建跑完”。
Ninja的构建文件是build.ninja,比Makefile简洁得多。它天生支持并行,增量编译也做得很好。我现在的项目,只要不是必须用IDE,一律用Ninja。
怎么用?很简单:
cmake -G "Ninja" -B build
cmake --build build
注意,Ninja本身不检测依赖变化,这事得CMake干。所以改完CMakeLists.txt后,记得重新跑cmake。
避坑指南:我曾经在一个项目里,直接用Ninja构建,没注意CMake缓存没更新。结果改了头文件,Ninja没重新编译。折腾了半天才发现,是CMake没重新生成Ninja文件。记住:Ninja只管执行,不管规则更新。
8.5 Visual Studio:Windows生态的标配
在Windows上,Visual Studio生成器是主流。它生成.sln和.vcxproj文件,可以直接在VS里打开、编译、调试。
它是个多配置生成器。你一次生成,就能在Debug、Release、RelWithDebInfo之间切换。这点在Windows开发中特别方便。
用法:
cmake -G "Visual Studio 17 2022" -B build
cmake --build build --config Release
注意,Visual Studio版本号要对。VS 2022是17,VS 2019是16,别搞错了。
8.6 Xcode:Apple开发者的首选
在macOS上做iOS或macOS开发,Xcode生成器是标配。它生成.xcodeproj文件,可以在Xcode里直接打开。
跟Visual Studio一样,它也是多配置生成器。你可以在Xcode的Scheme里选Debug/Release。
用法:
cmake -G "Xcode" -B build
cmake --build build --config Debug
我个人觉得,Xcode生成器在纯C++项目里用得不多。除非你要跟Apple的框架集成,或者做iOS开发,否则Ninja在macOS上更香。
8.7 CMAKE_GENERATOR:环境变量选择
每次敲-G挺烦的,对吧?CMake提供了CMAKE_GENERATOR环境变量,你设一次,以后就不用再指定了。
比如在Linux上,你想默认用Ninja:
export CMAKE_GENERATOR=Ninja
然后在项目目录里直接:
cmake -B build
CMake会优先读环境变量,没有才用默认值。这个技巧在CI/CD里特别有用。我在Jenkins pipeline里就经常这么干,省得每个项目都写-G。
建议:团队统一生成器时,在CMakePresets.json里配好,比环境变量更可控。
8.8 多配置生成器 vs 单配置生成器
这个区别,我再说细一点。
单配置生成器(Unix Makefiles、Ninja):
- 一次CMake生成一种配置。
- 切配置要重新跑
cmake,通常建不同目录(build/debug、build/release)。 - 适合Linux/macOS,或者CI里一次只构建一种配置的场景。
多配置生成器(Visual Studio、Xcode):
- 一次CMake生成所有配置。
- 构建时通过
--config指定。 - 适合IDE开发,或者需要频繁切换配置的场景。
我举个例子。你在Linux上用Ninja,想同时有Debug和Release:
cmake -G Ninja -B build/debug -DCMAKE_BUILD_TYPE=Debug
cmake -G Ninja -B build/release -DCMAKE_BUILD_TYPE=Release
在Windows上用Visual Studio,一次搞定:
cmake -G "Visual Studio 17 2022" -B build
cmake --build build --config Debug
cmake --build build --config Release
哪种方便?看场景。我个人在Linux上习惯建两个目录,在Windows上直接用VS的多配置。
8.9 知识体系图
下面这张图,把生成器的核心逻辑串起来了。你一看就明白。
8.10 如何选择生成器?
这个问题没有标准答案。我根据经验给几个建议:
- Linux服务器/CI环境:Ninja。速度快,依赖少。
- macOS开发,不用Xcode:Ninja。同样理由。
- Windows开发,用VS:Visual Studio生成器。跟IDE集成最好。
- iOS/macOS应用开发:Xcode生成器。没得选。
- 跨平台项目,团队习惯Make:Unix Makefiles。兼容性最好。
我个人现在几乎全用Ninja。除非项目强制用IDE,否则Ninja+VS Code的组合,又快又轻。
一句话总结:生成器是CMake的“翻译后端”。选Ninja求快,选IDE生成器求方便。搞清楚单配置和多配置的区别,你就不会再被构建目录搞晕了。