distcc + ccache 编译递归问题排查总结

文章目录

前言

打不过就加入,既然AI强那就不能一味地排斥,可以让它为我所用,这个问题解决过程中它也是一直误导我,最终我找到证据了告诉它,AI才分析的有点道理,情况就是我一直用着ccache+distcc的组合没问题,但是今天突然就编译不成功了,经过反复实验发现是更新代码后,其他人在CMakeLists.txt中增加了 RULE_LAUNCH_COMPILE 来控制ccache,和我本地的distcc冲突了,这还是我翻日志发现的,在我发现之前AI就说我本地的配置问题,不过最后关于这个问题的总结还是交给AI来做,毕竟这是它擅长的领域。


解决过程

一、问题背景

在一个 CMake + Make 的 C++ 项目中,引入了:

  • ccache:用于加速本地编译
  • distcc:用于分布式编译

编译脚本如下:

bash 复制代码
cmake ../../../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DWITH_COV=OFF
CCACHE_PREFIX=distcc make -j12

同时系统环境中存在:

bash 复制代码
PATH="/usr/lib/ccache:$PATH"

即 gcc/g++ 被 ccache wrapper 接管。


二、问题现象

编译过程中出现:

text 复制代码
distcc ... failed with exit code 111
CRITICAL! distcc seems to have invoked itself recursively!

特点:

  • 远端编译失败
  • 本地 fallback 后仍失败
  • 出现 distcc 递归调用警告

三、关键变更(触发问题)

CMakeLists.txt 中新增:

cmake 复制代码
FIND_PROGRAM(CCACHE_PROGRAM ccache)
IF(CCACHE_PROGRAM)
    SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
ENDIF()

四、问题定位过程

对比cmake生成的 build.make 编译命令发现:

未启用 RULE_LAUNCH_COMPILE:

bash 复制代码
/usr/lib/ccache/c++

启用 RULE_LAUNCH_COMPILE:

bash 复制代码
/usr/bin/ccache /usr/lib/ccache/c++

👉 差异:多了一层 ccache


五、问题根因分析(核心)

梳理下编译链结构:

情况 A(正常)

text 复制代码
gcc(ccache wrapper)
 → ccache
 → distcc(通过 CCACHE_PREFIX)
 → remote gcc

👉 单层 ccache ✔


情况 B(出问题)

text 复制代码
ccache(CMake 注入)
 → ccache(PATH wrapper)
 → distcc
 → remote
 → ccache(远端)
 → distcc
 → ...

👉 双层 ccache ❌ → 递归


六、递归产生的关键条件

必须同时满足:

条件1:CMake 注入 ccache

cmake 复制代码
RULE_LAUNCH_COMPILE = ccache

条件2:PATH 中存在 ccache wrapper

bash 复制代码
/usr/lib/ccache/g++

条件3:启用 distcc

bash 复制代码
CCACHE_PREFIX=distcc

七、递归链条(完整还原)

text 复制代码
ccache(外层)
 → distcc
 → ccache(内层)
 → distcc
 → ccache
 → ...

👉 💥 无限递归


八、为什么以前正常

可能原因:

  • ccache 命中率高(未触发 distcc)
  • distcc 未 fallback
  • 未使用 CMake launcher(只有一层 ccache)

九、解决方案(最终方案)

✔ CMake 控制 ccache 是否启用

cmake 复制代码
option(USE_DISTCC "Enable distcc build" OFF)

FIND_PROGRAM(CCACHE_PROGRAM ccache)
IF(CCACHE_PROGRAM)
    if(NOT USE_DISTCC)
        SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
    ENDIF()
ENDIF()

✔ 构建方式

distcc 模式
bash 复制代码
cmake ... -DUSE_DISTCC=ON
CCACHE_PREFIX=distcc make -j12

ccache 本地模式
bash 复制代码
cmake ... -DUSE_DISTCC=OFF
make -j12

十、核心原则(非常重要)

⚠️ 原则1:ccache 只能有一个入口

合法:

text 复制代码
ccache → distcc → gcc

非法:

text 复制代码
ccache → ccache → distcc → gcc

⚠️ 原则2:不要混用三种注入方式

方式 是否推荐
PATH /usr/lib/ccache ✔ 可用
RULE_LAUNCH_COMPILE ✔ 可用
CCACHE_PREFIX=distcc ✔ 可用
三者同时用 ❌ 禁止

⚠️ 原则3:distcc worker 必须是"干净 gcc"

远端必须:

bash 复制代码
which gcc → /usr/bin/gcc

不能是:

bash 复制代码
/usr/lib/ccache/gcc

十一、调试方法总结

查看真实编译命令

bash 复制代码
make VERBOSE=1

查看执行链(最强)

bash 复制代码
strace -f -e execve make -j1

查看 distcc 行为

bash 复制代码
DISTCC_VERBOSE=1 make -j1

查看 ccache 状态

bash 复制代码
ccache -s

十二、经验总结

本次问题本质

❗ 不是 distcc 或 ccache bug

❗ 而是"编译链多层 wrapper 冲突"


一句话结论

👉 编译链中只能有一个"入口控制点"


十三、推荐最佳实践(最终建议)

✔ 推荐结构

distcc 模式
bash 复制代码
PATH=/usr/bin:/bin
CCACHE_PREFIX=distcc
ccache 模式
cmake 复制代码
RULE_LAUNCH_COMPILE=ccache

❌ 避免

bash 复制代码
PATH=/usr/lib/ccache
+ RULE_LAUNCH_COMPILE=ccache
+ CCACHE_PREFIX=distcc

十四、附加优化(可选)

可以进一步优化为:

  • 用 CMake 控制 distcc / ccache 模式
  • 不依赖 PATH 劫持
  • 使用:
cmake 复制代码
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)

替代 RULE_LAUNCH_COMPILE(更标准)


补充说明(关键补充)


✔ 补充1:PATH + CCACHE_PREFIX 组合是安全的

bash 复制代码
PATH="/usr/lib/ccache:$PATH"
CCACHE_PREFIX=distcc

👉 这一组合本身是没有问题的

执行链为:

text 复制代码
gcc(ccache wrapper)
 → ccache
 → distcc
 → remote gcc

✔ 单层 ccache

✔ 不会递归


👉 问题只在于叠加了 CMake 的 ccache launcher


✔ 补充2:调试日志方法(非常重要)

可以通过以下环境变量查看完整调用链:

bash 复制代码
export CCACHE_DEBUG=1
export CCACHE_LOGFILE=/tmp/ccache.log
export DISTCC_VERBOSE=1

各变量作用

CCACHE_DEBUG
text 复制代码
开启 ccache 调试模式
CCACHE_LOGFILE
text 复制代码
输出 ccache 执行日志(包含命中、调用链等)
DISTCC_VERBOSE
text 复制代码
输出 distcc 分发、fallback、远端执行信息

实际用途

可以观察:

  • ccache 是否命中
  • 是否调用 distcc
  • distcc 是否 fallback
  • 是否发生递归调用

✔ 补充3:distcc和ccache的在成功失败的日志对比

这一部分是最终确认问题根因的关键证据


distcc 日志对比

失败的日志:

复制代码
distcc[134131] (dcc_scan_args) scanning arguments: /usr/lib/ccache/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
distcc[134131] (dcc_scan_args) found object/output file "CMakeFiles/kwgame_logicplugin.dir/kwboardmodule.cpp.o"
distcc[134131] (dcc_scan_args) found input file "xxx"

成功的日志

复制代码
distcc[135925] (dcc_scan_args) scanning arguments: /usr/bin/c++ -fPIC -O0 -Wall -g -ggdb -DDEBUG -g -shared -Wl,-soname,kwgame_logicplugin.so -o xxx
distcc[135925] (dcc_scan_args) found object/output file "../../../../../../../debug/kwgame_logicplugin.so"
distcc[135925] (dcc_scan_args) found object/output file "CMakeFiles/kwgame_logicplugin.dir/xxx.cpp.o"

失败情况

text 复制代码
distcc ... scanning arguments: /usr/lib/ccache/c++

👉 关键点:

❗ distcc 收到的是 /usr/lib/ccache/c++


成功情况

text 复制代码
distcc ... scanning arguments: /usr/bin/c++

👉 关键点:

✔ distcc 收到的是"真实编译器"


结论(非常重要)

❗ distcc 是否递归,取决于它收到的是:

  • /usr/lib/ccache/c++ → ❌ 会递归
  • /usr/bin/c++ → ✔ 正常

ccache 日志对比

失败的日志:

复制代码
[2026-04-17T11:00:38.365957 134110] === CCACHE 3.7.7 STARTED =========================================
...
[2026-04-17T11:00:38.366080 134110] Command line: /usr/bin/ccache /usr/lib/ccache/c++ -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:00:38.369547 134110] No such manifest file
[2026-04-17T11:00:38.369554 134110] Did not find object file hash in manifest
[2026-04-17T11:00:38.371333 134110] Running preprocessor
[2026-04-17T11:00:38.371355 134110] Executing /usr/lib/ccache/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
[2026-04-17T11:00:38.371968 134111] === CCACHE 3.7.7 STARTED =========================================
...
[2026-04-17T11:00:38.372098 134111] Command line: /usr/lib/ccache/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:00:38.372250 134111] Using command-line prefix distcc
[2026-04-17T11:00:38.372258 134111] Failed; falling back to running the real compiler
[2026-04-17T11:00:38.372263 134111] Executing /usr/bin/distcc /usr/bin/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
[2026-04-17T11:00:38.372284 134111] Result: called for preprocessing
...
2026-04-17T11:00:38.912259 134110] Using command-line prefix distcc
[2026-04-17T11:00:38.912272 134110] Running real compiler
[2026-04-17T11:00:38.912855 134110] Executing /usr/bin/distcc /usr/lib/ccache/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
[2026-04-17T11:00:38.915592 134132] === CCACHE 3.7.7 STARTED =========================================
...
[2026-04-17T11:00:38.915718 134132] Command line: /usr/lib/ccache/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:00:38.918396 134132] Did not find object file hash in manifest
[2026-04-17T11:00:38.919801 134132] Running preprocessor
[2026-04-17T11:00:38.919811 134132] Executing /usr/bin/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
[2026-04-17T11:00:39.490500 134132] Got object file hash from preprocessor
[2026-04-17T11:00:39.490542 134132] Object file /home/shz/.ccache/5/2/e126701e9f4e861edf1abfdd9a15d7-11562023.o not in cache
[2026-04-17T11:00:39.490591 134132] Using command-line prefix distcc
[2026-04-17T11:00:39.490608 134132] Running real compiler
[2026-04-17T11:00:39.490651 134132] Executing /usr/bin/distcc /usr/bin/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:00:39.498410 134132] Result: compile failed

成功的日志:

复制代码
[2026-04-17T11:04:58.767050 135920] === CCACHE 3.7.7 STARTED =========================================
[2026-04-17T11:04:58.767220 135920] Command line: /usr/lib/ccache/c++ -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:30:25.416455 138404] No such manifest file
[2026-04-17T11:30:25.416463 138404] Did not find object file hash in manifest
[2026-04-17T11:30:25.417699 138404] Running preprocessor
[2026-04-17T11:30:25.417715 138404] Executing /usr/bin/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:30:25.989594 138404] Using command-line prefix distcc
[2026-04-17T11:30:25.989603 138404] Running real compiler
[2026-04-17T11:30:25.989642 138404] Executing /usr/bin/distcc /usr/bin/c++ -O0 -Wall -g -ggdb -g -fPIC -std=c++2a -DELPP_NO_DEFAULT_LOG_FILE -DRECORD_FAST_QUERY_MODE -Dkwgame_logicplugin_EXPORTS -I/xxx.cpp
...
[2026-04-17T11:30:43.583089 138505] === CCACHE 3.7.7 STARTED =========================================
...
[2026-04-17T11:30:43.583222 138505] Command line: /usr/lib/ccache/c++ -fPIC -O0 -Wall -g -ggdb -DDEBUG -g -shared -Wl,-soname,kwgame_logicplugin.so -o ../../../../../../../debug/kwgame_logicplugin.so xxx
...
[2026-04-17T11:30:43.583393 138505] Using command-line prefix distcc
[2026-04-17T11:30:43.583404 138505] Failed; falling back to running the real compiler
[2026-04-17T11:30:43.583408 138505] Executing /usr/bin/distcc /usr/bin/c++ -fPIC -O0 -Wall -g -ggdb -DDEBUG -g -shared -Wl,-soname,kwgame_logicplugin.so -o ../../../../../../../debug/kwgame_logicplugin.so xxx
[2026-04-17T11:30:43.583447 138505] Result: called for link

失败链路(关键片段)

text 复制代码
Command line:
/usr/bin/ccache /usr/lib/ccache/c++

👉 第一层 ccache(CMake 注入)


text 复制代码
Executing /usr/lib/ccache/c++

👉 第二层 ccache(PATH wrapper)


text 复制代码
Using command-line prefix distcc
Executing /usr/bin/distcc /usr/lib/ccache/c++

👉 distcc 收到 ccache wrapper ❌


text 复制代码
=== CCACHE STARTED AGAIN
Command line: /usr/lib/ccache/c++

👉 💥 第二次进入 ccache


失败链路总结

text 复制代码
ccache
 → ccache
 → distcc
 → ccache
 → distcc
 → ...

👉 无限递归成立


成功链路(关键片段)

text 复制代码
Executing /usr/bin/c++

👉 ✔ 直接进入真实编译器


text 复制代码
Executing /usr/bin/distcc /usr/bin/c++

👉 ✔ distcc 使用干净编译器


成功链路总结

text 复制代码
ccache
 → distcc
 → gcc

👉 单层结构,无递归


最终结论

本次问题的根本原因是:

ccache 被调用了两次(CMake + PATH),再叠加 distcc,形成递归闭环


✔ 正确解法

👉 保证 ccache 只出现一次(唯一入口)


✔ 关键经验

⚠️ 多层 wrapper(CMake + PATH + distcc)是编译系统中最隐蔽、最危险的问题之一


总结

  • 原来好好的东西突然不好了,那一定是环境发生了变化,可能是外部环境,可能是内部环境
  • 硅基生物的问题往往能够重现,而碳基生物的不确定性实在让人无所适从,往往就是试试看吧

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==


时间都去哪了,还没好好感受年轻就老了~

相关推荐
小苗卷不动2 小时前
ps axj | grep 和 which命令
c++
云泽8082 小时前
第十五届蓝桥杯大赛软件赛省赛C/C++大学B组
c语言·c++·算法·蓝桥杯
Wadli2 小时前
集群C++聊天服务器
服务器·开发语言·c++
洛水水2 小时前
# 线程池详解:从原理到实现
c++·线程池
思麟呀3 小时前
HTTP的Cookie和Session
linux·网络·c++·网络协议·http
小明同学013 小时前
linux进程(下)
linux·服务器·c++
汉克老师3 小时前
GESP2023年12月认证C++三级( 第一部分选择题(1-8))
c++·string·字符数组·gesp三级·gesp3级
俺不要写代码3 小时前
lambda表达式理解
c++·算法
澈2073 小时前
动态内存管理:从基础到实战详解
c++·算法