久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

使用genrule如何從makefile向bazel轉變

194次閱讀
沒有評論

共計 3870 個字符,預計需要花費 10 分鐘才能閱讀完成。

使用 genrule 如何從 makefile 向 bazel 轉變,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

0x01 背景

現有的 makefile 構建工程如何切換到 bazel 構建系統。

bazel 提供了豐富的擴展方式,當然也支持從目前的 makefile 過渡到 bazel 構建。

再次說明下其特性:

多語言支持,并且支持擴展到任何語言的構建。
擴展 DSL 是 starlyke 語言,為 Python 的一個子集,容易上手。這一點是 cmake 和其他構建系統不具備的。

支持緩存。

支持分布式構建。

支持最小化構建。
在一個大型系統中,一個人可能只需要負責其中的一個小組件,這個組件可能又依賴其他組件。當這個組件需要更新測試時,只希望去構建這個組件依賴的組件和這個組件本身,其他不相關的可以不構建,這樣可以使用構建過程更快捷。bazel 就支持這種方式。

0x02 makefile 的問題

上文中說過 makefile 在處理小規模軟件時還不錯,當規模增大時,makefile 有以下問題。

各個組件之間的依賴難以管理。makefile 只支持將所有的源碼放在一個目錄下,然后由頂層的。
這個依賴關系只能是有經驗的人知道,新人想最小化編譯時,只能試錯,發現有依賴未構建時,再去手動構建。

增量式構建難以控制。
這一點和第 1 點是相關的,因為依賴不能自動化構建,所以增量式構建也不具備。

構建速度不足,難以做緩存。
makefile 本身不支持緩存,需要額外的工作自行實現緩存。

0x03 需要解決的問題

雖然說 bazel 兼容 makefile 的構建,但也不是直接的支持。需要對 bazel 的擴展方式有一些了解。也有以下幾個問題需要解決。

bazel 的規則中需要定義輸入輸出
makefile 中的輸出一般不定義。比如如下的 makefile 中。這個 makefile 中就沒有定義明確的輸出。

all:
 gcc hello.c

或者是這樣的。在 makefile 中規則中是去執行一個 make.sh 腳本。

install:
 bash -x make.sh

makefile 一般需要在當前目錄下執行
makefile 中定義的輸入和輸出,都是基于當前的目錄,而 bazel 是在頂層執行的,它的工作目錄就是頂層的 WORKSPACE 所在的目錄。這對 makefile 來說是不友好的。

針對這 2 個問題,通過查看 bazel 的 issue 和文檔并沒有發現好的解決方式。回答人基本上就推薦你去用對應語言的擴展,這對很多發有工程來說是不現實的。原因有:

對應語言的擴展不大可能無縫支持。
多半需要自己去修改構建的代碼。比如我遇到的 1 個 c 語言的工程,使用 cc_external_rule 就行不通。

額外的學習成本。
這個對應的語言的擴展也是需要時間去學習的,也是隱藏的成本。

所以,對 bazel 有興趣的多語言構建項目,希望以這樣的理想方式過渡。

現有的 makefile 工程可以無痛過渡。

新開發或者大規模重構的工程,可以直接上 bazel。

通過總結,給出了以下的過渡方案,基本上可以滿足再有的 makefile 工程。

0x04 過渡方案

方案要點:

使用 bazel 的沙盒環境變量,保留 makefile 的構建時的環境變量。
這些環境變量可能 INSTALLROOT 這種安裝環境變量,也可能有 LD_LIBRARY_PATH 這種編譯鏈接環境變量。

使用 genrule 規則,可以快速切換到 makefile 所在的目錄,執行 make。

示例工程見 gitee。https://gitee.com/ul1n/bazel-demo/tree/makefile 包含 src 和 lib 兩個目錄。各自有自己的 makefile。其中 src 依賴 lib。

方案中的第 1 點可以非常方便地通過 bazel build 時的選項 –action_env 傳遞。第 2 點實現有點曲折,不過并不復雜。這里詳細說明下。

通過熟悉 bazel 文檔我們知道 genrule 可以實現任何構建過程。這里我們希望如下的 genrule。只定義基本的屬性,其中 cmd 里可以 cd 到 BUILD_PATH,BUILD_PATH 可以自動變化,不同的子目錄,就變化為所屬的目錄相對路徑。同時可以生成一個偽目標,滿足 genrule 的要求。

genrule(
 name= hello ,
 srcs=[srcs],
 cmd= cd $(BUILD_PATH)   make ,
 outs=[test]
)

那么如何自動地控制 BUILD_PATH 的環境變量呢?bazel 不支持直接傳遞環境變量給 genrule 的上下文,換說法就是 cmd 中的環境變量,需要提前聲明好。通過查看官方的一些示例,可以這樣來實現。

注:BUILD 文件中涉及的 bazel 的語法可以參考官方文檔進行熟悉。

定義一個 def.bzl 文件。這個 bzl 就是可以為引用它的 BUILD 文件中引入一個 BUILD_PATH 的環境變量。

def _var_providing_rule_impl(ctx):
 build_path = ctx.build_file_path
 loc, _ = build_path.rsplit(/ , 2)
 return [platform_common.TemplateVariableInfo({ BUILD_PATH :loc}),]
var_providing_rule = rule(
 implementation = _var_providing_rule_impl,
 attrs = {  var_value : attr.string() }
)

然后在 lib 目錄下添加一個 BUILD 文件。這份文件編寫的非常通用,可以放在任何一個 makefile 目錄下。除了有其他依賴需要在 genrule 的 srcs 屬性中添加。

load(//:def.bzl ,  var_providing_rule)
var_providing_rule(
 name= set_build_path ,
 var_value= 
filegroup(
 name= srcs ,
 srcs=glob([**])
genrule(
 name =  default ,
 srcs=[srcs],
 cmd= cd $(BUILD_PATH)   make   cd -   touch $(RULEDIR)/out.txt ,
 visibility=[//visibility:public],
 outs=[out.txt],
 toolchains=[:set_build_path]
)

在 src 目錄下添加如下的 BUILD 文件,與 lib 中的基本上一致,只是 srcs 中多了對 lib 中規則的依賴。

load(//:def.bzl ,  var_providing_rule)
var_providing_rule(
 name= set_build_path ,
 var_value= 
filegroup(
 name= srcs ,
 srcs=glob([**])
genrule(
 name =  default ,
 srcs=[srcs ,  //lib:default],
 cmd= cd $(BUILD_PATH)   make   cd -   touch $(RULEDIR)/out.txt ,
 outs=[out.txt],
 toolchains=[:set_build_path]
)

這里對 cmd 參數做一下說明。

1  切換到 BUILD 文件所在的目錄。2  執行 make。這個也可以換成需要的命令,比如 make install。3  切換到上一個目錄,也就是 WORKSPACE 文件所在的目錄。4  創建一個偽輸出 out.txt。RULEDIR 是 bazel 約定的規則產出物的目錄。是一個相對路徑,這是為什么第 3 步中要切回目錄的原因。用 連接是為了在失敗時能立刻退出執行。

添加完成后,就可以通過如下的命令執行這個構建過程了。

bazel build --sandbox_writable_path=$INSTALLROOT --action_env=C_INCLUDE_PATH=$INSTALLROOT/include --action_env=INSTALLROOT=$INSTALLROOT //src:default

其中 –sandbox_writable_path 選項是為了開放權限,保證 makefile 中需要執行的目錄創建操作。另外兩個環境變量,則是為了保證原來的 makefile 可以成功構建。執行完成后,會在當前目錄的 tmp/bin/ 目錄下生成 app 可執行文件。tmp/lib 下生成動態鏈接庫。這樣一來,只要配置的環境變量合適,就可以完美執行原有的構建流程了。

0x05 總結

這種實現方式可能不是最好的,但目前來說是最直接的。當然也希望有知道更好方式的同學告知下。目前這種實現方式還有以下幾個問題。

產出物是偽造的,對于 bazel 來說不是 sound(可感知)的。無法緩存 INSTALLROOT 的產生物。

產生物不可感知,那么 INSTALLROOT 被刪除的情況下,bazel 的構建可能什么都不會做,因為它不知道 INSTALLROOT 的存在。

這 2 個問題作如下解答:如果是需要緩存的大型模塊,那么可以產生真正的產出物,同時復制一份到 RULEDIR。但 INSTALLROOT 被刪除這一塊無法通過技術手段保證。

關于使用 genrule 如何從 makefile 向 bazel 轉變問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注丸趣 TV 行業資訊頻道了解更多相關知識。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計3870字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 周口市| 富阳市| 炎陵县| 察哈| 定兴县| 龙江县| 山东| 秦安县| 神农架林区| 和顺县| 东乡族自治县| 钟祥市| 界首市| 策勒县| 灌南县| 吐鲁番市| 梁平县| 新绛县| 海林市| 延长县| 左云县| 兴业县| 泽库县| 内丘县| 顺平县| 化德县| 页游| 迁西县| 博客| 万全县| 晋州市| 秀山| 云南省| 英德市| 泸定县| 安义县| 涿鹿县| 利川市| 鞍山市| 察哈| 汝州市|