前幾天聽到同事說到 distcc 這工具,詢問了一下才知道是這麼好用的工具。其官方網站:https://code.google.com/p/distcc/。如同其標題所寫「distcc: a fast, free distributed C/C++ compiler」,就是一個可以進行分散式編譯的概念!C/C++ 程式在建置的過程中,最花時間的就是編譯了。這個工具的概念就是將編譯平行化,讓其他電腦也可以幫忙編譯程式碼,如此一來就可以節省下不少時間!

我本身使用的是 Macbook Air,本身搭載的就是低功耗處理器,對於編譯這種耗 CPU 資源的工作本來就非常不在行。然後看著公司配的桌機幾乎不用好像有點浪費,得知 distcc 後就心想一定要想辦法把這工具裝起來!

而且現在在研究 Firefox,不時就要重新建置 Firefox,一次就要 30 分鐘。使用 distcc 後,建置整個 Firefox 時間縮短為 15 分鐘!可以明顯發現 distcc 真的有效!這些時間都包含前處理、編譯、連結這三個步驟。前處理與連結都只能在本機執行,只有編譯的步驟可以被平行化。也就是前處理跟連結的時間是省不掉的,由此可知 distcc 的效果是如此顯著!

然而,現在要做的是利用 Linux 來編譯 OS X 可以使用的二進位檔,也就是進行 cross-compile。當然,要相反過來也是可行的。所以會在 Linux 上安裝 clang 這個編譯器,之後都會指定 distcc 使用 clang 來進行編譯。我有試過使用 gcc,但 Linux 那端會一直編譯失敗,使得 distcc 變得毫無效果。確切原因我還不太清楚,就先直接使用 clang 吧。

接下來,就來介紹怎麼安裝與使用!

Enviroment

Ubuntu server

  • CPU: Intel Core i7-4790 @ 3.60GHz × 8
  • Mem: 16GB
  • OS: Ubuntu 14.04

Macbook Air

  • CPU: Intel(R) Core(TM) i7-3667U CPU @ 2.00GHz × 2
  • Mem: 8GB
  • OS: OS X 10.9

單從規格就可以看出 Macbook Air 與 Ubuntu server 比起來根本就是懶趴比雞腿啊…。更加讓我希望可以用 Ubuntu server 來幫忙編譯了!

Installation

Ubuntu Server

安裝 distcc 與 clang:

1
$ sudo apt-get install distcc clang

Macbook Air

安裝 distcc:

1
$ brew install distcc

Setup

Ubuntu server

在 Ubuntu 這端,首先要編輯 /etc/default/distcc 這個檔案。修改以下三個設定:

  • STARTDISTCC
    • 開機使否啟動
  • ALLOWEDNET
    • 允許使用本機的 distcc 的網路或是機器
  • LISTENER
    • distcc 會聽來自哪些 IP 的連線

設定後的範例結果如下:

1
2
3
STARTDISTCC="true"
ALLOWEDNETS="127.0.0.1 10.247.27.0/24"
LISTENER="0.0.0.0"

這樣表示,開機會自動啟動。並且監聽所有連線,但僅允許本機 (localhost) 與 10.247.27.0/24 這個網域下的機器可以使用本機的 distcc 服務。

設定好後,啟動或是重新啟動 distcc:

1
2
$ sudo service distcc start # or use 'restart' to restart distcc
 * Restarting Distributed Compiler Daemon: distccd          [OK]

這樣一來,Ubuntu server 上的 distcc 服務就啟動了。可以利用以下指令來查看 distccd 使否真的執行成功:

1
2
3
4
5
6
7
8
$ ps aux | grep distccd
distccd  16927  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200
distccd  16928  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200
distccd  16929  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200
distccd  16930  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200
distccd  16931  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200
distccd  16932  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200
distccd  16933  0.0  0.0  19784   180 ?        SN   01:36   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --allow 10.247.27.0/24 --allow 10.247.24.0/24 --listen 0.0.0.0 --jobs 200

如果 grep 出來的結果不是當前指令的話,而是出現很多類似上面的訊息,就表示 distccd 成功啟動了!

Macbook Air

使用 homebrew 安裝的 distcc 設定檔會在 /usr/local/etc/distcc 目錄底下。這邊需要編輯的檔案只有 /usr/local/etc/distcc/hosts 這個檔案。這個檔案內會寫上有哪些網路上的機器提供 distcc 的服務,以及其相關設定。設定後的檔案內容如下:

1
2
10.247.27.101/200
localhost/2

以上的內容表示網路上有兩檯機器提供 distcc 的服務,分別是 IP 為 10.247.27.101 與本機 (localhost)。此外,可以發現兩個 IP/hostname 後面都加上了一個斜線及一個數字。這表示該機器最大可以指定的工作數量。如果沒有設定的話,除了本機之外的都是預設為 4,而本機則是預設為 2。這部分還有很多額外的設定可以操作,詳細請見 distcc 的文件中的 HOST SPECIFICATIONS 章節。

而如果在這檔案中沒寫上 localhost 的話,就目前目測觀察來看,似乎就不會把任何編譯工作指派到本機上。所以本機就只要進行前處理以及連結就好,編譯時期就不會 CPU 一直滿載導致電腦使用起來相當不順了。

在 server (Ubuntu server) 跟 client (Macbook Air) 都設定好 distcc 之後,可以在 client 上執行以下指令來查看 distcc 最大可以執行的工作數量:

1
2
$ distcc -j
202

以我前面設定的為例,可以看到顯示的結果為 202。表示之後在執行 make 指令時,最大可以使用 -j202 的參數來平行化。

Usage

在大部分情況下,只需要把環境變數的 CC 與 CXX 修改一下即可。

1
2
$ export CC="distcc clang -target x86_64-apple-darwin"
$ export CXX="distcc clang++ -target x86_64-apple-darwin"

或是直接去 makefile 中,把原本設定的編譯器加上 distcc 的前綴。這樣一來,執行 make 時,就會開始用 distcc 進行編譯了!

然而,如果使用的是 automake 這樣的方式來產生 makefile,則要在 ./configure 的時候加上 --cc--cxx 的參數,如下:

1
$ ./configure --cc="distcc clang -target x86_64-apple-darwin" --cxx="distcc clang++ -target x86_64-apple-darwin"

這樣產生的 makefile 就會設定好要使用 distcc 進行編譯了。

如果設定成功的話,執行編譯時,可以查看 Ubuntu server 下的 /var/log/distccd.log 該檔案。即可看到類似以下的輸出,表示 distcc 成功地在幫 OS X 進行編譯。

1
2
3
4
5
6
7
8
9
10
distccd[3738] (dcc_job_summary) client: 10.247.24.6:51236 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:271ms clang libavfilter/vsrc_mandelbrot.c
distccd[3738] (dcc_job_summary) client: 10.247.24.6:51238 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:21ms clang libavfilter/x86/af_volume_init.c
distccd[3738] (dcc_job_summary) client: 10.247.24.6:51239 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:45ms clang libavfilter/af_astats.c
distccd[3841] (dcc_job_summary) client: 10.247.24.6:51225 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:1194ms clang libavfilter/af_biquads.c
distccd[3841] (dcc_job_summary) client: 10.247.24.6:51212 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:123ms clang libavfilter/af_volume.c
distccd[4052] (dcc_job_summary) client: 10.247.24.6:51237 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:465ms clang libavfilter/vsrc_testsrc.c
distccd[3952] (dcc_job_summary) client: 10.247.24.6:51230 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:697ms clang libavfilter/avf_showcqt.c
distccd[3738] (dcc_job_summary) client: 10.247.24.6:51240 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:765ms clang libavfilter/x86/vf_idet_init.c
distccd[3816] (dcc_job_summary) client: 10.247.24.6:51220 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:1957ms clang libavfilter/vf_shuffleplanes.c
distccd[4792] (dcc_job_summary) client: 10.247.24.6:51193 COMPILE_OK exit:0 sig:0 core:0 ret:0 time:4771ms clang libavfilter/af_earwax.c

For Firefox

前面提到過,我是為了加速編譯 Firefox 才安裝 distcc 的。因為 Firefox 本身有自己的 Mozilla build system,所以在設定上會有些不同。不過其實很簡單,除了前面有提到的設定 CC 跟 CXX 變數外,就是把 -j 寫進 mozconfig 檔案裡。假如想要加上 -j100 的選項,就寫上下面這行在 mozconfig 裡即可。

1
mk_add_options MOZ_MAKE_FLAGS="-j100"

下圖有真相,可以看到當 Macbook Air 這端開始進行編譯時,Ubuntu 那端的 CPU 使用率也大幅出現變動。

Ubuntu Monitor

另外,附上兩張截圖顯示部屬 distcc 前後的編譯時間差異:

部屬 distcc 前 (部屬 distcc 前)

部屬 distcc 後 (部屬 distcc 後)

最後,引用自同事的話:

用 Air 來 build code 簡直是太閒…