starlark 設(shè)計(jì)一瞥

英文原文地址:https://blog.bazel.build/2017/03/21/design-of-skylark.html

本文主要介紹 starlark (舊名:skylark)的設(shè)計(jì)原理,Bazel 用 starlark 語(yǔ)言構(gòu)建工程。

簡(jiǎn)史

N年前,Google使用 Makefile 來(lái)管理代碼。正如坊間傳言,Makefile 管理代碼太多時(shí),就有點(diǎn) hold 不住了。救急的解決辦法是用 python 腳本來(lái)生成 Makefile,編譯過(guò)程中用到的 python 函數(shù)都存儲(chǔ)在 BUILD 文件中。但是這樣還是太慢,瓶頸在 Make。

Blaze(后來(lái)以 Bazel 開(kāi)源)項(xiàng)目開(kāi)始于2006年。Blaze 用一個(gè)簡(jiǎn)單的解釋器來(lái)讀取 BUILD 文件(只支持函數(shù)調(diào)用,列表解析和變量分配)。Blaze 不能直接解析 BUILD 文件,通過(guò) Python 解釋器將用戶(hù)的 BUILD 文件預(yù)處理為一個(gè)簡(jiǎn)化的 BUILD 文件,簡(jiǎn)化后的 BUILD 文件供 Blaze 使用。

這樣處理起來(lái)簡(jiǎn)便并且允許開(kāi)發(fā)者創(chuàng)建自己的宏。但是代碼維護(hù),性能,安全性又出現(xiàn)了很多問(wèn)題。因?yàn)锽laze 本身不能解析 BUILD 文件,導(dǎo)致編譯變得越來(lái)越復(fù)雜。

Bazel 經(jīng)過(guò)重新設(shè)計(jì),剔除了 Python 預(yù)處理的步驟。我們保留了 Python 的語(yǔ)法來(lái)移植基礎(chǔ)代碼。效果看上去不錯(cuò):很多人喜歡我們的 BUILD 文件語(yǔ)法,并對(duì)一些構(gòu)建工具進(jìn)行了適配,比如 Buck, Pants 和 Please。

設(shè)計(jì)要求

我們決定將構(gòu)建過(guò)程和擴(kuò)展功能(宏和規(guī)則)分開(kāi)描述,構(gòu)建過(guò)程的描述放在 BUILD 文件里,然后擴(kuò)展功能的描述放在 .bzl 文件里,但是他們?nèi)匀徊捎猛瑯拥慕忉屍?。我們希望代碼易讀且易于維護(hù),希望成千上萬(wàn)的工程師采用 Bazel,大部分工程師對(duì)編譯工具內(nèi)部不熟悉,也不愿意花時(shí)間來(lái)學(xué)習(xí)一門(mén)新語(yǔ)言。所以 BUILD 文件就需要簡(jiǎn)明扼要,便于使用。

語(yǔ)言其他要求:

???????? 1. 可以在 JVM 上運(yùn)行。因?yàn)锽azel 是用 Java寫(xiě)的,本語(yǔ)言需要與 Bazel 分享數(shù)據(jù)結(jié)構(gòu)。

???????? 2. 使用 Python 語(yǔ)法,保留我們的基礎(chǔ)代碼。

???????? 3. 確保確定性和密封性。我們必須保證代碼的執(zhí)行始終都能產(chǎn)生一致的結(jié)果。比如,我們禁止訪(fǎng)問(wèn) I/O、日期和時(shí)間,以便確保字典的迭代。

???????? 4. 確保線(xiàn)程安全。我們需要 BUILD 文件并行執(zhí)行。執(zhí)行的代碼需要線(xiàn)程安全來(lái)保證結(jié)果的確定性。

關(guān)于性能方面,一個(gè)典型的 BUILD 文件很簡(jiǎn)單,可以很快地被執(zhí)行。在大部分情況下,直接執(zhí)行代碼比先編譯一下再執(zhí)行要快。

并行性

Starlark 如何處理并行是它的一大特點(diǎn)。在 Bazel 中,一個(gè)大的工程需要處理很多的 BUILD 文件,所以我們需要并行加載它們。每個(gè) BUILD 文件可能會(huì)用到很多擴(kuò)展功能,擴(kuò)展功能又可能會(huì)用到很多文件。這就是說(shuō)我們需要準(zhǔn)備好一張依賴(lài)性圖表。

Bazel 首先會(huì)并行分析這張依賴(lài)表的各分支。依次加載它們各自依賴(lài)的文件,也就是解析各個(gè) BUILD 和 .bzl 文件,不關(guān)心 load 語(yǔ)句的順序。

每個(gè)文件幾乎同時(shí)加載。當(dāng)文件被解析后,它的定義(全局變量和函數(shù))都被緩存了。其他任意文件都可以通過(guò)這個(gè)緩存訪(fǎng)問(wèn)其中元素。

由于多個(gè)線(xiàn)程可能會(huì)同時(shí)訪(fǎng)問(wèn)一個(gè)變量,所以我們需要嚴(yán)格地保證線(xiàn)程安全。解決方法很簡(jiǎn)單:當(dāng)我們緩存了一個(gè)文件的定義,會(huì)把這些定義先“冷凍”起來(lái),設(shè)置成只讀,比如,你可以反復(fù)使用一個(gè)數(shù)組,但是不能修改其中的元素。但是你可以對(duì)這個(gè)數(shù)組做備份,然后進(jìn)行修改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容