如何在 Bazel 中解析 latex_document 构建警告并使构建失败?
结论
应将警告检查纳入 Bazel 的 action 依赖关系。可以在生成 PDF 的同一个 action 中解析日志,遇到指定警告时返回非零退出码;也可以将 .log 声明为输出,交给后续 action 检查。
原问题没有说明 latex_document 来自哪个规则库及其版本,因此无法确定它是否已经提供日志输出或检查钩子。具体接入点需要查看规则实现。
为什么不能直接读取 sandbox 中的日志?
在 sandbox 中看到 .log,只能说明编译工具生成了这个文件。后续 action 要使用日志,生成日志的 action 必须将它声明为输出,检查 action 也必须将它声明为输入。这是 Bazel 对 action 输入和输出的要求,见 Bazel 规则文档。
因此,在检查脚本中写入 sandbox 的绝对路径并不可靠。构建流程应通过声明的文件依赖找到日志。
如何接入 latex_document?
先检查规则的 .bzl 实现,确认日志是否已经通过默认输出、自定义 provider 或 output group 暴露出来。
如果可以修改编译 action,可以在它的执行脚本中增加以下步骤:
- 执行原有 LaTeX 编译流程,保留编译失败时的退出状态。
- 编译成功后,读取最终一轮编译产生的日志。
- 发现禁止的警告时打印诊断信息,并以非零状态退出。
这种方式在同一个 action 内读取日志,无需为警告检查单独导出 .log。
如果需要独立检查,应修改规则,将日志声明为输出,并确保编译命令把日志写入对应路径。随后让检查 action 依赖该日志。只在返回值里添加文件,却没有将它列入生成 action 的 outputs,无法完成接入。
独立检查的代码示例
下面假设规则已经暴露两个目标::raw_pdf 和 :latex_log,每个目标各包含一个文件。它们是示例标签,需要替换为项目实际提供的目标。
检查脚本 check_latex_log.py:
import re
import sys
from pathlib import Path
# 示例策略:将这两类诊断视为构建失败。
patterns = [
re.compile(r"Overfull \\hbox"),
re.compile(r"LaTeX Warning: There were undefined references\."),
]
log_path = Path(sys.argv[1])
lines = log_path.read_text(
encoding="utf-8", errors="replace"
).splitlines()
hits = [
line
for line in lines
if any(pattern.search(line) for pattern in patterns)
]
if hits:
print("LaTeX warning check failed:", file=sys.stderr)
for line in hits:
print(line, file=sys.stderr)
sys.exit(1)
在 Bazel 7.4 的 BUILD 文件中,可以用 py_binary 配合 genrule 接入。以下命令假设执行环境支持 POSIX shell 和 cp:
py_binary(
name = "check_latex_log",
srcs = ["check_latex_log.py"],
main = "check_latex_log.py",
)
genrule(
name = "checked_pdf",
srcs = [
":raw_pdf",
":latex_log",
],
tools = [":check_latex_log"],
outs = ["document.checked.pdf"],
cmd = "$(location :check_latex_log) " +
"$(location :latex_log) && " +
"cp $(location :raw_pdf) $@",
)
tools 用于声明检查工具,$(location ...) 获取声明文件的位置,$@ 表示该 genrule 的单个输出。相关语义见 genrule 文档。
构建时请求经过检查的目标:
bazel build //docs:checked_pdf
将 //docs 替换为实际包路径。命中警告时,检查程序返回 1,后续复制操作不会执行,构建随之失败。检查通过后,才会生成供后续流程使用的 PDF。
接入时需要注意什么?
- CI 和发布流程应使用
checked_pdf,让检查成为必经依赖。直接构建原始 PDF 目标仍会绕过检查。 - 检查最终一轮日志。如果构建流程会多次运行 LaTeX,中间轮次可能出现随后消失的交叉引用警告。
- 按实际日志制定匹配规则。示例只匹配两种文本,不是完整的 LaTeX 日志解析器。跨行警告、宏包诊断和白名单需要另外处理。
- 区分构建失败和测试失败。如果实现为测试目标,检查会在
bazel test时运行;需要bazel build因警告失败时,应将检查放在构建所需的 action 链中。 - 无法修改规则时,先确认已有的扩展能力。如果日志没有作为输出暴露,外层规则无法直接将 sandbox 中的临时日志变成可靠输入,通常需要扩展规则或调整其编译执行脚本。
备注:内容仅供参考。
