本文へ移動
Hikari 仕様

ビルド (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> は次の順で決定する:

  1. 環境変数 HIKARI_REPO の値 (設定されていれば検証だけして他の候補へ落ちない — 利用者の意図しないツリーを黙って使わない)
  2. ビルド時に焼き込んだ処理系クレートのパス
  3. 作業ディレクトリから最大 6 階層上向きの探索
  4. 実行バイナリの隣 ../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.mdhikari check を使う — こちらはバイナリを生成しない。