简介:cmake-3.24.0.tar.gz 面向 C++ 开发者、构建工程师与需要跨平台编译的项目团队,提供 CMake 3.24.0 源码归档,可用于在 Linux/Unix 环境自行解压、配置、编译与安装,解决多编译器、多平台下构建脚本不统一的问题。压缩包约 9.91MB,共 2000 个文件,内容以 txt 说明、cmake 模块、rst 文档、C/C++ 源文件(c、h、cxx、cpp)为主,并含少量脚本、测试输入输出与工程配置样例,较完整地呈现了 CMake 的源码结构、模块定义和测试体系。已有 427 人学习或下载,适合需要研究构建系统实现、复用 Find 模块或搭建本地工具链的读者。通过阅读目录与源码,可了解 CMakeLists 组织方式、平台检测逻辑、依赖查找与测试集成思路,也可作为编译安装和二次开发的底包。
1. 从源码装 CMake 3.24.0:一次被 3.22 卡住的编译现场
前阵子把一套 C++ 工程从旧机器挪到新机器,代码一行没动,configure 阶段直接一片失败,报错落在 CMakePresets.json 的 version 4 上——系统自带的 cmake 是 3.22,还没到能解析这个 schema 的版本。CMake 3.24.0 源码安装这件事,我在不同机器上做过不下十次,每次出问题的地方都不太一样,但原因高度集中:不是编译器太老,就是依赖库借错了,再不然就是装完之后 PATH 里先找到的还是系统旧版本。
发行版仓库里的 cmake 通常落后两三年,敲一下cmake --version,再看一眼工程里cmake_minimum_required写的是多少,心里基本就有数了。这篇记录的是 cmake-3.24.0.tar.gz 从解压到跑通的全过程:先盘点环境,再拆 bootstrap 参数,然后编译安装、理顺多版本共存,最后落到一套能反复执行的自检。手里有 C++17 以上工程、被旧版 CMake 挡在门口的人,照着走一遍应该能省掉半天。
2. 装前盘点:编译器、依赖库与 3.24.0 的版本要求
源码装 CMake 最容易犯的错,是把它当成「下载、解压、make 三连」就完事。实际上 bootstrap 阶段会先用系统里的 C++ 编译器编出一个临时的 cmake,再用这个临时 cmake 去配置整个构建树。也就是说,机器上可以没有 cmake,但绝对不能没有能用的 C++ 编译器。这一步没盘清楚,后面所有命令都会失败。
2.1 工具链最低要求与五条自查命令
CMake 3.24 系列对构建期编译器的要求比早期 3.x 高一档,需要支持 C++11;换算成常见版本,GCC 5 以上、Clang 3.5 以上基本都能过。make 得是 3.81 之后的版本,太老的 make 在处理 CMake 生成的 Makefile 时会莫名其妙地卡住。另外还需要一个 C 编译器,bootstrap 用它做特征探测,缺了会在日志里留下很不好找的失败记录。
我一般在解压之前先跑这五条,把结果记在便签上:
gcc --version | head -n 1 # C 编译器版本,bootstrap 做特征探测用 g++ --version | head -n 1 # C++ 编译器版本,必须支持 C++11 make --version | head -n 1 # 低于 3.81 建议先升级 nproc # 核数,决定后面 make -j 的上限 free -g | sed -n '2p' # 内存,决定 -j 到底敢开多大nproc和free这两条看着和安装无关,其实是后面编译阶段最关键的输入。CMake 源码里有几个模板展开极重的翻译单元,单个cc1plus进程峰值能到 500MB 以上,4 核 4G 的机器上直接make -j4,大概率在 80% 左右被内核 OOM 干掉,报错信息还只有一句Killed。
顺带看一眼磁盘,源码树解开约 90MB,构建产物加中间文件在 1GB 上下,df -h剩余空间低于 3GB 就别在这儿编了。
2.2 bootstrap 依赖的取舍:借系统库还是全自带
CMake 构建时会用到几个第三方库:curl(用于file(DOWNLOAD)和 FetchContent 的下载)、zlib、expat、bzip2、liblzma、libarchive、jsoncpp。每个都有对应的--system-xxx和--no-system-xxx开关,还有一个总开关--system-libs/--no-system-libs。
关键点是:不要让它自己猜。默认行为是能借就借,探测到系统装了开发包就用系统的,探测不到就退回自带的。这导致同一个 tar.gz 在两台机器上编出来的二进制依赖完全不同——A 机器上编的拷到 B 机器,一跑就报libcurl.so.4: cannot open shared object file。
| 参数 | 作用 | 借系统库的好处 | 借系统库的风险 |
|---|---|---|---|
--system-curl | 用系统 libcurl | 支持更多协议、走系统证书配置 | 系统 curl 太老时下载功能异常 |
--system-zlib | 用系统 zlib | 少编译一个库,快 | 交叉编译时架构对不上 |
--system-expat | 用系统 expat | XML 解析行为跟随系统安全更新 | 老系统 expat 有 CVE 未修 |
--system-libarchive | 用系统 libarchive | 支持更多压缩格式 | 依赖链最长,最容易缺包 |
--no-system-libs | 全部用自带第三方库 | 产物自洽,可整目录打包分发 | 编译时间增加约三分之一 |
我的习惯是分场景:内网构建机上走--system-libs图快,反正机器环境固定;要打出给别人用的分发包,一律--no-system-libs,把一个自洽的/usr/local目录打进去,到对面解压就能用。混合着写也不是不行,但每次都得记清楚哪个库借了、哪个没借,维护成本比省下来的那几分钟高得多。
还有个小依赖容易漏:想装ccmake(终端图形配置界面)就必须有 ncurses 的开发包,否则 bootstrap 会静默跳过,装完发现ccmake不在。要 GUI 版本则得装 Qt 开发包并加--qt-gui,服务器上一般用不着。
2.3 版本对照:3.24.0 到底比系统那版多了什么
很多人升级 CMake 只是因为报错,其实先对着表看一眼,能判断到底需不需要升、升到 3.24 够不够。
| 能力 / 语法 | 起始版本 | 典型触发场景 |
|---|---|---|
FILE_SET(头文件集) | 3.23 | 新的库导出写法 |
| Presets 文件 version 4 | 3.23 | IDE 读取 CMakePresets.json 报 schema 错 |
cmake --fresh | 3.24 | 想清空构建目录缓存但不想手动rm -rf |
CMAKE_COMPILE_WARNING_AS_ERROR | 3.24 | 想把警告当错误统一管控 |
FetchContent 的OVERRIDE_FIND_PACKAGE | 3.24 | 依赖替换,把 find_package 重定向到 FetchContent |
cxx_std_23编译特性 | 3.20 | 声明 C++23 标准 |
表里前五行都是 3.22 上跑不起来的。所以要处理的是「从 3.22 到 3.24」这一段升级,不是「随便装个新版」。这也是为什么直接apt install cmake常常无效——仓库里给的还是 3.22。
3. 解压与配置:./bootstrap 参数一行一行拆
CMake 的构建流程和一般 autotools 项目不完全一样:./bootstrap必须在源码根目录执行,它不接受 out-of-source 方式,先在Bootstrap.cmk/下编出一个最小的 cmake,再回过头来配置正式构建树。理解这一点很关键,因为所有配置失败的证据都留在Bootstrap.cmk/里,而不是你以为的build/目录。
3.1 目录规划、校验与解压
先把下载的包放到一个干净目录,别直接在~/Downloads里解压然后就地编译——中间产物和源码混在一起,出问题想重来只能整个重新解压。
mkdir -p ~/src && cd ~/src cp ~/Downloads/cmake-3.24.0.tar.gz . sha256sum cmake-3.24.0.tar.gz # 和下载页给的校验值对一遍,别跳过 tar -xzf cmake-3.24.0.tar.gz cd cmake-3.24.0 ls -1 | head -n 20 # 确认有 bootstrap、CMakeLists.txt、Sourcesha256sum这一步真别省。压缩包传输截断是玄学级别的问题,表现是解压到一半报gzip: stdin: unexpected end of file,或者更糟——解压成功但某个源文件末尾少了几行,编译时报一堆语法错误,你会以为是编译器的问题,排查两小时才发现是包坏了。
解压后确认三样东西:bootstrap脚本有可执行权限、CMakeLists.txt在根目录、Source/目录存在。缺任何一个都说明包不完整。
3.2 ./bootstrap 参数说明与一份可直接复制的配置
下面这份是我在 x86_64 内网构建机上用的,参数基本没改过:
./bootstrap \ --prefix=/usr/local \ --parallel="$(nproc)" \ --system-libs \ --enable-ccache \ -- \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_TESTING=OFF \ -DBUILD_CursesDialog=ON逐个说清楚:
--prefix=/usr/local决定最终安装位置。装到/usr/local而不是/usr,是为了不覆盖包管理器管的/usr/bin/cmake,出问题还能退回系统版本。这一条是多版本共存的前提,选错了后面补救很麻烦。
--parallel="$(nproc)"只影响 bootstrap 阶段自身那次构建,真正的大头编译在后面的make里,两者是分开的。
--system-libs表示第三方库优先用系统的。如果要打自洽分发包,把这一行换成--no-system-libs,其余不动。
--enable-ccache在机器上装了 ccache 时有效,第二次重编能快一半以上。反复调参数重编的场景下很值。
--之后的所有内容会原样传给真正的 cmake 配置阶段。-DCMAKE_BUILD_TYPE=Release别漏,默认不指定构建类型的话优化等级很低,编出来的 cmake 跑大工程明显慢。-DBUILD_TESTING=OFF跳过 CMake 自身的测试套件构建,省时间;-DBUILD_CursesDialog=ON是显式打开 ccmake,省得它自己判断。
bootstrap 过程大概 3 到 10 分钟,视机器而定。屏幕上滚的都是探测信息,正常结束会打印一行CMake has bootstrapped. Now run make.
3.3 配置失败时的黑匣子在哪
bootstrap 失败时的终端输出往往只有最后几行,真正的线索在Bootstrap.cmk/目录:
ls -1 Bootstrap.cmk/ # 里面有 CMakeCache.txt、cmake_bootstrap.log grep -n -i "error\|not found\|cannot" Bootstrap.cmk/cmake_bootstrap.log | tail -n 30 tail -n 60 Bootstrap.cmk/cmake_bootstrap.log先grep定位,再tail看上下文。这个日志里会完整记录编译器探测结果、每个第三方库的查找路径、以及最终的失败原因。九成配置失败能在前三十行 grep 结果里找到答案——通常是某个xxx.h找不到,或者编译器版本被判为不支持。
CMakeCache.txt也要看一眼,它记录了 bootstrap 阶段缓存下来的编译器路径和探测结果。如果之前用别的编译器跑过一次 bootstrap,再换编译器时缓存会干扰判断,这时把Bootstrap.cmk/整个删掉重跑最干净。
4. 编译与安装:-j 的取舍、前缀选择和卸载后悔药
配置过了只是拿到了 Makefile,真正耗时的是编译。这一步的风险主要集中在内存上,其次是安装位置带来的路径问题。
4.1 make 并行度:先算内存,再定 -j
make -j"$(nproc)" # 内存充足时的常规选择 make -j2 # 4G 内存以下机器的保守值判断标准不是核数,是内存。经验公式是j ≈ 可用内存GB ÷ 1.5,再和核数取小。比如 8 核 8G 的机器,按公式是 5,那就-j5或-j6;2 核 4G 的小机器,虽然公式给 2,但-j2就够,别贪。
被 OOM 杀掉的特征非常明显:编译进度停在某一个百分比不动,然后终端冒出c++: fatal error: Killed signal terminated program cc1plus,或者干脆整个 shell 断连。这时候别怀疑代码,去dmesg -T | tail -n 20看一眼,如果有Out of memory: Killed process ... (cc1plus),就是内存不够,降-j或者临时加一块 swap 再重来。
中途失败不用make clean,直接调低并行度重跑make就行,已经编好的目标文件会复用。这也是为什么--enable-ccache值得开。
完整的编译在 4 核机器上大约 15 到 25 分钟。编完之后先别急着装,源码根目录下已经有可执行文件了:
./bin/cmake --version # 安装前先验一下,省得装完才发现有问题这一步能提前暴露「编出来的二进制跑不起来」这类问题,比如缺动态库、架构不匹配。等装了才发现,就得走一遍卸载再重装。
4.2 make install 与 install_manifest.txt 这颗后悔药
sudo make install装到/usr/local需要 root。装完在构建目录里会生成一个install_manifest.txt,里面是这次安装写出去的每一个文件的绝对路径。这个文件非常关键,因为 CMake 的构建系统不提供make uninstall。
wc -l install_manifest.txt # 一般几百行 # 需要卸载时(先确认路径都在 /usr/local 下再执行) sudo xargs -a install_manifest.txt rm -fxargs -a是 GNU 版本才有的用法,换到别的实现上要改成sudo xargs rm -f < install_manifest.txt。执行前务必先head install_manifest.txt扫一眼,确认清单里没混进/usr/bin或/lib下的系统文件——如果 prefix 设错了,这份清单会把系统的包管理记录搞乱。
装完之后源码树和构建产物就可以删了,/usr/local下的那份是自洽的。但如果打算以后重编,install_manifest.txt和CMakeCache.txt建议留着,下次调参数重编能省很多时间。
4.3 PATH、MANPATH 与那个不能手动设的 CMAKE_ROOT
装到/usr/local之后,最典型的问题是敲cmake --version出来的还是系统旧版。原因是/usr/local/bin在 PATH 里的位置排在/usr/bin后面。
# /etc/profile.d/cmake.sh export PATH=/usr/local/bin:$PATH export MANPATH=/usr/local/share/man:${MANPATH:-}放到/etc/profile.d/下对所有用户生效,只给自己用就写进~/.bashrc。MANPATH那行管的是man cmake,不加的话手册页找不到,虽然不影响编译但查参数时很难受。
改完必须让 shell 重新计算路径缓存,否则当前会话里还是旧结果:
hash -r which -a cmake # 列出所有能找到的 cmake,确认 /usr/local/bin 排第一which -a这条比which有用得多,它会把 PATH 上所有同名可执行文件都列出来,路径顺序一目了然。
至于CMAKE_ROOT这个环境变量——不要手动设。cmake 会根据自己的可执行文件位置推导出资源目录(/usr/local/share/cmake-3.24),手动设一个错误的路径,会直接触发CMake Error: Could not find CMAKE_ROOT !!!。这个报错的含义不是「没设变量」,而是「按可执行文件位置找不到 share 目录」,通常发生在把bin/cmake单独拷到别的机器、却没带上share/的时候。
5. 踩坑排查:源码装 CMake 最常见的五个翻车现场
5.1 bootstrap 卡在 "Could not find OpenSSL"
现象:bootstrap 跑了几十秒后中断,日志里反复出现Could not find OpenSSL, try to set the path to OpenSSL root folder,或者curl相关的探测失败。
原因:加了--system-curl或--system-libs,系统里装了 curl 的运行库但没有开发头文件。运行库能跑程序,编译时缺curl/curl.h一样过不去。这类「运行时有、开发时没有」的包在精简系统镜像里特别常见。
解决:要么补开发包(名称通常是xxx-devel或libxxx-dev这类形式),要么直接改成--no-system-libs用自带的 curl 重新 bootstrap。改完记得先清掉Bootstrap.cmk/缓存,否则上次的探测结果还在。
5.2 编译到 80% 被 Killed,终端只留一句 "signal terminated program cc1plus"
现象:make -j8跑到一多半突然中断,没有任何语法错误提示,只有一句Killed。
原因:并行编译进程总内存超过物理内存,内核 OOM killer 挑了一个cc1plus杀掉。CMake 源码里cmSourceFile相关的几个文件模板展开层级很深,单进程内存占用远高于普通项目。
解决:make -j2或-j4重跑,不用清理,已编目标会复用。反复出现就临时加 2G swap 顶一下,比一直降并行度要快。编完再把 swap 关掉。
5.3 装完了cmake --version还是旧版本
现象:make install显示成功,ls /usr/local/bin/cmake也在,但新开终端敲cmake --version输出 3.22。
原因:三种可能——PATH 里/usr/local/bin排在后面;当前 shell 有路径哈希缓存;或者装了多个 prefix,实际生效的是另一个。
解决:先which -a cmake把所有候选列出来,再echo $PATH看顺序,然后hash -r。三条都排除了,才去怀疑是不是装到了别的前缀。这个问题排查顺序很重要,从前到后基本三分钟内定位。
5.4 报 "Could not find CMAKE_ROOT !!!"
现象:cmake --version能出结果,但一跑cmake -S . -B build就报找不到 CMAKE_ROOT。
原因:只把bin/cmake拷到了目标机器,没带share/cmake-3.24/目录。cmake 靠可执行文件位置推导资源目录,推导不出来就报这个。
解决:把整个/usr/local/share/cmake-3.24一起拷过去,保持和bin/的相对位置。真要挪位置,用cmake --system-information里的路径信息核对实际查找位置,而不是硬设CMAKE_ROOT掩盖问题。
5.5 换了编译器或前缀重编,配置结果还是老的
现象:删了源码重新解压,./bootstrap --prefix=$HOME/.local跑完,装出来还在/usr/local。
原因:Bootstrap.cmk/CMakeCache.txt里缓存着上一次的编译器路径和配置变量,重新解压时如果复用了同一个目录(比如原地tar -xzf覆盖),缓存文件还在。
解决:重编前把Bootstrap.cmk/删干净,或者干脆换个新目录解压。这条吃过一次亏之后我就改成了每次解压都用带时间戳的新目录,再没撞上过。
6. 装完怎么验证:四级自检和一个改不掉的习惯
装完只敲一次cmake --version是不够的,版本号对了但资源目录缺失、组件没装全、预设方案跑不通的情况我都遇到过。我现在固定走四级自检,从浅到深,每级都能独立定位问题。
第一级,确认二进制和路径:cmake --version看版本是不是 3.24.0,which -a cmake看/usr/local/bin是否排第一,cmake --help | head -n 5确认资源目录能被正常读取。第三��如果报 CMAKE_ROOT 相关错误,直接回到 5.4。
第二级,确认组件齐全:
ctest --version # 测试驱动,版本号应与 cmake 一致 cpack --version # 打包工具 ccmake --version # 装了 ncurses 才会有,没有不影响主流程三个版本号都该是 3.24.0。任何一个不存在或者版本对不上,说明安装过程中跳过了该组件。
第三级,跑一个真实工程,把 configure、build、install 全链路走一遍:
mkdir -p /tmp/smoke/src && cd /tmp/smoke cat > CMakeLists.txt <<'EOF' cmake_minimum_required(VERSION 3.24) # 低于 3.24 会直接报错,顺便验证版本 project(smoke LANGUAGES CXX) add_executable(smoke src/main.cpp) target_compile_features(smoke PRIVATE cxx_std_17) EOF cat > src/main.cpp <<'EOF' #include <iostream> int main() { std::cout << "cmake ok\n"; } EOF cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j4 ./build/smoke这段的关键在cmake_minimum_required(VERSION 3.24):如果 PATH 里生效的还是旧版本,第一步 configure 就会直接失败,比看版本号更可靠。最后输出cmake ok,说明编译器探测、标准特性、生成器三项都正常。
第四级,检查工具链信息快照:
cmake --system-information | head -n 40这份输出里记录了实际使用的编译器路径、系统架构、生成器名称。跨机器复制构建缓存出问题时,这份快照是唯一的对照依据。
提示:
cmake --fresh是 3.24 才有的选项,构建目录缓存混乱时用它比手动rm -rf build安全,它会保留生成器选择、只清配置缓存。
从那以后我每次装完 cmake 都强制把这四级走一遍,尤其是第三级那个 smoke 工程——它花不到一分钟,却能挡住后面在真实项目上浪费的半天。装环境这事,验证成本永远低于返工成本。希望帮到你。
本文还有配套的精品资源,点击获取