拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CMake完整学习指南:从安装到高级配置,避开那些坑

CMake完整学习指南:从安装到高级配置,避开那些坑

我很长一段时间对CMake的印象就是“一个生成Makefile的工具”,直到后来在一个跨平台项目里,需要在Windows上编出一个能用的DLL,在Linux上编出一个命令行工具,还得把Eigen、Qt、raylib这些依赖统一管起来,这才开始认真研究它。说句实话,CMake的学习曲线不算陡,周边坑却非常多,尤其是环境版本、工具链、缓存这三样,能把人折磨到怀疑人生。这篇东西我打算把从安装到进阶配置的完整链路写明白,把该避的坑都标出来,给你一份可以直接照着操作的指南。

1. 为什么CMake值得认真学?

先聊点务虚的。很多人写C/C++代码,编译靠IDE里点一下按钮,项目简单的时候完全够用。但一旦需要做这么几件事,手点就不太行了:要在不同操作系统上出同一套代码的产物;要集成几个外部库,带一堆头文件和链接参数;要按Debug和Release两套配置反复切换;要让同事拿到代码后少说十句话就能跑起来。这时候你不光需要一个构建工具,还需要一个能描述“项目怎么编译”的统一语言,CMake就是目前生态里最通用的那个。

CMake本身不直接编译代码,它做的事情是读取CMakeLists.txt配置,生成对应平台的构建脚本或工程文件,让真正的编译器去干活。你可以把它理解成一个“翻译官”:同一份项目描述,在Windows上翻译成Visual Studio工程,在Linux上翻译成Makefile,在macOS上翻译成Xcode工程。得益于这个设计,团队成员用什么IDE写代码都无所谓,最终构建入口是统一的。

还有一个更现实的理由:现代C/C++项目的第三方库集成,几乎默认支持CMake。我用过的Eigen、raylib、Qt、mosquitto,官方文档第一行基本都是CMake命令。你绕开CMake去手动配置这些库,等于每升级一个版本就要重新折腾一遍,时间成本完全划不来。

所以这篇文章适合谁?刚接触CMake想系统入门的新手,在Windows上用MinGW折腾半天跑不通的人,需要往项目里集成Eigen、raylib这些库的开发者,以及想把构建脚本写得更专业的老手。内容会覆盖安装、核心语法、真实项目实操、IDE配合、常见坑,照着敲就行。

2. 环境准备:下载安装与版本选择

2.1 各个平台的安装方式

先说Windows。最简单的就是去CMake官网下载msi安装包,一路下一步。安装时有一个选项“Add CMake to the system PATH for all users”,建议勾上,否则之后在命令行敲cmake会提示找不到命令。装了之后可以顺手验证一下,打开cmd输入:

cmake --version

如果能看到版本号,安装就成功了。

Windows上还有两条命令行安装路子。一是winget,二是Chocolatey,日常用起来更快:

winget install Kitware.CMake choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System'

这里要特别提醒一句:网上搜“cmake下载高级版本”,会冒出很多来路不明的网站和所谓的“高级版”“绿色汉化版”,CMake本身就是开源免费软件,不存在付费高级版,英文官网的msi和zip就是最靠谱的来源。那些第三方打包站往往捆绑了广告甚至恶意内容,别去碰。

Ubuntu用户通常直接apt装:

sudo apt update sudo apt install cmake

但apt仓库里的CMake版本一般偏旧。比如Ubuntu 20.04默认带的是3.16,很多新项目要求3.18以上,这时候两条路可走:一是从官网下载官方提供的cmake-版本-linux-x86_64.sh脚本安装;二是用pip装最新版,运行:

pip install cmake

再说说“ubuntu cmake 离线安装”,这个场景其实很常见,内网服务器没法访问外网。做法是在能联网的机器上去官网下载对应系统的cmake-版本-linux-x86_64.tar.gz,然后拷到目标机器上解压就行,不需要编译也不需要root权限:

tar -xzf cmake-3.29.3-linux-x86_64.tar.gz export PATH=$PWD/cmake-3.29.3-linux-x86_64/bin:$PATH cmake --version

官方提供的二进制tar包是预编译好的,解压即用,唯一要保证的是架构匹配和glibc版本别太老。如果目标机器架构是ARM,记得下arm64版,我当初在这上面栽过一次,x86_64的包解压完跑不起来,一查才发现机器是aarch64。

2.2 版本越新越好,但别被“高级版”忽悠

版本选择上我的建议很简单:能用多新用多新,至少不要低于3.16。这不是追新,而是CMake很多常见功能有最低版本限制:

功能最低CMake版本说明
target_include_directories3.1目标导向头文件目录
target_compile_features3.1指定C++标准
add_compile_definitions3.12添加编译宏
FetchContent3.11自动拉取外部源码
CMakePresets.json3.19预设配置,团队协作利器

我自己遇到过一个很典型的例子:项目里用FetchContent集成一个小库,同事的Ubuntu上CMake版本只有3.10,配置阶段直接报“Unknown CMake command FetchContent”,第一反应以为是代码写错了,后来发现是版本太低,命令行执行apt install cmake升级后问题消失。版本过旧时,CMake报错信息往往还指向你自己的CMakeLists.txt,干扰排查方向。

判断一个CMakeLists.txt需要的最低版本,别靠猜,看用了哪些特性就好,写完配置文件后把cmake_minimum_required(VERSION 3.16)这行改成你实际用到的最低版本。如果不想某个版本以下的用户拿到一堆莫名其妙的报错,还可以在project()前加判断:

if(CMAKE_VERSION VERSION_LESS 3.16) message(FATAL_ERROR "需要 CMake 3.16 或更高版本") endif()

3. 理解CMake的核心逻辑:从CMakeLists.txt说起

3.1 一个最小可用项目长什么样

CMake的入口文件叫CMakeLists.txt,放在项目根目录。一个最基本、能编出可执行文件的配置是这样:

cmake_minimum_required(VERSION 3.16) project(HelloDemo) add_executable(demo main.cpp)

三行,含义分别是:声明最低版本、声明项目名、把main.cpp编译成可执行文件demo。是不是比想象中简单?

到这里,整个CMake的工作流程已经走完了三个阶段的第一个。CMake的工作分两步:先configure,再build。Configure阶段会读取CMakeLists.txt,生成构建系统和缓存文件CMakeCache.txt;Build阶段才是真正调用编译器干活。很多人分不清报错出现在哪个阶段,导致排查思路混乱。以后看到“CMake Error at CMakeLists.txt”这类信息,就是configure阶段出错,跟编译器、代码本身一点关系都没有。

3.2 现代CMake的正确姿势:目标导向

早期CMake流行一股脑设置全局变量,比如include_directories、link_directories、add_definitions,写法很省事,但项目一复杂就出问题:全局的头文件目录污染了所有目标,A库是否需要某个宏根本没边界。现代CMake的核心思想是“目标导向”——把每个可执行文件、每个库都看成一个目标,依赖关系明明白白挂在目标上。

一个典型例子:

add_library(mylib STATIC mylib.cpp) target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_compile_features(mylib PUBLIC cxx_std_17) add_executable(app main.cpp) target_link_libraries(app PRIVATE mylib)

注意target_include_directories里的PUBLIC、PRIVATE、INTERFACE,很多新手在这里懵。我用一个电梯权限来比喻:

  • PRIVATE:自己能用,别人看不到。mylib内部需要某个头文件,但使用mylib的app不需要。
  • INTERFACE:自己不用,别人要用。典型场景是header-only库,它自己编译时不需要包含目录,但使用它的下游需要。
  • PUBLIC:自己用,别人也继承。mylib的头文件里包含了某个第三方库的头文件,那么mylib自己的源码要能include到它,链接mylib的app也需要能include到它。

用错作用域的最典型症状就是:配置阶段一切正常,编译到下游项目时报“找不到xxx头文件”。我调过好几次这种问题,最后发现就是PUBLIC写成了PRIVATE,依赖链断在半路。

说白了,现代CMake希望你思考的不是“往全局塞了什么”,而是“我这个目标对外承诺了什么”。养成这个习惯之后,多模块项目的管理会轻松很多。

3.3 生成器和构建系统:为什么要有Ninja

CMake本身不编译,它要生成构建系统,而“生成什么”由-G参数决定。Windows上默认会选Visual Studio生成器,Linux默认Unix Makefiles,还可以显式指定Ninja、MinGW Makefiles等。

这里有个重要概念:单配置生成器与多配置生成器。Unix Makefiles和Ninja是单配置生成器,你在configure阶段就必须用-DCMAKE_BUILD_TYPE=Release指定一种构建类型,之后想换类型得重新配置;Visual Studio和Xcode是多配置生成器,一套工程里同时包含Debug和Release配置,在IDE里切换就行,不用重新跑配置。

如果问我个人偏好,现在我自己开新项目都优先选用Ninja,尤其在Windows下配MinGW或MSVC时,速度比Visual Studio生成器快不少。安装Ninja就一个文件的事,Windows上可以用winget装:

winget install Ninja-build.Ninja

然后配置命令写成:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug

命令行构建方式统一用:

cmake --build build

这条命令会自动使用配置时指定的生成器,不管底层是Makefile还是Ninja,日常构建只需要记住这一句。

4. 实操:跑通一个真实项目

4.1 一个C++项目的完整配置

理论知识说得再多,不如动手跑一个。假设项目目录结构是这样:

demo/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ └── utils.h └── modules/ └── logger/ ├── CMakeLists.txt ├── logger.h └── logger.cpp

根目录CMakeLists.txt:

cmake_minimum_required(VERSION 3.16) project(DemoApp) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(modules/logger) add_executable(demo src/main.cpp src/utils.h ) target_link_libraries(demo PRIVATE logger)

modules/logger/CMakeLists.txt:

add_library(logger STATIC logger.cpp logger.h ) target_include_directories(logger PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

然后从项目根目录执行:

cmake -S . -B build cmake --build build

-S指定源码目录,-B指定构建目录。构建产物会集中在build目录里,不会污染源码目录,这在Git管理下特别重要——把build/写进.gitignore就完事。

这套结构做对了一件事:logger库把自己的头文件目录通过target_include_directories声明为PUBLIC,所以主程序里直接#include "logger.h"就行,主程序根本不知道logger的源码在哪。这就是目标导向的好处,添加新模块时不需要去改主程序的配置。

4.2 集成第三方库:以Eigen3为例

集成Eigen3是很多做数值计算的人遇到的第一个CMake集成需求,它本身是header-only库,不需要编译,所以集成起来非常简单,但有一个常见的坑:find_package找不到。

Ubuntu下先装依赖:

sudo apt install libeigen3-dev

Windows下可以从官网下载解压,把解压出来的eigen3目录记好位置。然后CMakeLists.txt里写:

find_package(Eigen3 REQUIRED) add_executable(solver solver.cpp) target_link_libraries(solver PRIVATE Eigen3::Eigen)

这里Eigen3::Eigen是CMake配置包提供的导入目标,链接了它,头文件目录和依赖都会自动处理好。find_package找不到时,最常见的解决办法是设置CMAKE_PREFIX_PATH,告诉CMake去哪找:

cmake -S . -B build -DCMAKE_PREFIX_PATH="D:/libs/eigen3"

顺便说一句,很多人以为集成库就一定要用find_package,其实还有另一条路:在CMakeLists.txt里用FetchContent直接把库的源码拉下来编。比如Eigen3也可以用:

include(FetchContent) FetchContent_Declare(eigen URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz ) FetchContent_MakeAvailable(eigen)

find_package适合系统里已经装好了库,FetchContent适合自动化构建,尤其适合做CI流水线——不用先手工装依赖,构建机器上只要有CMake和网络就能拉全。两条路的取舍很简单:本地开发用find_package,CI和跨平台发布用FetchContent保底。

4.3 用raylib做一个小游戏

raylib是这两年很火的简单图形库,它的CMake集成方式也很有代表性。官方鼓励用源码集成,最干净的路径是用FetchContent:

cmake_minimum_required(VERSION 3.16) project(GameDemo) include(FetchContent) FetchContent_Declare(raylib URL https://github.com/raysan5/raylib/archive/5.0.tar.gz ) FetchContent_MakeAvailable(raylib) add_executable(game main.c) target_link_libraries(game PRIVATE raylib)

这里有一个过去坑过不少人的问题:raylib在Windows下还要链接winmm等系统库。如果直接用官方5.0以上版本,它的CMake配置已经处理好了这些,你不需要自己手动link。但如果你在某个教程里看到还要手动target_link_libraries(game PRIVATE winmm),多半是版本太老,升级一下就好。

用FetchContent集成时,首次构建会花一段时间下载编译源码,这是正常现象。如果想要缓存源码避免每次干净构建都重新下载,可以设置:

set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/_deps") set(FETCHCONTENT_UPDATES_DISCONNECTED ON)

第二个选项特别有用,我一般在CUDA、raylib、spdlog这类库上都开,避免每次配置时都会检查更新。代价是之后想拉新版本需要手动清理build/_deps目录。

4.4 扩展到Qt和mosquitto这类复杂库

Qt的CMake集成是另一套玩法,因为Qt本身有moc、uic这些代码生成工具,CMake从5.15开始提供了很方便的接口,Qt6时代就更顺了。一个带界面的最小工程:

cmake_minimum_required(VERSION 3.16) project(QtDemo) find_package(Qt6 REQUIRED COMPONENTS Widgets) qt_standard_project_setup() qt_add_executable(demo main.cpp mainwindow.ui mainwindow.cpp mainwindow.h ) target_link_libraries(demo PRIVATE Qt6::Widgets)

关键点在于qt_add_executable和qt_standard_project_setup,前者会处理moc和uic的自动调用,后者帮你把构建目录、自动生成文件这些乱七八糟的事情都配好。用传统add_executable也能跑,但很多Qt专属的编译问题会自己冒出来。这里不展开Qt细节,只提醒一句:Qt6项目里,凡是手写add_executable后还要自己折腾AUTOMOC、AUTOUIC的,都是在走弯路。

mosquitto-2.1.2这种偏底层库的CMake集成,思路和Eigen3类似,但它提供了分支选项,比如是否构建broker、是否启用TLS、是否带websockets支持。用CMake配置时你会看到很多开关,它们的命名规律基本是-DWITH_XXX=ON/OFF。以mosquitto的源码构建为例:

cmake -S . -B build -DWITH_BROKER=ON -DWITH_PIC=ON cmake --build build

这类库一个共同点是:官方提供的CMake选项非常庞杂,但默认值一般够用。没有特殊需求就直接用默认,别去动那些理解不了的选项,很多人的问题就是手痒乱关开关,导致编出来的库缺功能。

5. 工具链配合与交互使用

5.1 VS Code + CMake Tools:Configure按钮到底在哪

你搜“vscode安装cmake tools 底部状态栏应该有configure按钮吗”,十有八九是装了插件但界面一片空白,没找到那个传说中的按钮。

先说结论:装完Microsoft官方的CMake Tools插件后,底部状态栏确实会出现一组按钮,从左到右依次是:Kit选择、Build、Run,以及Configure(有的版本显示为齿轮图标,有的显示文字)。但这组按钮有一个前提——你必须在VS Code里打开一个包含CMakeLists.txt的文件夹,而不是只打开一个单独的.cpp文件。

确认过这个前提还看不到按钮,按顺序检查三件事:

  1. 是否安装了C/C++扩展。CMake Tools依赖它做编译诊断,没有它插件有时候不激活。
  2. 是否真的打开了文件夹。文件管理器里拖一个文件夹进VS Code即可,别拖文件。
  3. 左下角有没有报错提示。插件激活失败时通常会有通知,点开看具体原因。

正常激活后,点击状态栏上的Kit按钮,会弹出编译器选择列表,里面会有Visual Studio、GCC、MinGW等选项。选好Kit之后,再点Configure按钮,CMake就会读取CMakeLists.txt并生成缓存,终端里会同步输出配置过程。

有一点值得提:状态栏上的Configure按钮,本质上就是在执行命令行里的configure操作。所以命令行老手完全可以不用鼠标点,直接在VS Code的终端里敲:

cmake -S . -B build

效果完全一样。状态栏按钮的好处是会自动带上VS Code插件当前选中的Kit和传递给CMake的额外参数,更适合不想记命令的人。

5.2 CMake GUI:什么时候用,什么时候别用

CMake GUI是我唯二推荐的图形化操作方式之一,另一个是VS Code的插件。官方安装包会附带CMake GUI,打开后界面分三块:源码目录、构建目录、配置选项列表。

GUI的操作流程是:填源码路径,填构建路径,点Configure,然后选择生成器(比如Visual Studio 16 2019或者MinGW Makefiles),如果列表里出现红色条目,那通常是需要填写的配置项,比如CMAKE_PREFIX_PATH。配置完成后点Generate,最后点Open Project,会用对应的IDE打开生成的工程。

我的观点是:GUI适合两种人,一是刚接触CMake、对命令行还不熟的新手,二是在Windows下用Visual Studio做开发、想省掉命令行操作的人。但你要长期做C/C++项目,还是尽早逼自己用命令行,因为命令行可以放进脚本、写进CI、通过一条命令在别的机器上复现。GUI的操作存在大量手动点击,没法自动化,而且它生成的CMakeCache.txt内容和命令行生成的是同一个文件,底层没有区别。

一个常见的困惑是“我用GUI配置过了,为什么之后跑cmake --build还是报错”?因为GUI只完成了configure和generate,没有帮你build。GUI点Open Project后实际打开的是IDE工程,你还需要在IDE里点编译,或者自己到命令行执行cmake --build。

5.3 Windows下用MinGW,别和MSVC打架

Windows上开发C/C++,编译器主要有两派:MSVC和MinGW系(gcc/g++)。CMake本身对两者都支持,但有一个坑特别容易踩:顺手用了Visual Studio生成器,却在命令行里指定了MinGW的编译器,或者反过来。

一个典型错误现场是这样的:执行cmake -S . -B build -G "MinGW Makefiles",结果CMake报错说找不到sh.exe或者make程序。这是因为MinGW的安装目录需要包含在PATH里,CMake要在PATH里找MinGW的make工具。解决办法是确认minGW的bin目录加到了PATH,或者直接在配置命令里指定编译器:

cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_CXX_COMPILER=g++

如果用MinGW,我强烈建议配Ninja而不是MinGW自带的make,速度差距明不明显另说,至少报错信息更清晰,对中文路径的兼容性也更好。

另外要记住:CMakeCache.txt一旦生成,编译器选项就会被记住。当你从MSVC切到MinGW,或者反过来,旧缓存还在,会出现莫名其妙的混合错误。这种情况下不要纠结,直接删掉build目录重新配置,比任何调试都省时间。

还有一个Windows特有的问题,安装CMake和编译器的路径里尽量不要有中文和空格字母,遇到问题的时候优先排查这个。我印象最深的一次:项目路径带中文,用MSVC编译正常,换成MinGW之后就疯狂报错,最后把项目挪到纯英文路径下编一次就过了。

6. 高级技巧:在CMake里集成strip指令

6.1 为什么要strip

strip的意思是去除编译产物中的符号表等调试信息,让可执行文件或库的体积明显变小。Linux下你可能有这个经历:编译一个Release版的程序,体积好几MB,执行strip之后能缩到不到一半。对需要分发安装包、嵌入到嵌入式设备镜像里的场景,strip几乎是必做的一步。

这个需求完全可以在CMake里自动完成,不用每次手动跑strip命令。常见的做法有三种,直接上命令行式的配置:

set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s")

-s是链接器选项,意思是链接时丢弃符号表。这段只作用在Release配置上,Debug配置不受影响,调试时还能看到完整符号。对单配置生成器(Makefiles、Ninja)来说直接用-DCMAKE_BUILD_TYPE=Release就能生效,对Visual Studio生成器则要确认实际构建的是Release配置。

第二种做法更灵活,适合你想在strip前做点其他事的情况:用add_custom_command在构建完成后挂一条命令。

add_executable(demo main.cpp) if(CMAKE_BUILD_TYPE STREQUAL "Release") add_custom_command(TARGET demo POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:demo> COMMENT "Stripping symbols from demo" ) endif()

${CMAKE_STRIP}是CMake自动检测到的strip工具路径,Linux下是/usr/bin/strip,Windows下如果用了MinGW则是strip.exe。$<TARGET_FILE:demo>会在生成时展开为可执行文件的完整路径,这一步很多人会傻傻地写成硬编码路径,一改构建目录就失效,不推荐。

注意这里的版本判断:如果项目同时用Ninja和Visual Studio生成器,CMAKE_BUILD_TYPE只在单配置生成器下有意义,多配置生成器下需要在add_custom_command里改用$<CONFIG>生成器表达式:

add_custom_command(TARGET demo POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:demo> CONFIGURATIONS Release COMMENT "Stripping symbols from demo" )

CONFIGURATIONS Release表示只在Release配置下执行。生成器表达式是CMake里比较高级但非常实用的东西,多花十分钟搞懂$<...>语法,后面很多场景都会受益。

6.2 三种方式怎么选

方式适用场景优缺点
链接器选项 -s简单项目,只想瘦身最省事,但没法控制时机
POST_BUILD + strip需要多步骤、条件定制灵活,会多花一点点构建时间
外部脚本/打包脚本统一strip有正式发布流水线构建层不管,打包层统一处理

个人建议:个人项目用第一种,release体积要求不严格,一行代码解决;正式发布项目用第二种,把strip写进CMake,保证任何人拿到源码构建出的Release包都是处理过的;如果公司有完整的CI打包流水线,那就让打包脚本统一处理,CMake这边反而不要多此一举了。

7. 常见问题排查实录

最后分享几个我实际踩过、也反复在社区里见到的经典问题,整理成速查表。

现象原因处理方法
配置时报“Unknown CMake command: FetchContent”CMake版本太低升级CMake到3.11以上
find_package找不到Eigen3/Qt等没有设置CMAKE_PREFIX_PATH配置时加-DCMAKE_PREFIX_PATH指定路径
编译时报找不到头文件,但配置阶段没出错target_include_directories作用域写错检查PUBLIC/PRIVATE是否合理
切换MSVC/MinGW后各种编译错误旧缓存CMakeCache.txt里残留编译器信息删除build目录重新配置
改完CMakeLists.txt但配置还是旧结果CMake缓存未更新删缓存重建,或点CMake Tools的Clean Reconfigure
Windows下MinGW配置时找不到sh.exeMinGW的bin目录不在PATH,或生成器选择错误检查PATH,用-G "MinGW Makefiles"并指定编译器
构建产物在Release下没变小strip没有生效检查CMAKE_BUILD_TYPE是否为Release,以及strip配置是否挂对目标

再补一条排查经验:CMake的报错信息其实很有价值,很多人看一眼Error就慌了,其实它会把出错文件的绝对路径、具体行数、出错原因全部输出。比如“No such file or directory”这种,报错里通常会直接写出它去找了哪些路径,顺着报错去检查路径远比猜靠谱。

关于VS Code的CMake Tools插件,还有一个高频问题:插件明明装好、按钮也出来了,但一点Configure就弹窗说“No kit selected”或者Kit列表是空的。这种情况通常是插件没有正确探测到编译器,先在VS Code里安装C/C++扩展再重载窗口,还是不行就检查编译器是否装好、是否在PATH里。插件探测编译器依赖系统PATH,如果你在PATH里加了MinGW却忘了重开VS Code,它看不到。

最后还有一个很多人没注意的小细节:CMakeLists.txt编码建议统一为UTF-8 without BOM。Windows上默认记事本保存会带BOM,偶尔会导致CMake解析字符串出现问题,尤其是message里带中文的时候。跨平台项目建议从一开始就统一编码规范。

写在最后

我个人在实际操作中的体会是:CMake最反直觉的地方是它有两个阶段,配置和构建,绝大多数报错分不清阶段就会卡很久。等你能一眼看出“这是配置阶段的问题还是编译阶段的问题”之后,CMake基本就不会再拦路。配置阶段多找缓存问题,编译阶段多找依赖和工具链问题,方向对了,剩下的就是耐心。

如果你用的库恰好没有提供CMake配置,也可以用CMake的方式自己包一层,写个FindXXX.cmake文件,把库的头文件和库文件声明清楚,这也是现代CMake比较值得投入的部分。后续你还可以研究一下CMakePresets.json,把常用配置写进预设文件,团队协作时开箱即用,省得每个人都要敲一长串命令行参数。


这篇文章从官网下载到真实项目集成,再到strip和问题排查,覆盖了CMake使用的完整链条。耽搁点时间的是版本、缓存和工具链这几个坑,它们虽然小,每一个都能让人浪费半天。真心建议你按文章的顺序走一遍,把一套配置跑通了再往项目里叠加复杂度,你会发现CMake远没有墙外的人描述的那么难。

返回列表