本頁著重於撰寫與 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")
中,會產生相同的結果。這也適用於其他語言。特性:應盡量避免動作使用自訂環境變數。
環境變數是動作快取金鑰的一部分。如果動作使用經常變更的環境變數,或對使用者自訂的變數,則會導致規則無法快取。
解決方法:
僅使用大寫的環境變數名稱。
這項功能適用於 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.run
的executable
。這類檔案也沒有+x
權限,因此您無法執行任何檔案,就像在 Linux 上一樣。Bash 指令:為確保資料可攜性,請避免直接在操作中執行 Bash 指令。
Bash 在 Unix 類系統上很廣泛,但通常在 Windows 上不支援。Bazel 本身對 Bash (MSYS2) 的執行程度較低,因此日後的使用者比較不可能同時安裝 MSYS2。如要在 Windows 上更輕鬆地使用規則,請避免在操作中執行 Bash 指令。
行結尾:Windows 使用 CRLF (
\r\n
),類 Unix 系統使用的是 LF (\n
)。比較文字檔案時,請留意這一點。請注意您的 Git 設定,尤其是檢查或提交時,尤其是行尾。(請參閱 Git 的
core.autocrlf
設定)。
解決方法:
使用無 Bash 用途的規則。
native.genrule()
是 Bash 指令的包裝函式,通常用於解決複製檔案或寫入文字檔案等簡單問題。您可以避免依賴 Bash (並重新發明輪盤):看看 bazel-skylib 是否具有專為您的需求建立的規則。在 Windows 上建構/測試時,全都不需要依賴 Bash。建立規則範例:
write_file()
(來源、說明文件):寫入文字檔案,並加入所需的行尾結尾 (auto
、unix
或windows
),可以選擇將其設為可執行 (如果是指令碼)run_binary()
(來源、說明文件):使用指定輸入內容和預期輸出內容做為建構動作 (這是ctx.actions.run
的建構規則包裝函式) 執行二進位檔 (或*_binary
規則)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 目前並未在存放區規則中,以有原則的方式執行 Baash 指令。
刪除檔案
問題:
檔案在開啟時無法刪除。
開啟的檔案根據預設無法刪除 (根據預設),嘗試會導致「存取遭拒」錯誤。如果無法刪除檔案,可能是因為有執行中的程序仍在保持開啟狀態。
無法刪除執行中程序的工作目錄。
程序對其工作目錄有開放式控制代碼,且在程序終止前,您無法刪除該目錄。
解決方法:
在程式碼中嘗試立即關閉檔案。
在 Java 中,請使用
try-with-resources
。在 Python 中,請使用with open(...) as f:
。原則上,請盡快關閉控點。