这一页重点介绍了与 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]:严格意义 交叉路口不是符号链接, 为了构建操作,您可以将连接视为目录符号链接。
在 actions / envvars 的路径中将
/
替换为 ``。为操作创建命令行或环境变量时,请将路径设置为 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
(批处理脚本)。请注意,Shell 脚本 (
.sh
) 在 Windows 上不可执行;您不能将其指定为ctx.actions.run
的executable
。此外,文件可能也没有+x
权限,因此 无法像在 Linux 上那样执行任意文件Bash 命令:为了实现可移植性,请避免直接在 Action 中运行 Bash 命令。
Bash 在类似 Unix 的系统上非常普遍,但在 Windows 上通常不可用。Bazel 本身 对 Bash (MSYS2) 的依赖程度越来越低,因此将来用户不太可能会用到 MSYS2 随 Bazel 一起安装为使规则在 Windows 上更易于使用,请避免在 操作。
行尾:Windows 使用 CRLF (
\r\n
),类似 Unix 的系统使用 LF (\n
)。比较文本文件时请注意这一点。请注意您的 Git 设置,尤其是 结尾。(请参阅 Git 的
core.autocrlf
设置。)
解决方案:
使用无 Bash 的专用规则。
native.genrule()
是 Bash 命令的封装容器,通常用于解决简单的问题 例如复制文件或写入文本文件您可以避免依赖 Bash(和 wheel):查看 bazel-skylib 是否有专门制定的规则来满足您的需求。它们都依赖于 Bash 。构建规则示例:
write_file()
(来源, 文档): 用于写入一个文本文件,以所需的行结尾(auto
、unix
或windows
),可选 使其可执行(如果是脚本)run_binary()
(来源, 文档): 将具有指定输入和预期输出的二进制文件(或*_binary
规则)作为构建操作运行 (这是ctx.actions.run
的构建规则封装容器)native_binary()
(来源, 文档): 将原生二进制文件封装在*_binary
规则中,您可以bazel run
或在run_binary()
的tool
属性或native.genrule()
的tools
属性
测试规则示例:
在 Windows 上,请考虑使用
.bat
脚本来实现一些简单操作。您可以使用
.bat
脚本而不是.sh
脚本来解决琐碎任务。例如,如果您需要不执行任何操作、输出消息或退出并显示固定内容的脚本, 错误代码,那么一个简单的
.bat
文件就足够了。如果您的规则返回DefaultInfo()
提供程序,executable
字段可以引用 Windows 上的该.bat
文件。由于文件扩展名在 macOS 和 Linux 上无关紧要,因此您可以随时使用
.bat
作为 甚至对于 Shell 脚本也是如此。请注意,无法执行空的
.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:
。原则上,请尝试 关闭标识名