bazel的所有代碼都在當(dāng)前工程伶唯,每個工程都是一個 WORKSPACE 。
每個WORKSPACE下有多個BUILD文件淑趾。
BUILD內(nèi)是多個targets吱殉,這些targets都是以starlark語言聲明。
Starlark語言
- 和python很像珊拼。
- 線程安全
- 數(shù)據(jù)類型有 None, bool, dict, function, int, list, string, depset, struct
- 可變數(shù)據(jù)結(jié)構(gòu)有 lists 和 dicts
命令行
規(guī)則
bazel [<startup options>] <command> [<args>]
或
bazel [<startup options>] <command> [<args>] -- [<target patterns>]
工作原理
- 加載與target有關(guān)的BUILD文件
- 分析inputs和dependencies食呻,生成 action graph
- 執(zhí)行g(shù)raph,產(chǎn)出outputs
action graph: bazel依賴這個圖來追蹤文件變化,以及是否需要重新編譯仅胞,并且還可以為用戶提供代碼之間的依賴關(guān)系圖浪感。
依賴聲明
- 同一個文件BUILD之內(nèi)
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
],
)
- 不同BUILD文件之間
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
"http://lib:hello-time",
],
)
:hello-time 定義在 lib 目錄
不同的目錄BUILD在bazel中被稱為 不同的package
- 可見性
同一個package內(nèi)的targets默認(rèn)互相可見
不同package之間targets的可見性需要手動定義
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["http://main:__pkg__"],
)
可以在每個package的BUILD文件頂部聲明其中的targets對其他包的默認(rèn)可見性
package(
default_visibility = [
"http://tensorflow_serving:internal",
],
features = ["-layering_check"],
)
對所有包可見聲明如下
cc_proto_library(
name = "cc_echo_c++_proto",
deps = [
":echo_c++_proto",
],
visibility = [
"http://visibility:public",
],
)
target
有2種
- rule target,比如 cc_library
- file target
C++ 最佳實(shí)踐
BUILD文件
- 每個BUILD文件包含一個 cc_library 規(guī)則目標(biāo)
- 盡可能細(xì)粒度C++庫饼问,以提高并行速度影兽,并減少增量編譯
- 如果srcs中只有一個文件,那么 cc_library的名字和這個文件名相同莱革,比如:
cc_library(
name = "mylib",
srcs = ["mylib.cc"],
hdrs = ["mylib.h"],
deps = [":lower-level-lib"]
)
- 每個library都有個單獨(dú)的test target峻堰,并且以_test結(jié)尾命名這個target和測試文件名,比如
cc_test(
name = "mylib_test",
srcs = ["mylib_test.cc"],
deps = [":mylib"]
)
include路徑
- 所有include路徑都相對于WORKSPACE目錄
- 非系統(tǒng)目錄用
#include "foo/bar/baz.h"
, 系統(tǒng)目錄用#include <foo/bar/baz.h>
- 不要使用
.
和..
- 對第三方庫可以使用
include_prefix
和strip_include_prefix
有時候依賴第三方庫的時候盅视,這些庫里的文件已有的include path如果放到當(dāng)前目錄捐名,會不符合從workspace root引用文件的規(guī)則,就需要添加目錄闹击,比如下面的目錄
└── my-project
├── legacy
│ └── some_lib
│ ├── BUILD
│ ├── include
│ │ └── some_lib.h
│ └── some_lib.cc
└── WORKSPACE
以上镶蹋,bazel要求some_lib.h
必須以legacy/some_lib/include/some_lib.h
這個形式包含,但some_lib.cc
現(xiàn)在是"include/some_lib.h"
這樣包含的赏半,要使這個include path有效贺归,需要按如下方式指定路徑(待驗(yàn)證):
cc_library(
name = "some_lib",
srcs = ["some_lib.cc"],
hdrs = ["include/some_lib.h"],
copts = ["-Ilegacy/some_lib/include"],
)
包含多個文件
使用glob
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"]),
hdrs = glob(["*.h"]),
)
依賴處理
- bazel中的依賴不傳遞解析
如果包含了其他頭文件,就要把這個頭文件的target包含進(jìn)來断箫。這個頭文件內(nèi)部的include則不用管拂酣。比如
sandwich依賴bread,bread依賴flour仲义,但sandwich不依賴flour婶熬。
cc_library(
name = "sandwich",
srcs = ["sandwich.cc"],
hdrs = ["sandwich.h"],
deps = [":bread"],
)
cc_library(
name = "bread",
srcs = ["bread.cc"],
hdrs = ["bread.h"],
deps = [":flour"],
)
cc_library(
name = "flour",
srcs = ["flour.cc"],
hdrs = ["flour.h"],
)
- 單個頭文件,如果沒有實(shí)現(xiàn)埃撵,也需要定義target赵颅,比如
cc_library(
name = "source_adapter",
hdrs = ["source_adapter.h"],
visibility = [
"http://visibility:public",
],
deps = [
":loader",
":servable_data",
":source",
":storage_path",
":target",
"http://tensorflow_serving/util:class_registration",
"@org_tensorflow//tensorflow/core:lib",
],
)
包含外部庫
假設(shè)我們要使用Google Test,可以在WORKSPACE中這樣指定:
new_http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
build_file = "gtest.BUILD",
)
【注】如果庫已經(jīng)包含了一個BUILD文件暂刘,可以使用 non-new_
函數(shù)饺谬。
創(chuàng)建文件gtest.BUILD
,這個文件用來編譯Google Test鸳惯,由于google test比較特殊的需求商蕴,所以它的編譯規(guī)則會更復(fù)雜,特殊性在于:
-
googletest-release-1.7.0/src/gtest-all.cc
#include
了googletest-release-1.7.0/src/
下的所有文件芝发,所以需要把這個文件排除掉 - 它的頭文件都是相對于這個目錄的
googletest-release-1.7.0/include/
绪商,比如"gtest/gtest.h"
,所以需要把這個目錄加到copts的-I選項(xiàng)中 - 需要鏈接pthread
所以辅鲸,最終編譯規(guī)則如下:
cc_library(
name = "main",
srcs = glob(
["googletest-release-1.7.0/src/*.cc"],
exclude = ["googletest-release-1.7.0/src/gtest-all.cc"]
),
hdrs = glob([
"googletest-release-1.7.0/include/**/*.h",
"googletest-release-1.7.0/src/*.h"
]),
copts = [
"-Iexternal/gtest/googletest-release-1.7.0/include"
],
linkopts = ["-pthread"],
visibility = ["http://visibility:public"],
)
這個看起來有點(diǎn)亂格郁,因?yàn)槔锩姘四莻€版本目錄名,這個名字可以在new_http_archive
中使用strip_prefix
去掉:
new_http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
build_file = "gtest.BUILD",
strip_prefix = "googletest-release-1.7.0",
)
去掉后的gtest.BUILD文件如下:
cc_library(
name = "main",
srcs = glob(
["src/*.cc"],
exclude = ["src/gtest-all.cc"]
),
hdrs = glob([
"include/**/*.h",
"src/*.h"
]),
copts = ["-Iexternal/gtest/include"],
linkopts = ["-pthread"],
visibility = ["http://visibility:public"],
)
現(xiàn)在,其他的 cc_ rules
可以依賴于 @gtest//:main
例书。
更詳細(xì)的cc rule說明參考 cc rules
編寫測試用例
創(chuàng)建文件 ./test/hello-test.cc
#include "gtest/gtest.h"
#include "lib/hello-greet.h"
TEST(HelloTest, GetGreet) {
EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}
創(chuàng)建 ./test/BUILD
cc_test(
name = "hello-test",
srcs = ["hello-test.cc"],
copts = ["-Iexternal/gtest/include"],
deps = [
"@gtest//:main",
"http://lib:hello-greet",
],
)
注意锣尉,要使hello-greet
對hello-test
可見,需要在 ./lib/BUILD
文件中添加屬性visibility
决采,值為 //test:__pkg__
自沧。
運(yùn)行測試用例:
bazel test test:hello-test
輸出:
INFO: Found 1 test target...
Target //test:hello-test up-to-date:
bazel-bin/test/hello-test
INFO: Elapsed time: 4.497s, Critical Path: 2.53s
//test:hello-test PASSED in 0.3s
Executed 1 out of 1 tests: 1 test passes.
該部分來自于 bazel C++ use case
包含預(yù)編譯的庫
- 動態(tài)庫
cc_library(
name = "mylib",
srcs = ["mylib.so"],
hdrs = ["mylib.h"],
)
處理外部依賴
Working with external dependencies
依賴bazel工程
依賴非bazel工程
需要編寫B(tài)UILD文件
依賴隱藏(Shadowing)
- 依賴同一個package的不同版本