构建系统政策

本文档详细介绍了设计原则和制定的与 Fuchsia build 的工作原理相关的具体技术决策。这些原则适用于使用 Fuchsia build 的所有模式,例如通过交互式工程工作流或通过 CI/CQ 等自动化系统。

构建的目标和优先事项

与任何系统一样,构建通常会受到多项相互冲突的要求。当发生冲突时,我们通常会按照重要性顺序来满足这些优先级:

  1. 满足由 Fuchsia 技术领导层确定的客户要求。
  2. 确保正确性:生成所需的输出。
  3. 促进可维护性:文档、完善的工程流程。
  4. 提升性能:以更低的费用执行相同的构建。

build 所需的属性

以下属性被视为适合 build 的良好属性:

  • 封闭 - build 是独立的,既不会影响外部软件和配置,也不受外部软件和配置的影响。
  • 可重复性和可再现性 - 来自同一源代码树的两个 build 确定性地产生相同的输出或相同的结果。可再现性可提高安全性和审核能力,并简化问题排查过程。
  • 高效 - build 应只将时间花在与构建相关的工作上,并且必须致力于最大限度地降低对人力和基础架构费用的影响。
  • 可移植性 - 构建应在所有受支持的主机平台上生成一致的结果。

这些都是理想情况。 我们的目标是实现这些理想,并根据这些措施衡量进展。

将 Python 脚本作为构建操作

Python 脚本可用作构建操作。

请遵循适用于 Python 的 Google 样式指南

Fuchsia 目前使用 Python 3.8。所有 Python 源代码都以以下代码开头:

#!/usr/bin/env fuchsia-vendored-python

将 Shell 脚本作为构建操作

Shell 脚本可用作构建操作。

我们推荐使用 Shell 脚本来执行可通过几个简单的 shell 命令表示的任务。对于复杂操作,首选其他语言。

请遵循 Shell 脚本的 Google 样式指南。请使用 shellcheck 查找和更正常见的 shell 编程错误。

我们更倾向于使用 POSIX(也称为 Bourne) Shell 脚本,以便在各种主机平台上实现可移植性。如果您要维护现有的 Bash 脚本,请仅限在 3.2 版中使用这些功能,或者考虑将此脚本重写为 POSIX Shell 脚本。如需检查您的脚本是否符合 POSIX 标准,您可以使用:

shellcheck --shell=sh

在 POSIX shell 上运行的脚本应以以下内容开头:

#!/bin/sh

特别需要 Bash 的脚本应以以下代码开头:

#!/bin/bash

迁移

构建系统可以协助执行针对编译器功能、新工具或各种最佳实践的普及等的迁移。旧版的不良行为通常可以表现为对应用此行为的 config() 的依赖。对 group() 目标的依赖项使用要替换的旧版工具或模板时。

签订方案

您随时都可以努力改善代码运行状况,但在开始之前,您应该有一个明确的计划来完成开始。只完成一半的迁移就没有势头会比完全不迁移更糟糕。

建立回归停止点

假设代码库每 8 个月就会翻一番,并尽早工作,以防止引入旧版行为的新实例。通过建立回归停止,您将“被动”清理代码库,具体取决于代码库加倍率。也就是说,每个加倍期,您都会被被动地清理一半代码库。

确保许可名单由 OWNERS 文件保护,并且迁移的 POC 被列为所有者。由于所有者是由文件定义的,因此最好将许可名单细分为不同的 BUILD.gn 文件。例如,将与 Rust 相关的 config() 目标提取到 //build/config/rust 中,以便更好地管理 OWNERS 分配。

文档迁移 / 清理步骤

发布清晰的文档,说明迁移的性质、如何参与以及如何执行相关维护工作。这可让您的迁移工作扩大规模,并防止任何个人成为持续迁移工作的障碍,例如,当他们因支持请求而应接不暇或无法参与问题时。

作为积极示例,请查看 C++ 隐式转换

简化并自动执行许可名单维护

对于 GN 目标,许可名单可轻松表示为 visibility 列表。这使得系统能够进行自动分析,并使违反许可名单的更改快速使构建失败。

将目标列入许可名单以使用您要迁离的旧版行为时,应使这些目标的所有者能够轻松进行简单的重构,例如,通过将基础目录(而不是各个目标)列入许可名单来重命名其目录中的各个目标。

记录重新生成并削减任何许可名单的步骤,以便任何人都可以执行。

请参见下面的示例:

group("foo_allowlist") {
  #  ________  _________  ________  ________
  # |\   ____\|\___   ___\\   __  \|\   __  \
  # \ \  \___|\|___ \  \_\ \  \|\  \ \  \|\  \
  #  \ \_____  \   \ \  \ \ \  \\\  \ \   ____\
  #   \|____|\  \   \ \  \ \ \  \\\  \ \  \___|
  #     ____\_\  \   \ \__\ \ \_______\ \__\
  #    |\_________\   \|__|  \|_______|\|__|
  #    \|_________|
  # This is an allowlist of targets that use the deprecated "foo" tool.
  # As of April 2021 we no longer use "foo". Users should migrate to the new
  # "bar" tool as described in this guide:
  # https://fuchsia.dev/...
  #
  # To regenerate:
  # fx gn refs $(fx get-build-dir) //path/to:foo_allowlist | sed 's|\(.*\):.*|"\1/*",|' | sort | uniq
  #
  # To trim:
  # scripts/gn/trim_visibility.py --target="//path/to:foo_allowlist"
  visibility = [
    "//src/project1/*",
    "//src/project2/*",
    ...
  ]
}

然后在其他位置自动添加对已列入许可名单的目标的依赖项。

# Invoke the legacy foo tool.
# For new usage, please consider using the new bar tool instead!
# See:
# https://fuchsia.dev/...
# ...
template("foo") {
  action(target_name) {
    ...
    deps += [ "//build/foo:foo_allowlist" ]
  }
}

第三方可能不在服务范围内

Fuchsia 使用了大量第三方代码,这些代码不在 Fuchsia 项目范围之内。一般来讲,针对主观更改或政策决策针对所有第三方代码输入一揽子许可名单通常没什么问题。

group("bar_allowlist") {
  ...
  visibility = [
    "//third_party/*",
    ...
  ]
}

您或许可以在上游进行更改,具体取决于更改的性质和相关第三方代码。请充分利用您的判断。