Bazel Builtins 注入机制深度解析:builtins_bzl 目录、@_builtins 伪仓库与 --experimental_builtins_bzl_path 实战指南
Bazel Builtins 注入机制深度解析builtins_bzl 目录、_builtins 伪仓库与 --experimental_builtins_bzl_path 实战指南【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel导读本指南以 Bazel 源码树中的src/main/starlark/builtins_bzl/目录为核心深入剖析 Bazel 的builtins 注入builtins injection机制该目录中的.bzl文件如何被打包为 builtins zip、如何以_builtins伪仓库的形式参与exports.bzl的求值以及--experimental_builtins_bzl_path旗标如何控制使用打包内置版本或直接读取源码目录版本。读完本文你将掌握 builtins zip 的打包与装载路径、exported_toplevels/exported_rules/exported_to_java三个导出字典的作用以及如何在本仓库源码树内调试与验证 builtins 改动。目录定位builtins_bzl 在 Bazel 源码树中的角色在仓库中src/main/starlark/builtins_bzl/是 Bazel内建符号predeclared symbols的 Starlark 源码根目录。其下的目录结构清晰分为两类bazel/与 OSS Bazel 发行版强相关的符号如exports.bzl顶层导出入口。common/与语言生态相关的公共实现包括cc/cc_common.bzl、java/java_common.bzl、objc/apple_common.bzl、python/py_internal.bzl、xcode/providers.bzl以及paths.bzl、util.bzl等工具模块。顶层exports.bzl与BUILD一起定义了该目录作为builtins_bzl 树根的身份。BUILD中的注释明确写道该目录在源码形态下即为 builtins 树根当--experimental_builtins_bzl_path设为%workspace%时运行时也以它为根同时由于使用 glob 收集源码该目录下不应存在子包BUILD。目录的官方自述文档README.md给出了三条关键事实是理解整个机制的起点这里的.bzl文件被打包为Bazel 的 builtins zip它们使用Bazel Build Language 的修改版方言modified dialect因此不能像普通.bzl文件那样被load()修改这些文件后效果是否立即可见取决于--experimental_builtins_bzl_path的取值设为%workspace%时立即生效设为%bundled%时需重启 Bazel server。下文逐一展开这三条事实背后的实现细节。builtins zip 的打包从源码目录到 Java 资源打包规则builtins_zipsrc/main/starlark/builtins_bzl/BUILD定义了将目录打包为 zip 的规则filegroup( name srcs, srcs glob([**]), visibility [//src:__pkg__], ) builtins_zip( name builtins_bzl_zip, srcs glob([**/*.bzl]), out builtins_bzl.zip, visibility [ //src/main/java/com/google/devtools/build/lib/bazel/rules:__pkg__, ], zipper //third_party/ijar:zipper, )该builtins_zip规则定义于 src/builtins_zip.bzl将所有.bzl文件打成builtins_bzl.zip产出被//src/main/java/com/google/devtools/build/lib/bazel/rules:builtins_bzl_zip目标消费BUILD最终作为 Java 资源随 Bazel 二进制发布。装载路径ConfiguredRuleClassProvider运行时BazelRuleClassProvider通过ResourceFileLoader.resolveResource(...)解析builtins_bzl.zip资源并调用setBuiltinsBzlPackagePathInSource(src/main/starlark/builtins_bzl)记录源码树内的相对位置BazelRuleClassProvider.java。ConfiguredRuleClassProvider中则定义了两种查找方式ConfiguredRuleClassProvider.java%bundled%模式从 jar 资源中读取内置的 builtins_bzl.zip解包到独立的虚拟文件系统注意解包时builtins_bzl/ 条目本身不会被复制只复制其子项ConfiguredRuleClassProvider.java。%workspace%模式直接读取 Bazel 源码树中相对包路径src/main/starlark/builtins_bzl下的文件该模式只应在源码树内运行 Bazel 时使用。修改版 Build Language 方言为什么不能直接 loadREADME 强调 builtins 目录中的.bzl使用Bazel Build Language 的修改版方言无法作为普通.bzl加载。结合源码可以确认两点这些文件依赖两个特殊符号_builtins.toplevel与_builtins.rule。例如bazel/exports.bzl中直接调用_builtins.toplevel.native.filegroup(...)common/exports.bzl中调用_builtins.toplevel.proto_common_do_not_use.incompatible_enable_proto_toolchain_resolution()。这些_builtins前缀符号由 Bazel 注入普通用户.bzl并不具备。解析与加载 builtins 文件走的是专用 Skyframe 逻辑StarlarkBuiltinsFunction求值_builtins伪仓库并上报导出值与BzlLoadFunction负责 .bzl 加载并对 builtins 走keyForBuiltins特殊键路径两处源码注释均要求读者参考对方以理解完整流程StarlarkBuiltinsFunction.java、README。_builtins是一个伪仓库pseudo-repositoryStarlarkBuiltinsFunction的 javadoc 说明它与bazel_tools共享 repo mapping并且用户被禁止定义名为_builtins的真实仓库以避免混淆它只能通过专用 SkyKey 访问StarlarkBuiltinsFunction.java。注入工作流exports.bzl 如何决定内建符号三个导出字典整个注入机制围绕_builtins//:exports.bzl导出的三个字符串键字典展开字典作用消费方exported_toplevels顶层全局符号如cc_common、java_common、apple_common、py_internalBUILD/.bzl 的预声明符号环境exported_rulesStarlark 化的原生规则native rulesBUILD 文件的规则解析exported_to_java可供原生规则实现调用的 Starlark 函数Java 侧 native rule 实现顶层 exports.bzl 的组装逻辑顶层 exports.bzl 并不直接定义符号而是通过load(_builtins//:bazel/exports.bzl, ...)与load(_builtins//:common/exports.bzl, ...)分别取回 Bazel 专属与公共的导出字典再用dict_union做严格并集重复键会直接fail见 util.bzlexported_rules dict_union(common_exported_rules, bazel_exported_rules) exported_toplevels dict_union(common_exported_toplevels, bazel_exported_toplevels) exported_to_java dict_union(common_exported_to_java, bazel_exported_to_java)其中common/exports.bzl贡献的顶层符号包括_builtins_dummy仅用于测试注入是否生效其内置值为original value注入后被覆盖为overridden value与proto_common_do_not_usecommon/exports.bzlbazel/exports.bzl则贡献py_internal、java_common、cc_common、apple_common等真实符号bazel/exports.bzl。已移除规则的兜底_removed_rule_failurebazel/exports.bzl还展示了规则迁移的一种模式_REMOVED_RULES列表中的规则如cc_binary、cc_library、cc_test、objc_library等已被从 Bazel 中移除若用户仍直接使用会命中_removed_rule_failure并给出明确的fail()信息提示请为该规则添加load()语句或运行buildifier --lintfix path自动修复bazel/exports.bzl。这是 builtins 机制在兼容性治理上的典型用法。Skyframe 侧的应用逻辑StarlarkBuiltinsFunction.computeInternal的流程StarlarkBuiltinsFunction.java可概括为读取StarlarkSemantics若--experimental_builtins_bzl_path为空字符串直接返回空 builtins 值即完全禁用注入加载exports.bzlinlining 模式下转发给BzlLoadFunction.computeInline并把结果缓存到InlineCacheManager.builtinsRef通过compareAndSet保证多线程竞争下只保留一个胜者值见 computeInline计算 exports.bzl 的transitiveDigest作为变更指纹从模块中取exported_toplevels、exported_rules、exported_to_java三个字典缺失或非字符串键字典会抛错见getDict调用BazelStarlarkEnvironment的createBuildBzlEnvUsingInjection、createModuleBzlEnvUsingInjection、createBuildEnvUsingInjection分别构建 BUILD 加载、MODULE 加载与 BUILD 文件的预声明符号环境汇总为StarlarkBuiltinsValue返回供BzlLoadFunction在解析普通.bzl/ BUILD 时使用。加载/应用失败分别包装为errorEvaluatingBuiltinsBzls与errorApplyingExports两种BuiltinsFailedExceptionStarlarkBuiltinsFunction.java错误信息形如 Failed to load builtins sources: ... 或 Failed to apply declared builtins: ...。--experimental_builtins_bzl_path三种取值模式该旗标在 BuildLanguageOptions.java 中定义默认值%bundled%属于 UNDOCUMENTED EXPERIMENTAL 选项且带有LOSES_INCREMENTAL_STATE与BUILD_FILE_SEMANTICS两个 effect tag——即修改它会导致增量状态失效语义上影响 BUILD 文件解析。取值含义生效时机%bundled%默认使用 Bazel 二进制内打包的 builtins_bzl/ 目录修改源码后需重启 Bazel server才能看到效果%workspace%使用 Bazel 源码树内的src/main/starlark/builtins_bzl相对包路径仅应在源码树内运行 Bazel 时使用修改后立即生效其他路径相对于当前 workspace 根目录的、指向备用 builtins_bzl/ 目录的路径视具体场景空字符串完全禁用 builtins 注入机制立即README 中%workspace%立即生效、%bundled%需重启 server的表述与ConfiguredRuleClassProvider中bundled 模式在启动时解包 zip 到虚拟文件系统、workspace 模式按需读源文件的实现是一致的。实战在本仓库源码树中验证 builtins 改动结合仓库内容可以按以下步骤在 Bazel 源码树内体验 builtins 注入确认当前 Bazel 的 builtins 路径在源码树内启动 Bazel 时追加--experimental_builtins_bzl_path%workspace%即让 Bazel 直接使用 src/main/starlark/builtins_bzl 目录避免每次修改都重启 server。修改后观察效果改动任一.bzl例如向 bazel/exports.bzl 的exported_toplevels增加测试符号%workspace%模式下无需重启即可看到新符号出现在 BUILD/.bzl 的预声明环境中。回归验证打包确认修改合法后builtins_zip会通过glob([**/*.bzl])自动纳入新文件重新构建//src/main/java/com/google/devtools/build/lib/bazel/rules:builtins_bzl_zip即可生成新的内置资源此时切换回默认%bundled%并重启 server验证发布形态下的行为。利用测试符号_builtins_dummy是官方留出的注入自检符号common/exports.bzl可在任意.bzl中引用它来确认注入链路是否生效。需要特别留意的是这些.bzl依赖_builtins.toplevel/_builtins.rule等专用方言不能被用户 BUILD 文件或普通.bzl直接load若在外部 workspace 中使用必须以%workspace%指向 Bazel 源码树为前提详见 README 与 BuildLanguageOptions.java 的 help 文本。总结src/main/starlark/builtins_bzl/是 Bazel 内建符号从 Java 原生实现走向 Starlark 化的关键载体builtins_zip完成打包、_builtins伪仓库完成隔离求值、exports.bzl的三个导出字典完成符号注入、--experimental_builtins_bzl_path完成开发与发布两种形态的切换。本文所述的全部事实均可在本仓库对应源码中验证读者可沿着 README → exports.bzl → StarlarkBuiltinsFunction.java → BuildLanguageOptions.java 这条链路逐步深入 builtins 注入的完整实现。【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考