本文档介绍了在 Fuchsia 开发环境中使用 fx
工具的基本工作流程。
设置 fx
fx
是一组子命令的入口点,可简化与 Fuchsia 开发相关的许多任务。(运行 fx help
可查看所有可用子命令。)
如果您将 bash
或 zsh
用作 shell,强烈建议您运行 source scripts/fx-env.sh
以在 shell 中启用自动补全功能。此设置已过测试,并经常与 bash
和 zsh
搭配使用,可能也适用于其他兼容的 Shell。
前往您的 Fuchsia 代码库,例如:
cd ~/Fuchsia
向 shell 添加配置以包含
fx-env.sh
:echo "source \"$PWD/scripts/fx-env.sh\"" >> "$HOME/.$(basename "$SHELL")rc"
(可选)如果您想使用 Fuchsia 脚本中的其他实用工具,请运行以下命令:
echo "fx-update-path" >> "$HOME/.$(basename "$SHELL")rc"
重启 shell:
exec "$SHELL"
这些步骤可提供最明确的特征集,并且通常不会侵入。如果它在 shell 环境中导致 bug,请报告项目 bug。
如果您出于某种原因需要使用多个 Fuchsia 检出(下面推荐的工作流应该可以避免这种情况),则可能需要执行上述操作以外的操作。在这种情况下,有几种受良好支持的方法:
- 始终明确执行
$FUCHSIA_DIR/scripts/fx
- 在特定 Fuchsia 目录中工作时,使用 direnv 或 dotenv 等工具将
$FUCHSIA_DIR/.jiri_root/bin
添加到$PATH
。
常用的日常工具
在检出 Fuchsia 树之后,您要做的第一件事就是构建 Fuchsia,然后将其安装到设备上。fx
提供了一些有助于实现此目的的命令:
fx set
配置 buildfx build
执行 buildfx mkzedboot
准备 Zedboot U 盘fx serve
分发 buildfx publish cache
迭代缓存软件包fx ota
更新目标fx test
执行测试fx shell
连接到目标 shell- 以及许多其他小任务
配置 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
即可查看已知开发板配置的列表。) - 您正在
universe
软件包集中暂时构建tests
。
软件包部署选项
--with
选项有三个变体,与软件包部署到 Fuchsia 设备的方式相关:--with-base
、--with-cache
和 --with
(隐含 universe
)。(请注意,fx set
还有一个 --with-host
选项,用于构建仅限主机的目标,例如基于主机的工具和库。)
那么,base
、cache
和 universe
分别是什么?
配置最终会指定有助于构建输出工件(主要是映像和软件包仓库)的依赖项(主要是软件包)。构建会进行参数化,以确定将哪些依赖项(主要是软件包)添加到哪些输出工件(映像或软件包仓库)。这三个轴分别称为“base”“cache”和“universe”:
- Base:添加到 Base 的软件包会包含在 build 生成的系统映像中。它们包含在无线下载更新中,并且始终作为一个单元进行更新。在运行时,系统无法从设备中驱逐 base 中的软件包,因为它们会编码尽可能小的配置大小。
- 缓存:缓存中的软件包包含在系统映像中,但不包含在无线下载系统更新中,并且可以根据资源需求(例如磁盘空间压力)从系统中驱逐。缓存中的软件包可在有可用更新时随时更新,并且这些软件包可以单独更新。这类软件是“可选”的,但最好能“开箱即用”。
- Universe:Universe 中的软件包是可按需提取和运行的额外可选软件包,但未预先烘焙到任何系统映像中。
“开发板”和“产品”配置会为每个软件包集选择一组预定义的成员。最常见的是,板级配置会指定一组关键启动驱动程序以添加到基本依赖项集,例如,可以在缓存集中添加一些可选但常用的外围设备驱动程序。开发板配置可能还包含一些特定于开发板的开发工具(通常是宿主工具,而不是目标软件包),用于在“universe”中与开发板交互。产品配置会根据其所代表的产品的定义和功能集,选择向基础、缓存或通用软件包集添加更多或更少的软件。例如,音箱产品会向基础架构中添加许多音频媒体相关软件包。工作台产品会向基础平台添加各种 GUI、媒体和许多其他软件包。
主要产品配置
除了以下配置之外,还有许多其他配置,但以下三个配置尤为重要,请务必熟悉:
bringup
是一款功能集极其简洁的产品,专注于极简设计。它旨在提供快速构建和小型映像(主要用于网络启动,而不是时尚),非常适合处理非常低级的设施,例如 Zircon 内核或板级驱动程序和配置。它缺少大多数网络功能,因此无法在运行时添加新软件或自行升级。这也意味着,某些fx
命令(例如fx serve
和fx shell
)无法与bringup
产品搭配使用。core
是一组最基本的功能,可安装其他软件(例如添加到“universe”依赖项集中的项)。它是所有更高级别商品配置的起点。它具有常见的网络功能,并且可以无线更新系统。workbench_eng
是通用开发环境的基础,适合处理界面、媒体和许多其他高级功能。这也是爱好者进行试玩和探索的最佳环境。
其他重要的构建目标
fx set
的 --with
标志可接受任意构建目标。为方便起见,我们定义了多个软件包,其中包含各种常用的构建目标。请务必熟悉以下软件包:
//bundles/tools
包含各种最常用的开发者工具。其中包括用于从命令行 Shell 生成组件的工具、用于重新配置和测试网络、发出 HTTP 请求、调试程序、更改音频音量的工具等。默认情况下,核心产品在其 Universe 软件包集中包含//bundles/tools
。//bundles/tests
会导致构建所有测试程序。大多数测试程序都可以在设备上使用run-test-suite
或通过fx test
调用。//bundles/kitchen_sink
是一个目标,会导致包含所有其他 build 目标。在测试核心更改的影响或在代码库中进行大规模更改时,此方法非常有用。它还可能是一个有趣的配置,供爱好者玩耍,因为它包含源代码树中提供的所有软件。请注意,厨房水槽将生成超过 20GB 的 build 工件,并且目标设备上需要至少 2GB 的存储空间(大小估算值基于 2019 年第 1 季度)。
执行 build
使用 fx set
配置 build 后(如上所示),您可以使用 fx build
运行 build。此命令会构建所有必需的目标及其输出。
清理 build
您可以继续更改结账中的文件,并运行 fx build
进行重新构建。如果有来自上一个 build 的结果,构建系统会尝试减少工作量。使用之前 build 结果的 build 称为增量 build,通常比干净重新构建的速度要快得多。
更改配置不应导致增量 build 中断,但在极少数情况下,由于构建系统的限制,这种情况仍可能会发生。如果发生这种情况,请提交详细的 bug,其中包含重现问题的所有步骤以及任何诊断信息(例如 build 日志)。然后,使用以下命令进行恢复:
fx clean
将清除所有 build 工件。fx clean-build
相当于fx clean
,然后是fx build
。fx cleandead-build
等效于fx cleandead
,然后fx build
如果您发现自己经常更改配置并清理输出目录,请考虑改用 fx set --auto-dir
。在此模式下,fx set
会为不同的配置选择不同的输出目录。请注意,这会增加磁盘用量,您可能需要删除不再需要的旧输出目录。
启用增量软件包重新构建
默认情况下,fx build
会为指定的产品配置构建所有软件包。这对于某些开发者工作流程来说是必要的,但对于许多其他工作流程来说却是过度的要求。如果您只是迭代测试,则无需重新构建和重新发布所有暂时性 (universe) 软件包。
您可以通过向 ~/.bashrc
添加 export FUCHSIA_DISABLED_incremental=0
或等效项来启用增量重新构建。这项变更会导致以下结果:
(
fx serve
)fx-serve-ref 会监控在 Fuchsia build 中创建或修改的软件包,并自动发布这些软件包。这样,您就可以让fx serve
从空树运行,并且它会在您工作时增量发布更改。fx test
仅构建运行所需的最低目标。对于组件测试,就是软件包、其 GN 依赖项和//zircon
。
请注意,fx build
的行为保持不变。
迭代缓存软件包
除了编译和发布缓存软件包之外,运行 fx build
还会触发完整的系统汇编。如果您的工作流程仅需要迭代重新构建缓存软件包,则运行 fx build
可能会过多,并导致速度变慢。
对于重新构建缓存软件包,您可以将 fx build
替换为 fx publish cache
,从而加快构建速度。在典型的开发工作流中,它可能如下所示:
# 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 目标的某个输出传递 Ninja 目标路径。对于默认工具链中定义的 GN 目标,GN 会定义类似于 GN 标签但不带 //
开头前缀的 Ninja 别名,因此 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
命令生成 build 归档文件(即 .tar
、.tgz
或 .zip
)。此 build 归档文件由 fx build
生成的 build 工件的特定组合组成,可让您的 build 输出可移植,以用于各种用途。例如,您可以将此 build 归档文件作为 ffx target flash
命令的输入,以将 build 刷写到 Fuchsia 设备。
如需生成 build 归档文件,请使用以下特殊目标运行 fx build
:
fx build build-archive.FORMAT
将 FORMAT
替换为 tar
、tgz
或 zip
,例如:
fx build build-archive.zip
构建完成后,此命令会在 Fuchsia 构建目录(默认为 out/default
)中创建构建归档文件(在上例中为 build-archive.zip
)。(如需查看 build 目录的确切位置,请运行 fx get-build-dir
。)
创建商品软件包 ZIP 文件
如果您已构建 Fuchsia 产品(通过运行 fx build
),则可以运行以下命令来创建包含产品软件包的 ZIP 文件:
fx create-pb-zip -o <path-to-pb-zip>
此命令会在您指定的路径中创建一个包含产品软件包的 ZIP 文件。
准备 Zedboot U 盘
将 Fuchsia 刷写到目标设备上所需的确切准备工作因具体设备而异,但您可以使用 fx mkzedboot
为启动到 Zedboot 的 x64
设备准备可启动的 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 中,“netboot”是指将一组工件发送到 Zedboot 实例,该实例只会从 RAM 启动,而不是更改磁盘。用户可以执行“netboot”,方法是先使用 fx flash
(arm64) 或 fx mkzedboot
(x64) 将设备引导至 Zedboot,然后在主机系统上执行 fx netboot
。
分发 build
Fuchsia 的许多 build 配置都包含软件,这些软件不会立即包含在 build 生成的基础映像中,而是会在刷写期间写入设备。相反,此类软件会按需提供给目标设备,这在民间通常被称为“短时性软件”。
命令 fx serve
在内部执行两项功能:
- 启动软件包仓库服务器,用于在运行时动态安装软件以及进行全系统更新。
在内部,fx serve
命令还会搜索要配置的设备,并在发现设备(可通过 fx set-device
或 fx -d
进行限制/调制)后,将目标设备配置为使用代码库服务器作为动态软件包和系统更新的来源。
更新目标设备
如前几部分所述,Fuchsia 设备上有不同的软件组:
- 属于核心系统“基础”的软件,会在单个事务中更新。
- 除可暂时更新的基础(缓存)之外,Zedboot 映像中的软件。
- 始终是短时性软件(universe)。
对于新用户开发工作流程,用于协助更新目标设备的最常用命令是 fx ota
。fx ota
命令会先更新“base”和“cache”软件,然后在完成后重启目标设备。从软件版本的角度来看,此过程的最终结果应与对设备执行全新刷写没有区别。
由于 fx ota
进程会导致设备重启,因此对于诊断、调试或其他非测试工作流或需求,它有时并不是最有效的流程。在这种情况下,用户可以通过一些方法确保设备上的软件定期更新。
fx serve
进程会配置具有自动更新功能的 Fuchsia 软件仓库。每当底层代码库更新时(每次成功执行 fx build
操作后都会发生),代码库都会通知目标设备新更新的软件。对于许多软件组件,在开发期间更新它们的最简单方法是确保它们未包含在基准集中,而是包含在“缓存”或“宇宙”中。在这种情况下,只需在目标设备上重启软件(例如通过完全关闭或调用 killall
),即可在软件再次启动时立即更新。
执行测试
Fuchsia 代码库包含许多测试。其中大多数测试本身就是组件,并且可以像其他组件一样在目标设备上启动。在目标设备上,某些程序还可帮助解决组件启动方面的测试专用问题,例如 run-test-suite
。您还可以通过 fx test
从开发主机轻松控制该进程。如需了解详情,请参阅运行 Fuchsia 测试。
有些用户发现,一种高效且专注的工作流是,让系统在用户保存源代码时进行构建、推送和执行测试。这可以非常轻松地通过 fx
实现,例如:
fx -i test hello-world-rust-tests
每当对树中的源代码进行更改时,上述命令都会执行测试。向 fx
添加 -i
标志会导致每当树中的源代码发生更改时,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 环境工具都已移植并可供使用,例如 ps
、ls
、cat
、curl
、vim
、fortune
等。
执行其他常见任务
获取日志
fx log
会捕获来自低级和高级程序(包括内核、驱动程序和其他用户空间程序)的所有日志。fx log
依赖于正常运行的高级网络堆栈和 SSH。因此,fx log
不适用于 Zedboot 或“启动”产品配置。如果设备处于 fx log
停止运行的状态,通常很有用的是切换到 fx klog
,以捕获有关可能原因的更多信息。
fx klog
仅捕获名为“klog”的低级日志流。klog 流包含 Zircon 内核本身的日志,以及一部分用户空间软件(最值得注意的是驱动程序和低级核心软件)的日志。fx klog
依赖于一个名为 netsvc
的轻量级网络堆栈,即使在更高级别的软件出现问题后,该堆栈也往往仍然可用。netsvc 套件始终可在“启动”产品配置中使用,因此,在处理低级软件(例如 Zircon 内核或驱动程序)时,fx klog
最有用。
如需了解详情,请参阅查看日志。
复制文件
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
重新启动到“恢复”模式 (Zedboot)fx reboot -b
重新启动到“引导加载程序”(Flash)
确定 CL 的状态
您可以使用 fx cl
命令在 Gerrit 中使用新的浏览器标签页打开当前 CL。
调试和开发 fx
命令
fx -x
-x
标志会为fx
脚本启用跟踪,并输出在fx
调用期间求值的所有表达式。fx exec
会在当前fx
环境中执行后续的任意程序。例如,fx exec env
会输出该环境中的所有环境变量(fx exec env | grep FUCHSIA
可能很有用)。
获取 fx
方面的帮助
fx help <command>
提供了该命令的最佳入门文档。某些命令也支持并提供 fx <command> -h
或 fx <command> --help
,但并非所有命令都提供此帮助。这并不常见,但取决于实现细节。在内部,许多 fx
命令只会运行其他程序(通常是 build 生成的程序),并且在许多情况下,标志会以不变的形式传递给这些程序。在这些情况下,传递常规的 -h
或 --help
标志可能不会为 fx <command>
提供文档,而是为 fx
下游调用的程序提供文档。
用户 ID 应始终以 fx help <command>
开头。
不带其他参数的 fx help
会提供 fx
中的所有可用命令的列表,以及 fx
全局标志的文档。
显示待处理的提交
fx pending-commits
会显示尚未推送到全局集成的提交。
如需查看 Fuchsia 的集成信息中心,请参阅构建器。
将 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
参考页面。
定义持久性本地 build 参数
如果您想定义每次运行 fx set
时都会包含的构建参数,请将其添加到 $FUCHSIA_DIR/local/args.gn
。每次重新生成 build 参数时,这些参数都会附加到 $FUCHSIA_BUILD_DIR/args.gn
。
如需禁止包含 local/args.gn
,请运行 fx set ... --skip-local-args
。