標籤:
轉載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裡面的規則嗎?
如果擴充機制對於你的情境來說不夠用,請把相關建議郵件到這個組:[email protected]
我可以給Bazel代碼貢獻嗎?
見我們的貢獻指南
為什麼目前Bazel的開發過程並不都是開源狀態
我們仍然在大量重構Bazel內部公用的代碼和我們內部擴充之間的介面部分。所以這部分要開源開發很困難。更多詳細資料見我們的governance plan
如何聯絡Bazel開發組?
通過 [email protected] 來聯絡
怎麼彙報bug?
給[email protected]發郵件,或者在GitHub上報bug
在代碼中的單詞"Blaze"是什麼意思?
這是這個工具的內部名稱。請使用Bazel來指代Bazel這個工具
為什麼其他Google的工程(Android,Chrome)使用其他的構建工具?
之前Bazel一直都是內部使用的,所以開源項目,例如Chromium,Android等都不能使用它。而且,缺乏對Windows支援而導致
不能構建Windows應用程式,例如Chrome。
"Bazel"怎麼發音?
跟美國英語中的“basil”(草本植物)一樣的:"BAY-zel".
標籤: 編譯, linux, C++, 構建, Bazel
Google軟體構建工具Bazel