Linux內核編譯實在是費時間的事,搞內核移植的時候總要編譯,生命有一部分就浪費在等內核編譯完成上,有心想買個HP的工作站,看了下Z840的價格,想想還是算了。distcc早就聽說過,一直沒有去試試,今天終於試了試,真是大贊啊!!下面說下如何配置,為了方便敘述,先定義幾個稱呼
- 我直接工作的電腦稱為L
- 用來加速編譯的電腦們稱為A、B、C(它們也被稱為compile farm)
安裝
# L電腦 sudo apt install distcc distccmon-gnome distcc-pump # A/B/C電腦 sudo apt install distcc
配置
在L/A/B/C電腦上更改 /etc/default/distcc內容如下(注釋已經刪除)
STARTDISTCC="true" # 下面的 /16表示前面的IP地址16位有效,即192.168.xx.xx的IP都是接受的 ALLOWEDNETS="127.0.0.1 192.168.0.0/16" LISTENER="" NICE="10" JOBS="" ZEROCONF="true"
然后執行
sudo systemctl restart distcc
此時,若在任何一台電腦上執行 distcc --show-hosts,將會列出L/A/B/C電腦的IP或IPv6,格式為
<A-IP>:3632/32 <C-IP>:3632/16 <B-IP>:3632/8 <L-IP>:3632/32
其中3632是端口,這個是默認端口,一般不用改變,'/'后面限制的任務數,默認按4倍<CPU-threads>來計算的,如果這個時候執行后面將會提到的distcc-pump就會報沒有host具有,cpp屬性(這可以認為是distcc的一個bug,不過人家在man distcc里說明了,zeroconf不支持lzo和cpp屬性,github上也明確表示不會合並patch,所以zeroconf我覺得也就是可以用來debug或初始化)
在L電腦的打開 /etc/distcc/hosts,將剛才 distcc --show-hosts的輸出寫進去,並在每行后面加上,cpp,lzo,大約如下(把+zeroconf注釋掉)
<A-IP>:3632/32,cpp,lzo <C-IP>:3632/16,cpp,lzo <B-IP>:3632/8,cpp,lzo <L-IP>:3632/32,cpp,lzo
使用hosts文件有幾個好處(可能就是因為這些好處,以至於開發者都不去修正zeroconf的BUG)
- 各電腦按照配置高低排序,把配置高的放前面,當任務少時先分配給配置高的機器
- 各電腦的任務限制數可以手動更改(給A/B/C電腦一點剩余CPU)
- L電腦自己需要執行預處理任務,應該把自己放到靠后的位置,並適當限制任務數,甚至不要放到列表中去
- 手動增加,cpp,lzo屬性,避開BUG
配置完成后,此時在L電腦上再次執行 distcc --show-hosts,輸出就是/etc/distcc/hosts的文件內容
安裝編譯器
所有電腦需要安裝編譯器,並且放到相同的位置(我認為不太必要,只要都在PATH環境變量中就可以了吧),最好都是相同的版本。
編譯內核
編譯內核時,一般會先export ARCH 和 CROSS_COMPILE,這個不用改變,正常來即可,也可以放到命令行上,我比較喜歡export,最后編譯執行命令是
distcc-pump make -j$(distcc -j) O=build-xxx CC="distcc ${CROSS_COMPILE}gcc"
這個時候可以打開 distccmon-gnome 看看壯觀的景象,幾分鍾之后內核就編譯好了!
后記
還有一個叫dmucs的東西,可以手動指定每台機器的power,然后自動執行負載均衡,並優先發給power強的機器,不過我配置的半天都不好使,而且我覺得配置起來也比較麻煩,就放棄了。有興趣的同志可以研究下。
補記
在編譯Linux內核某版本時,總是報遠程無法編譯過,但本地可以編譯過,然后后面就會使用plain distcc mode,也就是本地預處理,遠程編譯的方式。這種方式顯著降低編譯速度,因為大量工作由本機來完成,而我本機的性能還不如編譯服務器,一開始我也以為配置的問題,后來 man include_server告訴我,可以 export DISTCC_FALLBACK=0,然后遠程編譯的錯誤信息就會打出來,便於診斷,發現是下面的代碼的問題
#define __gcc_header(x) #x #define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) #define gcc_header(x) _gcc_header(x) #include gcc_header(__GNUC__)
也就是說distcc預處理時無法知道要發送哪個頭文件,並且沒有檢測出這個問題,導致遠程編譯時報 linux/compiler-gcc##x.h 未找到,這個問題work around的方法是,根據打印消息,把源代碼臨時改掉,不要因為這一個問題,導致編譯速度顯著下降。
另外 CC=distcc xxxx,如果xxxx不是絕對路徑,那在遠程編譯服務器上也會按PATH去搜索,不過要注意PATH在遠程是什么,如果是絕對路徑就不需要搜索了,直接也使用絕對路徑。