💮

Fuchsia のビルド概要

2021/03/15に公開

Fuchsia OS(本家ウィキペディア) のビルドについての簡単な紹介です。

Fuchsia OS のビルドは、次のように行います。
Get Started with Fuchsia

# ソースコードの取得
$ curl -s "https://fuchsia.googlesource.com/fuchsia/+/HEAD/scripts/bootstrap?format=TEXT" | base64 --decode | bash
# ビルド対象の設定
$ fx set workstation.qemu-x64
# ビルドの実行
$ fx build

本記事では、fx setfx build の概要を紹介します。

要約

  • fx set
    gn gen out/default.zircongn gen out/default を実行し、out/.nijna ファイルを生成します。

  • fx build
    ninja -C out/default.zirconninja -C out/default を実行します。
    out/default.zircon/ に Zircon カーネルイメージを生成、
    out/default/ にアプリケーションを生成します。

gn、ninja については、この記事 を参照ください。

fx set

fx setproductboard でビルド対象を指定します。
fx workflows

fx set product.board
$ fx list-products # product一覧
bringup
core
terminal
workstation

Key Product Configurations

$ fx list-boards # board一覧
arm64
as370
c18
chromebook-x64
cleo
*
kirin970
msm8998
msm8x53-som
mt8167s_ref
qemu-arm64
qemu-x64
toulouse
vim2
vim3
vs680
x64
x64-reduced-perf-variation

動作

fx の実体は .jiri_root/bin/fx です。
.jiri_root/bin/fx settools/devshell/set を実行します。
tools/devshell/setfx-gn gen ... を呼び出します。
fx-gntools/devshell/lib/vars.sh において定義され、 PREBUILT_GN を実行します。
PREBUILT_GNtools/devshell/lib/platform.sh で定義される gn コマンドです。

したがって、fx set は最終的に gn gen を実行します。

gn gen コマンドが使用するファイル

  • 入力
    .gn, build/config/BUILDCONFIG.gn, 各ディレクトリの BUILD.gn

  • 出力
    out/.ninja ファイル

gn gen コマンド概要

実際に実行される gn gen コマンドは次のとおりです。

prebuilt/third_party/gn/linux-x64/gn -v gen out/default --fail-on-unused-args --check=system --export-rust-project --export-compile-commands=default --ninja-executable=prebuilt/third_party/ninja/linux-x64/ninja --args= import("//boards/qemu-x64.gni") import("//products/workstation.gni")
# See: fx args --list=base_package_labels
base_package_labels+=[]

# See: fx args --list=cache_package_labels
cache_package_labels+=[]

# See: fx args --list=universe_package_labels
universe_package_labels+=[]

# See: fx args --list=host_labels
host_labels+=[]

各オプションについて見ていきます。
GN Reference

gn -v gen out/default

.ninja ファイルを out/default に生成します。
out/default.zircon については後述。

gn gen [--check] [<ide options>] <out_dir>

  Generates ninja files from the current tree and puts them in the given output directory.

--fail-on-unused-args

  --fail-on-unused-args: Treat unused build args as fatal errors.

--check=system

  "gn gen --check" is the same as running "gn check".
  "gn gen --check=system" is the same as running "gn check --check-system".
  gn help check --check-system

  GN's include header checker validates that the includes for C-like source
  files match the build dependency graph.

--export-rust-project

  --export-rust-project
      Produces a rust-project.json file in the root of the build directory
      This is used for various tools in the Rust ecosystem allowing for the
      replay of individual compilations independent of the build system.
      This is an unstable format and likely to change without warning.

--export-compile-commands=default

  --export-compile-commands[=<target_name1,target_name2...>]
      Produces a compile_commands.json file in the root of the build directory
      containing an array of “command objects”, where each command object
      specifies one way a translation unit is compiled in the project. If a list
      of target_name is supplied, only targets that are reachable from any
      target in any build file whose name is target_name will be used for
      “command objects” generation, otherwise all available targets will be used.
      This is used for various Clang-based tooling, allowing for the replay of
      individual compilations independent of the build system.
      e.g. "foo" will match:
      - "//path/to/src:foo"
      - "//other/path:foo"
      - "//foo:foo"
      and not match:
      - "//foo:bar"

--ninja-executable=prebuilt/third_party/ninja/linux-x64/ninja

  --ninja-executable=<string>
      Can be used to specify the ninja executable to use. This executable will
      be used as an IDE option to indicate which ninja to use for building. This
      executable will also be used as part of the gen process for triggering a
      restat on generated ninja files and for use with --clean-stale.

--args=(省略)

out/default/args.gn の中身を指定します。

  --args: Specifies build arguments overrides.

成果物

$ ls out
default  default.zircon

$ ls out/default
all_fidl_json.txt                binaries.json            cts                     gopher           kernel_x64                 prebuilt_binaries.json  tests.json                user.vdso_x64
all_package_manifest_paths.json  board_name               dartlang                host_arm64       linux_arm64                product.txt             toolchain.ninja           x64-shared
all_package_manifests.list       board.txt                efi_x64                 host-tools       linux_arm64-shared         recovery_images_list    tool_paths.json           zbi_tests.json
api.json                         build_info.json          fidling                 host_x64         linux_x64                  rustlang                triage_sources.json       zircon.json
archives.json                    build.ninja              flash.json              host_x64-shared  linux_x64-shared           rust-project.json       universe_packages.list    zircon_multiboot
args.gn                          build.ninja.d            fuzzers.json            image_paths.sh   max_fvm_size.txt           sdk_archives.json       unknown_wasm32
args.json                        cache_packages.list      fx.config               images.json      obj                        size_checker.json       user.libc_x64
banjoing                         checkout_artifacts.json  gen                     kernel.phys32    package-repositories.json  sysroot_toolchain       user.libc_x64-asan
base_packages.list               compile_commands.json    generated_sources.json  kernel.phys_x64  platforms.json             test_durations.json     user.libc_x64-asan-ubsan

$ ls out/default.zircon/
api.json   binaries.json  compile_commands.json   host-x64-linux-clang  legacy_dirs.json               legacy_unification-x64.json  userboot-arm64-clang         user.vdso-x64-clang.shlib
args.gn    build.ninja    gen                     kernel-arm64-clang    legacy_images.json             toolchain.ninja              userboot-x64-clang           user-x64-clang
args.json  build.ninja.d  generated_sources.json  kernel-x64-clang      legacy_unification-arm64.json  user-arm64-clang             user.vdso-arm64-clang.shlib

調査前の疑問への回答

各ディレクトリの BUILD.gn はどうやって呼ぶ

gn gen では、各ディレクトリの BUILD.gn を参照します。
厳密には、トップディレクトリの BUILD.gn から依存関係をたどれる BUILD.gn を参照します。

Everything in GN is rooted in the dependency graph. There is one root BUILD.gn file. The only way other BUILD.gn files are even read is if there is a dependency on a label in that directory.

Dependency graph and BUILD.gn files

どこで out/default.zircon を出力先としている

トップディレクトリの BUILD.gn にて、次を実行する記述があります。
gn gen -q --root=../../zircon --args=(省略) --export-compile-commands=default ../default.zircon

つまり、gn gen out/default コマンド中に gn gen out/default.zircon を別途実行します。
下は BUILD.gn の当該箇所のコメント。

BUILD.gn
# The Zircon GN is completely a puppet of this build.  This gen runs that gen.

環境変数としては tools/devshell/lib/vars.sh で指定しています。

tools/devshell/lib/vars.sh
export ZIRCON_BUILDROOT="${FUCHSIA_BUILD_DIR%/}.zircon"

zircon 以下は、BUILD.gn と BUILD.zircon.gn がある。どちらを使うか

gn gen out/default.zircon 時は、zircon/.gn で次のように指定しているため、BUILD.zircon.gn が使われます。

zircon/.gn
# Expect build files named BUILD.zircon.gn.
build_file_extension = "zircon"

ただ、gn gen out/default 時は、zirconBUILD.gn を参照します。
(アプリケーション用 BUILD.gn から zircon カーネルの BUILD.gn を参照する場合など)

また、ほとんどの BUILD.gnBUILD.zircon.gn へのシンボリックリンクになっています。

余談ですが、gn gen out/default.zircon 時の build configuration ファイルは zircon/public/gn/BUILDCONFIG.gn となります。これは zircon/.gn で指定されます。

fx build

fx build では、fx set で生成された out/.ninja に応じて、Zircon カーネル、アプリケーションのビルドを行います。

動作

fx の実体は .jiri_root/bin/fx です。
.jiri_root/bin/fx buildtools/devshell/build を実行します。
tools/devshell/buildfx-run-ninja ... を呼び出します。
fx-run-ninjatools/devshell/lib/vars.sh において定義され、 PREBUILT_NINJA を実行します。
PREBUILT_NINJAtools/devshell/lib/platform.sh で定義される ninja コマンドです。

したがって、fx build は最終的に ninja を実行します。

ninja コマンドが使用するファイル

  • 入力
    out/.ninja ファイル

  • 出力
    out/ のバイナリ

ninja コマンド概要

実際に実行される ninja コマンドは次のとおりです。

env -i TERM=xterm-256color PATH=prebuilt/third_party/python3/linux-x64/bin:${PATH} prebuilt/third_party/ninja/linux-x64/ninja -j 2 -C out/default.zircon
env -i TERM=xterm-256color PATH=prebuilt/third_party/python3/linux-x64/bin:${PATH} prebuilt/third_party/ninja/linux-x64/ninja -j 2 -C out/default

-j 2 の部分は論理プロセッサ数で、fx-run-ninja にて getconf _NPROCESSORS_ONLN コマンドの結果(私の環境では 2)を使用します。

$ ninja -h
usage: ninja [options] [targets...]

if targets are unspecified, builds the 'default' target (see manual).

options:
  --version      print ninja version ("1.10.2")
  -v, --verbose  show all command lines while building

  -C DIR   change to DIR before doing anything else
  -f FILE  specify input build file [default=build.ninja]

  -j N     run N jobs in parallel (0 means infinity) [default=3 on this system]
  -k N     keep going until N jobs fail (0 means infinity) [default=1]
  -l N     do not start new jobs if the load average is greater than N
  -n       dry run (don't run commands but act like they succeeded)

  -d MODE  enable debugging (use '-d list' to list modes)
  -t TOOL  run a subtool (use '-t list' to list subtools)
    terminates toplevel options; further flags are passed to the tool
  -w FLAG  adjust warnings (use '-w list' to list warnings)

成果物

Zircon カーネルの成果物の一部です。

out/default.zircon/kernel-x64-clang/obj/kernel/zircon.elf
out/default.zircon/kernel-x64-clang/obj/kernel/zircon.bin
out/default.zircon/kernel-x64-clang/obj/kernel/image
out/default.zircon/kernel-x64-clang/kernel.zbi

調査前の疑問への回答

fx build 時の FUCHSIA_BUILD_DIR はどうやって決定されるか

fx set 実行時、 tools/devshell/set にて fx-build-dir-write を呼び出し、
.fx-build-dir ファイルに out/default が書き込まれます。

.fx-build-dir
out/default

fx build 実行時、tools/devshell/build にて fx-config-read を呼び出し、FUCHSIA_BUILD_DIR.fx-build-dir の中身をセットします。

tools/devshell/lib/vars.sh
FUCHSIA_BUILD_DIR="$(<"${FUCHSIA_DIR}/.fx-build-dir")"

FUCHSIA_BUILD_DIR が決定すると ZIRCON_BUILDROOT (out/default.zircon)も決まります。

tools/devshell/lib/vars.sh
export ZIRCON_BUILDROOT="${FUCHSIA_BUILD_DIR%/}.zircon"
ファイルに書き出している理由

fx set --build-dir some_dir のように任意のディレクトリを出力先にできるが、後続する fx build などにそのディレクトリを伝えるため。

tools/devshell/set の当該コメントです。

tools/devshell/set
## This command stores the location of the build directory in the //.fx-build-dir
## file, which causes subsequent `fx` commands to use that build directory. Use
## `fx use` to switch build directories.

Discussion