基于Telegram二次開發(fā) --- Bazel初探

我們先從 Xcode 來分析,在打包出 ipa 文件時,Xcode 是怎么做的:

手頭的材料

代碼文件(m/cpp/swift/c/h)、簽名、資源文件(xcasset/png/json/html/...)、二進制文件(.a/.framework)

出來的產(chǎn)物

ipa:資源文件、二進制文件

Xcode 就是將手頭的材料編譯出我們需要的ipa;

進一步拆解 Xcode,會發(fā)現(xiàn)編譯的過程就是調(diào)用 Tool Chains 的過程,Xcode 在編譯過程中,調(diào)用了組合命令 xcodebuild, Xcode 其實就是一個殼。

將 xcodebuild 進行拆解,我們就可以得到一系列的編譯工具,clang/actool/ibtool/... 等等一系列工具,當我們有了這些命令,我們就可以自己對原料進行加工,輸出產(chǎn)物;不再依賴于 Xcode 即可進行編譯。


而 Bazel 正是一個現(xiàn)代化的多語言構(gòu)建/測試工具,它由 Google 內(nèi)部 Blaze 的開源,具有正確、快速、可管理、可擴展的特點。

Bazel 的設(shè)計原則:

  1. 效率:多級 Cache,每一層可以做高效的緩存,本地、遠程,來支持增量構(gòu)建
  2. 可擴展性:多種不同的語言可以抽象成一類 Action 進行編譯
  3. 靈活性:提供內(nèi)置規(guī)則,基于 starlark 的擴展,可以實現(xiàn)各種用戶自定義的 rules
  4. 正確性:文件緩存是基于文件內(nèi)容的(而 Xcode 是基于文件時間戳的)
  5. 可重復性:有沙盒,不被研發(fā)環(huán)境影響

Bazel 需要以下支持文件:

- BUILD:描述文件
- WORKSPACE:用于描述項目所需的構(gòu)建規(guī)則

因為是基于 Telegram 二次開發(fā)對 Bazel 的探索,所以我們主要研究 - BUILD 描述文件,- WORKSPACE 已經(jīng)在 Clone 下來的 Telegram-iOS 文件夾目錄下配置好了。


Bazel Version : 5.1.0


一、Objective-C 組件包

先打開 Telegram 的 Xcode 工程目錄,我們用 third-party 文件下 ZipArchive 來分析

image.png

ZipArchive 分為三部分

BUILD:描述文件
PublicHeaders:需要向外暴露的頭文件
Sources:.h .m .c 等實現(xiàn)文件

其實整個項目都是這樣以文件夾為單位,一個個組件包組成的,BUILD 就是來描述這個組件包的構(gòu)成,依賴項的 Starlark 語法的代碼文件。

既然是代碼文件,那就有對應(yīng) Starlark 語法

objc_library() : 描述 Objective-C 規(guī)則的函數(shù),此規(guī)則會根據(jù)給定的 Objective-C 源文件生成一個靜態(tài)庫。

  • name : 組件名稱。
  • enable_modules : 啟用 clang,為 True 時,可支持系統(tǒng)頭文件 import,默認為 False 。
  • module_name : 模塊名稱,默認名稱是模塊路徑,所有特殊符號都會被替換成 _
  • srcs : 編譯源文件;函數(shù) glob() 可以幫助我們匹配滿足路徑格式的文件。
  • hdrs : 需要暴露出來的頭文件。
  • includes : #include / #import 頭文件搜索路徑文件夾。
  • copts : 需要傳遞給編譯器的額外編譯選項:
    -x 編譯語言比如 Objective-C
    -arch 編譯的架構(gòu),比如 arm7
    -f 以 -f 開頭的,代表“旗幟”,定義控制代碼生成中使用的接口約定
    -W 以 -W 開頭的,可以通過這些定制編譯警告
    -D 以 -D 開頭的,指的是預編譯宏,通過這些宏可以實現(xiàn)條件編譯
    -iPhoneSimulator10.1.sdk 編譯采用的 iOS SDK 版本
    -I 把編譯信息寫入指定的輔助文件
    -F 需要的 Framework
    -c 標識符指明需要運行預處理器,語法分析,類型檢查,LLVM 生成優(yōu)化以及匯編代碼生成 .o 文件
    -o 編譯結(jié)果
  • sdk_frameworks : 需要依賴的 Framework ;為 iOS、tvOS 和 watchOS 平臺構(gòu)建時,始終包含 "UIKit""Foundation" 。對于 macOS,始終包含 "Foundation"
  • visibility : 可見性,控制此包是否可以在其他包中使用;
    "http://visibility:public" : 授予對所有包的訪問權(quán)限;
    "http://visibility:private" : 不授予任何額外的訪問權(quán)限;只有在這個包中的可以使用;
    "http://xxx/xx:__pkg__" : 授予 //xxx/xx 訪問權(quán)限,但不授予其子包;
    "http://xxx/xx:__subpackages__" : 授予 //xxx/xx 及其所有直接,間接子包的訪問權(quán)限;

二、swift 組件包

若我們的組件包是 swift 包,我們以 submodules 文件夾下的 AccountContext 舉例

image.png

AccountContext 分為兩部分

BUILD:描述文件
Sources:.swift 實現(xiàn)文件

因為 swiftObjective-C 相比,是沒有 .h 頭文件的,所以并不需要向外暴露頭文件的 PublicHeaders 文件夾;

我們還注意到 BUILD 文件第一行,跟 Objective-C 下的 BUILD 相比,多了一行

load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")

BUILD 文件第一行的 load 語句表明 swift_library 是一個外部依賴規(guī)則,它被定義在 WORKSPACE 中聲明的 build_bazel_rules_swift 倉庫內(nèi)部,而 Objective-C 下的 BUILD 里卻不需要聲明 objc_library 規(guī)則,這是因為 objc_libraryBazel 內(nèi)置規(guī)則。

swift_library() : 描述 swift 規(guī)則的函數(shù),此規(guī)則會根據(jù)給定的 swift 源文件生成一個靜態(tài)庫。

里面屬性跟 objc_library 是一致的,但因為 AccountContext 依賴了自身以外的其他組件包,所以,使用了屬性 deps

  • deps : 需要依賴的其他組件包,格式由 //submodules/TelegramAudio 相對路徑 + :TelegramAudio 組件名 組成。

注意:在這里(swift_library())編譯選項 copts 填寫的 -warnings-as-errorsobjc_library()-Werror),意思是在這個組件包內(nèi)將所有警告 warning 當成 error 輸出。這在 Telegram-iOS 中,幾乎在其 所有非第三方(如 third-party 文件夾下的所有第三方依賴)的自定義組件包 內(nèi)的 BUILD 文件里都存在,所以在日常開發(fā)中,沒有 ?? 存在,全都被爆紅替代,舉個例子,我們定義了一個屬性,在這個屬性 被使用前,Xcode 會一直出現(xiàn)該屬性 未被使用 的報錯,這讓開發(fā)變得更加嚴謹。

后記

前面說到 Xcode 編譯是個殼,其實 Xcode 還做了其他的很多事情的,比如說語法提示/高亮、LLDB 調(diào)試工具等等功能;平時開發(fā)還是離不開 Xcode。

Telegram 使用 tulsi 工具,將 Bazel 的配置文件,逆向生成 .xcodeproj 工程;

但是這個時候的 .xcodeproj 工程其實已經(jīng)去掉了 Xcode 的編譯功能了;這個時候 Xcode 就是個沒有編譯功能的殼,但是他還是有上面提到的語法提示/高亮、調(diào)試工具等一系列工具集合。

對于 Telegram 二次開發(fā)來說,只要了解基礎(chǔ)的 BUILD 文件格式即可。

由于 BUILD 文件規(guī)則比較多,上面只是基于 Telegram 做簡單介紹,詳情參考:

Starlark:https://github.com/bazelbuild/starlark
Objective-C Rules:https://docs.bazel.build/versions/main/be/objective-c.html
rule_apple:https://github.com/bazelbuild/rules_apple/tree/master/doc
tulsi:https://tulsi.bazel.build/
Apple 應(yīng)用和 Bazel:https://bazel.google.cn/docs/bazel-and-apple

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

相關(guān)閱讀更多精彩內(nèi)容

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