本页介绍了封闭性、使用封闭构建的好处,以及 识别 build 中的非封闭行为的策略。
概览
在给定相同的输入源代码和产品配置的情况下,封闭式模型 通过将 build 与更改隔离开来,构建系统始终返回相同的输出 发送到主机系统。
为了隔离 build,封闭 build 对库和 本地或远程主机上安装的其他软件。它们依赖于 特定版本的构建工具(如编译器)和依赖项(例如 库。这使得构建流程不依赖于 构建环境外部的服务
封闭的两个重要方面是:
- 隔离:封闭构建系统将工具视为源代码。他们 下载工具副本并管理其存储空间,以及在托管文件中使用 数据。这会在主机和本地用户之间创建隔离 包括已安装的语言版本。
- 源身份:封闭构建系统会尝试确保 输入。Git 等代码库使用 唯一哈希代码。封闭式构建系统使用此哈希来识别对 build 的输入。
优势
封闭构建的主要优势包括:
- 速度:可以缓存操作的输出,而不需要 再次运行。
- 并行执行:对于给定的输入和输出,构建系统可以 构造所有动作的图,以计算高效并行 执行。构建系统加载规则并计算操作图 对输入进行哈希处理,以便在缓存中查找。
- 多个 build:您可以在同一项上构建多个封闭 build 每个机器都使用不同的工具和版本进行构建。
- 可重现性:封闭 build 有助于排查问题,因为 了解生成相应 build 的确切条件。
识别非封闭性
如果您准备改用 Bazel, 现有 build 的保密。一些常见的 build 中的非封闭性:
- 在
.mk
文件中任意处理 - 以不确定的方式创建文件的操作或工具,通常涉及 build ID 或时间戳
- 不同主机不同的系统二进制文件(例如
/usr/bin
二进制文件、绝对二进制文件) 路径、用于原生 C++ 规则自动配置的系统 C++ 编译器) - 在构建期间向源代码树写入数据。这样可以防止与 不会用于另一个目标。第一个构建会向源代码写入数据 修复目标 A 的源代码树。然后尝试构建目标 B 失败。
对非封闭 build 进行问题排查
从本地执行开始,影响本地缓存命中的问题会显示 非封闭操作。
- 确保 null 顺序构建:如果运行
make
并获得成功的构建, 再次运行构建应该不会重新构建任何目标。如果运行每个 build 或者在不同系统上执行两次步,比较文件内容的哈希值,然后 获得不同的结果,构建不可重现。 - 运行步骤 调试本地缓存命中 各种潜在的客户端机器,以确保您可以捕获 客户环境泄漏到行动中的情况。
- 在 Docker 容器内执行构建 签出的源代码树和明确的主机工具列表。制造中断和 错误消息将捕获隐式系统依赖项。
- 使用以下代码发现并修复密封问题 remote execution rules。
- 启用严格沙盒 因为构建中的操作可能是有状态的 构建或输出
- 工作区规则
允许开发者向外部工作区添加依赖项,但它们
足够丰富,可在过程中进行任意处理。您可以
通过以下方法获取 Bazel 工作区规则中一些可能的非封闭操作的日志
添加国旗
--experimental_workspace_rules_log_file=PATH
至 运行 Bazel 命令
Bazel 的封闭性
有关其他项目如何使用封闭的成功的详细信息 使用 Bazel 构建,请参阅以下 BazelCon 讲座:
- 使用 Bazel 构建实时系统 (SpaceX)
- Bazel Remote Execution 和 Remote Caching(Uber 和 TwoSigma)
- 通过 Remote Execution 和缓存加快构建速度
- 融合 Bazel:更快的增量构建
- 远程执行与本地执行
- 提高远程缓存的可用性 (IBM)
- 使用 Bazel 打造自动驾驶型汽车 (BMW)
- 使用 Bazel 打造自动驾驶型汽车 + 问答 (GM Cruise)