distcc

出自 Arch Linux 中文维基

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 端口
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

另請參見[編輯 | 編輯原始碼]

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