| # fx workflows |
| |
| `fx` is the front-door to a collection of scripts that make many tasks |
| related to Fuchsia development easier. It contains a large number of |
| subcommands, which can be discovered by running `fx help`. If you use `bash` |
| or `zsh` as a shell, you can get some auto-completion for `fx` by sourcing |
| `scripts/fx-env.sh` into your shell. |
| |
| ## Setting up fx |
| |
| It is strongly recommended that you `source scripts/fx-env.sh` into your |
| shell. This is tested and regularly used with Bash and ZSH. It may work for |
| other compatible shells. |
| |
| ```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" |
| ``` |
| |
| The above method provides the most well defined feature set, and should be |
| generally non-invasive. If it causes bugs in your shell environment, please |
| file project bugs. |
| |
| If for some reason you need to work with multiple Fuchsia checkouts |
| (recommended workflows below should obviate such a need), then you may wish |
| to do something other than the above. In this case, there are a few well |
| supported methods: |
| |
| * Always execute `$FUCHSIA_DIR/scripts/fx` explicitly |
| * Use something like a cdenter or dotenv feature to add |
| `$FUCHSIA_DIR/.jiri_root/bin` to your `$PATH` while working in a particular |
| Fuchsia directory. |
| |
| It is NOT recommended (though presently works) to copy `fx` to other places, |
| such as `~/bin/fx` (as this could one day break), or to add |
| `$FUCHSIA_DIR/scripts` to your `$PATH` (as reviewers of code in `//scripts`) |
| do not block the addition of files in that directory which could lead to |
| unpredictable behaviors (for example, that directory contains binaries with |
| generic names like "bootstrap" which may unintentionally override the |
| behavior of other systems). |
| |
| ## Common Daily Tools |
| |
| The first thing you will want to do after checking out a Fuchsia tree is to |
| build Fuchsia, and then get it onto a device. `fx` has some commands to help |
| with this: |
| |
| * `fx set` [configure a build](#configure-a-build) |
| * `fx build` [execute a build](#execute-a-build) |
| * `fx flash ; fx mkzedboot` [flash a target; or prepare a zedboot USB key](#flash-a-board) |
| * `fx serve` [serve a build](#serve-a-build) |
| * `fx update` [update a target](#update-a-target-device) |
| * `fx run-test` [execute tests](#execute-tests) |
| * `fx shell` [connect to a target shell](#connect-to-a-target-shell) |
| * [and many other small tasks](#performing-other-common-tasks) |
| |
| First let's configure the build. To do this we need to make a few choices: |
| |
| * What [Product configuration](#key-product-configurations) do you want? |
| (unsure: try `workstation`) |
| * What board are you building for? (unsure: try `x64`) |
| * What extra [Bundles](#key-bundles) do you want? (unsure: try `tools`, and if |
| you're working on features, you probably want `tests`) |
| |
| ## Configure a build |
| |
| *We are working on a new command for configuring a build. This section describes |
| the new command, which is currently being beta-tested.* |
| |
| Armed with our above choices (if you didn't read above, do so now), you are |
| ready to configure your build: |
| |
| ```shell |
| $ fx set workstation.x64 --with //bundles:tools,//bundles:tests |
| ``` |
| |
| This command stores the configuration in an `args.gn` file in the build |
| directory (which is `out/default` by default). You can edit this file using the |
| `fx args` command to create more elaborate configurations. |
| |
| ### What just happened? |
| |
| * We selected the architecture `x64` |
| * We selected the product `workstation` (run `fx list-products` for a list of |
| other product configurations) |
| * We selected the board `x64` (on arm64 boards, the board choice is very |
| important! Run `fx list-boards` for a list of board configurations) |
| * We selected to "preinstall" various developer tools, this includes many basic |
| tools like `cat` and `ls`, as well as more advanced tools, such as `trace`. |
| * We selected to build "tests", but not have them included in our |
| [Paving](#what-is-paving) images. |
| |
| So what are `base`, `cache` and `universe`? (new names) |
| So what are `monolith`, `preinstall` and `available`? (deprecated names) |
| |
| Configurations ultimately specify dependencies (mostly packages) that |
| contribute to output artifacts of the build (mostly images and package |
| repositories). The build is parameterized to determine which dependencies |
| (mostly packages) are added to which output artifacts (images or package |
| repositories). The three axes are called "base", "cache", and "universe" |
| (previously called "monolith", "preinstall", and "available"): |
| |
| * *Base* (*Monolith*): Packages that are added to the monolith are included in |
| [Paving](#what-is-paving) images produced by the build. They are included |
| in over-the-air updates, and are always updated as a single unit. Packages |
| in the monolith can not be evicted from a device at runtime - they encode |
| the minimum possible size of a configuration. |
| * *Cache* (*Preinstall*): Packages in preinstall are included in |
| [Paving](#what-is-paving) images, but they are not included in over-the-air |
| system updates, and are allowed to be evicted from the system in response |
| to resource demands, such as disk-space pressure. Packages in preinstall |
| can be updated at any time that updates are available, and each of |
| these packages may be updated independently. This is software that is |
| "optional", but is good to have available instantly "out of the box". |
| * *Universe* (*Available*): Packages in available are additional optional |
| packages that can be fetched and run on-demand, but are not pre-baked into |
| any [Paving](#what-is-paving) images. |
| |
| The "board" and "product" configurations pick a predefined set of members for |
| each of these package sets. Most commonly the board configurations specify a |
| set of boot-critical drivers to add to the monolith package set, and could |
| for example include some optional but common peripheral drivers in the |
| preinstall set. The board configuration may also include some board-specific |
| development tools (more commonly host tools, rather than target packages) for |
| interacting with the board in "available". The product configurations make |
| choices to add more or less software to the monolith, preinstall or available |
| package sets based on the definition and feature set of the product they |
| represent. A speaker product, for example, adds many audio-media-related |
| packages to the monolith. A workstation product adds a wide range of GUI, |
| media and many other packages to the monolith. |
| |
| ### Key product configurations |
| |
| There are many more than below, but the following three particularly |
| important configurations to be familiar with: |
| |
| * `bringup` is a minimal feature set product that is focused on being very |
| simple and very lean. It exists to provide fast builds and small images |
| (primarily used in a [netboot](#what-is-netbooting) rather than |
| [paved](#what-is-paving) fashion), and is great for working on very |
| low-level facilities, such as the Zircon kernel or board-specific drivers |
| and configurations. It lacks most network capabilities, and therefore is |
| not able to add new software at runtime or upgrade itself. |
| * `core` is a minimal feature set that can install additional software (such as |
| items added to the "available" build group). It is the starting point for |
| all higher-level product configurations. It has common network capabilities |
| and can update a system over-the-air. |
| * `workstation` is a basis for a general purpose development environment, good |
| for working on UI, media and many other high-level features. This is also |
| the best environment for enthusiasts to play with and explore. |
| |
| ### Key bundles |
| |
| As with products, there are many more, but the following bundles are most |
| important to be familiar with: |
| |
| * `tools` contains a broad array of the most common developer tools. This |
| includes tools for spawning components from command-line shells, tools for |
| reconfiguring and testing networks, making http requests, debugging programs, |
| changing audio volume, and so on. |
| * `tests` causes all test programs to be built. Most test programs can be |
| invoked using `run-test-component` on the device, or via `fx run-test`. |
| * `kitchen_sink` is a target that causes all other build targets to be |
| included. It is useful when testing the impact of core changes, or when |
| making large scale changes in the code base. It also may be a fun |
| configuration for enthusiasts to play with, as it includes all software |
| available in the source tree. Note that kitchen sink will produce more than |
| 20GB of build artifacts and requires at least 2GB of storage on the target |
| device (size estimates from Q1/2019). |
| |
| ## Execute a build |
| |
| For most use cases, only `fx build` is needed. The build is optimized |
| for fast incremental rebuilds, as such, repeating this command does the |
| minimal work required after code has been changed, and no work if the source |
| files are unchanged. |
| |
| Additionally to `fx build`, a few other build related commands provide |
| more granular control: |
| |
| * `fx build-zircon` builds only the Zircon portion of the build. |
| * `fx build` builds only the Fuchsia portion (all above Zircon, but not Zircon |
| itself) of the build. |
| * `fx clean` clear out all build artifacts. |
| * `fx clean-build` perform a clean, then a build. |
| * `fx gen` repeat the `gn gen` process that `fx set` performed. Users making |
| fine grained build argument changes (e.g. by editing `args.gn` directly) can |
| run `fx gen` to reconfigure their build. |
| |
| ### Building a specific target |
| |
| `fx build` can be given the name of a specific target or file to build. For |
| example, a target with the label `//foo/bar:blah` can be built with |
| `fx build foo/bar:blah`. |
| |
| Note that this only works for targets declared in the default GN toolchain. For |
| targets in other toolchains, the path of an output file may be used instead. For |
| example, an executable target with the label |
| `//foo/bar:blah(//build/toolchain:host_x64)` can be built with |
| `fx build <output_dir>/host_x64/blah`. |
| |
| ## Flash a board / Prepare Zedboot |
| |
| The exact preparation required to put Fuchsia onto a target device varies by |
| specific device, but there are two general groups in common use today, made |
| convenient behind `fx` commands: |
| |
| * `fx flash` is used with most `arm64` devices to perform a raw write of |
| Zedboot to the device, preparing it for [Paving](#what-is-paving). |
| * `fx mkzedboot` is used with most `x64` devices to prepare a bootable USB key |
| that boots into Zedboot, preparing the device for [Paving](#what-is-paving). |
| |
| ### What is Zedboot? |
| |
| Zedboot is a special configuration of Zircon that contains a simple network |
| stack, a simple device advertisement and discovery protocols, and a suite of |
| protocols to write Fuchsia to a target disk and/or to network boot a target |
| system. Zedboot is a term used for both the overall process, as well as a |
| special build configuration. Many people come to know it as "the blue screen |
| with ASCII art". |
| |
| To enter Zedboot on an arm64 target, power on the device while triggering a |
| boot into fastboot flashing mode (often this involves holding a particular |
| button while rebooting or powering on that varies by particular hardware |
| target). Once in flashing mode, execute `fx flash` on the host system. |
| |
| To enter Zedboot on an x64 target, first produce a Zedboot USB key using |
| `fx mkzedboot <path-to-usb-device>` (to list suitable USB devices on your |
| system, execute `fx list-usb-disks`). Remove the USB key after completion, |
| insert it to the target device, and reboot the target device, selecting "Boot |
| from USB" from the boot options, or in the device BIOS. There are additional |
| instructions for preparing a |
| [Pixelbook](../hardware/pixelbook.md). |
| |
| ### What is Paving? |
| |
| Paving is in many ways similar to "flashing" from other worlds, however, it |
| has some differences. Specifically, paving refers to a group of processes and |
| protocols in Fuchsia to transfer a set of artifacts to a target system that |
| will be written into various partitions on a target system. By contrast, the |
| process of "flashing" is more of a raw process of writing a raw data stream |
| to a raw disk device, and not strictly partition-oriented. |
| |
| Users can start a paving process by first flashing Zedboot using `fx flash`, |
| or by booting a Zedboot USB key made by `fx mkzedboot`, then executing `fx pave` |
| on the host system. In general most users actually will want to use `fx serve` |
| instead of `fx pave`. `fx serve` is covered in the [next section](#serve). |
| |
| ### What is Netbooting? |
| |
| In Fuchsia, "netboot" refers to sending a set of artifacts to a Zedboot |
| instance that instead of making changes to the disk, will just be booted from |
| RAM. Users can perform a "netboot" by first booting a device into Zedboot by |
| using either `fx flash` (arm64) or `fx mkzedboot` (x64), and then executing |
| `fx netboot` on the host system. |
| |
| Note: the `netboot` artifacts are not produced by all builds by default, |
| because for larger builds such as the "workstation" product configuration |
| such builds are extremely large, and producing them many times a day is both |
| slow as well as measurably wearing on host disk hardware. The `bringup` |
| configuration always prepares `netboot` artifacts. For all other build |
| configurations, a user can optionally build the netboot artifacts using |
| `fx build netboot`. |
| |
| ## Serve a build |
| |
| A lot of build configurations for Fuchsia include software that is not |
| immediately included in the base images that a build produces, that are |
| written to devices during paving. Such software is instead made available to |
| target devices on-demand, which is often colloquially referred to as |
| "ephemeral software". |
| |
| The command `fx serve` performs two functions internally: |
| |
| * `fx pave` start a paving server, used for "fresh installs" of a Fuchsia |
| device from a Zedboot state. |
| * `fx serve-updates` start a package repository server, used for dynamic |
| installation of software at runtime, as well as whole-system updates. |
| |
| Internally the `fx serve-updates` command also searches for a device to |
| configure, and upon discovery (which may be restricted/modulated with |
| `fx set-device` or `fx -d`) the target device is configured to use the |
| repository server as a source of dynamic packages and system updates. |
| |
| ## Update a target device |
| |
| As described in prior sections, there are different groups of software on a |
| Fuchsia device: |
| |
| * Software that is part of the core system "monolith", that is updated in a |
| single transaction. |
| * Software that is part of Zedboot images other than the monolith (preinstall) |
| that can be updated ephemerally. |
| * Software that is always ephemeral. |
| |
| For new user development workflows, the most general command to assist with |
| updating a target device is `fx update`. The `fx update` command first |
| updates all "preinstall" software, and then performs an `fx ota` or, a core |
| system update. This command reboots the target device when it is complete. |
| The end result of this process should be indistinguishable in terms of |
| software versions from performing a fresh pave of a device. |
| |
| As the `fx update` process causes a device reboot, it is sometimes not the |
| most efficient process for diagnosis, debugging or other non-testing based |
| workflows or needs. In these cases a user has some options for how to ensure |
| that software on a device is being regularly updated. |
| |
| The `fx serve` process configures a Fuchsia software repository with |
| automatic update features. The repository informs the target device of newly |
| updated software every time the underlying repository is updated (which |
| happens at the end of every successful `fx build`). For many software |
| components, the easiest way to update them during development is to ensure |
| that they are not included in the monolith set, but instead included in |
| either "preinstall" or "available". In that case, simply restarting the |
| software on the target (e.g. by closing it completely, or by invoking |
| `killall`) will result in the software being immediately updated when it is |
| started again. |
| |
| The commands `fx push-package` and `fx build-push` perform manual, forceful |
| updates of packages on a target device. These commands do not however know |
| how to re-start software on the device, as such they provide little benefit |
| over simply restarting software correctly which, along with `fx serve`, will |
| cause software to be updated as a natural course of restarting. These |
| commands are sometimes used to diagnose issues, or in cases where automatic |
| updates are disabled in special build configurations. |
| |
| Note: some software may not appear to be updating because it is being run |
| inside of a "runner" process or some other surrounding environment that is |
| "holding on" to resources for the previous package version, only spawning |
| programs from the old package. As packages in Fuchsia are immutable and |
| content-addressed, when host environments retain resources in this manner, |
| there is nothing that the update system can do to forcefully trigger updates |
| in the rest of the system. Users who find themselves with this issue mostly |
| need to find efficient workflow methods to fully restart the relevant |
| software stack. |
| |
| XXX: TODO: NEEDED: simple example command to restart all GUI / shell |
| components, e.g. if basemgr spawned things under a job or a component |
| topology, a method to restart that topology (e.g. `killall basemgr.cmx`, |
| however that's no good today). |
| |
| ## Execute tests |
| |
| The Fuchsia codebase contains many tests. Most of these tests are themselves |
| Components, and can be launched on the target device in the same way as other |
| components. On the target device, some programs also assist with test |
| specific concerns for component launching, such as `runtests` and |
| `/bin/run-test-component`. The process can also conveniently be controlled |
| from the development host by way of `fx run-test`. |
| |
| The command `fx run-test <package-name>` requires the user to specify a |
| particular package name to execute. A package may contain one or more tests. |
| Arguments after `fx run-test package-name` are passed to the program |
| `runtests`. One particularly common use case is to execute: |
| `fx run-test <package-of-many-tests> -t <name-of-one-test>` to execute only a |
| single test. |
| |
| Some users find that an effective high focus workflow is to have the system |
| build, push and execute tests whenever they save their source code. This can |
| be achived with `fx` very easily, for example: |
| |
| ```shell |
| $ fx -i run-test rolldice-tests |
| ``` |
| |
| The above command will execute the rolldice tests every time a change is made |
| to the source code in the tree. The `-i` flag to `fx` causes `fx` to repeat |
| the rest of it's command every time the source code in the tree is changed. |
| As the `fx run-test` command first performs a build, then executes a test on |
| a target, this combination provides a convenient auto-test loop, great for |
| high focus workflows like test driven development. |
| |
| ## Connect to a target shell |
| |
| Most [product configurations](#key-product-configurations) include an SSH |
| server with a Fuchsia specific configuration. The command `fx shell` is a |
| convenient wrapper to connect to the target device over SSH and provides |
| access to a very simply POSIX-style shell. Users should note that while the |
| shell is a fork of a POSIX shell, it does not provide all features of a |
| common Unix shell. In particular users will find that CTRL+C has odd quirks, |
| and may often find quirks for sub-shell expressions and certain more advanced |
| IO redirections or environment variable propagations. These misfeatures are |
| side effects of Fuchsia not being a POSIX system. |
| |
| Nonetheless the shell made available via `fx shell` is extremely useful for |
| imperatively executing programs on the Fuchsia target, as well as exploring |
| some of the diagnostic / debug interfaces made available in a filesystem |
| tree, such as `/hub` and `/dev`. It is also useful for invoking programs such |
| as `/bin/run` that provides facilities for launching Fuchsia components. If |
| the `tools` bundle is available in the build configuration, many tools common |
| to unix shell environments have been ported and are available, such as `ps`, |
| `ls`, `cat`, `curl`, `vim`, `fortune` and so on. |
| |
| ## Performing other common tasks |
| |
| ### Getting logs |
| |
| `fx syslog` captures all logs from low-level and high-level programs, |
| including the kernel, drivers and other userspace programs. `fx syslog` |
| depends upon a working high level network stack and SSH. As such, `fx syslog` |
| does not work with Zedboot or "bringup" product configurations. If a device |
| is in a state where `fx syslog` ceases to function, it is often useful to |
| switch to `fx log` to capture more information about probable causes. |
| |
| `fx log` captures only a low-level log stream called "klog". The klog stream |
| includes logs from the Zircon kernel itself, as well as a subset of userspace |
| software (most notably drivers and low-level core software). `fx log` depends |
| on a lightweight network stack called `netsvc` that has a tendency to remain |
| available even after problems in higher-level software. The netsvc suite is |
| also always available in "bringup" product configurations, as such, `fx log` |
| is most useful when working on low-level software, such as the Zircon kernel, |
| or drivers. |
| |
| ### Copying files |
| |
| `fx cp` provides a basic wrapper around `scp`, similar to how `fx shell` is a |
| wrapper around `ssh`. |
| |
| ```shell |
| # 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 |
| ``` |
| |
| ### Start Fuchsia in QEMU |
| |
| `fx run` starts a Fuchsia build under QEMU, a general purpose virtual |
| machine. Users on Linux host systems with KVM can execute `fx run -k` for |
| significantly improved performance. |
| |
| The QEMU environment does not support any GUI programs. It also has limiting |
| network capabilities. Hardware devices are recommended for day-to-day Fuchsia |
| software development whenever possible. |
| |
| ### Using multiple Fuchsia devices with set-device |
| |
| Some users will have more than one Fuchsia device on a network, and will want |
| to limit the effects of various commands to particular of those devices. The |
| `fx set-device` command exists to help with this use case. |
| |
| The `fx set-device` command binds a particular device node name to a |
| particular build directory. This is particularly useful when a user wishes to |
| keep several different devices in several build configurations, and could be |
| setup as follows: |
| |
| ```shell |
| $ fx --dir out/workstation set workstation.x64 |
| $ fx build |
| $ fx set-device <workstation-node-name> |
| |
| $ fx --dir out/core set core.arm64 |
| $ fx build |
| $ fx set-device <core-node-name> |
| |
| # Start a server for the workstation: |
| $ fx --dir=out/workstation 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 |
| ``` |
| |
| Additionally, for users who wish to execute a command against a single |
| Fuchsia device from the current default build directory, as a one-off |
| command, the `fx` global flag `-d` allows overriding the target node name for |
| a single command invocation. |
| |
| ### Reboot a device |
| |
| `fx reboot` |
| |
| On some devices (most arm64 devices at present) there are also some useful flags: |
| |
| * `fx reboot -r` reboot into "recovery" (Zedboot) |
| * `fx reboot -b` reboot into "bootloader" (Flash) |
| |
| ### Debugging and developing `fx` commands |
| |
| * `fx -x` the `-x` flag turns on tracing for the `fx` scripts, printing out all |
| expressions evaluated during the `fx` invocation. |
| * `fx exec` executes an abitrary program that follows inside of the current |
| `fx` environment. As an example `fx exec env` prints all environment |
| variables in that environment (`fx exec env | grep FUCHSIA` is likely of |
| interest). |
| |
| ### Getting help with `fx` |
| |
| `fx help <command>` provides the best introductory documentation for that |
| command. Some commands also support/provide `fx <command> -h` or |
| `fx <command> --help`, however this help is not available for all commands. |
| This is unusual, but is a function of implementation details. Internally many |
| `fx` commands just run other programs, most often those produced by the |
| build, and flags are in many cases passed on unaltered to those programs. In |
| those cases, passing the usual `-h` or `--help` flags may not provide |
| documentation for `fx <command>`, but instead for the program invoked |
| downstream of `fx`. |
| |
| Users should always start with `fx help <command>`. |
| |
| `fx help` with no other arguments provides a list of all available commands |
| in `fx`, as well as documentation for `fx` global flags. |