ビルド (hikari build) 仕様
本書は hikari build の仕様を定める。起動ディスパッチ全体と終了コードの共通表は hikari-command.md、静的検査は static-analysis.md、third-party パッケージは packages.md を参照。
エントリ .hika とその import 依存を成果物へ抱えた単体バイナリを生成する。生成バイナリはホストに Hikari 処理系をインストールしなくても動く。抱えたツリーは実行時に LIR VM で走る。
--aot を付けると、同梱ではなくエントリを Rust ソースへ低レベル化してビルドする。生成バイナリに処理系は載らない。低レベル化できる構文の範囲と生成の規則は rust-backend.md を参照。
モードは 2 つである — 同梱と AOT で、AOT の生成先は Rust の 1 本である。生成先が 1 本しか無いので --aot 単独で足り、生成先を明示する --rust は任意である (「オプション」)。
両モードとも cargo を要求する (「ホスト要件」)。同梱モードが抱える処理系も Rust だからである。「生成バイナリ自体の実行にツールチェーンが要らない」性質は両モードで変わらない。
構文
hikari build [-o <output>] [--smt=z3] [--aot [--rust]] <entry.hika>
引数の並びは フラグ → エントリ の順で書く。フラグは位置を問わず読む — エントリの後ろに書いても効く (hikari test --smt=z3 と同じ規律)。
オプション
| フラグ | 既定値 | 意味 |
|---|---|---|
-o <output> |
エントリの basename から .hika を除いたもの |
出力ファイル名のベース |
--target <os>/<arch> |
— | 受け付けない。指定するとエラーで停止する (「対応ターゲット」) |
--smt=z3 |
off | refinement 述語の証明に外部 SMT solver (z3) を使う (language-spec.md §17.7)。z3 が PATH に無い場合・版が古い場合はエラーで停止する |
--aot |
off | エントリを Rust ソースへ低レベル化してビルドする (rust-backend.md)。既定は .hika の同梱。単独で指定してよい — 生成先は Rust の 1 本しか無いので、選ぶ余地が無い |
--rust |
off | AOT の生成先が Rust であることを明示する。任意であり、付けても付けなくても --aot と同じ結果になる。--aot を伴わない指定はエラー (「同梱モードで Rust」という組み合わせは無い) |
出力名
<output> をそのまま使う。ターゲットはホストの 1 つだけなので、展開も拡張子の付与も無い。
対応ターゲット
ホストだけである。 --target を渡すとエラーで停止する。
import の静的解決
ビルドはまず entry を起点に 静的検査 (static-analysis.md §1) を行う。構文エラー (動的 import を含む) や import 先不在があればビルドを中止し exit code 1。検査を通過した場合のみ、import <対象> := "<path>" のリテラルパスを再帰収集して embed する。embed ルート (相対 slash パスの 0 点) は、プロジェクトに package.toml (packages.md) があれば その manifest dir、無ければ エントリの所属ディレクトリ。
- 構文エラー / import 先不在 → 静的エラーで 停止 (ファイル実行 (hikari-command.md §5)・
hikari check(check.md) と同一規則)。 - embed ルートより外 (
../...) に出る相対 import は エラー で停止する (embed FS の制約)。 pkg:依存 (third-party、packages.md) は lockfile で解決したグラフを別名前空間pkg/<source>@<version>/...に embed する。path dep は embed ルート相対の元位置に embed し、embed ルート外 (../...) を指す path dep は embed 不可として エラー で停止する (git dep 化を案内)。path dep は commit 固定が無いため embed 時に再現性警告を stderr に出す。std:モジュールは従来どおり host コンパイル同梱 (embed FS とは独立)。
AOT モード (--aot)
エントリを Rust ソースへ低レベル化し、ランタイム層だけを依存とする単体バイナリを生成する。処理系を積まない分バイナリは小さくなる。
- 生成物が引くのはランタイム層 (
rt) だけで、Cargo.tomlは path 依存でそれを指す。ホスト能力を使うプログラムだけが、その能力の実装を feature で引く (rust-backend.md §5)。 - AOT がまだ低レベル化できない入口は、名前を出して止まる面だけが生成物に入る (rust-backend.md §6「面と意味を分ける」)。ビルドは通る — どんなに短いプログラムでも prelude の面が丸ごと生成物へ入り、その中には到達しない未実装の入口が必ず含まれるので、「当たったかどうか」を生成の時点で決めることはできない。エントリから実際にその入口へ到達したときは、生成物が名前を stderr へ書いて非ゼロで終わる — 黙って誤答はしない。そこへ当たったら
--aotを外して同梱モードでビルドする。勝手に同梱モードへ落ちることはしない。 - 静的検査 (「import の静的解決」「静的型検査」) は同梱モードと同一で、モードによる差は無い。
- 低レベル化できる構文の範囲は rust-backend.md §7 を参照。
ホスト要件
- ホストに
cargoが必要。両モードとも要る — 同梱モードが抱える処理系も Rust だからである。無ければその旨を stderr に出して停止する。 - 内部で
cargo build --releaseを実行する。 - 生成バイナリ自体の実行にツールチェーンは不要。
- ホスト能力を使うプログラムは C コンパイラーとレジストリへの経路も要る。 AOT の生成物は、その能力を使ったときだけ実装を引く (rust-backend.md §5)。
std:db/sqliteの実装は C のエンジンを同梱ビルドするのでccが必要で、実装が引く外部クレートを取りに初回のビルドはレジストリへ出る。能力を使わないプログラムはどちらも要らない — 生成物の依存はランタイム層だけで、ビルドはネットワークを見ない。
Hikari リポジトリの位置解決
生成プロジェクトはランタイム層を path 依存で参照する。その <path> は次の順で決定する:
- 環境変数
HIKARI_REPOの値 (設定されていれば検証だけして他の候補へ落ちない — 利用者の意図しないツリーを黙って使わない) - ビルド時に焼き込んだ処理系クレートのパス
- 作業ディレクトリから最大 6 階層上向きの探索
- 実行バイナリの隣
../share/hikari
ルートの判定には stdsrc/prelude.hika の存在を使う。いずれも見つからなければエラーで停止する。
進捗出力
cargo build の stdout/stderr はそのまま stderr に流す。
静的型検査
hikari build は、「import の静的解決」の構文層 静的検査 (static-analysis.md §1) の通過後・cargo build の起動前に、entry を起点とした静的型検査 (static-analysis.md §2) を必ず走らせる。型エラーが 1 件でもあれば診断を stderr に出してビルドを中止し exit code 1 で停止する (バイナリは生成しない)。検査がクリーンなときのみ通常どおりビルドを続行する。
- 規則はファイル実行
hikari <path>(hikari-command.md §5.5) と同じ (static-analysis.md §2)。 - オプトアウトは無い。ファイル単位で切り替える手段も持たない (ファイルは中身だけを宣言し、処理系の振る舞いを変える属性は持たない。language-spec.md §13.1)。診断だけを見たい場合は check.md の
hikari checkを使う — こちらはバイナリを生成しない。