bazel C++語法入門

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>]

命令行參數(shù)文檔

工作原理

  • 加載與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_prefixstrip_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 #includegoogletest-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-greethello-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的不同版本

其他

getting started bazel C++

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市树瞭,隨后出現(xiàn)的幾起案子拇厢,更是在濱河造成了極大的恐慌,老刑警劉巖晒喷,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孝偎,死亡現(xiàn)場離奇詭異,居然都是意外死亡凉敲,警方通過查閱死者的電腦和手機(jī)衣盾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爷抓,“玉大人势决,你說我怎么就攤上這事》显蓿” “怎么了徽龟?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長唉地。 經(jīng)常有香客問我,道長传透,這世上最難降的妖魔是什么耘沼? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮朱盐,結(jié)果婚禮上群嗤,老公的妹妹穿的比我還像新娘。我一直安慰自己兵琳,他們只是感情好狂秘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著躯肌,像睡著了一般者春。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上清女,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天钱烟,我揣著相機(jī)與錄音,去河邊找鬼。 笑死拴袭,一個胖子當(dāng)著我的面吹牛读第,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拥刻,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怜瞒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了般哼?” 一聲冷哼從身側(cè)響起盼砍,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎逝她,沒想到半個月后浇坐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黔宛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年近刘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臀晃。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡觉渴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出徽惋,到底是詐尸還是另有隱情案淋,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布险绘,位于F島的核電站踢京,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宦棺。R本人自食惡果不足惜瓣距,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望代咸。 院中可真熱鬧蹈丸,春花似錦、人聲如沸呐芥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽思瘟。三九已至荸百,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間潮太,已是汗流浹背管搪。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工虾攻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人更鲁。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓霎箍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親澡为。 傳聞我的和親對象是個殘疾皇子漂坏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容