在 FreeBSD 9.1 裡完全使用 clang 代替系統的 gcc

已經算是有相當多年沒有把系統的版本做提升了,趁著 FreeBSD 9.1-RELEASE 開始內建 LLVM 3.1 的機會,我也順便做了一次多年來罕見的升級。
畢竟 FreeBSD base system 上使用的 GCC 實在是太舊了,是變成 GPLv3 之前的最後一個版本,也就是 4.2.1 這個早就該作古的版本。
加上我對 GCC 的內部的設計實在是有點反胃,認識我的人應該也知道我蠻討厭那個大鬍子教主,所以聽到能換成 LLVM 當然就是馬上安排時間衝了。

FreeBSD 9.1 並沒有正式將系統的 cc 換成 clang,這要到 10-CURRENT 才行,但我不想衝 -CURRENT 線,所以先選用了 9.1-STABLE。
因為 FreeBSD 9.1-RELEASE 的 LLVM 版本是 3.1,而 9.1-STABLE 的 LLVM 版本是 3.2,所以裝完 9.1-RELEASE 以後我馬上就先升上去了,當然考慮用 snapshot ISO 也是一個方法。
在這新版本的 FreeBSD 下 man src.conf 可以看到一些有趣的東西,按照自己的喜好做開關即可:

其中 WITH_CLANG_EXTRA 建議是打開,否則 LLVM 裡的一些程式像是 opt、llc、lli 就會沒有。
不過經過測試,WITHOUT_GCC=yes 在 FreeBSD 9.x 是行不通的,在 make buildworld 做到一半的時候就會遇上這個錯誤訊息:

===> usr.bin/xlint/llib (all)
lint -cghapbx -Cposix /usr/src/usr.bin/xlint/llib/llib-lposix
llib-lposix:
lint: cannot exec /usr/obj/usr/src/tmp/usr/bin/cc: No such file or directory
*** [llib-lposix.ln] Error code 1
1 error
*** [all] Error code 2
1 error
*** [all] Error code 2
1 error
*** [usr.bin.all__D] Error code 2

因為這是寫死的,所以無視了 CC 環境變數,直接在 object tree 裡找 cc。
據說在 10-CURRENT 裡已經修掉了:CLANG buildworld failure: lint: cannot exec /usr/obj/usr/src/tmp/usr/bin/cc: No such file or directory
但因為我不想用 10-CURRENT,所以姑且還是把 WITHOUT_GCC=yes 先拿掉。

在 FreeBSD 裡完全使用 LLVM 替代 GCC 的方法早已不是新聞,所以躺著就能找到最基本的教學:Building FreeBSD with clang/llvm
目前為止我編譯 ports 是沒有遇到什麼問題,唯一的例外就是 openjdk6,這個問題當然也已經有人發現了:Quick and dirty hack to build OpenJDK6 with clang and libc++ on FreeBSD
在這邊比較值得一提的就是隱藏參數 WITH_LIBCPLUSPLUS=yes 在 man src.conf 是找不到的,相關說明可以在這邊看到:The New C++11 Stack
既然標題上有個關鍵字 C++11,我當然在做 world 的時候是一定會把這參數開下去了,連想都不用想。
至於想在做 world 的時候就在 CXXFLAGS 裡放 -stdlib=libc++ 的話,因為 FreeBSD 9.x 預設是沒有 libc++ 的,所以得事先裝一下。
在這篇有提到可以事先進入 src tree 裡編譯和安裝 libc++ 的方法:Help on getting C++11 to work

至於 CXXFLAGS 裡是否該放 -std=c++11 這個參數,我的建議是放 -std=gnu++11。
畢竟長年來 GCC 預設的就是 gnu 字頭而不是 c 字頭,如果貿然用了 c 字頭會讓一些 GNU extensions 失效,可能編譯某些 source code 會出問題。
C++ 倒是無所謂,但要注意在純 C 裡面 static inline 在這兩個標準裡語意是顛倒的,這麼老的問題應該不用我再說明了吧。