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