Fuchsia のビルド概要
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 set と fx build の概要を紹介します。
要約
-
fx set
gn gen out/default.zircon、gn gen out/defaultを実行し、out/に.nijnaファイルを生成します。 -
fx build
ninja -C out/default.zircon、ninja -C out/defaultを実行します。
out/default.zircon/に Zircon カーネルイメージを生成、
out/default/にアプリケーションを生成します。
gn、ninja については、この記事 を参照ください。
fx set
fx set は product、board でビルド対象を指定します。
— fx workflows
fx set product.board
$ fx list-products # product一覧
bringup
core
terminal
workstation
$ 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 set は tools/devshell/set を実行します。
tools/devshell/set は fx-gn gen ... を呼び出します。
fx-gn は tools/devshell/lib/vars.sh において定義され、 PREBUILT_GN を実行します。
PREBUILT_GN は tools/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 の当該箇所のコメント。
# The Zircon GN is completely a puppet of this build. This gen runs that gen.
環境変数としては 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 が使われます。
# Expect build files named BUILD.zircon.gn.
build_file_extension = "zircon"
ただ、gn gen out/default 時は、zircon の BUILD.gn を参照します。
(アプリケーション用 BUILD.gn から zircon カーネルの BUILD.gn を参照する場合など)
また、ほとんどの BUILD.gn は BUILD.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 build は tools/devshell/build を実行します。
tools/devshell/build は fx-run-ninja ... を呼び出します。
fx-run-ninja は tools/devshell/lib/vars.sh において定義され、 PREBUILT_NINJA を実行します。
PREBUILT_NINJA は tools/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 が書き込まれます。
out/default
fx build 実行時、tools/devshell/build にて fx-config-read を呼び出し、FUCHSIA_BUILD_DIR に .fx-build-dir の中身をセットします。
FUCHSIA_BUILD_DIR="$(<"${FUCHSIA_DIR}/.fx-build-dir")"
FUCHSIA_BUILD_DIR が決定すると ZIRCON_BUILDROOT (out/default.zircon)も決まります。
export ZIRCON_BUILDROOT="${FUCHSIA_BUILD_DIR%/}.zircon"
ファイルに書き出している理由
fx set --build-dir some_dir のように任意のディレクトリを出力先にできるが、後続する fx build などにそのディレクトリを伝えるため。
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