distcc (简体中文) - ArchWiki

Jump to content

相关文章

- TORQUE
- Slurm

翻译状态：本文是 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 地址就不会有这些麻烦。
注意： `CFLAGS` 和 `CXXFLAGS` 中不能使用 `-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提供了所有的工具链、配置文件，和系统服务：

- distccd-alarm-armv7hAUR
- distccd-alarm-armv8AUR

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

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

目标架构 | distcc 端口
--- | ---
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-armv7hAUR，或 distccd-alarm-armv8AUR）提供的distccd。

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

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

## 另请参见

- https://github.com/distcc/distcc

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

Categories:

- Package development (简体中文)
- Distributed computing (简体中文)
- Networking (简体中文)
- Development (简体中文)