拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Bazel 共享变量指南:在 BUILD 文件与 .bzl 文件中复用配置值

Bazel 共享变量指南在 BUILD 文件与 .bzl 文件中复用配置值【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel本指南讲解 Bazel 构建系统中BUILD文件的变量共享机制如何在单个BUILD文件内用全局常量消除重复配置如何在多个BUILD文件之间通过.bzl文件与load()语句共享值以及何时不该引入变量遵循 DAMP 优于 DRY 的原则。读完本文你将掌握copts等重复属性值的正确抽象方式并能写出既便于人读、又便于工具自动维护的声明式构建文件。BUILD 文件的本质简单、声明式、面向人读与工具Bazel 的BUILD文件被设计为简单且声明式simple and declarative的配置文件通常由一系列目标target声明组成。以仓库中的真实示例 examples/cpp/BUILD 为参照典型的声明形如cc_library( name hello-lib, srcs [hello-lib.cc], hdrs [hello-lib.h], ) cc_binary( name hello-world, srcs [hello-world.cc], deps [:hello-lib], )随着代码库和BUILD文件不断变大重复会自然出现。例如下面的两个cc_library都携带相同的编译选项cc_library( name foo, copts [-DVERSION5], srcs [foo.cc], ) cc_library( name bar, copts [-DVERSION5], srcs [bar.cc], deps [:foo], )为什么BUILD文件中的重复通常是可接受的先纠正一个常见直觉BUILD文件中的代码重复通常是没问题的。原因在于可读性——每一条声明都能脱离上下文被独立阅读和理解。这一点不仅对人类重要对外部工具同样关键。例如工具可能读取并修改BUILD文件以补全缺失依赖如果文件里充满了间接抽象这类自动化修改就无法安全进行。过度的重构与代码复用反而会阻碍工具化的批量修改。仓库中的 BUILD 风格指南 对此给出了更精确的表述BUILD文件不是代码而是配置它们不像代码那样被测试却需要被人和工具共同维护因此DAMPDescriptive and Meaningful Phrases描述性且有意义的短语比 DRYDont Repeat Yourself更适合BUILD文件。DAMP 鼓励以可读性换取唯一性让文件更易理解、更易维护。何时值得引入变量值必须保持同步时既然重复被容忍那变量存在的意义是什么文档给出的判断标准是如果共享值是有价值的——例如这些值必须保持同步must be kept in sync——就可以引入变量。典型场景是版本号、宏开关这类改一处处处生效的配置COPTS [-DVERSION5] cc_library( name foo, copts COPTS, srcs [foo.cc], ) cc_library( name bar, copts COPTS, srcs [bar.cc], deps [:foo], )这里多个声明统一引用常量COPTS升级版本号时只需修改一行。命名约定全局常量一律使用大写字母命名如COPTS、GLOBAL_CONSTANT这一约定在 BUILD 风格指南 中被明确为正式规范——常量用大写加下划线GLOBAL_CONSTANT局部变量用小写加下划线my_variable。跨多个 BUILD 文件共享.bzl文件 load()单个BUILD文件内的常量只能服务本包package。如果需要在多个BUILD文件之间共享同一个值就必须把它放进.bzl文件。.bzl文件Starlark 扩展文件包含可在BUILD文件中使用的定义——既可以是变量也可以是函数。首先在path/to/variables.bzl中写入定义COPTS [-DVERSION5]然后在需要使用该变量的BUILD文件中通过load()语句加载load(//path/to:variables.bzl, COPTS) cc_library( name foo, copts COPTS, srcs [foo.cc], ) cc_library( name bar, copts COPTS, srcs [bar.cc], deps [:foo], )load() 标签语法要点load()的第一个参数是指向.bzl文件的标签。标签的语法规则在 标签Labels概念文档 中有完整定义//path/to:variables.bzl中//path/to是包路径BUILD文件所在目录相对于仓库根目录的路径冒号后是包内文件名加载同一个仓库内的文件时省略仓库名前缀即//开头而非repo//开头第二个参数列出要导入的符号名可以是单个符号也可以是多个load(//path/to:variables.bzl, COPTS, OTHER_CONST)。仓库源码中到处可见这一模式。例如 docs/extending/macros.mdx 中加载宏的写法load(//macro:macro.bzl, my_macro)以及 examples/cpp/BUILD 中加载规则实现的写法load(rules_cc//cc:cc_binary.bzl, cc_binary) load(rules_cc//cc:cc_library.bzl, cc_library) load(rules_cc//cc:cc_test.bzl, cc_test)注意rules_cc//cc:cc_binary.bzl是外部仓库以单个开头的 apparent 仓库名中的文件而//path/to:variables.bzl是当前仓库内的文件——两者的load()语法结构完全相同只是仓库名前缀不同。从变量到宏共享能力的延伸load()不仅能共享常量还能共享函数与宏。.bzl文件可以同时导出变量和宏定义BUILD文件加载后既能引用常量也能调用宏来批量生成目标。关于宏的完整用法可进一步阅读 宏Macros教程 与 Bazel 规则语言概览。实践指南哪些东西不该放进变量变量共享虽然方便但滥用会损害可维护性。BUILD 风格指南 给出了几条直接相关的红线1. 不要用变量封装公共依赖deps将多个目标共用的依赖塞进一个列表变量是被明确禁止的反模式# 反面示例不要这样做 COMMON_DEPS [ //d:e, //x/y:z, ] cc_library(name a, srcs [a.cc], deps COMMON_DEPS [ ... ], )正确做法是让每个目标独立列出自己的直接依赖。把公共依赖抽成变量会降低可维护性、让工具无法修改单个目标的依赖还容易引入未被使用的依赖。让 Gazelle 等自动化工具去维护依赖列表——虽然会有重复但你不必操心如何管理依赖。2. 优先使用字面量字符串避免拼接虽然 Starlark 支持字符串拼接和格式化%但拼接后的值难以一眼读懂且自动化工具如 buildozer、代码搜索难以找到并正确更新被拆分的值。风格指南因此要求标签类属性name、deps等应使用完整字面量字符串绝不可拆分标签即使超过 79 字符也不拆分。3. 限制每个 .bzl 文件导出的符号数量应最小化每个公共.bzl文件导出的符号规则、宏、常量、函数数量。只有当多个符号确定会被一起使用时才放在同一文件否则应拆分为多个.bzl文件。原因很实际过度膨胀的.bzl文件会变成符号大杂烩导致单个文件的改动迫使 Bazel 重建大量目标影响增量构建性能。4. 保持BUILD文件结构整洁按风格指南推荐BUILD文件的元素顺序应为包描述注释 → 所有load()语句 →package()函数 → 规则与宏调用。这意味着变量共享场景下的load()语句应始终置于文件顶部、规则声明之前这也是 buildifier 自动格式化所遵循的顺序。小结场景推荐做法依据值只需在单个BUILD文件内复用定义大写命名的全局常量docs/build/share-variables.mdx值需要跨多个BUILD文件共享写入.bzl文件用load(//path/to:file.bzl, NAME)加载docs/build/share-variables.mdx、标签文档需要共享生成目标的逻辑在.bzl中定义宏并加载宏教程公共依赖列表不要用变量封装逐目标列出直接依赖BUILD 风格指南字符串 / 标签值使用完整字面量禁止拼接与格式化BUILD 风格指南核心取舍始终如一BUILD文件优先服务于人类阅读与工具自动化而非代码复用。当重复的值需要保持同步时才引入变量当共享范围跨越包边界时才引入.bzl文件其余情况下宁可保留显式的重复也不要牺牲声明式构建文件的可读性与可工具化能力。格式化统一交给 buildifier风格约定以 docs/build/style-guide.mdx 为权威参考。【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门