Redhat環境下編譯安裝bazel##
作者:Jack47
目前Google Bazel沒有提供各個操作系統下的二進制安裝包,只提供源代碼,需要我們自己編譯安裝,詳情可以見我翻譯的中文版Google Bazel FAQ。Google Bazel官方安裝文檔在這里,里面只介紹了在Ubuntu(14.04,14.10)和Mac OS X下的編譯安裝。而我們公司的構建機器是Redhat Linux系列,在編譯Bazel的時候遇到了很多問題,在這里跟大家分享下解決思路和方法,為了照顧像作者這樣的小白,文章寫的稍微有點啰嗦,見諒。
編譯##
我編譯Bazel的系統環境配置是:
系統環境###
操作系統:Redhat Enterprise 5.7
內核版本:2.6.32-220
gcc: 4.1.2
后來發現需要JDK 1.8, 支持C++ 11的編譯器才可以順利編譯Bazel,下文會介紹如何安裝這些依賴。
下載代碼###
$ git clone https://github.com/google/bazel/
編譯###
直接執行./compile.sh
腳本來編譯Bazel
$ ./compile.sh
報錯:
Package libarchive was not found in the pkg-config search path.
Perhaps you should add the directory containing 'libarchive.pc' to the PKG_CONFIG_PATH environment variable
No package 'libarchive' found`
可以看到提示是 libarchive 包不在PKG_CONFIG_PATH下。利用Redhat Linux下的包管理工具yum查看到底安裝了這個包沒有:
$ rpm -qa | grep libarchive
發現就沒有安裝這個包,於是進行安裝。libarchive是一個支持多種格式的檔案和壓縮的庫。
安裝libarchive###
從官方網站下載最新版本的 libarchive :
$ wget http://libarchive.org/downloads/libarchive-3.1.2.tar.gz
解壓縮得到源碼:
$ gunzip libarchive-3.1.2.tar.gz
$ tar libarchive-3.1.2.tar
然后通過查看libarchive-3.1.2目錄下的 INSTALL 文件,找到編譯安裝方法:
編譯:
$ ./configure
$ make
安裝[需要管理員權限]:
$ sudo make install
此時再次執行Bazel的編譯腳本:
$ ./compile.sh
發現還是跟沒安裝之前報一樣的錯誤:
Package libarchive was not found in the pkg-config search path.
Perhaps you should add the directory containing 'libarchive.pc' to the PKG_CONFIG_PATH environment variable
No package 'libarchive' found
提示是說在pkg-config的搜索路徑下找不到 libarchive 這個包,需要把libarchive.pc這個文件的路徑添加到PKG_CONFIG_PATH這個環境變量里。回過頭查看 libarchive 的安裝過程中打印出的信息,可以看到:
/usr/bin/install -c -m 644 build/pkgconfig/libarchive.pc '/usr/local/lib/pkgconfig
發現libarchive.pc是安裝到了 /usr/local/lib/pkgconfig 目錄下。
於是設定環境變量PKG_CONFIG_PATH:
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
再編譯Bazel,發現又出錯了:
JDK version is lower than 1.8, please set $JAVA_HOME.
是jdk的版本不對,看了一下當前環境下的java版本:
$ java -version
java version "1.6.0_20"
安裝jdk 1.8###
從Oracle官網下載jdk1.8, 由於我的機器是x86架構,64位機器,於是下載這個版本。如果直接 wget 會失敗,需要在網頁里同意License才可以下載,所以從瀏覽器中下載jdk1.8。如果是遠程登錄到服務器,可以在本地下載,然后使用scp
命令上傳到服務器:
$scp jdk-8u45-linux-x64.rpm usename@hostname:~/
安裝####
$ sudo rpm -ivh jdk-8u45-linux-x64.rpm
bazel需要通過環境變量$JAVA_HOME
來得到jdk的安裝路徑。而jdk rpm安裝包不會自動幫助我們設置環境變量JAVA_HOME
,需要我們自己設置。
設置JAVA_HOME####
很奇怪,安裝后包名稱變了,使用如下rpm命令查看安裝后jdk 1.8的包名稱:
$ rpm -qa | grep jdk
jdk1.8.0_45-1.8.0_45-fcs
查看這個包中文件都安裝到哪些路徑下了:
$ rpm -ql jdk1.8.0_45-1.8.0_45-fcs
發現安裝到/usr/java/jdk1.8.0_45/
這個目錄下去了。
於是設置JAVA_HOME:
$ export JAVA_HOME=/usr/java/jdk1.8.0_45/
查看JAVA_HOME是否設置正確:
$ echo $JAVA_HOME
/usr/java/jdk1.8.0_45/
可以看到確實設置成功了。
再次編譯Bazel,終於看到編譯的輸出了:
$ ./compile.sh
Compiling Java stubs for protocol buffers...
Compiling Bazel Java code...
Extracting helper classes for Bazel Java...
Creating libblaze.jar...
Compiling SingleJar tool code...
Extracting helper classes for SingleJar tool...
Creating SingleJar_deploy.jar...
Compiling JavaBuilder tool code...
Extracting helper classes for JavaBuilder tool...
Creating JavaBuilder_deploy.jar...
Compiling client .cc files...
cc1plus: error: unrecognized command line option "-std=c++0x"
看起來是不支持這個選項: "-std=c++0x"。
如何查看到底./compile.sh
這個腳本執行了哪些語句,到底是哪條命令失敗了?編輯這個shell腳本,在開頭寫入set命令:
set -x
然后再次運行Bazel編譯,此時可以看到 ./compile.sh
腳本的每一行命令。最終出錯誤的命令是:
g++ -I. -std=c++0x -c '-DBLAZE_JAVA_CPU="k8"' -DBLAZE_OPENSOURCE=1 -o output/objs/blaze_startup_options.cc.o src/main/cpp/blaze_startup_options.cc
看起來是 g++
不支持 c++0x標准。上網搜了一下,發現gcc 4.6以上的版本才支持 C++ 11。怎么在Redhat Linux下安裝更高版本的gcc呢?
上網搜索后,發現Red Hat Enterprise Linux下有開發工具套件 devtoolset,可以方便的安裝各個版本的gcc,而且是可以多個版本並存的,方便的解決了我等小白在源碼編譯、安裝gcc時可能出現的問題。但官方的那一套東西,需要付費,而公司的這個Red Hat版本不支持。后來發現Redhat Linux的社區版本--Centos下有人已經構建好了Redhat Developer Toolset的相關rpm包,參照此文來進行devtoolset的安裝。
$ sudo wget http://people.centos.org/tru/devtools-2/devtools-2.repo -O /etc/yum.repos.d/devtools-2.repo
$sudo yum install devtoolset-2-gcc devtoolset-2-binutils devtoolset-2-gcc-c++
安裝完成后,使用scl命令在shell環境中啟用devltoolset-2
$ scl enable devtoolset-2 bash
然后驗證此時gcc的版本:
$ gcc -v
可以看到此時已經是gcc 4.8.2版本了。有興趣的同學可以查看一下enable這個腳本的實現,非常簡潔,會讓你收獲一些東西,路徑是:/opt/rh/devtoolset-2/
再次編譯Bazel,發現又出錯了:
src/main/tools/namespace-sandbox.c: In function ‘main’:
src/main/tools/namespace-sandbox.c:140:36: error: ‘CLONE_NEWUTS’ undeclared (first use in this function) CHECK_CALL(unshare(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER));
在網上看到unshare
這個函數的CLONE_NEWUTS參數在我的這個系統版本里2.6.32 里面應該是已經支持了得。后來發信給bazel郵件組求助,他們說是我得系統內核版本太老了,不支持namespace,讓我把namespace-sandbox的編譯去掉,不影響正常功能。
於是注釋掉,sandbox的編譯:
#if [[ $PLATFORM == "linux" ]]; then
# log "Compiling sandbox..."
# "${CC}" -o output/namespace-sandbox -std=c99 src/ main/tools/namespace-sandbox.c
#fi`
再次編譯,編譯終於成功了!
Build successful! Binary is here: /home/jack47/bazel/output/bazel
明天如果把bug修完了,會更新一篇如何上手bazel的文章,大家周末愉快!
后記:
其實我在搞明白可以簡單的使用devltoolset來安裝高版本的gcc之前,自己源碼編譯,安裝gcc后,遇到了一些稀奇古怪的錯誤,比如系統頭文件里的某些宏沒有定義,libstdc++中找不到GLIBCXX_3.4.20等,還是花了好幾天時間在上面的。所以讀者朋友們,你們是幸福的啊,按照我的這篇文章,半天時間怎么着也能編譯出Bazel來。
做個調查,C++程序員,你能分清楚這幾個名詞之間的區別和聯系嗎?不清楚的默默給我點下文章右下角的“推薦”按鈕吧,哈哈。其實我寫這篇文章之前也不太清楚glibc和libstdc++這兩個東東的:)
參考資料:
- Redhat Developer toolset的介紹:很有意思,解釋了這套工具解決的問題,背后的原理等
- Google軟件構建工具Bazel原理及使用方法介紹