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/debugbuild/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 知识体系图

下面这张图,把生成器的核心逻辑串起来了。你一看就明白。

CMake生成器知识体系 CMake 元构建系统 生成器(Generator) 单配置生成器 多配置生成器 Ninja(跨平台) Unix Makefiles Ninja(单配置) Visual Studio Xcode 选择方式:-G 参数 / CMAKE_GENERATOR

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生成器求方便。搞清楚单配置和多配置的区别,你就不会再被构建目录搞晕了。

公众号:蓝海资料掘金营,微信deep3321