distcc (简体中文)

From ArchWiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

翻译状态:本文是 Distcc翻译。上次翻译日期:2021-04-15。如果英文版本有所更改,则您可以帮助同步翻译。

distcc 是一个将 C、C++、Objective C 或 Objective C++ 等程序的编译任务分发到网络中多个主机的程序。distcc 力求实现和本地编译相同的结果,安装、使用都很方便,而且通常比本地编译快很多。distcc 也可以与 Arch 原生的编译工具,比如 makepkg,很好搭配使用。

名词定义

客户机
启动编译的计算机。
志愿机
接受客户机发送的编译请求的计算机。一个 distcc 编译集群可以包含一台或多台志愿机。

开始使用

将整个编译集群中的计算机都安装软件包 distcc。如果是其他的发行版,甚至包括使用 Cygwin 的 Windows 操作系统,请阅读 distcc 文档distcc(1)distccd(1) 的手册页。请保持 distcc 使用的端口畅通(默认是TCP 3632 端口),参见Category:Firewalls

配置

工作模式

Distcc 可以在普通模式(默认模式)或泵模式下使用。简单来讲,这两个模式的核心区别在于如何处理预处理过的源代码。普通模式会传递预处理器展开过的源代码和编译选项,由客户机负责预处理,而泵模式会把预处理和编译工作全部分发到 distcc 编译集群中,通常会更快、效率更高。更多细节请参见手册页 man distcc

志愿机配置

志愿机的配置文件储存在 /etc/conf.d/distccd 处。最简单的例子,是添加 --allow-private 选项,这样就能够覆盖整个 ipv4 局域网的范围。保存日志到文件也是排错时经常需要的:

DISTCC_ARGS="--allow-private --log-file /tmp/distccd.log"

如果设备有很多网卡,请考虑添加 --listen <监听地址>。其它设置请参考 distccd(1)

在所有志愿机上启动服务 distccd.service。要使服务开机自启,请启用此服务。

客户机配置

makepkg 编译选项

编辑/etc/makepkg.conf的这些部分:

  1. 确保 BUILDENV 数组中的 distcc 没有被禁用(即前面没有感叹号)
  2. 取消注释并编辑DISTCC_HOSTS行 ,加入可以使用的志愿机的 IP 地址或主机名。可以加上一个正斜杠("/")以及最大使用线程数。不同 IP 地址用空白隔开,这个清单应该按照处理器性能从高到低排列。
  3. 修改 MAKEFLAGS 中的 -jN 为所有使用线程数的和的两倍。在下面的示例为 2x(9+5+5+3)=44。
注意: 虽然 IP 地址或主机名都可以描述志愿机,但如果使用 devtools 的编译脚本,现在仍然不支持主机名解析,此时请使用 IP 地址代替。另外,每次编译都进行的主机名解析可能会塞满一些DNS设备的日志(比如pi-hole),此时指定 IP 地址就不会有这些麻烦。
注意: CFLAGSCXXFLAGS 中不能使用 -march=native 选项,否则 distccd 不会将编译任务发给其它机器。

另外,没有一个万能配置能够覆盖全部(尤其是线程数与 MAKEFLAGS 的并行线程数)。请一个一个测试您的参数,并与其他参数的结果做比较,以获取最优的配置。下面是一些例子。

普通模式例子
BUILDENV=(distcc fakeroot color !ccache check !sign)
MAKEFLAGS="-j44"
DISTCC_HOSTS="localhost/9 192.168.10.2/5 192.168.10.3/5 192.168.10.4/3"
泵模式例子
BUILDENV=(distcc fakeroot color !ccache check !sign)
MAKEFLAGS="-j70"
DISTCC_HOSTS="localhost/9 192.168.10.2,cpp,lzo 192.168.10.3,cpp,lzo 192.168.10.4,cpp,lzo"

请注意以下事项:

  • 并行数高的话,泵模式的表现通常更好。
  • 在泵模式下,IP 地址或主机名会跟上指示泵模式所需要的",cpp,lzo"的后缀。此处的本机localhost没有加上这个后缀,这意味着,distcc会按照普通模式严格向localhost安排9个任务,并激进地以泵模式向志愿机分发其他任务,这是一个大集群中的通常实践:客户机通常不希望编译任务阻塞他们,以此限制客户机的任务数。如果您一视同仁,也可以加上这个后缀。
  • 正如提到的那样,没有一个万能配置能够覆盖全部情况。如何选择一个最优的设置通常需要一些经验。

非 makepkg 编译选项

普通模式例子

下面的最小 distcc 客户机配置包括了志愿者设置,并将他们附加到PATH环境变量上。

$ export PATH="/usr/lib/distcc/bin:$PATH"
$ export DISTCC_HOSTS="localhost/9 192.168.10.2/5 192.168.10.3/5 192.168.10.4/3"
泵模式例子
$ export PATH="/usr/lib/distcc/bin:$PATH"
$ export DISTCC_HOSTS="localhost/9 192.168.10.2,cpp,lzo 192.168.10.3,cpp,lzo 192.168.10.4,cpp,lzo"

编译

makepkg 编译

普通模式

只要按照上面的过程配置好 /etc/makepkg.conf 就可以了。正常运行 makepkg 即可。

泵模式

用户必须在编译前启动分发泵。因为分发泵pump程序会在启动时检查DISTCC_HOSTS是否正确配置,因此我们需要先定义一个 DISTCC_HOSTS 搪塞过去。makepkg 会使用 /etc/makepkg.conf 里定义的变量,因此不会影响。

$ export DISTCC_HOSTS="localhost,cpp,lzo"
$ eval `pump --startup`

然后正常运行 makepkg 即可。

结束时,执行以下指令把分发泵关掉:

$ pump --shutdown

非 makepkg 编译

普通模式

按照#非 makepkg 编译选项章节配置好需要的变量后,直接调用编译器即可:

$ make -j44

有些程序可能需要定义CC 和/或 CXX 变量才能正常工作:

 $ make -j44 CC=distcc CXX=distcc

泵模式

按照上面一节方法操作分发泵。其他内容和普通模式相同。

CMake 编译

使用以下 CMake 选项来使用 distcc 编译一个使用 CMake 管理的项目:

$ cmake -DCMAKE_C_COMPILER_LAUNCHER=distcc -DCMAKE_CXX_COMPILER_LAUNCHER=distcc ...

监视进度

软件包 distcc 提供了一个命令行界面的监视器 distccmon-text 来检查编译进度。

如果在调用这个命令行界面监视器加上一个空格和一个等待秒数,就可以按照秒数不断更新显示。

$ distccmon-text 3
29291 Preprocess  probe_64.c                                 192.168.10.2[0]
30954 Compile     apic_noop.c                                192.168.10.2[0]
30932 Preprocess  kfifo.c                                    192.168.10.2[0]
30919 Compile     blk-core.c                                 192.168.10.2[1]
30969 Compile     i915_gem_debug.c                           192.168.10.2[3]
30444 Compile     block_dev.c                                192.168.10.3[1]
30904 Compile     compat.c                                   192.168.10.3[2]
30891 Compile     hugetlb.c                                  192.168.10.3[3]
30458 Compile     catalog.c                                  192.168.10.4[0]
30496 Compile     ulpqueue.c                                 192.168.10.4[2]
30506 Compile     alloc.c                                    192.168.10.4[0]

使用 distcc 交叉编译

交叉编译也可使用 distcc 助力。

  • 客户机必须运行在目标架构上。
  • 其他架构的志愿机可以协助编译,但必须安装对应的工具链,并配置 distcc。

ARM 架构 Arch Linux 客户机与 x86_64 架构的志愿机

下面一节介绍了如何使用 x86_64 架构的志愿机来帮助 Arch Linux ARM 架构设备编译。只需要一台 x86_64 架构的志愿机就能够加快 2 到 4 倍的编译速度,具体可以参见这些测试

志愿机

Arch ARM 开发者强烈推荐使用并在 x86_64 架构的志愿机上安装官方的工具链。与其手动配置,AUR提供了所有的工具链、配置文件,和系统服务:

这些工具链的配置过程和#志愿机配置一节完全相似,除了配置文件和系统服务文件对应包名有所更改。比如 armv7h 的配置文件是 /etc/conf.d/distccd-armv7h,systemd 服务文件是 distccd-armv7h.service

注意这些工具链的端口都不同,使得他们可以共存而不冲突。请一定保持他们使用的端口畅通。(参见Category:Firewalls 和手册页 distcc(1)

目标架构 distcc 端口
armv5 3633
armv6h 3634
armv7h 3635
armv8h/aarch64 3636

客户机

配置 Arch ARM 客户机的最简单办法是使用distccd-arch-armAUR包。这个包提供了针对Arch ARM架构的所有四个配置文件和系统服务配置文件。比如说如果运行的是armv7h固件,只需要配置 /etc/conf.d/distccd-armv7h 文件并按照上述内容编辑默认值。再启动 distccd-armv7h.service 服务以编译。

更详细的介绍,请参见使用示例

如果希望不使用AUR包而手动配置客户机,可以按照通用的方法配置客户机,但需要更改如下两个内容来更改默认端口。例如(端口假设是按照上面的表格):

  1. /etc/conf.d/distcc: armv7h 示例: DISTCC_ARGS="--allow-private --log-level info --log-file /tmp/distccd-armv7h.log --port 3635"
  2. /etc/makepkg.conf: armv7h 示例: DISTCC_HOSTS="192.168.10.2/5:3635 192.168.10.3/5:3635"

x86_64 架构的 Arch Linux 客户机与 ARM 架构志愿机

下面一节介绍了如何使用 ARM 架构的志愿机来帮助x86_64 架构客户机编译。只需要一台 x86_64 架构的志愿机就能够显著加快编译速度,两台设备就能翻倍。具体可以参见这些测试

客户机

可以按照通用的方法配置客户机,其对应的标准端口是 3632。

志愿机

distccd-x86_64AUR 提供了装在 Arch ARM 设备上的交叉编译工具。

附加工具链

  • EmbToolkit: 创建交叉编译工具链的工具;支持 ARM 和 MIPS 架构;支持创建LLVM工具链
  • crosstool-ng:和EmbToolkit相似,支持更多架构(更多信息参见其网站)
  • Linaro:提供了ARM开发的工具链

EmbToolkit 有一个很好看的配置工具链的图形配置菜单(make xconfig)。

故障排除

编译 Arch Linux 内核包时的奇怪现象

如果使用官方的PKGBUILD来编译内核,distcc 将无法工作,因为内核硬编码使用了一些GCC插件,因为一些技术原因distccd不能够支持他们。

可以通过编辑内核、删掉这些对 GCC 插件的要求来迂回。可以在编译前在 PKGBUILD 中用一行 sed 命令搞定:

sed -i '/HAVE_GCC_PLUGINS/d' arch/x86/Kconfig

如果不这样就无法编译。参见 FS#64275

另一种办法是编译时传递 CC=distcc 和 CXX=distcc 变量:

make all CC=distcc CXX=distcc

编译 chromium 包时的奇怪现象

编译 chromium 会使用 clang,目前受到issue#386的影响。规避这个bug可以在PKGBUILD的_flags数组中添加这些:

'is_cfi=false'
'use_gold=false'
'clang_use_default_sample_profile=false'
'chrome_pgo_phase=0'

Journalctl

使用 journalctl 查看什么地方出错了:

# journalctl $(which distccd) -e --since "5 min ago"

调整日志记录等级

通常来说,distcc会把log写到 /var/log/messages.log 里。一个技巧(这个是distccd的手册页推荐的)是写到其他文件里面,比如写到内存(通过 /tmp)里去。另一个技巧是提高日志记录等级,只记录错误信息。这个等级可以是任何标准系统日志等级,即critical、error、warning、notice、info,或者debug。

在客户机上按照这些参数启动distcc,或修改志愿机的/etc/conf.d/distccd文件的DISTCC_ARGS参数:

DISTCC_ARGS="--allow 192.168.10.0/24 --log-level error --log-file /tmp/distccd.log"

修改 $HOME/.distcc 文件夹位置以减少硬盘读写

distcc 默认会创建 $HOME/.distcc 文件夹来暂时保存节点编译相关的信息。下面的命令可以减少不必要的硬盘读写,尤其对 SSD 友好:

$ export DISTCC_DIR=/tmp/distcc

distccd-alarm 相关

没有那个文件或目录

与下例类似的错误表明用户错误地启动了 distcc 而不是 distccd-alarm 包(即distccd-alarm-armv5AURdistccd-alarm-armv6hAURdistccd-alarm-armv7hAUR,或 distccd-alarm-armv8AUR)提供的distccd。

请一定针对目标架构启动正确的服务。

distcc[25479] (dcc_execvp) ERROR: failed to exec armv7l-unknown-linux-gnueabihf-g++: No such file or directory

另请参见

  • icecreamAUR - 一个更好配置的 distcc 分支。