Bazel概念和術(shù)語(yǔ)

概念和術(shù)語(yǔ)

說(shuō)明

本文檔概述了Bazel構(gòu)建源代碼樹(shù)形結(jié)構(gòu)和Bazel中使用的術(shù)語(yǔ)北启。翻譯來(lái)源:https://docs.bazel.build/versions/master/build-ref.html

介紹

Bazel使用被稱為“工作區(qū)”的目錄中的源代碼構(gòu)建軟件。工作空間中的源文件以嵌套的包層次結(jié)構(gòu)進(jìn)行組織培廓,其中每個(gè)包位于一個(gè)目錄泣港,其中包含一組相關(guān)的源文件和一個(gè)BUILD文件当纱。BUILD文件指定可以從源文件構(gòu)建哪些軟件輸出。

工作區(qū)(Workspace)箫柳,軟件包(packages)和目標(biāo)(targets)

工作空間(Workspace)

工作區(qū)包含構(gòu)建程序所需源文件的文件系統(tǒng),同時(shí)包含鏈接到輸入的文件夾涮毫。每個(gè)工作空間目錄都有一個(gè)名為WORKSPACE的文本文件罢防,該文件可以為空咒吐,也可以包含 構(gòu)建程序所需外部依賴項(xiàng)的的引用。

WORKSPACE所在目錄被視為工作區(qū)的根目錄妄呕。因此,Bazel會(huì)忽略工作空間中子目錄的WORKSPACE文件(因?yàn)樗鼈冃纬闪硪粋€(gè)工作空間)疏魏。

Bazel還支持將WORKSPACE.bazelfile作為WORKSPACE文件的別名大莫。如果兩個(gè)文件都存在烙丛,WORKSPACE.bazel將具有優(yōu)先權(quán)河咽。

儲(chǔ)存庫(kù)(Repositories)

代碼在存儲(chǔ)庫(kù)中組織。包含WORKSPACE文件的目錄是主存儲(chǔ)庫(kù)的根目錄搁凸,也稱為@褥芒。其他(外部)存儲(chǔ)庫(kù)在WORKSPACE通過(guò)工作區(qū)規(guī)則定義惜颇。

Bazel工作空間規(guī)則記錄在Build Encyclopedia 的“ 工作空間規(guī)則”部分中凌摄,以及嵌入式Starlark存儲(chǔ)庫(kù)規(guī)則文檔中 痴怨。

由于外部存儲(chǔ)庫(kù)本身就是存儲(chǔ)庫(kù)浪藻,因此它們通常也包含一個(gè)WORKSPACE文件。但是萌丈,Bazel將忽略這些 WORKSPACE文件辆雾。需要注意的是藤乙,依賴傳遞的存儲(chǔ)庫(kù)不會(huì)被自動(dòng)添加。

軟件包(Packages)

儲(chǔ)存庫(kù)中組織代碼的主要單位是軟件包罚勾。軟件包集合相關(guān)的文件并描述它們之間的依賴性。

位于工作空間的頂級(jí)目錄下包含名為BUILDBUILD.bazel文件的目錄定義為一個(gè)程序包划煮。軟件包包括其目錄中的所有文件及子目錄器躏,但不包含自身有BUILD文件的子目錄。

例如揽浙,在下面的目錄樹(shù)中馅巷,有兩個(gè)軟件包my/app钓猬,和子軟件包my/app/tests。請(qǐng)注意异雁,這my/app/data不是包,而是屬于package的目錄my/app示绊。

src/my/app/BUILD
src/my/app/app.cc
src/my/app/data/input.txt
src/my/app/tests/BUILD
src/my/app/tests/test.cc

目標(biāo)(Targets)

軟件包是容器拌禾。包的元素稱為 target。大多數(shù)目標(biāo)是文件規(guī)則這兩種主要類型之一您市。另外,還有另一種目標(biāo)榕莺,即 包裝組,但數(shù)量卻要少得多亏拉。

文件進(jìn)一步分為兩種莽使。 源文件通常是在人們的努力下編寫(xiě)的灵再,并檢入到存儲(chǔ)庫(kù)中翎迁。 生成的文件(有時(shí)稱為派生文件)未檢入,而是由構(gòu)建工具根據(jù)特定規(guī)則從源文件生成的雌团。

第二類目標(biāo)是規(guī)則。規(guī)則指定一組輸入和一組輸出文件之間的關(guān)系,包括從輸入派生輸出的必要步驟替久。規(guī)則的輸出始終是生成的文件蚯根。規(guī)則的輸入可能是源文件教藻,但也可能是生成的文件距帅。因此,一條規(guī)則的輸出可能是另一條規(guī)則的輸入括堤,從而可以構(gòu)建較長(zhǎng)的規(guī)則鏈碌秸。

在大多數(shù)情況下,規(guī)則輸入是源文件還是生成文件都是無(wú)關(guān)緊要的悄窃。重要的只是該文件的內(nèi)容讥电。這個(gè)事實(shí)使用規(guī)則生成的生成文件替換復(fù)雜的源文件變得很容易轧抗,例如恢口,當(dāng)手動(dòng)維護(hù)高度結(jié)構(gòu)化的文件的負(fù)擔(dān)變得太累,而有人編寫(xiě)程序來(lái)派生該文件時(shí),就會(huì)發(fā)生這種情況竖螃。該文件的使用者不需要更改。相反,生成的文件可以很容易地被僅具有本地更改的源文件替換嫡意。

規(guī)則的輸入也可以包括其他規(guī)則整袁。這種關(guān)系的確切含義通常非常復(fù)雜戈钢,并且依賴于語(yǔ)言或規(guī)則薪铜,但是從直觀上來(lái)說(shuō)很簡(jiǎn)單:C ++庫(kù)規(guī)則A可能有另一個(gè)C ++庫(kù)規(guī)則B用于輸入帮掉。這種依賴性的結(jié)果是劈猪,在編譯期間B的頭文件對(duì)A可用,在鏈接期間B的符號(hào)對(duì)A可用坡倔,而在執(zhí)行期間B的運(yùn)行時(shí)數(shù)據(jù)對(duì)A可用。

所有規(guī)則的不變之處在于畔柔,規(guī)則生成的文件始終與規(guī)則本身屬于同一包棚放;無(wú)法將文件生成到另一個(gè)包中。但是,規(guī)則的輸入來(lái)自另一個(gè)程序包并不少見(jiàn)球凰。

軟件包組是一組軟件包英遭,其目的是限制某些規(guī)則的可訪問(wèn)性相味。包組由package_group功能定義 逛裤。它們具有兩個(gè)屬性:它們包含的軟件包列表及其名稱。引用它們的唯一允許方式是從visibility規(guī)則的default_visibility屬性或從package 函數(shù)的 屬性。它們不生成或使用文件军拟。有關(guān)更多信息舵变,請(qǐng)參考Build Encyclopedia的相應(yīng)部分蒂萎。

標(biāo)簽(Labels)

所有目標(biāo)完全屬于一個(gè)包晦雨。目標(biāo)的名稱稱為其標(biāo)簽(label)罗珍,典型的標(biāo)簽形式如下:

@myrepo//my/app/main:app_binary

在標(biāo)簽引用它所在的相同存儲(chǔ)庫(kù)的典型情況下藕坯,存儲(chǔ)庫(kù)名稱可能會(huì)被忽略。因此俩由,在@myrepo 此標(biāo)簽內(nèi)通常寫(xiě)為

//my/app/main:app_binary

每個(gè)標(biāo)簽都有兩部分菲嘴,包名稱(my/app/main)和目標(biāo)名稱(app_binary)。每個(gè)標(biāo)簽都唯一標(biāo)識(shí)一個(gè)目標(biāo)汰翠。標(biāo)簽有時(shí)以其他形式出現(xiàn)龄坪;如果省略冒號(hào),則假定目標(biāo)名稱與程序包名稱的最后一個(gè)組成部分相同复唤,因此這兩個(gè)標(biāo)簽是等效的:

//my/app
//my/app:app

諸如此類的簡(jiǎn)短標(biāo)簽//my/app不要與軟件包名稱混淆健田。標(biāo)簽以開(kāi)頭//,但包名稱從不my/app包含佛纫,因此包含//my/app妓局。(一個(gè)常見(jiàn)的誤解是//my/app指一個(gè)程序包或程序包中的所有目標(biāo);都不是真的呈宇。)

在BUILD文件中好爬,可以省略label的package-name部分,也可以省略冒號(hào)甥啄。因此存炮,在用于程序包的BUILD文件 my/app(即//my/app:BUILD)中,以下“相對(duì)”標(biāo)簽都是等效的:

//my/app:app
//my/app
:app
app

(按照慣例,文件中省略了冒號(hào)穆桂,規(guī)則中保留了冒號(hào)宫盔,但是在其他方面并不重要。)

類似地享完,在BUILD文件中灼芭,可以通過(guò)相對(duì)于軟件包目錄的未修飾名稱來(lái)引用屬于該軟件包的文件:

generate.cc
testdata/input.txt

但是,從其他軟件包或從命令行般又,這些文件目標(biāo)必須始終通過(guò)其完整標(biāo)簽來(lái)引用彼绷,例如 //my/app:generate.cc

相對(duì)標(biāo)簽不能用于引用其他程序包中的目標(biāo)倒源。在這種情況下苛预,必須始終指定完整的軟件包名稱。例如笋熬,如果源樹(shù)同時(shí)包含該包 my/app和該包 my/app/testdata(即,這兩個(gè)包中的每一個(gè)都有其自己的BUILD文件)腻菇。后者包含一個(gè)名為的文件testdepot.zip胳螟。這里有兩種方法(一種錯(cuò)誤,一種正確)來(lái)引用此文件 //my/app:BUILD

testdata/testdepot.zip # Wrong: testdata is a different package.
//my/app/testdata:testdepot.zip # Right.

如果錯(cuò)誤地引用testdepot.zip了錯(cuò)誤的標(biāo)簽(例如//my/app:testdata/testdepot.zip 或)//my:app/testdata/testdepot.zip筹吐,則會(huì)從構(gòu)建工具中收到一條錯(cuò)誤消息糖耸,指出標(biāo)簽“跨越了包裝邊界”。您應(yīng)該通過(guò)將冒號(hào)放在包含最里面的BUILD文件的目錄之后來(lái)更正標(biāo)簽 //my/app/testdata:testdepot.zip丘薛。

以開(kāi)頭的標(biāo)簽@//是對(duì)主存儲(chǔ)庫(kù)的引用嘉竟,即使從外部存儲(chǔ)庫(kù)也可以使用。因此@//a/b/c與從//a/b/c外部存儲(chǔ)庫(kù)引用時(shí)有所不同 洋侨。前者返回主存儲(chǔ)庫(kù)舍扰,而后者//a/b/c在外部存儲(chǔ)庫(kù)本身中查找。當(dāng)在主存儲(chǔ)庫(kù)中編寫(xiě)引用主存儲(chǔ)庫(kù)中的目標(biāo)的規(guī)則時(shí)希坚,這尤其重要边苹,并將在外部存儲(chǔ)庫(kù)中使用這些規(guī)則。

標(biāo)簽的詞匯規(guī)范

標(biāo)簽的語(yǔ)法是故意嚴(yán)格的裁僧,以禁止對(duì)shell具有特殊含義的元字符个束。這有助于避免無(wú)意的引號(hào)問(wèn)題,并使得構(gòu)建用于操縱標(biāo)簽的工具和腳本(例如Bazel Query Language)更加容易 聊疲。允許的目標(biāo)名稱的詳細(xì)信息如下茬底。

目標(biāo)名稱 //...:**target-name**

target-name是包中目標(biāo)的名稱。規(guī)則名稱是name BUILD文件中規(guī)則聲明中的屬性值获洲;文件名是其相對(duì)于包含BUILD文件的目錄的路徑名阱表。目標(biāo)名稱必須完全由從集合azAZ09和標(biāo)點(diǎn)符號(hào)中提取的字符組成!%-@^_ "#$&'()*-+,;<=>?[]{|}~/.捶枢。不要..用來(lái)引用其他軟件包中的文件握截;使用 代替。文件名必須是標(biāo)準(zhǔn)格式的相對(duì)路徑名烂叔,這意味著它們既不能以斜杠開(kāi)頭或結(jié)尾(例如谨胞,并且被禁止),也不能包含多個(gè)連續(xù)的斜杠作為路徑分隔符(例如)蒜鸡。同樣胯努,上級(jí)引用(//<var style="box-sizing: border-box;">packagename</var>:<var style="box-sizing: border-box;">filename</var>/foofoo/foo//bar..)和當(dāng)前目錄引用(./)。該規(guī)則的唯一例外是目標(biāo)名稱可以完全由'.`'組成逢防。

雖然通常使用/文件目標(biāo)的名稱叶沛,但我們建議您避免在/規(guī)則名稱中使用。特別是當(dāng)使用標(biāo)簽的縮寫(xiě)形式時(shí)忘朝,可能會(huì)使讀者感到困惑灰署。即使沒(méi)有這樣的包裝 ,標(biāo)簽//foo/bar/wiz始終是其簡(jiǎn)寫(xiě); 即使該目標(biāo)存在局嘁,它也不會(huì)引用溉箕。//foo/bar/wiz:wiz``foo/bar/wiz``//foo:bar/wiz

但是,在某些情況下使用斜杠比較方便悦昵,有時(shí)甚至是必要的肴茄。例如,某些規(guī)則的名稱必須與它們的主要源文件匹配但指,該文件可以位于包的子目錄中寡痰。

套件名稱 //**package-name**:...

包的名稱是包含其BUILD文件的目錄的名稱,相對(duì)于源樹(shù)的頂級(jí)目錄棋凳。例如:my/app拦坠。軟件包名稱必須完全由從集合A- Za- z贫橙, 0- 9贪婉,' /',' -'卢肃,' .'疲迂,'和' _' 得出的字符組成,并且不能以斜杠開(kāi)頭莫湘。

對(duì)于具有對(duì)其模塊系統(tǒng)重要的目錄結(jié)構(gòu)的語(yǔ)言(例如Java)尤蒿,重要的是選擇作為該語(yǔ)言有效標(biāo)識(shí)符的目錄名稱。

盡管Bazel允許在構(gòu)建根目錄下使用軟件包(例如//:foo)幅垮,但不建議這樣做腰池,項(xiàng)目應(yīng)嘗試使用描述性更強(qiáng)的軟件包。

程序包名稱不得包含substring //,也不能以斜杠結(jié)尾示弓。

規(guī)則

規(guī)則指定輸入和輸出之間的關(guān)系讳侨,以及構(gòu)建輸出的步驟。規(guī)則可以是許多不同種類或類中的一種奏属,它們可以生成編譯的可執(zhí)行文件和庫(kù)跨跨,測(cè)試可執(zhí)行文件和其他支持的輸出,如 Build Encyclopedia中所述囱皿。

每個(gè)規(guī)則都有一個(gè)由name屬性指定的字符串類型的名稱勇婴。該名稱必須是語(yǔ)法上有效的目標(biāo)名稱,按規(guī)定以上嘱腥。在某些情況下耕渴,名稱有些隨意,而由規(guī)則生成的文件的名稱更有趣齿兔。屬實(shí)是正確的橱脸。在其他情況下,名稱是有意義的:例如對(duì)于*_binary*_test規(guī)則愧驱,規(guī)則名稱確定由構(gòu)建生成的可執(zhí)行文件的名稱慰技。

cc_binary(
    name = "my_app",
    srcs = ["my_app.cc"],
    deps = [
        "http://absl/base",
        "http://absl/strings",
    ],
)

每個(gè)規(guī)則都有一套屬性 ; 給定規(guī)則的適用屬性以及每個(gè)屬性的重要性和語(yǔ)義是規(guī)則類別的函數(shù);有關(guān)規(guī)則及其對(duì)應(yīng)屬性的列表组砚,請(qǐng)參見(jiàn)構(gòu)建百科全書(shū)。每個(gè)屬性都有一個(gè)名稱和一個(gè)類型掏颊。屬性可以具有的一些常見(jiàn)類型是整數(shù)糟红,標(biāo)簽,標(biāo)簽列表乌叶,字符串盆偿,字符串列表,輸出標(biāo)簽准浴,輸出標(biāo)簽列表事扭。并非在每個(gè)規(guī)則中都需要指定所有屬性。因此乐横,屬性形成了一個(gè)從鍵(名稱)到可選的求橄,鍵入的值的字典。

srcs許多規(guī)則中存在 的屬性的類型為“標(biāo)簽列表”葡公;其值(如果存在)是標(biāo)簽列表罐农,每個(gè)標(biāo)簽都是作為該規(guī)則輸入的目標(biāo)名稱。

outs許多規(guī)則中存在 的屬性的類型為“輸出標(biāo)簽列表”催什;這與srcs屬性的類型相似涵亏,但是在兩個(gè)重要方面有所不同。首先,由于規(guī)則的輸出與規(guī)則本身屬于同一包气筋,因此輸出標(biāo)簽不能包含包組件拆内。它們必須采用上面顯示的“相對(duì)”形式之一。其次宠默,(普通)標(biāo)簽屬性所隱含的關(guān)系與輸出標(biāo)簽所隱含的關(guān)系相反:規(guī)則取決于srcs麸恍,而規(guī)則則取決于outs。因此光稼,兩種類型的標(biāo)簽屬性將方向分配給目標(biāo)之間的邊緣或南,從而產(chǎn)生依賴圖。

這個(gè)針對(duì)目標(biāo)的有向無(wú)環(huán)圖稱為“目標(biāo)圖”或“構(gòu)建依賴關(guān)系圖”艾君,并且是Bazel Query工具在其上運(yùn)行的域采够。

構(gòu)建文件

上一節(jié)對(duì)軟件包,目標(biāo)和標(biāo)簽以及構(gòu)建依賴關(guān)系圖進(jìn)行了抽象描述冰垄。在本節(jié)中蹬癌,我們將研究用于定義包的具體語(yǔ)法。

根據(jù)定義虹茶,每個(gè)軟件包都包含一個(gè)BUILD文件逝薪,這是一個(gè)簡(jiǎn)短的程序。使用命令性語(yǔ)言Starlark評(píng)估BUILD文件 蝴罪。它們被解釋為語(yǔ)句的順序列表董济。

通常,順序確實(shí)很重要:例如要门,必須在使用變量之前定義變量虏肾。但是,大多數(shù)BUILD文件僅包含構(gòu)建規(guī)則的聲明欢搜,并且這些語(yǔ)句的相對(duì)順序無(wú)關(guān)緊要封豪。重要的是,到評(píng)估包完成時(shí)炒瘟,將宣布哪些規(guī)則以及具有哪些值吹埠。當(dāng)執(zhí)行構(gòu)建規(guī)則函數(shù)(例如)時(shí)cc_library,它將在圖形中創(chuàng)建一個(gè)新目標(biāo)疮装。以后可以使用標(biāo)簽來(lái)引用此目標(biāo)缘琅。因此,在簡(jiǎn)單的BUILD文件中斩个,可以在不更改行為的情況下自由地對(duì)規(guī)則聲明進(jìn)行重新排序胯杭。

為了鼓勵(lì)代碼和數(shù)據(jù)之間的清晰區(qū)分,BUILD文件不能包含函數(shù)定義受啥,for語(yǔ)句或 if語(yǔ)句(但可以使用列表推導(dǎo)和if 表達(dá)式)做个。應(yīng)該在.bzl 文件中聲明函數(shù)鸽心。此外, BUILD文件中不允許使用*args**kwargs參數(shù)居暖。而是顯式列出所有參數(shù)顽频。

至關(guān)重要的是,Starlark中的程序無(wú)法執(zhí)行任意I / O太闺。這個(gè)不變性使得BUILD文件的解釋是封閉的糯景,即僅依賴于一組已知的輸入,這對(duì)于確保構(gòu)建可復(fù)制是必不可少的省骂。

盡管從技術(shù)上說(shuō)蟀淮,它們是使用Latin-1字符集來(lái)解釋的,但BUILD文件應(yīng)僅使用ASCII字符寫(xiě)入钞澳。

由于只要基礎(chǔ)代碼的依賴性發(fā)生變化怠惶,就需要更新BUILD文件,因此它們通常由團(tuán)隊(duì)中的多個(gè)人維護(hù)轧粟。鼓勵(lì)BUILD文件作者自由地使用注釋來(lái)記錄每個(gè)構(gòu)建目標(biāo)的作用(無(wú)論它是否打算供公眾使用)策治,并記錄軟件包本身的作用。

加載擴(kuò)展

Bazel擴(kuò)展名是以結(jié)尾的文件.bzl兰吟。使用該load語(yǔ)句從擴(kuò)展名導(dǎo)入符號(hào)通惫。

load("http://foo/bar:file.bzl", "some_library")

此代碼將加載文件foo/bar/file.bzl并將some_library符號(hào)添加 到環(huán)境中。這可用于加載新規(guī)則混蔼,函數(shù)或常量(例如履腋,字符串,列表等)惭嚣「鳎可以通過(guò)使用附加參數(shù)來(lái)調(diào)用多個(gè)符號(hào)load。參數(shù)必須是字符串文字(無(wú)變量)料按,并且load語(yǔ)句必須出現(xiàn)在頂層,即它們不能在函數(shù)體內(nèi)卓箫。的第一個(gè)參數(shù)load是 標(biāo)識(shí)文件的標(biāo)簽.bzl载矿。如果是相對(duì)標(biāo)簽,則相對(duì)于包含當(dāng)前bzl文件的包(而非目錄)進(jìn)行解析 烹卒。load語(yǔ)句中的相對(duì)標(biāo)簽應(yīng)使用前導(dǎo):闷盔。 load還支持別名,即您可以為導(dǎo)入的符號(hào)分配不同的名稱旅急。

load("http://foo/bar:file.bzl", library_alias = "some_library")

您可以在一個(gè)load語(yǔ)句中定義多個(gè)別名逢勾。此外,參數(shù)列表可以包含別名和常規(guī)符號(hào)名稱藐吮。以下示例完全合法(請(qǐng)注意何時(shí)使用引號(hào))溺拱。

load(":my_rules.bzl", "some_rule", nice_alias = "some_other_rule")

.bzl文件中逃贝,_不會(huì)導(dǎo)出以開(kāi)頭的符號(hào),也無(wú)法從另一個(gè)文件中加載符號(hào)迫摔°灏猓可見(jiàn)性不影響加載(尚未):您無(wú)需使用exports_files即可使.bzl文件可見(jiàn)。

構(gòu)建規(guī)則的類型

大多數(shù)構(gòu)建規(guī)則來(lái)自家庭句占,按語(yǔ)言分組沪摄。例如,cc_binary纱烘,cc_librarycc_test分別是C ++的二進(jìn)制文件杨拐,庫(kù)和測(cè)試,生成規(guī)則擂啥。其他語(yǔ)言使用相同的命名方案鼎兽,但前綴不同,例如java_*對(duì)于Java彭羹。其中一些功能記錄在 Build Encyclopedia中工扎,但是任何人都可以創(chuàng)建新規(guī)則。

  • *_binary 規(guī)則以給定的語(yǔ)言構(gòu)建可執(zhí)行程序变骡。生成后离赫,可執(zhí)行文件將以規(guī)則標(biāo)簽的相應(yīng)名稱駐留在生成工具的二進(jìn)制輸出樹(shù)中,因此//my:program將出現(xiàn)在(例如)處$(BINDIR)/my/program塌碌。

    這樣的規(guī)則還會(huì)創(chuàng)建一個(gè)runfiles目錄渊胸,其中包含data 屬于該規(guī)則的屬性中提及的所有文件,或者該文件在其依賴關(guān)系的傳遞性關(guān)閉中的任何規(guī)則台妆;這組文件集中在一個(gè)位置翎猛,以便于部署到生產(chǎn)環(huán)境。

  • *_test 規(guī)則是規(guī)則的一種特殊化*_binary接剩,用于自動(dòng)化測(cè)試切厘。測(cè)試只是簡(jiǎn)單的程序,成功返回零懊缺。

    與二進(jìn)制文件一樣疫稿,測(cè)試也具有運(yùn)行文件樹(shù),其下的文件是測(cè)試可以在運(yùn)行時(shí)合法打開(kāi)的唯一文件鹃两。例如遗座,程序cc_test(name='x', data=['//foo:bar'])可以$TEST_SRCDIR/workspace/foo/bar在執(zhí)行期間打開(kāi)并讀取。(每種編程語(yǔ)言都有其自己的實(shí)用程序函數(shù)來(lái)訪問(wèn)的值$TEST_SRCDIR俊扳,但它們均等同于直接使用環(huán)境變量途蒋。)不遵守該規(guī)則將導(dǎo)致在遠(yuǎn)程測(cè)試主機(jī)上執(zhí)行測(cè)試時(shí)測(cè)試失敗。

  • *_library 規(guī)則以給定的編程語(yǔ)言指定單獨(dú)編譯的模塊馋记。庫(kù)可以依賴于其他庫(kù)号坡,二進(jìn)制文件和測(cè)試可以依賴于具有預(yù)期的單獨(dú)編譯行為的庫(kù)懊烤。

依存關(guān)系

如果在構(gòu)建或執(zhí)行時(shí)需要目標(biāo),則 目標(biāo)A 取決于目標(biāo) 筋帖。將取決于關(guān)系誘導(dǎo) 向無(wú)環(huán)圖上的目標(biāo)(DAG)奸晴,我們稱之為一個(gè) 依賴圖。目標(biāo)的直接依存關(guān)系是依存關(guān)系圖中長(zhǎng)度為1的路徑可到達(dá)的其他目標(biāo)日麸。目標(biāo)的 傳遞依存關(guān)系是通過(guò)圖形中任意長(zhǎng)度的路徑所依賴的目標(biāo)寄啼。 B``B``A

實(shí)際上,在構(gòu)建的上下文中代箭,有兩個(gè)依賴關(guān)系圖墩划,實(shí)際依賴關(guān)系圖和聲明的依賴關(guān)系圖 。在大多數(shù)情況下嗡综,兩個(gè)圖是如此相似乙帮,以至于不需要進(jìn)行區(qū)分,但對(duì)于下面的討論很有用极景。

實(shí)際和聲明的依賴關(guān)系

一個(gè)目標(biāo)X實(shí)際上取決于目標(biāo) Y當(dāng)且僅當(dāng)Y必須存在察净,并內(nèi)置了最新的,以便X于正確建立盼樟∏饪ǎ“構(gòu)建”可能意味著生成,處理晨缴,編譯译秦,鏈接,歸檔击碗,壓縮筑悴,執(zhí)行或在構(gòu)建期間例行發(fā)生的任何其他類型的任務(wù)。

當(dāng)且僅當(dāng)?shù)陌写嬖趶?到的依賴邊時(shí)稍途, 目標(biāo)X聲明對(duì)目標(biāo) Y具有依賴關(guān)系阁吝。 X``Y``X

為了正確構(gòu)建,實(shí)際依賴項(xiàng)A的圖必須是已聲明依賴項(xiàng)D的圖的子圖械拍。也就是說(shuō)求摇,每對(duì)直接連接的節(jié)點(diǎn)的x --> y必須也可以直接連接在d。我們說(shuō) doverapproximation一個(gè)殊者。

重要的是,不要過(guò)分逼近验夯,因?yàn)槎嘤嗟穆暶饕蕾囮P(guān)系可能會(huì)使生成速度變慢而二進(jìn)制文件更大猖吴。

對(duì)于BUILD文件編寫(xiě)者而言,這意味著每條規(guī)則都必須明確聲明其對(duì)構(gòu)建系統(tǒng)的所有實(shí)際直接依賴關(guān)系挥转,并且不再聲明海蔽。不遵守該原理會(huì)導(dǎo)致未定義的行為:構(gòu)建可能會(huì)失敗共屈,但是更糟糕的是,構(gòu)建可能取決于某些先前的操作党窜,或者目標(biāo)恰好具有這些可傳遞聲明的依賴項(xiàng)拗引。構(gòu)建工具會(huì)積極嘗試檢查缺少的依存關(guān)系并報(bào)告錯(cuò)誤,但是不可能在所有情況下都完成此檢查幌衣。

您無(wú)需(也不應(yīng))嘗試列出間接導(dǎo)入的所有內(nèi)容矾削,即使A在執(zhí)行時(shí)“需要”它也是如此。

在構(gòu)建目標(biāo)期間X豁护,構(gòu)建工具將檢查的依賴關(guān)系的整個(gè)可傳遞性關(guān)閉哼凯,X以確保最終結(jié)果中反映了這些目標(biāo)的任何更改,并根據(jù)需要重建中間件楚里。

依賴項(xiàng)的傳遞性導(dǎo)致常見(jiàn)錯(cuò)誤断部。通過(guò)粗心的編程,一個(gè)文件中的代碼可以使用間接依賴關(guān)系(即聲明的依賴關(guān)系圖中的可傳遞但不是直接邊緣)提供的代碼班缎。間接依賴項(xiàng)未出現(xiàn)在BUILD文件中蝴光。由于規(guī)則不直接取決于提供者,因此無(wú)法跟蹤更改达址,如以下示例時(shí)間線所示:

1.首先蔑祟,一切正常

package中的代碼a使用package中的代碼b。包中的代碼b使用包中的代碼c苏携,因此可a傳遞地依賴c做瞪。

The code in package a uses code in package b. The code in package b uses code in package c, and thus a transitively depends on c.

a/BUILD

rule(
    name = "a",
    srcs = "a.in",
    deps = "http://b:b",
)

a/a.in

import b;
b.foo();

b/BUILD

rule(
    name = "b",
    srcs = "b.in",
    deps = "http://c:c",
)

b/b.in

import c;
function foo() {
  c.bar();
}

| [圖片上傳失敗...(image-ea0f72-1583474417950)]

Declared dependency graph

| [圖片上傳失敗...(image-62d6e1-1583474417950)]

Actual dependency graph

|

The declared dependencies overapproximate the actual dependencies. All is well.

聲明的依賴關(guān)系過(guò)于逼近實(shí)際依賴關(guān)系。一切都很好右冻。

2.引入了潛在危害装蓬。

有人不小心在上面添加了代碼a,從而直接創(chuàng)建了對(duì)的實(shí)際依賴c纱扭,但忘記聲明了牍帚。

a/a.in

import b;
import c;
b.foo();
c.garply();

</pre>

| [圖片上傳失敗...(image-cd9880-1583437362875)]

聲明的依賴圖

| [圖片上傳失敗...(image-c8b0b4-1583437362875)]

實(shí)際依賴圖

|

聲明的依賴關(guān)系不再與實(shí)際依賴關(guān)系近似。這可能會(huì)成立乳蛾,因?yàn)閮蓚€(gè)圖的傳遞閉包是相等的暗赶,但掩蓋了一個(gè)問(wèn)題:a對(duì)具有實(shí)際但未聲明的依賴性c

3.危害被發(fā)現(xiàn)

有人進(jìn)行重構(gòu)b肃叶,使其不再依賴于 c蹂随,無(wú)意間突破a了自己的錯(cuò)。

b/BUILD
    name = "b",
    srcs = "b.in",
    deps = "http://d:d",
)
b/b.in
import d;
function foo() {
  d.baz();
}

聲明的依賴圖

|
Declared dependency graph

實(shí)際依賴圖

Actual dependency graph

聲明的依賴關(guān)系圖現(xiàn)在是實(shí)際依賴關(guān)系的近似值因惭,即使在傳遞關(guān)閉時(shí)也是如此岳锁;構(gòu)建可能會(huì)失敗。通過(guò)確保在BUILD文件中正確聲明了步驟2中引入的從a到的實(shí)際依賴關(guān)系蹦魔,可以避免該問(wèn)題c激率。

依賴類型

大多數(shù)的生成規(guī)則有通用的依賴咳燕,指定不同類型的三個(gè)屬性:srcsdepsdata乒躺。這些將在下面說(shuō)明招盲。另請(qǐng)參閱 “構(gòu)建百科全書(shū)”中所有規(guī)則共有的屬性

許多規(guī)則還對(duì)規(guī)則的特定種類的依賴嘉冒,例如附加屬性compiler曹货,resources等等,這些都在Build百科全書(shū)詳細(xì)說(shuō)明健爬。

srcs 依存關(guān)系

一個(gè)或多個(gè)輸出源文件的規(guī)則直接消耗的文件控乾。

deps 依存關(guān)系

指向單獨(dú)編譯的模塊的規(guī)則,這些模塊提供頭文件娜遵,符號(hào)蜕衡,庫(kù),數(shù)據(jù)等设拟。

data 依存關(guān)系

構(gòu)建目標(biāo)可能需要一些數(shù)據(jù)文件才能正確運(yùn)行慨仿。這些數(shù)據(jù)文件不是源代碼:它們不會(huì)影響目標(biāo)的構(gòu)建方式。例如纳胧,單元測(cè)試可以將函數(shù)的輸出與文件的內(nèi)容進(jìn)行比較镰吆。在構(gòu)建單元測(cè)試時(shí),我們不需要文件跑慕;但是運(yùn)行測(cè)試時(shí)確實(shí)需要它万皿。這同樣適用于在執(zhí)行過(guò)程中啟動(dòng)的工具。

構(gòu)建系統(tǒng)在一個(gè)隔離的目錄中運(yùn)行測(cè)試核行,在該目錄中只有列為“數(shù)據(jù)”的文件可用牢硅。因此,如果二進(jìn)制/庫(kù)/測(cè)試需要運(yùn)行某些文件芝雪,請(qǐng)?jiān)跀?shù)據(jù)中指定它們(或包含它們的構(gòu)建規(guī)則)减余。例如:

# I need a config file from a directory named env:
java_binary(
    name = "setenv",
    ...
    data = [":env/default_env.txt"],
)

# I need test data from another directory
sh_test(
    name = "regtest",
    srcs = ["regtest.sh"],
    data = [
        "http://data:file1.txt",
        "http://data:file2.txt",
        ...
    ],
)

這些文件可通過(guò)相對(duì)路徑使用 path/to/data/file。在測(cè)試中惩系,也可以通過(guò)將測(cè)試的源目錄的路徑和工作空間相對(duì)的路徑(例如)連接起來(lái)來(lái)引用它們 ${TEST_SRCDIR}/workspace/path/to/data/file位岔。

使用標(biāo)簽引用目錄

查看我們的BUILD文件時(shí),您可能會(huì)注意到一些data標(biāo)簽引用目錄堡牡。這些標(biāo)簽以/./類似結(jié)尾:

data = ["http://data/regression:unittest/."] # don't use this

或者像這樣:

data = ["testdata/."] # don't use this

或者像這樣:

data = ["testdata/"] # don't use this

這似乎很方便抒抬,特別是對(duì)于測(cè)試(因?yàn)樗试S測(cè)試使用目錄中的所有數(shù)據(jù)文件)。

但是晤柄,請(qǐng)不要這樣做瞧剖。為了確保更改后正確的增量重建(和測(cè)試的重新執(zhí)行),構(gòu)建系統(tǒng)必須知道作為構(gòu)建(或測(cè)試)輸入的完整文件集。當(dāng)您指定目錄時(shí)抓于,僅當(dāng)目錄本身更改時(shí)(由于添加或刪除文件),構(gòu)建系統(tǒng)才會(huì)執(zhí)行重建浇借,但是由于這些更改不會(huì)影響封閉目錄捉撮,因此無(wú)法檢測(cè)到對(duì)單個(gè)文件的編輯。不應(yīng)將目錄指定為構(gòu)建系統(tǒng)的輸入妇垢,而應(yīng)顯式或使用glob()函數(shù)枚舉其中包含的文件集 巾遭。(**用于強(qiáng)制遞歸。) glob()

data = glob(["testdata/**"]) # use this instead

不幸的是闯估,在某些情況下必須使用目錄標(biāo)簽灼舍。例如,如果testdata目錄包含名稱不符合嚴(yán)格標(biāo)簽語(yǔ)法的文件 (例如涨薪,它們包含某些標(biāo)點(diǎn)符號(hào))骑素,則文件的顯式枚舉或使用該 glob()函數(shù)將產(chǎn)生無(wú)效的標(biāo)簽錯(cuò)誤。在這種情況下刚夺,您必須使用目錄標(biāo)簽献丑,但要注意上述伴隨錯(cuò)誤重建的風(fēng)險(xiǎn)。

如果必須使用目錄標(biāo)簽侠姑,請(qǐng)記住创橄,您不能使用相對(duì)../路徑來(lái)引用父包。相反莽红,請(qǐng)使用“ //data/regression:unittest/.”之類的絕對(duì)路徑妥畏。

請(qǐng)注意,目錄標(biāo)簽僅對(duì)數(shù)據(jù)依賴項(xiàng)有效安吁。如果您嘗試將目錄用作以外的參數(shù)中的標(biāo)簽data醉蚁,它將失敗,并且您將收到(可能是隱秘的)錯(cuò)誤消息柳畔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馍管,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子薪韩,更是在濱河造成了極大的恐慌确沸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俘陷,死亡現(xiàn)場(chǎng)離奇詭異罗捎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拉盾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)桨菜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事倒得⌒汉欤” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵霞掺,是天一觀的道長(zhǎng)谊路。 經(jīng)常有香客問(wèn)我,道長(zhǎng)菩彬,這世上最難降的妖魔是什么缠劝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮骗灶,結(jié)果婚禮上惨恭,老公的妹妹穿的比我還像新娘。我一直安慰自己耙旦,他們只是感情好脱羡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著母廷,像睡著了一般轻黑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琴昆,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天氓鄙,我揣著相機(jī)與錄音,去河邊找鬼业舍。 笑死抖拦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舷暮。 我是一名探鬼主播态罪,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼下面!你這毒婦竟也來(lái)了复颈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沥割,失蹤者是張志新(化名)和其女友劉穎耗啦,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體机杜,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帜讲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椒拗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片似将。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡获黔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出在验,到底是詐尸還是另有隱情玷氏,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布腋舌,位于F島的核電站预茄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏侦厚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一拙徽、第九天 我趴在偏房一處隱蔽的房頂上張望刨沦。 院中可真熱鬧,春花似錦膘怕、人聲如沸想诅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)来破。三九已至,卻和暖如春忘古,著一層夾襖步出監(jiān)牢的瞬間徘禁,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工髓堪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留送朱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓干旁,卻偏偏與公主長(zhǎng)得像驶沼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子争群,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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