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