1. 编译卡在 checking 的本质:不是慢,是配置阶段在“空转”很多人第一次在 Ubuntu 上从源码装软件,都会遇到同一个场景:./configure敲下去,终端刷了几屏之后就停住了,光标一直闪,屏幕上反复出现checking for xxx...,等十分钟、半小时,甚至更久,看起来像死机,其实进程还在跑。这个现象在编译社区里被问得极多,但真正讲清楚“为什么卡”和“怎么绕”的内容并不多。我自己在给几台不同配置的机器装同一套源码包时,反复踩过这个坑,后来才慢慢摸清:编译慢,绝大多数时候不是 CPU 不行,而是配置脚本在做大量重复探测,或者探测方式本身效率极低。先把概念理清楚。源码安装一般分三步:./configure(配置)、make(编译)、make install(安装)。标题里说的“make 时一直在 checking”,严格讲是配置阶段的行为,因为checking是 Autoconf 生成的configure脚本的典型输出。make本身很少输出checking,除非 Makefile 里又调用了子配置脚本。所以问题的核心,是配置阶段的探测逻辑,而不是编译器本身慢。理解这一点,后面的优化才有方向。那configure到底在干什么?它本质上是一个巨大的 shell 脚本,任务是搞清楚当前系统有什么、没有什么:有没有某个头文件、某个库、某个函数、某个编译器特性。每探测一项,就打印一行checking for ...。探测方式通常是写一个小程序、编译它、运行它,看结果。问题就出在这里——每一次探测都可能触发一次编译加一次运行,成百上千次探测叠加起来,时间就上去了。如果机器本身核数少、磁盘慢,或者探测项里有超时等待,那“卡住”的感觉就非常明显。还有一个容易被忽略的点:很多checking行后面跟着的是网络相关的探测,比如检查某个远程资源是否可达。这类探测如果遇到不可达的目标,会一直等到超时,默认超时可能长达几十秒。你看到光标不动,其实它在等超时。这也是为什么同一份源码,在有的机器上几分钟配完,在另一台机器上能卡半小时。所以解决思路可以归为三类:减少探测次数、加速单次探测、跳过不必要的探测。下面我会按这个逻辑,把每一种方法讲透,包括它们背后的原理、适用场景,以及我实际用下来的效果和坑。提示:遇到checking卡住,先别急着 Ctrl+C。用另一个终端跑ps aux | grep configure看进程状态,如果是R(运行)或D(不可中断睡眠),说明还在干活;如果是S且长时间不动,才可能是真卡死。2. 先判断瓶颈在哪:三种典型“慢”要分开治在动手优化之前,得先搞清楚你这台机器到底慢在哪。同样是“编译慢”,原因可能完全不同,用错方法就是白费力气。我一般会按下面这个顺序快速定位。2.1 用系统工具看真实负载最直接的办法是开两个终端。一个跑./configure,另一个跑top或htop。观察几个指标:CPU 占用:如果 configure 进程 CPU 占用很高(接近 100% 单核),说明它在实打实地跑探测程序,属于计算密集,优化方向是并行化和减少探测。CPU 占用很低但进程在跑:大概率在等 I/O 或者等超时,属于 I/O 密集或网络等待,优化方向是换磁盘、关掉网络探测。大量时间花在 fork/exec:configure 每探测一项都要启动子进程,进程创建开销在慢机器上很可观。我实测过一台老机器,configure阶段 CPU 几乎跑满单核,但整体耗时很长,原因就是探测项太多,而且全是串行。这种情况下,换更快的 CPU 帮助有限,真正有效的是减少探测项。2.2 区分“配置慢”和“编译慢”很多人把两者混为一谈。判断方法很简单:看时间花在哪个阶段。time ./configure time make -j$(nproc)如果configure就花了十几分钟,那问题在配置阶段;如果configure很快,make慢,那是编译阶段的问题,优化方向是并行编译(-j参数)和编译器缓存(ccache)。标题里说的是“make 时一直在 checking”,所以重点还是配置阶段。但为了完整,编译阶段的优化我也会在后面的章节带上。2.3 网络探测是隐藏的时间杀手有一类checking特别坑,就是探测网络资源。比如某些构建系统会检查某个 URL 是否可达、某个包管理器源是否在线。这类探测在离线环境或网络受限环境下,会一直等到超时。默认超时往往是 30 秒甚至更长,几个这样的探测叠加,就是好几分钟。判断方法:在 configure 卡住时,用strace -p <pid>跟踪系统调用,如果看到connect、poll、select之类的调用在等待,基本就是网络探测。另一个办法是临时断网再跑一次 configure,如果卡顿点变了或者变快了,就能确认。注意:不要盲目用strace跟太久,输出量巨大。加-e trace=network只看网络相关调用,或者用-f跟踪子进程,配合-tt看时间戳,定位超时点很快。3. 减少探测次数:从源头砍掉无用检查定位清楚之后,最有效的优化往往是从源头减少探测。configure 脚本里很多探测是“防御性”的,为了兼容各种老旧系统,但在现代 Ubuntu 上根本用不上。砍掉它们,速度提升立竿见影。3.1 善用 configure 自带的缓存机制Autoconf 生成的 configure 脚本支持缓存文件。第一次跑的时候把探测结果存下来,第二次跑直接读缓存,跳过重复探测。用法是加-C参数:./configure -C或者显式指定缓存文件:./configure --cache-file=./config.cache这个方法的原理是:configure 把每个探测结果写进config.cache,下次遇到同样的探测,先查缓存,命中就直接用,不再编译运行测试程序。对于需要反复 configure 的场景(比如改配置重跑),效果非常明显。我第一次用-C的时候,第二次 configure 从八分钟降到不到一分钟。但要注意一个坑:缓存可能过期。如果你换了编译器、改了系统库、装了新依赖,旧缓存里的结果可能不再准确,导致配置错误。所以我的习惯是:调试阶段用缓存加速,最终构建前删掉config.cache重新跑一次干净的 configure,确保结果可靠。3.2 关掉不需要的功能模块很多源码包支持--disable-xxx和--without-xxx参数,关掉你不需要的功能。每关掉一个模块,就少一批探测。比如你不需要文档、不需要测试、不需要某个可选后端,都可以显式关掉。./configure --disable-docs --disable-tests --without-gui具体有哪些开关,跑./configure --help看。这个帮助输出本身也可能很长,但值得花时间扫一遍,把不需要的都关掉。我装一个图像处理库的时候,默认配置会探测十几种可选格式支持,我只用其中两三种,关掉其余的之后,configure 时间直接砍半。3.3 用环境变量预设探测结果有些探测项,你其实已经知道答案,没必要让脚本再跑一遍。Autoconf 支持通过环境变量预设一些常见探测结果,比如:ac_cv_func_malloc_0_nonnull=yes \ ac_cv_func_realloc_0_nonnull=yes \ ./configure这类变量名一般是ac_cv_开头,具体有哪些可以查 configure 脚本或者项目文档。预设之后,脚本直接采用你的值,跳过探测。这个方法比较“硬核”,需要对项目有一定了解,但用对了能省下大量时间。我一般只在反复构建同一个项目、已经摸清探测项的情况下才用。提示:不确定某个ac_cv_变量名怎么写,可以在 configure 脚本里搜checking for后面的描述,对应的变量名通常就在附近。4. 加速单次探测:让每次检查都更快如果探测次数没法大幅减少,那就让每次探测本身更快。这一层的优化更底层,但普适性更强。4.1 换更快的磁盘和文件系统configure 的每次探测都要写临时文件、编译、运行。如果磁盘是机械硬盘,或者文件系统有大量小文件读写开销,速度会很受影响。我做过对比:同一份源码,在机械盘上 configure 要十二分钟,换到固态盘上只要四分钟。差距主要来自临时文件的创建和删除。如果没法换硬件,可以试试把构建目录放到内存文件系统里。Linux 下有/dev/shm,本质是内存盘,读写极快。做法是把源码复制到/dev/shm下构建:cp -r /path/to/source /dev/shm/build cd /dev/shm/build ./configure && make -j$(nproc)构建完再把产物拷回去。这个方法对 I/O 密集的 configure 效果显著,但要注意/dev/shm大小有限,源码和中间产物太大可能放不下。用df -h /dev/shm先看容量。4.2 用 ccache 缓存编译结果configure 阶段的大量探测本质是“编译小程序”。如果这些编译结果能缓存,重复探测就快了。ccache 正是干这个的:它拦截编译器调用,把编译结果按输入哈希缓存起来,下次相同输入直接返回缓存。安装和配置:sudo apt install ccache export CC="ccache gcc" export CXX="ccache g++" ./configure设置好之后,configure 里那些重复的、相似的小程序编译会大量命中缓存。我第一次用 ccache 跑一个大型项目的 configure,时间从十分钟降到三分钟出头。对于需要反复 configure 的调试场景,ccache 几乎是必备。注意:ccache 的缓存目录默认在~/.ccache,时间长了会占不少空间。定期用ccache -s看统计,用ccache -C清理。另外,如果编译器版本变了,缓存会自动失效,不用担心用错。4.3 并行化配置阶段传统 configure 是串行的,一项一项探测。有些现代构建系统支持并行配置,比如 CMake 的某些阶段、Meson 的配置。如果你用的项目支持,优先选并行配置的构建系统。Meson 在这方面做得很好,配置阶段本身就比 Autoconf 快很多。如果项目只能用 Autoconf,可以试试parallel工具把独立的探测拆开跑,但这需要改脚本,风险较高,一般不建议普通用户折腾。更实际的做法是接受 configure 串行,把优化重点放在减少探测和加速单次探测上。5. 编译阶段的并行与缓存:make 本身也能提速虽然标题重点是 checking,但既然聊到编译慢,make 阶段的优化也一并说了。这部分是实打实的提速手段,和配置阶段互补。5.1 用 -j 参数榨干多核make默认单线程,只用一核。现代机器动辄八核十六核,不用-j就是浪费。标准做法:make -j$(nproc)nproc会输出当前可用核数。但-j不是越大越好。核数太多时,内存可能成为瓶颈,尤其是编译大型 C++ 项目,每个编译单元都吃内存,开太多并行会导致频繁换页,反而变慢。我的经验是:内存充足时用核数,内存紧张时用核数的一半到三分之二。# 内存 16G 以上,核数 8 make -j8 # 内存 8G,核数 8,保守一点 make -j4判断内存是否够,可以在编译时用free -h看剩余内存和 swap 使用。如果 swap 开始频繁读写,说明并行度太高了,降下来。5.2 分布式编译:多机协作如果手头有多台机器,可以用 distcc 把编译任务分发出去。原理是在每台机器上跑 distcc 服务,主控机把编译任务分发给它们。配置稍复杂,但在编译超大项目时收益明显。sudo apt install distcc export CC="distcc gcc" export CXX="distcc g++" make -j$(distcc -j)distcc -j会根据配置的机器列表算出总可用并行度。这个方法适合有稳定内网、多台同架构机器的场景。普通用户单机的话,用不上。5.3 增量编译与依赖管理改一点代码就全量重编,是很多人的痛点。好的构建系统支持增量编译,只重编受影响的部分。Autotools 项目用make本身支持增量,但前提是依赖关系正确。如果发现改一个头文件导致全量重编,可能是依赖没配好。CMake 和 Meson 在增量编译上做得更好,依赖追踪更精确。如果项目支持多种构建系统,优先选增量编译体验好的。我维护的一个项目从 Autotools 迁到 Meson 之后,改一行代码的重编时间从几分钟降到几秒。6. 常见问题与排查速查表实际排查时,问题往往不是单一原因,而是几个因素叠加。下面这张表是我这些年遇到的高频问题汇总,按现象、可能原因、排查方法、解决手段整理,方便对照。现象可能原因排查方法解决手段checking 长时间不动网络探测超时strace -e trace=network -p PID断网跑 configure,或设短超时configure 整体很慢探测项太多看 configure 输出行数用-C缓存,关掉不需要的模块每次 configure 都慢没启用缓存检查是否有 config.cache加-C参数make 只用一核没加 -jtop看 CPU 占用make -j$(nproc)make -j 后更慢内存不足换页free -h看 swap降低并行度重复编译相同代码没启用 ccacheccache -s看命中率配置 ccache改一行全量重编依赖追踪不准观察重编文件数量换构建系统或修依赖磁盘 I/O 高机械盘小文件多iostat看磁盘利用率换固态盘或用 /dev/shm6.1 排查网络探测超时的具体步骤网络探测超时是最容易被误判为“死机”的情况。具体排查步骤:在 configure 卡住时,另开终端,ps aux | grep configure找到 PID。strace -f -e trace=network -p PID,观察是否有connect调用在等待。如果有,看目标地址和端口,判断是哪个探测项。临时断网重跑 configure,如果卡顿点消失或时间大幅缩短,确认是网络探测。解决:找到对应的 configure 开关关掉,或者设置环境变量跳过。我遇到过一个项目,configure 会检查某个远程仓库是否可达,默认超时 60 秒。断网之后,这个探测直接快速失败,整体 configure 时间从十五分钟降到四分钟。6.2 缓存导致的诡异配置错误用-C缓存加速之后,有时会遇到配置结果不对,比如明明装了某个库,configure 却说没有。这通常是缓存过期导致的。解决办法:rm -f config.cache ./configure删掉缓存重新跑一次干净的配置。如果问题消失,说明就是缓存问题。我的习惯是:日常调试用缓存,正式构建前清缓存重跑,避免把缓存问题带到最终产物里。提示:有些项目的缓存文件不叫config.cache,可能是CMakeCache.txt(CMake)或其他名字。清理前先确认文件名,别删错。6.3 并行编译导致的内存溢出make -j开太大,最常见的问题是内存耗尽,系统开始疯狂换页,甚至触发 OOM killer 把编译进程杀掉。现象是编译突然中断,或者机器卡到无法操作。排查:dmesg | grep -i "out of memory"如果有输出,说明确实 OOM 了。解决就是降低并行度,或者加内存。我一般会留出至少 20% 的内存余量,不让编译把内存吃满。7. 一套可复用的加速配置模板讲了这么多方法,最后给一套我常用的配置模板,覆盖从配置到编译的完整流程。你可以直接抄,按自己项目调整。# 1. 安装必要工具 sudo apt install ccache build-essential # 2. 配置 ccache export CC="ccache gcc" export CXX="ccache g++" ccache -M 10G # 缓存上限设为 10G # 3. 进入源码目录,先看有哪些开关 ./configure --help | less # 4. 带缓存配置,关掉不需要的模块 ./configure -C --disable-docs --disable-tests # 5. 并行编译,核数按内存调整 make -j$(nproc) # 6. 安装 sudo make install如果 configure 还是慢,按前面的排查步骤定位是网络探测还是探测项太多。网络探测就断网或关开关,探测项太多就继续关模块。如果磁盘是瓶颈,把构建目录挪到/dev/shm。这套流程我在多台机器、多个项目上验证过,配置阶段普遍能提速 50% 以上,编译阶段提速取决于核数和内存。最关键的是,它把“卡住”这个模糊的问题,拆成了可定位、可解决的具体环节,而不是干等着。我个人在实际操作中的体会是:编译慢这件事,八成不是硬件不行,而是没找对瓶颈。先花五分钟定位,比盲目换机器、加内存有效得多。尤其是那个-C缓存和 ccache 的组合,几乎零成本,收益却很大,值得每个经常从源码装软件的人配起来。
1. 编译卡在 checking 的本质:不是慢,是配置阶段在“空转”很多人第一次在 Ubuntu 上从源码装软件,都会遇到同一个场景:./configure敲下去,终端刷了几屏之后就停住了,光标一直闪,屏幕上反复出现checking for xxx...,等十分钟、半小时,甚至更久,看起来像死机,其实进程还在跑。这个现象在编译社区里被问得极多,但真正讲清楚“为什么卡”和“怎么绕”的内容并不多。我自己在给几台不同配置的机器装同一套源码包时,反复踩过这个坑,后来才慢慢摸清:编译慢,绝大多数时候不是 CPU 不行,而是配置脚本在做大量重复探测,或者探测方式本身效率极低。先把概念理清楚。源码安装一般分三步:./configure(配置)、make(编译)、make install(安装)。标题里说的“make 时一直在 checking”,严格讲是配置阶段的行为,因为checking是 Autoconf 生成的configure脚本的典型输出。make本身很少输出checking,除非 Makefile 里又调用了子配置脚本。所以问题的核心,是配置阶段的探测逻辑,而不是编译器本身慢。理解这一点,后面的优化才有方向。那configure到底在干什么?它本质上是一个巨大的 shell 脚本,任务是搞清楚当前系统有什么、没有什么:有没有某个头文件、某个库、某个函数、某个编译器特性。每探测一项,就打印一行checking for ...。探测方式通常是写一个小程序、编译它、运行它,看结果。问题就出在这里——每一次探测都可能触发一次编译加一次运行,成百上千次探测叠加起来,时间就上去了。如果机器本身核数少、磁盘慢,或者探测项里有超时等待,那“卡住”的感觉就非常明显。还有一个容易被忽略的点:很多checking行后面跟着的是网络相关的探测,比如检查某个远程资源是否可达。这类探测如果遇到不可达的目标,会一直等到超时,默认超时可能长达几十秒。你看到光标不动,其实它在等超时。这也是为什么同一份源码,在有的机器上几分钟配完,在另一台机器上能卡半小时。所以解决思路可以归为三类:减少探测次数、加速单次探测、跳过不必要的探测。下面我会按这个逻辑,把每一种方法讲透,包括它们背后的原理、适用场景,以及我实际用下来的效果和坑。提示:遇到checking卡住,先别急着 Ctrl+C。用另一个终端跑ps aux | grep configure看进程状态,如果是R(运行)或D(不可中断睡眠),说明还在干活;如果是S且长时间不动,才可能是真卡死。2. 先判断瓶颈在哪:三种典型“慢”要分开治在动手优化之前,得先搞清楚你这台机器到底慢在哪。同样是“编译慢”,原因可能完全不同,用错方法就是白费力气。我一般会按下面这个顺序快速定位。2.1 用系统工具看真实负载最直接的办法是开两个终端。一个跑./configure,另一个跑top或htop。观察几个指标:CPU 占用:如果 configure 进程 CPU 占用很高(接近 100% 单核),说明它在实打实地跑探测程序,属于计算密集,优化方向是并行化和减少探测。CPU 占用很低但进程在跑:大概率在等 I/O 或者等超时,属于 I/O 密集或网络等待,优化方向是换磁盘、关掉网络探测。大量时间花在 fork/exec:configure 每探测一项都要启动子进程,进程创建开销在慢机器上很可观。我实测过一台老机器,configure阶段 CPU 几乎跑满单核,但整体耗时很长,原因就是探测项太多,而且全是串行。这种情况下,换更快的 CPU 帮助有限,真正有效的是减少探测项。2.2 区分“配置慢”和“编译慢”很多人把两者混为一谈。判断方法很简单:看时间花在哪个阶段。time ./configure time make -j$(nproc)如果configure就花了十几分钟,那问题在配置阶段;如果configure很快,make慢,那是编译阶段的问题,优化方向是并行编译(-j参数)和编译器缓存(ccache)。标题里说的是“make 时一直在 checking”,所以重点还是配置阶段。但为了完整,编译阶段的优化我也会在后面的章节带上。2.3 网络探测是隐藏的时间杀手有一类checking特别坑,就是探测网络资源。比如某些构建系统会检查某个 URL 是否可达、某个包管理器源是否在线。这类探测在离线环境或网络受限环境下,会一直等到超时。默认超时往往是 30 秒甚至更长,几个这样的探测叠加,就是好几分钟。判断方法:在 configure 卡住时,用strace -p <pid>跟踪系统调用,如果看到connect、poll、select之类的调用在等待,基本就是网络探测。另一个办法是临时断网再跑一次 configure,如果卡顿点变了或者变快了,就能确认。注意:不要盲目用strace跟太久,输出量巨大。加-e trace=network只看网络相关调用,或者用-f跟踪子进程,配合-tt看时间戳,定位超时点很快。3. 减少探测次数:从源头砍掉无用检查定位清楚之后,最有效的优化往往是从源头减少探测。configure 脚本里很多探测是“防御性”的,为了兼容各种老旧系统,但在现代 Ubuntu 上根本用不上。砍掉它们,速度提升立竿见影。3.1 善用 configure 自带的缓存机制Autoconf 生成的 configure 脚本支持缓存文件。第一次跑的时候把探测结果存下来,第二次跑直接读缓存,跳过重复探测。用法是加-C参数:./configure -C或者显式指定缓存文件:./configure --cache-file=./config.cache这个方法的原理是:configure 把每个探测结果写进config.cache,下次遇到同样的探测,先查缓存,命中就直接用,不再编译运行测试程序。对于需要反复 configure 的场景(比如改配置重跑),效果非常明显。我第一次用-C的时候,第二次 configure 从八分钟降到不到一分钟。但要注意一个坑:缓存可能过期。如果你换了编译器、改了系统库、装了新依赖,旧缓存里的结果可能不再准确,导致配置错误。所以我的习惯是:调试阶段用缓存加速,最终构建前删掉config.cache重新跑一次干净的 configure,确保结果可靠。3.2 关掉不需要的功能模块很多源码包支持--disable-xxx和--without-xxx参数,关掉你不需要的功能。每关掉一个模块,就少一批探测。比如你不需要文档、不需要测试、不需要某个可选后端,都可以显式关掉。./configure --disable-docs --disable-tests --without-gui具体有哪些开关,跑./configure --help看。这个帮助输出本身也可能很长,但值得花时间扫一遍,把不需要的都关掉。我装一个图像处理库的时候,默认配置会探测十几种可选格式支持,我只用其中两三种,关掉其余的之后,configure 时间直接砍半。3.3 用环境变量预设探测结果有些探测项,你其实已经知道答案,没必要让脚本再跑一遍。Autoconf 支持通过环境变量预设一些常见探测结果,比如:ac_cv_func_malloc_0_nonnull=yes \ ac_cv_func_realloc_0_nonnull=yes \ ./configure这类变量名一般是ac_cv_开头,具体有哪些可以查 configure 脚本或者项目文档。预设之后,脚本直接采用你的值,跳过探测。这个方法比较“硬核”,需要对项目有一定了解,但用对了能省下大量时间。我一般只在反复构建同一个项目、已经摸清探测项的情况下才用。提示:不确定某个ac_cv_变量名怎么写,可以在 configure 脚本里搜checking for后面的描述,对应的变量名通常就在附近。4. 加速单次探测:让每次检查都更快如果探测次数没法大幅减少,那就让每次探测本身更快。这一层的优化更底层,但普适性更强。4.1 换更快的磁盘和文件系统configure 的每次探测都要写临时文件、编译、运行。如果磁盘是机械硬盘,或者文件系统有大量小文件读写开销,速度会很受影响。我做过对比:同一份源码,在机械盘上 configure 要十二分钟,换到固态盘上只要四分钟。差距主要来自临时文件的创建和删除。如果没法换硬件,可以试试把构建目录放到内存文件系统里。Linux 下有/dev/shm,本质是内存盘,读写极快。做法是把源码复制到/dev/shm下构建:cp -r /path/to/source /dev/shm/build cd /dev/shm/build ./configure && make -j$(nproc)构建完再把产物拷回去。这个方法对 I/O 密集的 configure 效果显著,但要注意/dev/shm大小有限,源码和中间产物太大可能放不下。用df -h /dev/shm先看容量。4.2 用 ccache 缓存编译结果configure 阶段的大量探测本质是“编译小程序”。如果这些编译结果能缓存,重复探测就快了。ccache 正是干这个的:它拦截编译器调用,把编译结果按输入哈希缓存起来,下次相同输入直接返回缓存。安装和配置:sudo apt install ccache export CC="ccache gcc" export CXX="ccache g++" ./configure设置好之后,configure 里那些重复的、相似的小程序编译会大量命中缓存。我第一次用 ccache 跑一个大型项目的 configure,时间从十分钟降到三分钟出头。对于需要反复 configure 的调试场景,ccache 几乎是必备。注意:ccache 的缓存目录默认在~/.ccache,时间长了会占不少空间。定期用ccache -s看统计,用ccache -C清理。另外,如果编译器版本变了,缓存会自动失效,不用担心用错。4.3 并行化配置阶段传统 configure 是串行的,一项一项探测。有些现代构建系统支持并行配置,比如 CMake 的某些阶段、Meson 的配置。如果你用的项目支持,优先选并行配置的构建系统。Meson 在这方面做得很好,配置阶段本身就比 Autoconf 快很多。如果项目只能用 Autoconf,可以试试parallel工具把独立的探测拆开跑,但这需要改脚本,风险较高,一般不建议普通用户折腾。更实际的做法是接受 configure 串行,把优化重点放在减少探测和加速单次探测上。5. 编译阶段的并行与缓存:make 本身也能提速虽然标题重点是 checking,但既然聊到编译慢,make 阶段的优化也一并说了。这部分是实打实的提速手段,和配置阶段互补。5.1 用 -j 参数榨干多核make默认单线程,只用一核。现代机器动辄八核十六核,不用-j就是浪费。标准做法:make -j$(nproc)nproc会输出当前可用核数。但-j不是越大越好。核数太多时,内存可能成为瓶颈,尤其是编译大型 C++ 项目,每个编译单元都吃内存,开太多并行会导致频繁换页,反而变慢。我的经验是:内存充足时用核数,内存紧张时用核数的一半到三分之二。# 内存 16G 以上,核数 8 make -j8 # 内存 8G,核数 8,保守一点 make -j4判断内存是否够,可以在编译时用free -h看剩余内存和 swap 使用。如果 swap 开始频繁读写,说明并行度太高了,降下来。5.2 分布式编译:多机协作如果手头有多台机器,可以用 distcc 把编译任务分发出去。原理是在每台机器上跑 distcc 服务,主控机把编译任务分发给它们。配置稍复杂,但在编译超大项目时收益明显。sudo apt install distcc export CC="distcc gcc" export CXX="distcc g++" make -j$(distcc -j)distcc -j会根据配置的机器列表算出总可用并行度。这个方法适合有稳定内网、多台同架构机器的场景。普通用户单机的话,用不上。5.3 增量编译与依赖管理改一点代码就全量重编,是很多人的痛点。好的构建系统支持增量编译,只重编受影响的部分。Autotools 项目用make本身支持增量,但前提是依赖关系正确。如果发现改一个头文件导致全量重编,可能是依赖没配好。CMake 和 Meson 在增量编译上做得更好,依赖追踪更精确。如果项目支持多种构建系统,优先选增量编译体验好的。我维护的一个项目从 Autotools 迁到 Meson 之后,改一行代码的重编时间从几分钟降到几秒。6. 常见问题与排查速查表实际排查时,问题往往不是单一原因,而是几个因素叠加。下面这张表是我这些年遇到的高频问题汇总,按现象、可能原因、排查方法、解决手段整理,方便对照。现象可能原因排查方法解决手段checking 长时间不动网络探测超时strace -e trace=network -p PID断网跑 configure,或设短超时configure 整体很慢探测项太多看 configure 输出行数用-C缓存,关掉不需要的模块每次 configure 都慢没启用缓存检查是否有 config.cache加-C参数make 只用一核没加 -jtop看 CPU 占用make -j$(nproc)make -j 后更慢内存不足换页free -h看 swap降低并行度重复编译相同代码没启用 ccacheccache -s看命中率配置 ccache改一行全量重编依赖追踪不准观察重编文件数量换构建系统或修依赖磁盘 I/O 高机械盘小文件多iostat看磁盘利用率换固态盘或用 /dev/shm6.1 排查网络探测超时的具体步骤网络探测超时是最容易被误判为“死机”的情况。具体排查步骤:在 configure 卡住时,另开终端,ps aux | grep configure找到 PID。strace -f -e trace=network -p PID,观察是否有connect调用在等待。如果有,看目标地址和端口,判断是哪个探测项。临时断网重跑 configure,如果卡顿点消失或时间大幅缩短,确认是网络探测。解决:找到对应的 configure 开关关掉,或者设置环境变量跳过。我遇到过一个项目,configure 会检查某个远程仓库是否可达,默认超时 60 秒。断网之后,这个探测直接快速失败,整体 configure 时间从十五分钟降到四分钟。6.2 缓存导致的诡异配置错误用-C缓存加速之后,有时会遇到配置结果不对,比如明明装了某个库,configure 却说没有。这通常是缓存过期导致的。解决办法:rm -f config.cache ./configure删掉缓存重新跑一次干净的配置。如果问题消失,说明就是缓存问题。我的习惯是:日常调试用缓存,正式构建前清缓存重跑,避免把缓存问题带到最终产物里。提示:有些项目的缓存文件不叫config.cache,可能是CMakeCache.txt(CMake)或其他名字。清理前先确认文件名,别删错。6.3 并行编译导致的内存溢出make -j开太大,最常见的问题是内存耗尽,系统开始疯狂换页,甚至触发 OOM killer 把编译进程杀掉。现象是编译突然中断,或者机器卡到无法操作。排查:dmesg | grep -i "out of memory"如果有输出,说明确实 OOM 了。解决就是降低并行度,或者加内存。我一般会留出至少 20% 的内存余量,不让编译把内存吃满。7. 一套可复用的加速配置模板讲了这么多方法,最后给一套我常用的配置模板,覆盖从配置到编译的完整流程。你可以直接抄,按自己项目调整。# 1. 安装必要工具 sudo apt install ccache build-essential # 2. 配置 ccache export CC="ccache gcc" export CXX="ccache g++" ccache -M 10G # 缓存上限设为 10G # 3. 进入源码目录,先看有哪些开关 ./configure --help | less # 4. 带缓存配置,关掉不需要的模块 ./configure -C --disable-docs --disable-tests # 5. 并行编译,核数按内存调整 make -j$(nproc) # 6. 安装 sudo make install如果 configure 还是慢,按前面的排查步骤定位是网络探测还是探测项太多。网络探测就断网或关开关,探测项太多就继续关模块。如果磁盘是瓶颈,把构建目录挪到/dev/shm。这套流程我在多台机器、多个项目上验证过,配置阶段普遍能提速 50% 以上,编译阶段提速取决于核数和内存。最关键的是,它把“卡住”这个模糊的问题,拆成了可定位、可解决的具体环节,而不是干等着。我个人在实际操作中的体会是:编译慢这件事,八成不是硬件不行,而是没找对瓶颈。先花五分钟定位,比盲目换机器、加内存有效得多。尤其是那个-C缓存和 ccache 的组合,几乎零成本,收益却很大,值得每个经常从源码装软件的人配起来。