在 Windows 上編寫規則

回報問題 查看原始碼 。 。 。 。 夜間。 。 7.37.2 。 。 7.1 。 。 7.0 。 。 6.5

本頁主要說明如何編寫 Windows 相容規則,以及 編寫可攜式規則和一些解決方案

路徑

問題:

  • 長度限制:路徑長度上限是 259 個字元。

    雖然 Windows 也支援較長的路徑 (最多 32767 個字元),但許多程式在建構時使用的是 提出的問題

    請留意您在操作中執行的程式。

  • 工作目錄:長度上限為 259 個字元。

    程序不能將 cd 移入超過 259 個字元的目錄。

  • 區分大小寫:Windows 路徑不區分大小寫,Unix 路徑會區分大小寫。

    建立動作的指令列時,請注意這一點。

  • 路徑分隔符:為反斜線 (\`), not forward slash (/`)。

    Bazel 會使用 / 分隔符儲存 Unix 樣式的路徑。雖然部分 Windows 程式 Unix 樣式的路徑則不同。cmd.exe 中的部分內建指令支援這些指令,但有些指令則不支援。

    建議您在建立指令時一律使用 \` separators on Windows: replace/with 程式碼和環境變數

  • 絕對路徑:開頭不得為斜線 (/)。

    Windows 上的絕對路徑開頭是磁碟機字母,例如 C:\foo\bar.txt。沒有任何單曲 檔案系統根目錄

    請注意,如果您的規則會檢查路徑是否為絕對,絕對路徑 建議避免使用,因為這類檔案往往無法移動。

解決方法:

  • 路徑應力求簡短

    避免使用冗長的目錄名稱、多層巢狀結構的目錄結構、檔案名稱過長、工作區過長 名稱、較長的目標名稱

    這些都可能會成為動作的路徑元件可能會耗盡路徑長度 我們會自動向帳單帳戶扣款 並每月或在您達到用量上限時發送帳單

  • 使用簡短輸出根目錄。

    請使用 --output_user_root=<path> 標記指定 Bazel 輸出的簡短路徑。好主意 就是只具備用於 Bazel 輸出的磁碟 (或虛擬磁碟),例如 D:\`), and adding this line to your.bazelrc` 檔案:

    build --output_user_root=D:/
    

    build --output_user_root=C:/_bzl
    
  • 使用接管。

    阻斷式則是目錄符號連結[1]。分隔線易於建立 並指向包含長路徑的目錄 (在同一部電腦上)。如果建構動作 路徑很短但目標很長的連接詞,路徑較短的工具就能存取 目錄中的檔案

    .bat 檔案中或 cmd.exe 中,您可以建立接線法,如下所示:

    mklink /J c:\path\to\junction c:\path\to\very\long\target\path
    

    [1]:嚴格說詞 阻斷連結並非符號連結,但適用於 您或許會將 Junctions 視為目錄符號連結,藉此執行建構操作。

  • 將動作 / 環境變數中的 / 替換為「`」。

    為動作建立指令列或環境變數時,請建立路徑 Windows 版,範例:

    def as_path(p, is_windows):
        if is_windows:
            return p.replace("/", "\\")
        else:
            return p
    

環境變數

問題:

  • 區分大小寫:Windows 環境變數名稱不區分大小寫。

    例如,在 Java System.getenv("SystemRoot")System.getenv("SYSTEMROOT") 中,會產生 相同的結果。這也適用於其他語言。

  • Hermeticity:應盡量避免動作使用自訂環境變數。

    環境變數是動作快取金鑰的一部分。如果動作使用環境變數 頻率會經常變更,或者對使用者而言,會導致規則無法快取。

解決方法:

  • 僅使用大寫的環境變數名稱。

    這項功能適用於 Windows、macOS 和 Linux。

  • 盡可能減少動作環境。

    使用 ctx.actions.run 時,請將環境設為 ctx.configuration.default_shell_env。如果 動作需要更多環境變數並全部放到字典中,再傳送至動作 範例:

    load("@bazel_skylib//lib:dicts.bzl", "dicts")
    
    def _make_env(ctx, output_file, is_windows):
        out_path = output_file.path
        if is_windows:
            out_path = out_path.replace("/", "\\")
        return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
    

動作

問題:

  • 可執行的輸出:每個執行檔都必須具有可執行的副檔名。

    最常見的副檔名為 .exe (二進位檔檔案) 和 .bat (批次指令碼)。

    請注意,殼層指令碼 (.sh) 無法在 Windows 上執行。就無法將這些項目指定為 ctx.actions.runexecutable。檔案也沒有「+x」權限,因此你不會這麼做 無法像 Linux 一樣執行任何檔案

  • Bash 指令:為確保資料可攜性,請避免直接在操作中執行 Bash 指令。

    Bash 在 Unix 類系統上很廣泛,但通常在 Windows 上不支援。Bazel 本身就是 對 Bash (MSYS2) 的依賴較少和較低,因此未來使用者訂閱 MSYS2 的可能性較低 會連同 Bazel 一併安裝為了在 Windows 上更輕鬆地使用規則,請避免在 Windows 中執行 Bash 指令 動作。

  • 行結尾:Windows 使用 CRLF (\r\n),類 Unix 系統使用的是 LF (\n)。

    比較文字檔案時,請留意這一點。留意 Git 設定,尤其是行 結尾。(請參閱 Git 的 core.autocrlf 設定)。

解決方法:

  • 使用無 Bash 用途的規則。

    native.genrule() 是 Bash 指令的包裝函式,通常用於解決簡單問題 例如複製檔案或寫入文字檔您可以避免依賴 Bash (也不必為了重新發明 )。這些都沒有仰賴 Bash 建立/測試映像檔

    建立規則範例:

    • copy_file() (資料來源說明文件): 將檔案複製到其他位置,並視需要設為可執行

    • write_file() (資料來源說明文件): 寫入文字檔及所需的行尾 (autounixwindows),並視需要 使其可執行 (如果是指令碼)

    • run_binary() (資料來源說明文件): 使用指定輸入內容和預期輸出內容做為建構動作執行二進位檔 (或 *_binary 規則) (這是 ctx.actions.run 的建構規則包裝函式)

    • native_binary() (資料來源說明文件): 將原生二進位檔納入 *_binary 規則中,您可以 bazel run 或在 run_binary()tool 屬性或 native.genrule()tools 屬性

    測試規則範例:

  • 在 Windows 上,建議使用 .bat 指令碼執行處理複雜的工作。

    除了 .sh 指令碼外,您還可以使用 .bat 指令碼解決常見工作。

    例如,您需要執行沒有任何動作的指令碼、輸出訊息,或用固定字串結束。 那麼簡易的 .bat 檔案就已足夠了。如果規則傳回 DefaultInfo() 提供者,executable 欄位可能會參照 Windows 上的 .bat 檔案。

    由於 macOS 和 Linux 中的副檔名並不重要,因此您隨時可以使用 .bat 做為副檔名 延伸至殼層指令碼

    請注意,系統無法執行空白的 .bat 檔案。如需空白指令碼,只要撰寫一個空格 。

  • 秉持原則使用 Bash。

    在 Starlark 建構及測試規則中,使用 ctx.actions.run_shell 執行 Bash 指令碼和 Bash 做為動作

    在 Starlark 巨集中,將 Bash 指令碼和指令納入 native.sh_binary()native.genrule()。Bazel 會檢查 Bash 是否可用,並透過以下方式執行指令碼或指令: Bash。

    在 Starlark 存放區規則中,盡量避免使用 Bash。Bazel 目前就無法執行 以原則方式在存放區規則中對指令進行 Bash 指令。

刪除檔案

問題:

  • 檔案在開啟時無法刪除。

    開啟的檔案預設無法刪除 (根據預設),嘗試會導致「存取遭拒」 發生錯誤。如果你無法刪除檔案,可能仍在執行中的處理程序保留該檔案 開啟。

  • 無法刪除執行中程序的工作目錄。

    程序有工作目錄開啟的控制代碼,因此無法刪除該目錄 直到程序終止為止

解決方法:

  • 在程式碼中嘗試立即關閉檔案。

    在 Java 中,請使用 try-with-resources。在 Python 中,請使用 with open(...) as f:。原則上 。