最近重構代碼以後,打算在本地用bazel來做項目構建。主要是由於brpc已經支持了bazel,因此在此以前料想會簡單許多。html
安裝比較簡單,centos直接用yum就行。按照這個指示:c++
https://docs.bazel.build/versions/master/install-redhat.htmlgit
1 wget https://copr.fedorainfracloud.org/coprs/vbatts/bazel/repo/epel-7/vbatts-bazel-epel-7.repo -O /etc/yum.repos.d/ 2 yum install bazel
最基本的使用,參考tutorial就好了。github
https://docs.bazel.build/versions/master/tutorial/cpp.htmlapache
經常使用的也就是cc_library和cc_binary。(由於我如今用blade也是這樣……)centos
固然寫c++,這裏有個common case能夠看看。ide
https://docs.bazel.build/versions/master/cpp-use-cases.htmlui
頭文件
頭文件的引入比較複雜些,分幾種狀況:google
1. 多文件。(使用通配符)spa
1 cc_library( 2 name = "build-all-the-files", 3 srcs = glob(["*.cc"]), 4 hdrs = glob(["inlcude/**/*.h"]), 5 )
2. 使用copts來指定引用目錄。
1 cc_library( 2 name = "some_lib", 3 srcs = ["some_lib.cc"], 4 hdrs = ["include/some_lib.h"], 5 copts = ["-Ilegacy/some_lib/include"], 6 )
這裏就涉及到另外一個參數,includes。includes和copts的使用區別主要有兩點:
a. includes不須要加-I,並且直接是相對路徑就行。也就是說,若是相對於主目錄是./sub/subsub/a.h,sub/BUILD裏,includes只須要寫['subsub'], 若是是copts則須要寫['-Isub/subsub/']。
b. copts只在當前目標裏生效。includes則全部依賴到該目錄都會繼承。因此通常library仍是用includes。
這裏還要注意,若是用cc_binary,srcs裏也要包含引用的頭文件,否則也會報錯。
其餘參數就看看文檔:
https://docs.bazel.build/versions/master/be/c-cpp.html
外部引用
能夠在WORKSPACE文件裏寫。
https://docs.bazel.build/versions/master/be/workspace.html
具體個人使用場景是把第3方庫代碼download下來放在項目裏,而後經過WORKSPACE來設置。因此我會用到的是local_repository。好比我在個人項目WORKSPACE裏這樣寫:
1 local_repository( 2 name = "com_google_protobuf", 3 path = "3rdlib/protobuf-3.6.1/", 4 ) 5 6 local_repository( 7 name = "com_github_google_leveldb", 8 path = "3rdlib/leveldb-1.20", 9 ) 10 11 local_repository( 12 name = "com_github_gflags_gflags", 13 path = "3rdlib/gflags-master", 14 )
而後把brpc裏對應的leveldb.BUILD拷到leveldb的源碼目錄,這樣brpc的BUILD基本就不須要改了。
可是這裏碰到另外一個坑,就是編譯protobuf要指定HAVE_LIB=1。這裏就經過在項目根目錄的.bazelrc裏寫:
1 build --copt -DHAVE_ZLIB=1
這樣bazel build就會默認調用這句命令。這裏有個問題,是必需要在項目的根目錄.bazelrc裏寫,在第三方目錄裏寫是沒用的。
https://github.com/bazelbuild/bazel/issues/6319
https://github.com/brpc/brpc/issues/275
外部非bazel的項目也能夠用genrule,使用make來編譯。genrule會自動執行。被依賴的文件,可能經過filegroup暴露出去。
https://docs.bazel.build/versions/master/be/general.html
genrule能夠用到一些內置變量。系統變量用$$引用。內置變量見:
https://docs.bazel.build/versions/master/be/make-variables.html
可是獲取不了本項目的絕對路徑。因此我也不知道應該怎麼撈取,獲得的都是sandbox裏的,只能用..來取到項目目錄。
1 genrule( 2 name = "libevent-srcs", 3 outs = include_files + lib_files, 4 cmd = "\n".join([ 5 "export INSTALL_DIR=$$(pwd)/$(@D)/libevent", 6 "export TMP_DIR=$$(mktemp -d -t libevent.XXXXXX)", 7 "mkdir -p $$TMP_DIR", 8 "cp -R $$(pwd)/../../../../../external/com_github_libevent_libevent/* $$TMP_DIR", 9 "cd $$TMP_DIR", 10 "./autogen.sh", 11 "./configure --prefix=$$INSTALL_DIR CFLAGS=-fPIC CXXFLAGS=-fPIC --enable-shared=no --disable-openssl", 12 "make install", 13 "rm -rf $$TMP_DIR", 14 ]), 15 )
動態庫查找問題
有個庫用到了boost。boost太大沒有包含到項目裏,放在另外一個目錄裏,可是bazel找不到庫目錄,雖然已經export了LIBRARY_PATH和LD_LIBRARY_PATH。可是實際執行時是:
1 exec env - \ 2 LD_LIBRARY_PATH=:/home/myaccount/boost_1_68_0/release/lib/ \ 3 PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/local/apache-hive-2.3.3-bin:/usr/local/apache-hive-2.3.3-bin:/home/xxj/.local/bin \ 4 PWD=/proc/self/cwd \ 5 TMPDIR=/tmp \
由於沒有傳遞LIBRARY_PATH,因此boost庫找不到。LIBRARY_PATH和LD_LIBRARY_PATH的區別見:
https://stackoverflow.com/questions/4250624/ld-library-path-vs-library-path
IBRARY_PATH is used by gcc before compilation to search directories containing static libraries that need to be linked to your program.
LD_LIBRARY_PATH is used by your program to search directories containing shared libraries after it has been successfully compiled and linked.
解決方案就在經過--action_env指定。
1 bazel build //3rdlib/test:bintest --action_env=LIBRARY_PATH=:/home/myaccount/boost_1_68_0/release/lib/
https://bazel.build/designs/2016/06/21/environment.html
Currently, Bazel provides a cleaned set of environment variables to the actions in order to obtain hermetic builds.
If the effective option for a variable has an unspecified value, the value from the invocation environment of Bazel is taken.
因此這裏也能夠不給LIBRARY_PATH指定值,這樣就會直接使用環境變量。
1 bazel build //3rdlib/test:bintest --action_env=LIBRARY_PATH
proto處理
https://blog.bazel.build/2017/02/27/protocol-buffers.html
定義一個proto_library和對應的cc_proto_library。
1 proto_library( 2 name = "http_proto", 3 srcs = [ 4 "http.proto", 5 ], 6 ) 7 8 cc_proto_library( 9 name = "http_cc_proto", 10 deps = [":http_proto"], 11 )
這裏cc_proto_library的deps必定要指向proto_library。
https://docs.bazel.build/versions/master/be/c-cpp.html#cc_proto_library
而後對應的cc_binary能夠依賴到它和它產生的文件:
1 cc_binary( 2 name = "http_server", 3 srcs = ["http_server.cpp"], 4 deps = [ 5 ":http_cc_proto", 6 "//3rdlib/brpc-0.9.5:brpc", 7 ], 8 )
不過要想include生成的.pb.h文件,須要用相對於workspace的相對路徑才行。
待定問題
1. -fopenmp這類參數無法繼承。好比某個庫編譯須要用到-fopenmp。那麼依賴到的binary的copts也要加上這個。如今尚未其餘方案。
1 copts = [ 2 '-fopenmp', 3 '-march=native', 4 ],