Xcode分布式编译调研distcc

这几天研究了下在 Xcode 上使用 distcc 进行分布式编译,无疾而终,在此记录下过程中遇到的一些主要问题,以备后续研究。

distcc

distcc 是一个开源的分布式编译工具,它可以将 C 语言的编译任务分发到多台机器上进行编译,最终再发回主机进行链接,以此加快编译速度。

使用 PSPDF 的方案,本地编译成功,远程编译失败

最初 distcc 的分布式编译方案就是在 PSPDF 的 Blog 上看到的,之前配置 CCache 的时候也参考过他们的 Blog。原文地址在此:Crazy Fast Builds Using Distcc

文中提到,目前 distcc 原生不支持 Xcode + clang,因为 Xcode 调用 clang 编译时,使用了许多特殊的选项,distcc 缺少了对这些选项的支持。因此,PSPDF 团队提供了一份打了补丁的 distcc。下面我快速总结下他们的方案,详细的讲解请看原文。

配置步骤

  • 在配置好 CCache 的情况下(不是必要条件,只是为了方便配置)
  • 先使用 brew 安装原生 distcc:命令行中 brew install distcc
  • 拉下 PSPDF 打补丁后的源代码:PSPDF distcc
  • 编译源码:
1
2
3
./autogen.sh
./configure --without-libiberty --disable-Werror
make
  • /usr/local/Cellar/distcc/ 目录下,找到刚刚用 brew 安装的 distcc 的所有二进制文件,用刚刚编译出来的几个二进制文件替换;
  • ~/.distcc/ 目录下创建 hosts 文件,写入远程的编译机器的地址,如172.16.0.1
  • 让 Xcode 调用 distcc:在配置了 CCache 的工程目录下,把 ccache-clang 脚本中原有的命令都注释掉,换成exec distcc clang "$@";(这是一个偷懒办法,使用包含 CCache 的工程就是为了利用 ccache-clang 脚本拦截 clang 的调用。此外,还可以在这行命令前,加上export DISTCC_VERBOSE=0来输出 distcc 的日志)
  • 本地配置好后,给远端的编译服务器也按上述步骤

启动

  • 在编译的机器上跑起 distcc 的后台编译线程:
1
distccd --no-detach --daemon --allow 172.16.0.0/16 --allow 127.0.0.1 --log-stderr --verbose
  • 在本机 brew install watch,然后新开一个终端窗口执行 watch distccmon-text,用来监控本机任务分发的情况;
  • Xcode 开始编译;

遇到的问题

  • 如果只把 localhost 作为编译服务器,则编译没问题,输出 COMPILE_OK;
  • 如果不在本地编译,把任务分发到远端的编译服务器,则远端全部编译失败 COMPILE_ERROR exit code 1,然后 distcc 回滚到本地编译;

使用 distcc with pump mode

看到网上有一个类似的错误,声称开启 pump mode后可以解决上述问题,于是尝试 distcc with pump mode

pump mode是指不仅将编译任务分发到远端,而且还将预处理的任务分发到远端,这使得传输的数据量变得非常大,但是当远端服务器数量够多,且带宽超过100M 的情况下,它可能会极大提升编译速度。

开启方法

  • 在之前提到的 hosts 文件中的所有 IP 后面都加上,lzo,cpp,如172.16.0.1,lzo,cpp;
  • ccache-clang的那句脚本上,加上 pump,变成exec pump distcc clang "$@";

遇到的问题

  • 直接编译,发现报错,缺少某些.so .sh .py文件,尝试将本地编译生成的一些对应的文件拷贝到 /usr/local/Cellar/distcc/ 目录下,最终不再报类似错误;
  • 解决上述编译错误的问题后,Xcode 显示编译成功,但远端的控制台发现编译失败。检查后发现,似乎是本地分析代码依赖的时候,发生了错误,导致无法分发预处理的任务,在本地完成了预处理,而本地预处理后,分发编译任务给远端时,就又出现了最初的本地编译成功,远端而编译失败的情况。错误信息如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
__________Using distcc-pump from /usr/local/Cellar/distcc/3.2rc1/bin
__________Using 1 distcc server in pump mode
WARNING include server: Preprocessing locally. Include server not covering: Could not locate name of translation unit: ['/Users/zj-db0524/Library/Developer/Xcode/DerivedData/MTHawkeye-bgzsavpygorewzcnobhqjehindcn/Index/DataStore', '/Users/zj-db0524/Library/Developer/Xcode/DerivedData/MTHawkeye-bgzsavpygorewzcnobhqjehindcn/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/AFNetworking.build/Objects-normal/x86_64/AFImageDownloader.dia', '/Users/zj-db0524/Documents/Code/MTHawkeye/MTHawkeyeDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m']. for translation unit 'unknown translation unit'
distcc[74951] (dcc_talk_to_include_server) Warning: include server gave up analyzing
distcc[74951] (dcc_build_somewhere) Warning: failed to get includes from include server, preprocessing locally
distcc[74951] ERROR: compile /Users/zj-db0524/Documents/Code/MTHawkeye/MTHawkeyeDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m on 172.16.3.77,lzo,cpp failed
distcc[74951] (dcc_build_somewhere) Warning: remote compilation of '/Users/zj-db0524/Documents/Code/MTHawkeye/MTHawkeyeDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m' failed, retrying locally
distcc[74951] Warning: failed to distribute /Users/zj-db0524/Documents/Code/MTHawkeye/MTHawkeyeDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m to 172.16.3.77,lzo,cpp, running locally instead
distcc[74951] (dcc_please_send_email_after_investigation) Warning: remote compilation of '/Users/zj-db0524/Documents/Code/MTHawkeye/MTHawkeyeDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m' failed, retried locally and got a different result.
distcc[74951] (dcc_note_discrepancy) Warning: now using plain distcc, possibly due to inconsistent file system changes during build
__________Warning: 1 pump-mode compilation(s) failed on server, but succeeded locally.
__________Distcc-pump was demoted to plain mode.
See the Distcc Discrepancy Symptoms section in the include_server(1) man page.
__________Shutting down distcc-pump include server

总结

分布式编译十分美好,在 Xcode 上理论上是可行的,Xcode 4 之前甚至内嵌了 distcc。但是目前 distcc 目前原生不支持 Xcode,且其社区不是很活跃,特别是 Xcode 上的应用成功的案例更是少之又少,几乎为零,提及它的内容大多是几年前发布的。以此初步判断,目前除非投入较多精力寻找变通手段,进行适配,否则较难实现分布式编译。欢迎成功实践了 distcc 或其他分布式编译方式的朋友和我