從 Xcode 遷移至 Bazel

回報問題 查看原始碼 Nightly · 8.0 . 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

本頁說明如何使用 Bazel 建構或測試 Xcode 專案。說明 Xcode 和 Bazel 之間的差異,並提供將 Xcode 專案轉換為 Bazel 專案的步驟。並提供解決常見錯誤的疑難排解解決方案。

Xcode 和 Bazel 的差異

  • Bazel 要求您明確指定每個建構目標及其依附元件,以及透過建構規則指定對應的建構設定。

  • Bazel 要求專案所依附的所有檔案必須位於工作區目錄中,或是在 WORKSPACE 檔案中指定為匯入檔案。

  • 使用 Bazel 建構 Xcode 專案時,BUILD 檔案會成為可靠的來源。如果您在 Xcode 中處理專案,則每次更新 BUILD 檔案時,都必須使用 Tulsi 產生與 BUILD 檔案相符的 Xcode 專案新版本。如果您未使用 Xcode,bazel buildbazel test 指令會提供建構和測試功能,但有特定限制,詳情請參閱本指南稍後的說明。

  • 由於建構設定結構 (例如目錄版面配置或建構標記) 有所差異,Xcode 可能無法完全瞭解建構的「大局」,因此某些 Xcode 功能可能無法運作。具體來說:

    • 視您在 Tulsi 中選取的轉換目標而定,Xcode 可能無法正確編入專案來源。這會影響 Xcode 中的程式碼完成和導覽功能,因為 Xcode 無法查看專案的所有原始程式碼。

    • 由於 Bazel 不會產生 Xcode 針對這些功能所需的輸出內容,因此靜態分析、位址淨化器和執行緒淨化器可能無法運作。

    • 如果您使用 Tulsi 產生 Xcode 專案,並使用該專案在 Xcode 中執行測試,Xcode 會執行測試,而非 Bazel。如要使用 Bazel 執行測試,請手動執行 bazel test 指令。

事前準備

開始之前,請先執行下列操作:

  1. 如果尚未安裝 Bazel,請安裝 Bazel

  2. 如果您不熟悉 Bazel 及其概念,請完成 iOS 應用程式教學課程。您應瞭解 Bazel 工作區,包括 WORKSPACEBUILD 檔案,以及目標、建構規則和 Bazel 套件等概念。

  3. 分析並瞭解專案的依附元件。

分析專案依附元件

與 Xcode 不同,Bazel 要求您在 BUILD 檔案中明確宣告每個目標的所有依附元件。

如要進一步瞭解外部依附元件,請參閱「使用外部依附元件」。

使用 Bazel 建構或測試 Xcode 專案

如要使用 Bazel 建構或測試 Xcode 專案,請按照下列步驟操作:

  1. 建立 WORKSPACE 檔案

  2. (實驗功能) 整合 CocoaPods 依附元件

  3. 建立 BUILD 檔案:

    a. 新增應用程式目標

    b. (選用) 新增測試目標

    c. 新增程式庫目標

  4. (選用) 細分建構作業

  5. 執行版本

  6. 使用 Tulsi 產生 Xcode 專案

步驟 1:建立 WORKSPACE 檔案

在新目錄中建立 WORKSPACE 檔案。這個目錄會成為 Bazel 工作區根目錄。如果專案不使用任何外部依附元件,這個檔案可以是空白。如果專案依附的檔案或套件不在專案的其中一個目錄中,請在 WORKSPACE 檔案中指定這些外部依附元件。

步驟 2:(實驗功能) 整合 CocoaPods 依附元件

如要將 CocoaPods 依附元件整合至 Bazel 工作區,您必須將依附元件轉換為 Bazel 套件,如「轉換 CocoaPods 依附元件」一文所述。

步驟 3:建立 BUILD 檔案

定義工作區和外部依附元件後,您需要建立 BUILD 檔案,告訴 Bazel 專案的結構。在 Bazel 工作區的根目錄中建立 BUILD 檔案,並將其設為執行專案的初始建構作業,如下所示:

提示:如要進一步瞭解套件和其他 Bazel 概念,請參閱「工作區、套件和目標」一文。

步驟 3a:新增應用程式目標

新增 macos_applicationios_application 規則目標。這個目標會分別建構 macOS 或 iOS 應用程式套件。在目標中,至少指定下列項目:

  • bundle_id:二進位檔的軟體包 ID (反向 DNS 路徑,後面接著應用程式名稱)。

  • provisioning_profile:Apple 開發人員帳戶中的佈建設定檔 (如果是為 iOS 裝置建構)。

  • families (僅限 iOS) - 是否要為 iPhone、iPad 或兩者建構應用程式。

  • infoplists - 要合併至最終 Info.plist 檔案的 .plist 檔案清單。

  • minimum_os_version:應用程式支援的 macOS 或 iOS 最低版本。這可確保 Bazel 以正確的 API 級別建構應用程式。

步驟 3b:(選用) 新增測試目標

Bazel 的 Apple 建構規則支援在 iOS 和 macOS 上執行以程式庫為基礎的單元測試,以及在 macOS 上執行以應用程式為基礎的測試。針對 iOS 上的應用程式測試或任一平台上的 UI 測試,Bazel 會建構測試輸出內容,但測試必須透過使用 Tulsi 產生的專案,在 Xcode 中執行。新增測試目標,如下所示:

  • macos_unit_test 可在 macOS 上執行程式庫和應用程式單元測試。

  • ios_unit_test 可在 iOS 上執行以程式庫為基礎的單元測試。對於需要 iOS 模擬器的測試,Bazel 會建構測試輸出內容,但不會執行測試。您必須使用 Tulsi 產生 Xcode 專案,並在 Xcode 中執行測試。

  • ios_ui_test 來建構使用 Xcode 在 iOS 模擬器中執行使用者介面測試所需的輸出內容。您必須使用 Tulsi 產生 Xcode 專案,並在 Xcode 中執行測試。Bazel 無法原生執行 UI 測試。

至少請為 minimum_os_version 屬性指定值。雖然 bundle_identifierinfoplists 等其他封裝屬性預設為最常用的值,但請確保這些預設值與專案相容,並視需要調整。如果測試需要 iOS 模擬器,請一併指定 ios_application 目標名稱做為 test_host 屬性的值。

步驟 3c:新增程式庫目標

為每個 Objective-C 程式庫新增 objc_library 目標,並為每個應用程式和/或測試依附的 Swift 程式庫新增 swift_library 目標。

新增程式庫目標,如下所示:

  • 將應用程式程式庫目標新增為應用程式目標的依附元件。

  • 將測試程式庫目標新增為測試目標的依附元件。

  • srcs 屬性中列出實作來源。

  • hdrs 屬性中列出標頭。

如要進一步瞭解建構規則,請參閱「Bazel 適用的 Apple 規則」。

此時建議您測試建構項目:

bazel build //:<application_target>

步驟 4:(選用) 細分版本

如果專案很大,或隨著專案的成長,請考慮將其分割成多個 Bazel 套件。更精細的篩選維度可提供下列功能:

  • 提高建構作業的增量程度

  • 增加建構工作平行處理的比例

  • 方便日後的使用者維護

  • 進一步控管各個目標和套件中的原始碼可見度。這可避免程式庫包含實作細節,導致資料外洩至公用 API 的問題。

細分專案的訣竅:

  • 將每個程式庫放入專屬的 Bazel 套件。請從需要最少依附元件的依附元件開始,然後逐步向上瀏覽依附元件樹狀結構。

  • 新增 BUILD 檔案並指定目標時,請將這些新目標新增至依附這些目標的目標的 deps 屬性。

  • glob() 函式不會跨越套件邊界,因此隨著套件數量增加,glob() 比對的檔案數量也會減少。

  • BUILD 檔案新增至 main 目錄時,也請將 BUILD 檔案新增至對應的 test 目錄。

  • 在各套件中強制執行健康的瀏覽權限限制。

  • 每次對 BUILD 檔案進行重大變更後,請建構專案,並修正遇到的建構錯誤。

步驟 5:執行版本

執行已完全遷移的版本,確認其完成時沒有任何錯誤或警告。個別執行每個應用程式和測試目標,以便更輕鬆找出發生錯誤的來源。

例如:

bazel build //:my-target

步驟 6:使用 Tulsi 產生 Xcode 專案

使用 Bazel 進行建構時,WORKSPACEBUILD 檔案會成為建構作業的真實來源。如要讓 Xcode 瞭解這項資訊,您必須使用 Tulsi 產生與 Bazel 相容的 Xcode 專案。

疑難排解

當 Bazel 與所選 Xcode 版本不同步時,就可能發生錯誤,例如在套用更新時。如果您在使用 Xcode 時遇到錯誤,例如「必須指定 Xcode 版本才能使用 Apple CROSSTOOL」,請嘗試以下幾種方法。

  • 手動執行 Xcode,並接受所有條款及細則。

  • 使用 Xcode 選取功能來指出正確的版本、接受授權,並清除 Bazel 的狀態。

  sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  sudo xcodebuild -license
  bazel sync --configure
  • 如果這個方法無效,您也可以嘗試執行 bazel clean --expunge