fx 工作流程

fx 是一组子命令的入口点,子命令可以简化许多与 Fuchsia 开发相关的任务。运行 fx help 即可查看所有可用的子命令。如果您使用 bashzsh 作为 shell,请对 scripts/fx-env.sh 执行源代码操作以获取一些自动补全功能。

正在设置 fx

强烈建议您将 source scripts/fx-env.sh 添加到 shell 中。此测试已经过测试,并经常与 Bash 和 ZSH 一起使用。它可能适用于其他兼容的 shell。

# In your fuchsia checkout:
$ cd fuchsia
# Add a configuration to your shell to include fx-env.sh
$ echo "source \"$PWD/scripts/fx-env.sh\"" >> "$HOME/.$(basename "$SHELL")rc"
# If you would like additional convenience tools from the Fuchsia scripts, also
# optionally run the following:
$ echo "fx-update-path" >> "$HOME/.$(basename "$SHELL")rc"
# Restart your shell
$ exec "$SHELL"

上述方法提供了定义最明确的特征集,一般应该是非侵入性的。如果会导致 shell 环境出错,请提交项目错误。

如果出于某种原因,您需要使用多个 Fuchsia 检出程序(下方的推荐工作流程可以避免这种需求),那么您可能需要执行除上述操作之外的其他操作。在本示例中,有几种受到良好支持的方法:

  • 始终显式执行 $FUCHSIA_DIR/scripts/fx
  • 处理特定 Fuchsia 目录时,请使用 direnvdotenv 等工具将 $FUCHSIA_DIR/.jiri_root/bin 添加到 $PATH

常用的日常工具

在检出 Fuchsia 树后,您要做的第一件事是构建 Fuchsia,然后将其安装到设备上。fx 有一些命令可帮助您解决此问题:

配置 build

首先,我们来配置 build。为此,您需要做出以下几个选择:

  • 您想要什么产品配置? (不确定:请尝试workbench_eng
  • 您要为哪个主板开发应用?(不确定:请尝试x64
  • 您还想要哪些额外的测试目标?(不确定:请尝试 //bundles/tools,如果您正在开发功能,则可能需要 //bundles/tests

有了上述选择(如果您尚未阅读上文,请立即完成操作)后,您就可以配置 build 了:

fx set workbench_eng.x64 --with //bundles/tests

在结账过程中运行 fx set 后,无需再次运行它,除非您需要修改后面的参数。

fx set 将其配置存储在输出目录下的 args.gn 文件中。直接输出为 out/default。您可以使用 fx --dir <out_dir> set <set_args> 指定其他目录。

您可以使用 fx args 命令修改生成的 args.gn 文件,以创建更详细的配置。fx args 将在编辑器中打开 args.gn,让您进行更改,然后重新生成构建图。

刚刚发生了什么?

  • 您选择了产品 workbench_eng(运行 fx list-products 可查看其他产品配置的列表)。
  • 您已选择开发板 x64,它支持基于 x64 架构的许多典型开发板。(请注意,arm64 开发板的可互换性较低,在构建到 arm64 架构时,您很可能需要为 fx set 提供特定开发板。请运行 fx list-boards 以获取已知板级配置的列表。)
  • 您正在临时构建 tests,并将其作为 universe 软件包集的一部分,而不是作为铺砌映像的一部分。

软件包部署选项

--with 选项有三个变体,与如何部署到 Fuchsia 设备相关:--with-base--with-cache--with(隐含 universe)。(请注意,fx set 还有一个 --with-host 选项,用于构建主机专用目标,例如基于主机的工具和库。)

那么,basecacheuniverse 是什么呢?

配置最终会指定对 build 的输出工件(主要是映像和软件包代码库)有贡献的依赖项(大多数是软件包)。系统会对 build 进行参数化处理,以确定将哪些依赖项(主要是软件包)添加到哪些输出工件(映像或软件包代码库)中。这三条轴分别称为“基准”“缓存”和“宇宙”:

  • 基础版本:添加到基础版本的软件包包含在 build 生成的铺砌映像中。它们包含在无线下载更新中,并且始终作为单个单元进行更新。基础中的软件包无法在运行时从设备中移除,它们会对配置的最小可能大小进行编码。
  • 缓存:缓存中的软件包包含在铺路映像中,但无线系统更新中不包含这些软件包,并且为了响应资源需求(例如磁盘空间压力),可以将这些软件包从系统中逐出。缓存中的软件包可在有可用更新时随时更新,并且其中每个软件包均可独立更新。这是一个“可选”软件,但最好是“开箱即用”立即使用。
  • 宇宙:宇宙中的软件包是额外的可选软件包,可以提取和按需运行,但不会预先烘焙到任何铺砌映像中。

“board”和“product”配置会为其中每个软件包集选择一组预定义成员。板级配置通常会指定一组要添加到基本依赖项集的启动关键型驱动程序,例如在缓存集中包含一些可选但常用的外设驱动程序。板级配置可能还包括一些板级开发工具(更常见的是托管工具,而不是目标软件包),用于与“宇宙”中的开发板进行交互。产品配置会根据所代表产品的定义和功能集,选择向基础软件包集、缓存软件包集或宇宙软件包集中添加更多软件。例如,扬声器产品会在基础上添加许多与音频媒体相关的软件包。工作台产品在基础中添加了各种 GUI、媒体和许多其他软件包。

关键产品配置

除下方代码之外,还有很多其他配置,但需要熟悉以下三个特别重要的配置:

  • bringup 是一款极简的功能集产品,专注于极其简单和精简。它旨在提供快速 build 和小映像(主要以 netboot,而非铺砌方式使用),并且非常适合用于非常低级别的设施,例如 Zircon 内核或板级驱动程序和配置。它缺少大多数网络功能,因此无法在运行时添加新软件或自行升级。这也意味着,某些 fx 命令(如 fx servefx shell)不能与 bringup 产品一起使用。
  • core 是最低限度的功能集,可安装其他软件(例如添加到“Universe”依赖项集的项目)。它是所有更高级别的产品配置的起点。它具有常用的网络功能,可以通过无线下载方式更新系统。
  • workbench_eng 是通用开发环境的基础,适用于界面、媒体和许多其他高级功能。这也是发烧友们尽情玩耍和探索的最佳环境。

其他关键的构建目标

fx set--with 标志可接受任意构建目标。为方便起见,我们定义了许多软件包,其中包括各种常用的 build 目标。请务必熟悉以下软件包:

  • //bundles/tools 包含各种最常见的开发者工具。其中包括用于从命令行 shell 生成组件的工具、用于重新配置和测试网络、发出 http 请求、调试程序、更改音频音量等的工具。核心产品在默认的 Universe 软件包中包含 //bundles/tools
  • //bundles/tests 会导致编译所有测试程序。可以使用设备上的 run-test-suite 或通过 fx test 调用大多数测试程序。
  • //bundles/kitchen_sink 是会导致包含所有其他构建目标的目标。在测试核心更改的影响或在代码库中进行大规模更改时,此参数非常有用。它也是一个很适合爱好者使用的有趣配置,因为它包含源代码树中的所有软件。请注意,厨房接收器将生成超过 20 GB 的 build 工件,并且目标设备上至少需要 2GB 的存储空间(2019 年第一季度估算大小)。

执行构建

按如上所示使用 fx set 配置 build 后,您就可以使用 fx build 运行 build。此命令会构建所有必需的目标及其输出。

清理 build

您可以继续在检出时更改文件,并运行 fx build 进行重新构建。如果已有先前构建的结果,构建系统会尝试减少工作量。使用以前的构建结果的构建称为增量构建,通常比干净重建要快得多。

更改配置不会导致增量构建损坏,但在极少数情况下,由于构建系统的限制,这种情况可能仍会发生。如果发生这种情况,请提交详细的 bug,其中要捕获重现问题的所有步骤以及所有诊断信息(例如 build 日志)。然后使用以下命令进行恢复:

  • fx clean 会清除所有构建工件。
  • fx clean-build 等同于 fx clean,则等同于 fx build

如果您发现自己经常更改配置并清理输出目录,请考虑改用 fx set --auto-dir。在此模式下,fx set 将为不同的配置选择不同的输出目录。请注意,这将增加您的磁盘使用量,并且您可能需要删除不再需要的旧输出目录。

启用增量软件包重新构建

默认情况下,fx build 会为指定的产品配置构建所有软件包。这对某些开发者工作流来说很有必要,但对许多其他工作流而言却过于冗长。如果您只是对测试进行迭代,则无需重新构建和重新发布所有临时(宇宙)软件包。

您可以通过向 ~/.bashrc 或等效项添加 export FUCHSIA_DISABLED_incremental=0 来启用增量重新构建。此更改会导致以下结果:

  • pm(继而产生 fx serve)会在创建软件包之前对其进行监控。创建或修改软件包时,pm 会自动发布该软件包,因此您可以保持 fx serve 从空树运行,并且会随着您的使用而逐步发布。

  • fx test 仅构建运行所需的最小目标。对于组件测试,指的是软件包、其 GN 依赖项和 //zircon

  • fx serve 不会铺路或闪光。

  • 默认情况下,fx pave 会在铺平一次后退出。请使用 --keep-running 进行替换。

请注意,fx build 的行为保持不变。

迭代缓存软件包

除了编译和发布缓存软件包之外,运行 fx build 还会触发完整的系统汇编。如果您的工作流只需要迭代重新构建缓存软件包,则运行 fx build 可能会过多,导致运行速度变慢。

如需重新构建缓存软件包,您可以将 fx build 替换为 fx publish cache,以加快构建速度。在典型的开发工作流中,此 API 可能如下所示:

# Set up your workspace here.
$ fx serve

# Make changes to cache packages here.

# Rebuild and publish cache packages:
$ fx publish cache

# Restart your component, for example:
$ ffx component stop /core/your_component
$ ffx session restart

已知问题:重新启动 Fuchsia 模拟器不会导致组件从更新后的软件包运行。您需要手动重启这些组件。

如需查看所有缓存软件包的列表,您可以运行 fx list-packages --cache

构建特定目标

您可以为 fx build 指定要构建的特定目标或文件的名称。

如果启用了实验性 build-with-labels 功能,则可以将 GN 标签直接传递给 fx build。例如,fx build //examples/hello_world 将为 Fuchsia 构建 //examples/hello_world:hello_world GN 目标,而 fx build --host //examples/hello_world 将为主机构建 GN 目标。

如果未启用该功能,您还可以为某个 GN 目标的输出传递 Ninja 目标路径。对于在默认工具链中定义的 GN 目标,GN 会定义 Ninja 别名,这些别名看起来与 GN 标签类似(没有起始 // 前缀),因此 fx build examples/hello_world:hello_world 将在默认工具链中构建 GN 目标 //examples/hello_world 的输出。

不过,如果在非默认工具链中声明目标,您必须猜测 Ninja 输出路径,这通常非常复杂。不过,对于主机二进制文件,该文件通常位于 host_x64 子目录下。因此,如果目标仅定义为 executable(),则可以使用 fx build host_x64/blah 构建 //foo/bar:blah(//build/toolchain:host_x64)

如需详细了解 build 目标,请参阅构建系统概览

生成 build 归档文件

除了执行构建之外,您还可以使用 fx build 命令生成构建归档文件(即 .tar.tgz.zip)。此 build 归档文件包含由 fx build 生成的 build 工件的特定组合,使您的 build 输出可移植用于各种用途。例如,您可以将此 build 归档文件作为 ffx target flash 命令的输入提供,以将 build 刷写到 Fuchsia 设备上。

如需生成 build 归档文件,请运行 fx build 并采用以下特殊目标:

fx build build-archive.FORMAT

FORMAT 替换为 tartgzzip,例如:

fx build build-archive.zip

构建完成后,此命令会在 Fuchsia build 目录(默认为 out/default)中创建 build 归档文件(上例中的 build-archive.zip)。(如需查看 build 目录的确切位置,请运行 fx get-build-dir。)

创建商品套装 ZIP 文件

如果您已通过运行 fx build 构建了 Fuchsia 产品,可以运行以下命令来创建包含该产品软件包的 ZIP 文件

fx create-pb-zip -o <path-to-pb-zip>

此命令会创建一个包含此商品套装的 ZIP 文件(位于您指定的路径中)。

刷写开发板并准备 Zedboot

将 Fuchsia 放到目标设备上所需的确切准备工作因特定设备而异,但目前有两个常规组是通用的,通过 fx 命令可以很方便地进行操作:

  • 大多数 arm64 设备都会使用 fx flash 将 Zedboot 原始写入设备,以便为铺路做好准备。
  • 大多数 x64 设备都会使用 fx mkzedboot 准备可启动到 Zedboot 的可启动 USB 密钥,从而为铺路准备设备。

什么是 Zedboot?

Zedboot 是 Zircon 的一种特殊配置,包含一个简单的网络堆栈、一个简单的设备通告和发现协议,以及一套用于将 Fuchsia 写入目标磁盘和/或向目标系统进行网络启动的协议。Zedboot 是一个术语,用于表示整个过程以及一种特殊的 build 配置。许多人将其称为“带有 ASCII 艺术的蓝屏”。

如需在 arm64 目标上进入 Zedboot,请在触发设备启动并进入 fastboot 刷写模式的同时接通电源(通常需要在重新启动或开机时按住特定按钮,这因特定硬件目标而异)。进入刷写模式后,在主机系统上执行 fx flash

如需在 x64 目标设备上进入 Zedboot,请先使用 fx mkzedboot <path-to-usb-device> 生成 Zedboot USB 密钥(要列出系统中合适的 USB 设备,请执行 fx list-usb-disks)。完成后,移除 USB 密钥,将其插入目标设备,然后重新启动目标设备,并从启动选项中或在设备 BIOS 中选择“从 USB 启动”。

什么是铺路?

铺路在许多方面类似于其他世界的“闪光灯”,不过也有一些区别。具体而言,铺砌是指 Fuchsia 中的一组进程和协议,用于将一组工件传输到目标系统,这些工件将被写入目标系统的各个分区。相比之下,“刷写”的过程更像是将原始数据流写入原始磁盘设备的原始过程,而不是严格面向分区的过程。

用户可以通过以下方式启动铺路过程:首先使用 fx flash 刷写 Zedboot,或者启动由 fx mkzedboot 制作的 Zedboot USB 密钥,然后在主机系统上执行 fx pave。一般来说,大多数用户实际上想要使用 fx serve,而不是 fx pave提供 build 部分介绍了 fx serve

什么是 Netbooting?

在 Fuchsia 中,“netboot”是指将一组工件发送到 Zedboot 实例,该实例将仅从 RAM 启动,而不是对磁盘进行更改。用户可以通过以下方式执行“netboot”:首先使用 fx flash (arm64) 或 fx mkzedboot (x64) 将设备启动到 Zedboot,然后在主机系统上执行 fx netboot

提供 build

Fuchsia 的许多 build 配置包含的软件不会立即包含在 build 生成的基础映像中,而这些软件会在铺路期间写入设备。此类软件改为按需提供给目标设备,这通常称为“临时软件”。

fx serve 命令会在内部执行两个函数:

  • fx pave 会启动铺砌服务器,用于从 Zedboot 状态“新安装”Fuchsia 设备。
  • fx serve 会启动一个软件包代码库服务器,该服务器用于在运行时动态安装软件以及整个系统更新。

在内部,fx serve 命令还会搜索要配置的设备,在发现设备(可通过 fx set-devicefx -d 进行限制/调制)时,将目标设备配置为使用存储库服务器作为动态软件包和系统更新的来源。

更新目标设备

如前几部分所述,Fuchsia 设备上有不同的软件组:

  • 属于核心系统“基础”的软件,在单个事务中更新。
  • 属于 Zedboot 映像一部分的软件,除基本(缓存)之外可以临时更新。
  • 始终处于短暂(宇宙)的软件。

对于新用户开发工作流,有助于更新目标设备的最通用命令是 fx otafx ota 命令会先更新“基本”和“缓存”软件,然后在更新完成后重新启动目标设备。就软件版本而言,此过程的最终结果应与对设备执行新的铺砌过程难以区分。

由于 fx ota 进程会导致设备重新启动,因此对于诊断、调试或其他并非基于测试的工作流或需求,该进程有时不是最高效的过程。在这些情况下,用户可以选择如何确保设备上的软件定期更新。

fx serve 进程用于配置具有自动更新功能的 Fuchsia 软件代码库。每次底层代码库更新时,代码库都会通知目标设备有新更新的软件(每次成功的 fx build 结束时发生)。对于许多软件组件而言,在开发过程中更新它们的最简单方法是确保它们未包含在基础集中,而是包含在“缓存”或“宇宙”中。在这种情况下,只需在目标平台上重启软件(例如,完全关闭软件,或调用 killall)会导致软件在再次启动时立即更新。

执行测试

Fuchsia 代码库包含许多测试。其中大多数测试本身都是组件,可以在目标设备上启动,方式与其他组件相同。在目标设备上,某些程序还可以帮助解决特定于测试的组件启动问题,例如 run-test-suite。您也可以通过 fx test 从开发主机方便地控制此过程。如需了解详情,请参阅运行 Fuchsia 测试

一些用户发现,在每次保存源代码时,都让系统构建、推送和执行测试,是一种非常有效的高度聚焦工作流。使用 fx 可以非常轻松地做到这一点,例如:

fx -i test hello-world-rust-tests

每次更改树中的源代码时,以上命令都会执行这些测试。将 -i 标志设置为 fx 后,每当树中的源代码发生更改时,fx 都会重复其命令的其余部分。由于 fx test 命令会先执行构建,然后在目标上执行测试,因此这种组合可提供便捷的自动测试循环,非常适合测试驱动开发等高度集中的工作流。

连接到目标 shell

大多数产品配置都包括具有 Fuchsia 特定配置的 SSH 服务器。fx shell 命令是一个通过 SSH 连接到目标设备的便捷封装容器,可让您访问非常简单的 POSIX 样式的 shell。用户应注意,虽然 shell 是 POSIX shell 的分支,但它并未提供通用 Unix shell 的所有功能。特别是,用户会发现 CTRL+C 的怪异行为,并且可能经常发现子 shell 表达式和某些更高级的 IO 重定向或环境变量传播的怪异行为。这些故障特征是 Fuchsia 不是 POSIX 系统的附带效应。

不过,通过 fx shell 提供的 shell 对于命令式执行 Fuchsia 目标上的程序以及探索文件系统树中提供的一些诊断 / 调试接口(例如 /hub/dev)非常有用。它还可用于调用 /bin/run 等提供启动 Fuchsia 组件的工具。如果 build 配置中提供了 tools 软件包,则表示 unix shell 环境的许多常用工具均已移植且可供使用,例如 pslscatcurlvimfortune 等。

执行其他常见任务

获取日志

fx log 会捕获来自低层级和高级程序(包括内核、驱动程序和其他用户空间程序)的所有日志。fx log 依赖于正常运行的高级网络堆栈和 SSH。因此,fx log 不适用于 Zedboot 或“bringup”产品配置。如果设备处于 fx log 停止运行的状态,通常可切换到 fx klog 以捕获有关可能原因的更多信息。

fx klog 仅捕获名为“klog”的低级别日志流。klog 流包括来自 Zircon 内核本身以及用户空间软件(最值得注意的是驱动程序和低级核心软件)的日志。fx klog 依赖于名为 netsvc 的轻量级网络堆栈,即使在更高级别软件出现问题后,该网络也倾向于仍然可用。netsvc 套件也始终在“启动”产品配置中提供,因此 fx klog 在处理低级别软件(例如 Zircon 内核或驱动程序)时最为有用。

如需了解详情,请参阅查看日志

复制文件

fx cp 提供了一个围绕 scp 的基本封装容器,类似于 fx shell 是围绕 ssh 的封装容器。

# copy ./book.txt from the host, to /tmp/book.txt on the target
$ fx cp book.txt /tmp/book.txt
# copy /tmp/poem.txt on the target to poem.txt on the host
$ fx cp --to-host /tmp/poem.txt poem.txt

使用多个 Fuchsia 设备

某些用户的网络中会有多个 Fuchsia 设备,他们会希望将各种命令的影响范围限定为这些设备中的特定设备。可以使用 fx set-device 命令来帮助实现此用例。

fx set-device 命令可将特定设备节点名称绑定到特定的 build 目录。当用户希望以多个 build 配置保留多个不同的设备时,这尤其有用,并且可以按如下方式进行设置:

$ fx --dir out/workbench set workbench_eng.x64
$ fx build
$ fx set-device <workbench-node-name>

$ fx --dir out/core set core.arm64
$ fx build
$ fx set-device <core-node-name>

# Start a server for the workbench:
$ fx --dir=out/workbench serve
# Set the default build-dir and target device to the arm64 core, and
# connect to a shell on that device:
$ fx use out/core
$ fx shell

此外,如果用户希望对当前默认 build 目录中的单个 Fuchsia 设备执行命令(作为一次性命令),fx 全局标志 -d 允许为单个命令调用替换目标节点名称。

重新启动设备

fx reboot

在某些设备(目前大多数 arm64 设备)上,还有一些有用的标志:

  • fx reboot -r 重新启动到“recovery”(Zedboot)
  • fx reboot -b 重新启动到“引导加载程序”(Flash)

确定 CL 的状态

fx whereiscl <query>

此命令会指示是否合并给定的更改,如果是,则指示它是否通过了全局集成。查询可以是 Gerrit 审核网址、更改编号、Change-Id 或 git 修订版本。

$ fx whereiscl fxr/286748
CL status: MERGED
GI status: PASSED

$ fx whereiscl
https://fuchsia-review.googlesource.com/c/fuchsia/+/287311/1/garnet/go/src/amber/source/source.go
CL status: NEW

$ fx whereiscl I94c56fa4e59842d398bfa90a48c45b388f095184
CL status: MERGED
GI status: PASSED

$ fx whereiscl 6575aee
CL status: MERGED
GI status: PENDING

调试和开发 fx 命令

  • fx -x -x 标志会开启对 fx 脚本的跟踪,输出在 fx 调用期间评估的所有表达式。
  • fx exec 用于执行在当前 fx 环境内部运行的任意程序。例如,fx exec env 会输出该环境中的所有环境变量(可能对 fx exec env | grep FUCHSIA 感兴趣)。

获取fx方面的帮助

fx help <command> 提供了关于该命令的最佳入门文档。某些命令也支持并提供 fx <command> -hfx <command> --help,但并非所有命令都提供此帮助。这种情况不常见,但取决于实现细节。在内部,许多 fx 命令只运行其他程序,大多数情况下是由 build 生成的程序,并且在很多情况下,标志会原封不动地传递给这些程序。在这些情况下,传递常规的 -h--help 标志可能不会提供 fx <command> 的文档,而是提供在 fx 下游调用的程序。

用户应始终以 fx help <command> 开头。

不带其他参数的 fx help 会提供 fx 中所有可用命令的列表,以及 fx 全局标志的文档。

显示待处理的提交

fx pending-commits 显示尚未滚动至全局集成的提交内容。

如需查看 Fuchsia 的集成信息中心,请参阅 Builders

将 Fuchsia 检出同步到版本分支

如需将本地 Fuchsia 检出同步到特定版本分支,请运行以下命令:

fx sync-to RELEASE_BRANCH

RELEASE_BRANCH 替换为您要切换到的版本分支(例如 refs/heads/releases/f6)。如需查看所有可用版本分支的列表,请参阅 Fuchsia 全局集成代码库页面上的“分支”部分。

以下示例命令会将 Fuchsia 签出同步到 F6 版本分支:

fx sync-to refs/heads/releases/f6

如需将 Fuchsia 签出重置为树的顶部,请运行以下命令:

fx sync-to reset

如需了解更多选项,请参阅 fx sync-to 参考页面。

定义永久性本地构建参数

如果要定义运行 fx set 时将包含的 build 参数,请将这些参数添加到 $FUCHSIA_DIR/local/args.gn 中。每次重新生成 build 参数时,它们都会附加到 $FUCHSIA_BUILD_DIR/args.gn

如需禁止包含 local/args.gn,请运行 fx set ... --skip-local-args