尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从源码编译安装新版 CMake:解决版本过低与 PATH 配置问题

从源码编译安装新版 CMake:解决版本过低与 PATH 配置问题 简介CMake 3.24.0 源码包面向需要从源码构建或定制CMake的C开发者、系统集成与构建系统维护人员主要解决多编译器、多平台环境下构建配置复杂、依赖管理繁琐的问题。该版本在跨平台构建、依赖检测与测试集成方面表现稳定适合在Linux/Unix环境中通过bootstrap、make等流程自行编译部署也可作为学习CMake内部机制与研究CMakeLists编写范式的参考素材。整个压缩包约9.91MB内含约2000个文件核心类型包括txt说明文档、cmake构建脚本、rst文档以及大量C/C头文件与源文件整体目录结构清晰文档部分便于查阅使用说明脚本与源码则呈现了完整的构建逻辑与实现细节。已有425人学习下载。通过这份源码开发者能够获得一套可编译的完整构建树深入理解add_executable、find_package、add_library等命令背后的实现逻辑同时可以复用其官方测试用例与CMake模块为自身项目的跨平台构建配置和持续集成提供有价值的模板与排错思路。 前几天在一台老旧的 Linux 服务器上部署一个内部项目configure 阶段直接弹了一句CMake 3.16 or higher is required. You are running version 2.8.12.2。系统包管理仓库里的 CMake 版本早就被冻结在远古时代没办法我只能去官网下载cmake-3.24.0.tar.gz源码包手动编译安装。整个过程不算难但中间有几个点特别容易踩坑比如校验、PATH 优先级、版本冲突还有编译到一半才发现缺依赖。这篇就完整记录一下我是怎么从拿到 tar.gz 到最终跑出新版本 CMake 的给同样被老环境逼到手动编译的朋友做个参考。1. 为什么系统包管理器里的 CMake 总是不够用1.1 发行版稳定策略和实际需求之间的落差用 apt 或 yum 装 CMake 确实方便一条命令就完事。但很多生产环境用的都是长期支持发行版比如 CentOS 7 或者 Ubuntu 18.04这类系统的软件源为了保证整体稳定性往往会把版本号锁得很低。CentOS 7 自带的是 CMake 2.8.12.2Ubuntu 18.04 最多到 3.10.2而现代 C 项目尤其是这两年基于新标准重写的工程通常会要求 3.16 甚至 3.20 以上。这个落差不是个小问题它不是一个能用就行的差异而是新写的target_precompile_headers、CMAKE_CUDA_ARCHITECTURES、FetchContent增强这些功能在旧版本里根本不存在。我当时遇到那个项目报错时也想过要不要直接升级系统的 cmake 包。但仔细一看系统里有好几个软件包是依赖/usr/bin/cmake的如果直接卸载或者替换旧版本可能会把系统工具链搅乱。更稳妥的思路是源码安装到一个独立目录然后通过 PATH 控制用哪个版本。这正是cmake-3.24.0.tar.gz这类官方源码包的典型用途。1.2 源码包适合什么场景源码编译适合几种情况。一是没有 root 权限或者不想污染系统环境想装到用户目录二是项目对 CMake 版本有明确要求而官方 apt 源里的版本不满足三是服务器架构特殊比如 aarch64 或者自定义交叉编译环境官方预编译二进制不一定能用。源码包的好处是足够“干净”你完全控制安装路径不依赖系统包管理器的依赖关系。不过也别误会源码编译不是唯一选项。CMake 官网除了cmake-3.24.0.tar.gz源码包之外还提供了cmake-3.24.0-linux-x86_64.tar.gz这种平台二进制包。如果你只是日常使用不关心怎么从源码构建那直接下二进制包解压配置 PATH 就行。我这次选择源码包一方面是想保证和系统的 libc、编译器兼容另一方面也是想顺便看一下新版 CMake 的 bootstrap 机制有没有变化。1.3 旧版本带来的实际报错版本过低最常见的报错就是开头那段CMake X.Y.Z or higher is required. You are running version x.y.z。有些项目还会在cmake_minimum_required上做额外判断版本不够直接FATAL_ERROR。还有一些更隐蔽的情况比如target_precompile_headers这个命令在旧版里根本没有configure 时不报错编译到一半才提示 command not found排查起来更费劲。所以如果你也遇到这类问题别急着去改项目的 CMakeLists 文件来绕开检查。正确做法是安装一个满足要求的新版 CMake然后确保命令行里实际执行的是那个新版。这个“实际执行”说起来简单实际上后面配置 PATH 时最容易出问题我会在第 4 部分细讲。2. 下载与校验解压之前先做三件事2.1 版本选择3.24.0 能覆盖哪些需求下载之前先确认版本号是否满足项目要求。我用的cmake-3.24.0在 2022 年 8 月发布对当时主流项目的 3.16、3.18、3.20 要求都能满足。它支持CMP0074到CMP0130这一堆策略对FetchContent、file(GENERATE)、CUDA的支持也很完善。需要注意一点CMake 源码包命名很简单就是cmake-版本号.tar.gz。如果你不想自己编译下载页面还有带平台后缀的二进制包比如cmake-3.24.0-linux-x86_64.tar.gz。两者的区别在于前者是源代码需要先编译才能用后者解压出来就能跑。这次我选择源码包但如果你要装的环境是内网没有外网又不想带一堆编译依赖可以提前在官网把对应平台的二进制包拉下来。另外CMake 每个大版本后面还有小补丁版本比如 3.24.1、3.24.2。如果项目没有强制要求 3.24.0 这个名字建议能拿最新补丁就拿最新补丁因为修了不少 build 层面的 bug。我当时因为构建脚本里写死了这个文件名所以还是用了 3.24.0。2.2 下载方式和官网地址下载地址我习惯用官网的 files 目录https://cmake.org/files/v3.24/cmake-3.24.0.tar.gz。直接 wget 就行wget https://cmake.org/files/v3.24/cmake-3.24.0.tar.gz如果服务器没有外网也可以在自己电脑上下载再通过 scp 或者 U 盘拷贝进去。这个包不到 10 MB传起来很快。顺便说一句官网首页的 Download 按钮跳转的是 GitHub 的 release 页面文件名和官网 files 目录是一致的但考虑到生产环境网络策略我一般优先用 cmake.org 官方地址避免被 GitHub 的跳转搞得很慢。2.3 校验哈希和 GPG 签名下载完成后第一件事不是解压而是校验文件完整性。这一步很多人会跳过但真不能省。源码包体积不小传输过程可能出错哪怕一个字节损坏后面 bootstrap 或 make 阶段都会出现莫名其妙的报错排查起来比重新下载还浪费时间。官方在同一个目录下提供了.sha256文件下载后校验sha256sum -c cmake-3.24.0.tar.gz.sha256如果输出OK说明哈希一致。更严格的校验是用 GPG 签名文件.asc验证签名但很多场景下 sha256 已经能拦住传输错误。我个人建议至少做 sha256如果是从 GitHub 或者镜像站下载那签名验证就更重要了因为镜像不可控。2.4 编译前的依赖确认源码编译 CMake 需要几样东西C/C 编译器、make、openssl 开发头文件。前两个不用多说gcc、g、make都要装好。openssl 那块比较特殊CMake 在 bootstrap 阶段会检测 OpenSSL用于支持 HTTPS 下载相关功能。如果没有bootstrap 会自动把相关功能关掉不会直接报错但之后某些模块可能功能不完整。所以我通常先确认一下gcc --version g --version make --version在 Debian/Ubuntu 系上如果缺依赖就执行sudo apt install build-essential libssl-devCentOS 上对应的是yum install gcc gcc-c make openssl-devel。编译前把这些装好能省去后面一半的排错功夫。3. 从 tar.gz 到可执行文件完整的源码编译过程3.1 解压命令与目录规划拿到cmake-3.24.0.tar.gz之后解压是第一步。最常见的命令是tar -zxvf cmake-3.24.0.tar.gz这里z表示解 gzip 压缩x表示解压v是显示解压文件列表f后面跟文件名。如果不想要那么多输出刷屏可以换成tar -zxf cmake-3.24.0.tar.gz。新版 tar 其实会自动识别压缩格式直接tar -xf cmake-3.24.0.tar.gz也可以。解压出来的目录名就是cmake-3.24.0。我一般会把它放到/tmp下编译因为源码编译会生成大量临时文件放/tmp不占用家目录空间装完之后删掉也省事。但要注意/tmp在某些系统上可能被清空如果编译到一半机器重启你可能要重新解压所以根据自己的环境取舍。还有一个细节编译产物默认放在源码目录里所以解压后要先cd cmake-3.24.0再执行后面的命令。如果目录已经存在残留的编译缓存建议先清理一下rm -rf CMakeCache.txt CMakeFiles避免上次的缓存干扰这次构建。3.2 用 bootstrap 脚本生成构建系统进入目录后核心命令是./bootstrap --prefix/opt/cmake-3.24.0这个bootstrap脚本是 CMake 自己写的一个“自举”过程。因为 CMake 本身太复杂不能一步到位用 CMake 构建所以脚本会先生成一个最小化的临时 CMake 可执行文件再用这个临时 cmake 去配置和构建完整版本。类似“先有鸡还是先有蛋”的问题用一个小鸡先孵化出整只鸡。--prefix指定安装目录。这里我建议不要直接设成/usr/local而是用一个带版本号的独立目录比如/opt/cmake-3.24.0或者$HOME/opt/cmake-3.24.0。这样以后切换版本、删旧版本都清晰不会跟系统自带版本混在一起。如果你的机器核数多想让 bootstrap 也并行跑可以加--parallel4或者后面在 make 阶段用-j。bootstrap 本身很快主要时间花在后面的正式编译上。3.3 make 与 make installbootstrap 执行完后会生成 Makefile。接下来就是常规操作make -j$(nproc)-j是并行编译参数$(nproc)返回 CPU 核心数。如果你的编译器版本比较老或者机器内存不大-j$(nproc)可能会因为同时编译太多文件导致内存爆掉进程被 kill。这时候可以保守一点用make -j2或make -j4。编译过程中会有大量警告大部分是从系统头文件来的只要不中断就问题不大。整个编译在我的四核服务器上大概跑了八九分钟如果你的机器更强两三分种也可能完成。等 make 结束确认没有报错再执行sudo make install如果--prefix使用的是用户目录比如$HOME/opt/cmake-3.24.0那就不需要 sudo。安装完成后可以看一下安装目录的结构ls /opt/cmake-3.24.0/bin里面应该有cmake、ctest、cpack这几个主要可执行文件。cmake-gui默认不会编译除非你安装了 Qt 相关依赖这也说明源码包安装的默认路径确实轻量。3.4 额外构建选项和性能控制如果你明确不需要 OpenSSL可以在 bootstrap 时直接禁用避免因为依赖缺失导致某些功能静默关闭./bootstrap --prefix/opt/cmake-3.24.0 -- -DCMAKE_USE_OPENSSLOFF不过我认为一般不需要能装 openssl 就装上。还有一个选项是--no-qt-gui强制不构建图形界面。默认情况下只要检测不到 Qt它也不构建所以通常不用手动加。这里有一个小坑如果你在 bootstrap 之后发现编译选项想调整不要重新执行./bootstrap而是直接rm -rf CMakeCache.txt CMakeFiles重新 bootstrap不然旧配置会污染新配置。编译失败也一样先看错误输出再用make clean或者清缓存重来。4. 安装完成不等于能用PATH 配置与版本验证4.1 敲 cmake --version 还是旧版本的根因装完新 CMake 之后你可能会兴冲冲地敲cmake --version结果发现输出还是老的 2.8.12.2。我第一次编译 CMake 时就遇到这个问题第一反应是“安装失败了”其实安装完全成功问题是 shell 执行的cmake还是/usr/bin/cmake。原因很简单/usr/bin在 PATH 里的优先级通常低于/usr/local/bin但你可能既没有把/opt/cmake-3.24.0/bin加到 PATH也没有对系统里的旧 CMake 做替换。shell 按 PATH 顺序找第一个叫cmake的可执行文件找到/usr/bin/cmake就用旧版。所以安装完第一件事应该看which cmake确认它指向哪里。如果指向/usr/bin/cmake说明新版还没接管。可以用hash -r清一下 shell 的命令缓存因为 bash 会把之前找到的命令路径缓存下来即使 PATH 更新了也可能继续用旧路径。4.2 配置 PATH 的三种方式临时使用可以这样export PATH/opt/cmake-3.24.0/bin:$PATH这条命令只对当前终端会话生效关掉就没了。想持久化就把这一行加到~/.bashrc末尾然后执行source ~/.bashrc如果你用 zsh加在~/.zshrc。不建议把这种配置写在/etc/profile里因为那是系统级配置影响面太大除非你确定这台机器上所有用户都应该用新版 CMake。还有一种方式是做一个软链接sudo ln -s /opt/cmake-3.24.0/bin/cmake /usr/local/bin/cmake因为/usr/local/bin在默认 PATH 里优先级比/usr/bin高所以这条软链接能让所有用户直接使用新版 cmake。但这样做需要系统里没有其他冲突的/usr/local/bin/cmake而且要小心以后升级时先把旧软链接删掉。4.3 验证命令集合配置完成后用下面几条命令确认which cmake cmake --version ctest --version cpack --version如果which cmake返回/opt/cmake-3.24.0/bin/cmakecmake --version第一行显示cmake version 3.24.0就说明成功接管了。不过要注意一些构建脚本内部可能写死了/usr/bin/cmake绝对路径这个不会受 PATH 影响。如果你遇到脚本里调用的还是旧版本可以直接把脚本里的路径改成/opt/cmake-3.24.0/bin/cmake或者用update-alternatives配置系统级默认版本。我个人的习惯是尽量不在脚本里写绝对路径统一靠 PATH 控制然后用cmake --version在脚本开头做一次版本断言避免静默用错版本。4.4 源码编译装上后还有哪些东西除了cmake可执行文件这个安装目录里还有cmake-curses-gui之类的东西吗不一定。源码编译在默认配置下不会生成图形界面但会带ccmake吗这取决于 bootstrap 时是否检测到 ncurses。大多数情况下安装后 bin 目录里能看到cmake、ctest、cpack三个基本够用。ctest是测试驱动工具cpack是打包工具它们和cmake配套使用很多项目在 CI 里都需要。如果你发现自己运行ccmake提示命令不存在而你又需要图形化配置界面那得重新安装 libncurses-dev 后再次编译。不过对这种“服务器上编译安装”的场景来说命令行cmake已经覆盖百分之百的日常工作我不太建议为了 GUI 多折腾一轮。5. 版本冲突、编译报错和后续升级经验5.1 要不要卸载系统自带 CMake安装完新版之后很多人会想“把系统里那个旧的卸掉省得冲突”。我的建议是不要轻易卸载。系统自带的 CMake 可能被其他软件包通过依赖关系引用比如某些图形库或者系统构建脚本会调用/usr/bin/cmake。你一旦卸载旧版轻则那些软件变成 broken 状态重则某些系统升级流程直接失败。正确做法是保留旧包让新版通过 PATH 来“遮蔽”它。你验证过cmake --version显示新版之后日常使用就都是新版万一哪天需要旧版直接把 PATH 里那一行注释掉就行。这种隔离思路比暴力替换安全得多也方便回滚。5.2 编译与运行阶段常见错误排查源码编译 CMake 最常见的问题集中在 bootstrap 阶段。比如提示C compiler cannot create executables大概率是 gcc 没装或者编译器版本太老提示Could NOT find OpenSSL则看是否要补装 libssl-dev。make 阶段如果进程被 killed基本可以判断是内存不够把-j改小重新来。还有一个容易忽视的错误如果你之前已经用老版本 CMake 配置过同一个源码目录重新用新版配置时可能会报CMakeCache.txt中的版本不匹配。解决办法就是删掉这个缓存文件别让它一直留在目录里影响判断。我一般在编译前会先跑一遍rm -rf CMakeCache.txt CMakeFiles特别是反复下载不同版本试的时候。至于项目本身报CMake 3.16 or higher is required. You are running version 2.8.12.2如果你已经完成 PATH 配置再用cmake --version看到新版那这种报错不会再出现。但要注意如果你下的是 3.24.0而某个项目必须要求 3.26 或更高那 3.24 也是不够的。遇到这种情况不要抱着“应该差不多”的侥幸直接去官网拿 3.26 或更新版本省得 configure 到一半又被打回来。5.3 新版 CMake 能带来哪些实际体验变化装了 3.24.0 之后你会发现很多之前在旧版上没法用的 CMake 命令现在可以写了。比如target_precompile_headers这个功能从 CMake 3.16 开始引入但从 3.16 到 3.24 之间不断在完善。该命令可以帮你把vector、string这类常用头文件预先编译减少重复解析时间。一个典型用法是cmake_minimum_required(VERSION 3.16) project(PCHDemo CXX) add_executable(app main.cpp) target_precompile_headers(app PRIVATE vector string )如果你还在用 2.8.12.2写这段代码连target_precompile_headers这个命令都不会被识别。所以对于想尝试现代 CMake 写法的人来说手动装一个新版源码包几乎是一条必经之路。另外新版 CMake 对策略的处理更清晰CMAKE_POLICY_DEFAULT_CMP????这种解耦方式也比老版本可靠迁移项目时更容易定位问题。当然新版也会带来一些默认策略变化可能导致旧项目意外报 warning 或 error。遇到这种变化不用慌看一下它提示的策略编号可以在 CMakeLists.txt 里临时设置兼容行为但我建议还是按新版本的写法去修代码毕竟你装新版就是为了把项目往前推。5.4 内网环境与 CI 里的安装技巧如果你不是在本地开发机编译而是在内网 CI 或者离线环境下载cmake-3.24.0.tar.gz之前最好就把源码包和校验文件都放好。更好的方案是在 CI 构建机里缓存编译后的/opt/cmake-3.24.0整个目录因为 CMake 的安装目录不依赖源码目录你可以在一个地方编译好然后 tar 走。缓存一个大目录比每次跑 10 分钟编译划算得多。如果 CI 用的镜像可以直接拉官方提供的 Linux 二进制包我反而更推荐那个方案。它不需要编译解压之后同样配置 PATH 就行。源码编译的价值更多在于理解机制和适配特殊环境日常追求效率和确定性预编译包是个最优解。最后分享一个我自己的检查习惯下载后第一件事永远是sha256sum -c安装后第一件事永远是which cmake而不是cmake --version。前者能过滤掉 80% 的“编译到一半才炸”的问题后者能避免你浪费半天时间怀疑安装失败最后发现只是 PATH 顺序不对。这两个动作看着小但在多次折腾 CMake 版本的过程中真的帮我省了最多的返工时间。本文还有配套的精品资源点击获取
返回列表