Google软件构建工具Bazel
轉(zhuǎn)載Google軟件構(gòu)建工具Bazel FAQ
本文是我的翻譯,原文在這里。歡迎轉(zhuǎn)載,轉(zhuǎn)載請注名本文作者和原始鏈接
注:如果想了解Bazel的原理,可以看看我之前翻譯的Google Blaze原理及使用方法介紹系列
Bazel是什么?
Bazel是一個構(gòu)建工具,即一個可以運(yùn)行編譯和測試來組裝軟件的工具,跟Make、Ant、Gradle、Buck、Pants和Maven一樣。
Bazel有什么特殊之處
Bazel是設(shè)計(jì)用來配合Google的軟件開發(fā)模式。有以下幾個特點(diǎn):
多語言支持:Bazel支持Java,Objective-C和C++,可以擴(kuò)展來支持任意的編程語言
高級別的構(gòu)建語言:工程是通過BUILD語言來描述的。BUILD語言以簡潔的文本格式,描述了由多個小的互相關(guān)聯(lián)的庫、二進(jìn)制程序和測試程序來組成的一個項(xiàng)目。而與之相比,Make這類的工具需要描述各個單獨(dú)的文件和編譯的命令
多平臺支持:同一套工具和同樣的BUILD文件可以用來構(gòu)建不同架構(gòu)和不同平臺的軟件。在Google,我們使用Bazel來構(gòu)建在我們數(shù)據(jù)中心系統(tǒng)中運(yùn)行的服務(wù)器端程序和在手機(jī)上運(yùn)行的客戶端應(yīng)用程序。
重現(xiàn)性[Reproducibility]:在BUILD文件中,每個庫,測試程序,二進(jìn)制文件必須明確完整地指定直接依賴。當(dāng)修改源代碼文件后,Bazel使用這個依賴信息就可以知道哪些必須重新構(gòu)建,哪些任務(wù)可以并行執(zhí)行。這意味者所有的構(gòu)建都是增量形式的并能夠每次都生成相同的結(jié)果。
伸縮性[Scalability]:Bazel可以處理巨大的構(gòu)建;在Google,一個服務(wù)器端程序超過100k的源碼是常有的事情,如果沒有文件被改動,構(gòu)建過程需要大約200ms
為什么Google不使用...?
Make,Ninja: 通過這些工具都能夠控制執(zhí)行哪些命令來構(gòu)建文件,但是需要用戶書寫正確的規(guī)則。
用戶跟Bazel在更高級別上交互。例如,它有內(nèi)置的"Java test", "C++ binary"的規(guī)則[rule],有例如“目標(biāo)平臺”[target platform],“主機(jī)平臺"[host platform]這種標(biāo)記。這些規(guī)則都經(jīng)歷了充分的測試,是不會出錯的。
Ant和Maven:Ant和Maven主要是面向Java,而Bazel可以處理多種語言。Bazel鼓勵把代碼庫的內(nèi)容劃分成小的,可復(fù)用的單元,并且只重新構(gòu)建需要重新構(gòu)建的文件。這會提高在龐大的代碼庫上開發(fā)的速度。
Gradle: Bazel 配置文件比Gradle的要更加結(jié)構(gòu)化,讓Bazel能夠準(zhǔn)確理解每個行為的所作所為。使得能夠有更多的并發(fā)和更好的可重現(xiàn)性
Pants, Buck: 這兩個工具都是前Google員工在Twitter和Foursquare創(chuàng)造并開發(fā)的。他們都是在模仿Bazel,但是他們的特性跟Bazel是不同的,所以不會是Bazel的替代品
Bazel的起源是什么?
Bazel是Google內(nèi)部用來構(gòu)建自己的服務(wù)器端軟件的工具。它已經(jīng)被擴(kuò)展成也可以構(gòu)建連接到服務(wù)器端的客戶端軟件(iOS, Android)。
Bazel是內(nèi)部工具的重寫,然后開源?還是說它是一個fork?
Bazel和內(nèi)部工具的大部分代碼是一樣的,它的規(guī)則每天被使用無數(shù)次。
為什么Google創(chuàng)建Bazel?
很久以前,Google使用大的,生成的Makefile來構(gòu)建軟件。這導(dǎo)致構(gòu)建的速度慢而且不可靠,開始干擾開發(fā)人員的生產(chǎn)率和公司的敏捷度。因此,我們創(chuàng)造了Bazel
Bazel需要一個構(gòu)建集群嗎?
Google內(nèi)部使用的Bazel確實(shí)使用了一個構(gòu)建集群,所以Bazel在代碼庫里添加了一個遠(yuǎn)程構(gòu)建緩存或者是遠(yuǎn)程執(zhí)行系統(tǒng)的鉤子。
我們開源的Bazel是在本地執(zhí)行任務(wù)的。我們很自信這對于Bazel的大多數(shù)用戶來說是足夠快的。
Google開發(fā)模式是怎樣的?
對于我們的服務(wù)器端代碼庫,我們的開發(fā)流程如下:
所有的服務(wù)器端代碼庫都在一個巨大的版本控制系統(tǒng)里
每個人都用Bazel構(gòu)建軟件
不同的組負(fù)責(zé)源碼樹的不同部分,所有的組件都是作為BUILD目標(biāo)來用
分支主要是用來管理發(fā)布,所以每個人都在最新版本上開發(fā)軟件
Bazel是以下理念的奠基石:由于Bazel需要所有的依賴都被完整地指定,我們可以預(yù)測改動影響了哪些程序和測試,并在提交前執(zhí)行他們。
更多Google開發(fā)模式的背景知識,可以在工具組的博客上看到。譯者注:這四篇文章的中文翻譯見分布式構(gòu)建軟件。
為什么開源Bazel?
構(gòu)建軟件應(yīng)該是好玩并且容易的,緩慢而且不可預(yù)料的構(gòu)建剝奪了編程的樂趣。
為什么我要使用Bazel?
Bazel可以成倍提高構(gòu)建速度,因?yàn)樗恢匦戮幾g需要重新編譯的文件。類似的,它會跳過沒有被改變的測試。
Bazel產(chǎn)出確定的結(jié)果。這消除了增量和干凈構(gòu)建,開發(fā)機(jī)器和持續(xù)集成之間的構(gòu)建結(jié)果的差異。
Bazel可以使用同一個工程下的相同的工具來構(gòu)建不同的客戶端和服務(wù)器端應(yīng)用程序。例如,你可以在一次提交里修改一個客戶端/服務(wù)器協(xié)議,然后測試更新后的手機(jī)程序和服務(wù)器端程序能夠正常工作,構(gòu)建時使用的是同樣的工具,利用的都是上面提到的Bazel的特性。
我可以看到例子嗎?
是的,一個簡單的例子,見:
https://github.com/google/bazel/blob/master/examples/cpp/BUILD
Bazel源代碼本身提供了更復(fù)雜的例子,例如:
https://github.com/google/bazel/blob/master/src/main/java/BUILD
https://github.com/google/bazel/blob/master/src/test/java/BUILD
Bazel最擅長做什么?
Bazel適合于構(gòu)建和測試有如下特點(diǎn)的項(xiàng)目:
有龐大代碼庫的項(xiàng)目
用(多種)需要編譯的語言寫的項(xiàng)目
在多平臺上部署的項(xiàng)目
有大量測試的工程
Bazel在什么平臺上運(yùn)行
目前,在Linux和MacOS上。移植到其他Unix平臺上是很簡單的,提供的JDK是可用的。
支持Windows平臺嗎?
我們利用MinGW/MSYS,實(shí)驗(yàn)了一個Windows的移植版本,但是目前沒有計(jì)劃去在這個移植版本上花費(fèi)精力。由于Bazel是基于Unix的,移植Bazel需要大量的工作。例如,Bazel大量使用了符號鏈接,這在Windows版本中支持的程度各不相同。
不應(yīng)該使用Bazel的場景
Bazel試著在緩存方面智能一些。這意味者不適于不應(yīng)該被緩存的構(gòu)建步驟。例如,下面的步驟就不應(yīng)該被Bazel控制:
從網(wǎng)絡(luò)上獲取數(shù)據(jù)的編譯步驟
連接你的網(wǎng)站測試實(shí)例的測試步驟
改變站點(diǎn)云環(huán)境的發(fā)布步驟
Bazel試著縮小耗時的編譯[compile]步驟。如果你只使用了解釋性語言,例如JavaScript和Python,Bazel就沒有吸引力。
Bazel的功能集合是否穩(wěn)定?
核心的功能(C++、Java和shell規(guī)則)已經(jīng)在Google內(nèi)部大量使用了,所以經(jīng)歷了完整的測試,只可能出現(xiàn)很小很小的問題。類似的,最新的版本每天被我們在成百上千的目標(biāo)上測試來回歸功能,我們每個月會多次發(fā)布新版本。
總之,除了被標(biāo)記為實(shí)驗(yàn)性質(zhì)的功能,任何時候,Bazel都應(yīng)該工作。對于非實(shí)驗(yàn)性質(zhì)規(guī)則的修改肯定會做到向前兼容。更詳細(xì)的支持的功能可以在我們的功能文檔里找到。
作為二進(jìn)制程序Bazel的穩(wěn)定性如何?
在Google內(nèi)部,Bazel極少崩潰。對于我們開源的Bazel也是一樣的。
我應(yīng)該如何開始使用Bazel?
看我們的開始使用的文檔。
為什么我需要在包路徑里添加一個 tools/目錄?
你的工程肯定不是單獨(dú)工作的。通常情況下,它是使用某個特定版本的JDK/C++ 編譯器,使用一個固定版本的測試框架,在某個特定的操作系統(tǒng)版本上運(yùn)行的。
為了保證我們即使升級了我們的開發(fā)機(jī)器,構(gòu)建過程仍然是可重現(xiàn)的,Google會把這些工具中的絕大部分都版本控制起來,包含了工具鏈(toolchains)和Bazel本身。慣例是把這些放到一個叫做"tools"的目錄。
Bazel允許JDK這樣的工具放在工程目錄之外,但是這個配置項(xiàng)(JDK在哪,C++編譯器在哪?)仍然需要放在某個地方,這個地方也就是tools/目錄。
Bazel的compile.sh腳本構(gòu)建了一個配置文件的最小集合,適合運(yùn)行來自標(biāo)準(zhǔn)系統(tǒng)目錄的工具鏈 ,例如/usr/bin
Docker沒有解決可重現(xiàn)[reproducibility]的問題嗎?
利用Docker可以很容易的創(chuàng)建固定操作系統(tǒng)版本的沙箱,例如Ubuntu 12.04, Fedora 21。這解決了系統(tǒng)環(huán)境的可重現(xiàn)問題(例如,“需要哪個版本的/usr/bin/C++?”)。
它不能解決針對源代碼修改的可重現(xiàn)問題。在Docker內(nèi)部運(yùn)行一個不完美的Makefile仍然會出現(xiàn)不可預(yù)料的結(jié)果。
在Google內(nèi)部,為了可重現(xiàn),我們把工具也放到版本控制里。這樣我們能夠像發(fā)現(xiàn)基礎(chǔ)庫的修改(“修復(fù)OpenSSL里的邊界檢查”)一樣,發(fā)現(xiàn)針對工具的修改(“升級GCC到4.6.1”)。
能構(gòu)建部署在Docker上的二進(jìn)制程序嗎?
利用Bazel,可以構(gòu)建獨(dú)立的,靜態(tài)鏈接的C(++)二進(jìn)制程序,Java的自包含的jar文件。這些程序在正常的Unix系統(tǒng)里需要極少的依賴,所以在Docker容器里安裝同樣也是簡單的。
Bazel有構(gòu)建更復(fù)雜程序的例子,例如消費(fèi)一系列數(shù)據(jù)文件的Java程序,或者把另外一個程序作為子進(jìn)程運(yùn)行。可以把這種環(huán)境打包成單獨(dú)的包,以便于可以在不同的系統(tǒng)里進(jìn)行部署,包括Docker的鏡像。但是我們目前沒有代碼這樣做。
能夠使用Bazel構(gòu)建Docker鏡像嗎?
Bazel構(gòu)建的程序的可重現(xiàn)性是相對于構(gòu)建的源碼而言的。Bazel的設(shè)計(jì)里面,它對源碼樹之外的環(huán)境是無法感知的。因此,Bazel不知道Docker自己的環(huán)境是否和Docker鏡像相一致。所以,如果你跟Docker一起使用Bazel,我們推薦在跟部署的環(huán)境一樣的環(huán)境下運(yùn)行Bazel,來確保可重現(xiàn)性。
可以跟文件一樣寫規(guī)則產(chǎn)生Docker鏡像。然而,由于Docker鏡像跟正常的文件系統(tǒng)一樣,有很多時間戳,這讓可重現(xiàn)充滿了挑戰(zhàn)。
Bazel能自動地讓我的構(gòu)建可重現(xiàn)嗎?
對于Java和C++可執(zhí)行程序,如果你沒有修改工具鏈,那答案是肯定的。如果構(gòu)建步驟包含定制的東西(例如,在一個規(guī)則內(nèi)通過shell腳本執(zhí)行可執(zhí)行程序),那就需要額外注意:
不要使用沒有聲明的依賴。沙箱模式的執(zhí)行(-spawn_strategy=sandboxed, 只能用在Linux下)可以幫助發(fā)現(xiàn)未聲明的依賴。
不要在產(chǎn)生的文件中存儲時間戳。ZIP文件和其他的歸檔文件尤其需要注意這一點(diǎn)。
避免連接到網(wǎng)絡(luò)。在沙箱里執(zhí)行也是可以的。
避免使用了隨機(jī)數(shù)的處理過程,特別是,在很多編程語言中,字典遍歷是隨機(jī)的。
有二進(jìn)制的版本嗎?
沒有,但我們應(yīng)該出二進(jìn)制的版本。敬請期待!
我使用Eclipse/IntelliJ. Bazel如何跟IDE結(jié)合起來?
我們目前沒有跟IDE交互的API,但是iOS規(guī)則可以根據(jù)BUILD目標(biāo)來產(chǎn)生Xcode可用的工程。
Bazel如何跟Xcode交互?
Bazel產(chǎn)出可以使用任何輸入和依賴的Xcode工程,可以直接從Xcode構(gòu)建APP然后部署到模擬器和設(shè)備上。打開Bazel構(gòu)建任何iOS目標(biāo)后打印出的工程文件的路徑就可以使用這個功能。不支持從Xcode里調(diào)用Bazel(例如基于proto文件來重新產(chǎn)生Objc源文件),也不支持從Bazel直接打開Xcode。
我使用Jenkins/CircleCI/TravisCI. Bazel如何跟持續(xù)集成系統(tǒng)結(jié)合起來?
如果構(gòu)建或者測試過程失敗,Bazel返回非0值,這對于基本的持續(xù)集成系統(tǒng)來說,已經(jīng)夠用了。由于Bazel不需清除構(gòu)建就可以保持構(gòu)建結(jié)果的正確性,所以持續(xù)集成系統(tǒng)可以配置成在啟動一個構(gòu)建/測試的時候不進(jìn)行清除操作
關(guān)于返回值的更多細(xì)節(jié),參見用戶手冊。
未來Bazel會加入哪些功能?
我們一開始的目標(biāo)是滿足Google內(nèi)部使用。這包括Google的主要編程語言(C++, Java, Go)和主要平臺(Linux,Android,iOS)。由于一些原因,并不是所有的這些都是開源的。更多細(xì)節(jié)見路線圖
關(guān)于Python呢?
可以把書寫的Python的規(guī)則當(dāng)作擴(kuò)展(見下面的例子)。之后的例子是如何產(chǎn)生自包含python的zip文件
https://github.com/google/bazel/blob/master/tools/build_rules/py_rules.bzl
https://github.com/google/bazel/tree/master/examples/py
我們正在準(zhǔn)備開源一套Google內(nèi)部使用的Python規(guī)則的子集,這些規(guī)則可以當(dāng)作輔助腳本而成為構(gòu)建的一部分
我們目前沒有計(jì)劃要提供打包整個自滿足的Python二進(jìn)制的過程。
關(guān)于Go呢?
如果你的代碼庫里的代碼,100%都是Go語言,那么go工具在構(gòu)建和測試方面表現(xiàn)很出色,Bazel不會給你帶來go工具這么大的收益。
在Google用Go寫的服務(wù)器端代碼是用Bazel構(gòu)建的。然而,由于Go語言的代碼和我們C++庫的交互而導(dǎo)致使用Bazel構(gòu)建Go語言部分的過程很復(fù)雜,并和go工具的慣例不兼容。因?yàn)檫@個原因,我們寧愿不開源目前的Go相關(guān)的規(guī)則
可以使用Bazel來構(gòu)建我的LISP/Python/Haskell/Scala/Rust的工程嗎?
Bazel有一套擴(kuò)展機(jī)制來允許添加新的規(guī)則而不需要重新編譯Bazel。文檔見這里。
但是到目前為止,這套擴(kuò)展機(jī)制是實(shí)驗(yàn)性質(zhì)的。
我需要更多的功能。我可以添加編譯到Bazel里面的規(guī)則嗎?
如果擴(kuò)展機(jī)制對于你的場景來說不夠用,請把相關(guān)建議郵件到這個組:bazel-discuss@googlegroups.com
我可以給Bazel代碼貢獻(xiàn)嗎?
見我們的貢獻(xiàn)指南
為什么目前Bazel的開發(fā)過程并不都是開源狀態(tài)
我們?nèi)匀辉诖罅恐貥?gòu)Bazel內(nèi)部公共的代碼和我們內(nèi)部擴(kuò)展之間的接口部分。所以這部分要開源開發(fā)很困難。更多詳細(xì)信息見我們的governance plan
如何聯(lián)系Bazel開發(fā)組?
通過bazel-discuss@googlegroups.com來聯(lián)系
怎么匯報(bào)bug?
給bazel-discuss@googlegroups.com發(fā)郵件,或者在GitHub上報(bào)bug
在代碼中的單詞"Blaze"是什么意思?
這是這個工具的內(nèi)部名稱。請使用Bazel來指代Bazel這個工具
為什么其他Google的工程(Android,Chrome)使用其他的構(gòu)建工具?
之前Bazel一直都是內(nèi)部使用的,所以開源項(xiàng)目,例如Chromium,Android等都不能使用它。而且,缺乏對Windows支持而導(dǎo)致
不能構(gòu)建Windows應(yīng)用程序,例如Chrome。
"Bazel"怎么發(fā)音?
跟美國英語中的“basil”(草本植物)一樣的:"BAY-zel".
標(biāo)簽:編譯,linux,C++,構(gòu)建,Bazel
總結(jié)
以上是生活随笔為你收集整理的Google软件构建工具Bazel的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端项目构建——运维
- 下一篇: pfx格式密钥库修改密码