如何在Bazel中解析latex_document构建警告并按需终止构建
拦截Bazel LaTeX构建特定警告并终止构建的最佳实践
针对Bazel 7.4中latex_document规则生成的LaTeX警告,要将其纳入构建流程并拦截特定警告终止构建,核心思路是扩展原生规则,提取沙箱内的log文件并通过自定义脚本检查警告,具体步骤如下:
1. 自定义Bazel规则扩展原生latex_document
原生latex_document不会暴露沙箱内的.log文件,因此需要编写自定义规则,先调用原生规则生成PDF,再将沙箱中的log文件拷贝到可访问路径,最后执行警告检查。
创建latex_rules.bzl文件,添加以下Starlark代码:
load("@bazel_latex//:latex.bzl", "latex_document") def _strict_latex_document_impl(ctx): # 依赖原生latex_document生成的PDF产物 latex_doc = ctx.attr.latex_doc[DefaultInfo] # 声明log文件的输出路径,方便后续检查 log_file = ctx.actions.declare_file(f"{ctx.label.name}.log") # 从沙箱中拷贝log文件到bazel可访问目录 ctx.actions.run_shell( inputs = [latex_doc.files_to_run.executable], outputs = [log_file], command = """ # 定位沙箱内的LaTeX log文件(与主tex文件同名) LOG_FILE=$(find $(dirname {exec_path}) -name "{tex_base}.log") cp "$LOG_FILE" {output_log} """.format( exec_path = latex_doc.files_to_run.executable.path, tex_base = ctx.attr.main.split(".")[0], output_log = log_file.path, ), ) # 执行警告检查脚本 check_script = ctx.file._check_script ctx.actions.run( inputs = [log_file, check_script], outputs = [], executable = check_script, arguments = [log_file.path], mnemonic = "LatexWarningCheck", ) return DefaultInfo( files = depset([latex_doc.files_to_run.executable, log_file]), runfiles = latex_doc.runfiles, ) strict_latex_document = rule( implementation = _strict_latex_document_impl, attrs = { "latex_doc": attr.label(providers = [DefaultInfo], mandatory = True), "main": attr.string(mandatory = True), "_check_script": attr.label( default = Label("//:check_latex_warnings.py"), allow_single_file = True, ), }, )
在项目BUILD文件中使用自定义规则:
# 原生latex_document目标 latex_document( name = "my_pdf", main = "main.tex", # 其他必要属性(如依赖的tex文件、宏包等) ) # 带警告检查的严格构建目标 strict_latex_document( name = "my_pdf_strict", latex_doc = ":my_pdf", main = "main.tex", )
2. 编写LaTeX警告检查脚本
创建check_latex_warnings.py脚本,解析log文件,匹配特定警告并在发现时终止构建:
#!/usr/bin/env python3 import sys import re def check_forbidden_warnings(log_path): # 定义需要拦截的警告正则,可根据项目需求修改 forbidden_patterns = [ r"LaTeX Warning: Reference `.+' on page \d+ undefined", r"Font shape `.+' in size `.+' not available", r"Overfull \\hbox \(\d+.\d+pt too wide\) in paragraph at lines \d+--\d+", r"Underfull \\hbox \(badness \d+\) in paragraph at lines \d+--\d+", ] with open(log_path, "r", encoding="utf-8", errors="ignore") as log_file: content = log_file.read() for pattern in forbidden_patterns: matches = re.findall(pattern, content) if matches: print("ERROR: 发现禁止的LaTeX警告:") for match in matches: print(f" - {match}") sys.exit(1) print("INFO: 未发现禁止的LaTeX警告") sys.exit(0) if __name__ == "__main__": if len(sys.argv) != 2: print(f"用法: {sys.argv[0]} <LaTeX日志文件路径>") sys.exit(1) check_forbidden_warnings(sys.argv[1])
给脚本添加可执行权限:
chmod +x check_latex_warnings.py
3. 关键注意事项
- 沙箱路径适配:通过
find命令定位log文件是通用方案,避免依赖固定的沙箱路径(Bazel沙箱路径会随构建变化)。 - 缓存机制兼容:log文件作为检查脚本的输入,Bazel会自动识别内容变化并重新检查,符合缓存逻辑。
- 警告规则定制:根据项目规范调整
forbidden_patterns中的正则,比如只拦截严重警告,忽略轻微提示。 - 依赖顺序保证:自定义规则依赖原生
latex_document的产物,确保LaTeX构建完成后再执行警告检查。
4. 验证构建流程
运行严格构建目标:
bazel build //:my_pdf_strict
如果log中存在匹配的警告,构建会立即终止并输出错误信息;无禁止警告时,构建正常完成,同时生成PDF和对应的log文件。
内容的提问来源于stack exchange,提问作者Peder
相关产品推荐
相关产品推荐

