なぜパッケージか
言語を学んでいたり、スニペットを試したりしているうちは、ひとつの .0 ファイルで十分です。プロジェクトが 1 ファイルを超えた瞬間に欲しくなるのが パッケージ——マニフェストと、ツールチェーンが理解する既知のレイアウトを持つディレクトリです。
ばらばらのファイルからパッケージへ移ることで得られるものは、
- プロジェクトの名前、バージョン、メタデータをひとつの正規の場所に置ける。
- 1 つのツリーに複数のエントリーポイント(実行ファイル、ライブラリ、テスト)を置ける。
- 予測可能なレイアウト——ツールが設定なしにソースを見つけられる。
- ファイル単位ではなくツリー全体に対する
zero check/zero build。
パッケージをスキャフォールドする
最速で始める方法は zero new です。
zero new cli hello
これで hello/ ディレクトリが次のように作られます。
hello/
├── zero.json
└── src/
└── main.0
cli はテンプレート名で、実行可能なコマンドラインプログラムを生成します。他のテンプレート(ライブラリ、システムプログラム)も同じ形で、デフォルトが異なります。
新しいディレクトリに cd して実行すれば、もう動きます。
cd hello
zero run
パッケージディレクトリ内で、ファイル名を指定せずに zero run を実行すると、zero.json のデフォルトターゲットを拾って実行します。
zero.json マニフェスト
スキャフォールドされた cli パッケージのマニフェストはこんな見た目です。
{
"package": { "name": "hello", "version": "0.1.0" },
"targets": { "cli": { "kind": "exe", "main": "src/main.0" } }
}
トップレベルのキーは 2 つ: package と targets。前者がパッケージを識別し、後者がコンパイラーに何をビルドするかを伝えます。
package
"package": {
"name": "hello",
"version": "0.1.0"
}
name——パッケージを識別するスラッグ。小文字とハイフンを使います。version——semver 文字列。pre-1.0 パッケージは0.x.yを使います。
その他のメタデータフィールド(description、author、license、repository)がサポートされる場合があります。マニフェストはまだ進化中なので、権威あるスキーマは現行の Zero ドキュメントに従ってください。
targets
"targets": {
"cli": { "kind": "exe", "main": "src/main.0" }
}
キー(ここでは cli)は自分で選ぶ ターゲット名 です。値が各ターゲットを記述します。
kind——ターゲットの種類。実行ファイルならexe。他の種類(ライブラリ、テスト)も同じ形に従います。main——パッケージルートからの相対パスのエントリーソースファイル。
1 つのパッケージに複数のターゲットを宣言できます。
{
"package": { "name": "image-tools", "version": "0.1.0" },
"targets": {
"convert": { "kind": "exe", "main": "src/convert.0" },
"resize": { "kind": "exe", "main": "src/resize.0" },
"lib": { "kind": "lib", "main": "src/lib.0" }
}
}
CLI からターゲット名を指定して特定のターゲットをビルドできます。
zero build convert
zero run resize
src/ ディレクトリ
すべてのソースファイルは src/ 配下に住みます。コンパイラーがこのディレクトリを自動で走査するので、マニフェストにすべてのファイルをリストする必要はありません。各ターゲットの main フィールドがエントリーファイルを指し、コンパイラーはそこから import を辿って必要なものを見つけます。
ヘルパーモジュールがいくつかあるパッケージは、こんな見た目になるかもしれません。
image-tools/
├── zero.json
└── src/
├── convert.0
├── resize.0
├── lib.0
└── internal/
├── decoder.0
└── encoder.0
internal/ サブディレクトリは単なる慣習です——マニフェストにそれらのファイル名は出てきません。convert.0 内の import は internal/decoder.0 に直接届きます。
ビルドと実行
パッケージ内に入ったあとのよくあるワークフローです。
zero check # ツリー全体を型検査する
zero run # デフォルトターゲットをビルドして実行
zero run convert # 指定したターゲットをビルドして実行
zero build # デフォルトターゲットをビルド
zero build --all # すべてのターゲットをビルド(サポートされている場合)
zero test # すべてのテストターゲットを実行
CLI は zero.json を読み、何をすべきかを把握して進みます。パッケージ内で作業しているなら、パスを綴り出すことはまずありません。
複数のソースファイル: 簡単な例
src/main.0 が src/math.0 のヘルパーを呼ぶとします。ヘルパーファイル。
pub fun double(value: i32) -> i32 {
return value * 2
}
エントリーファイル。
pub fun main(world: World) -> Void raises {
let result = double(21)
if result == 42 {
check world.out.write("forty two\n")
}
}
zero run で実行します。この単純なケースでは、明示的な import 宣言がなくても、コンパイラーがソースツリーの残りに対して double への参照を解決します。パッケージが大きくなると、明示的な import システムがモジュール間の可視性を扱います——import 構文は 1.0 までに動きやすい部分のひとつなので、現行の Zero ドキュメントを参照してください。
git にチェックイン しない もの
Zero パッケージの .gitignore には通常、次が入ります。
# ビルド成果物とキャッシュ
/build/
/target/
# エディタ由来のゴミ
.DS_Store
*.swp
ビルド出力ディレクトリの正確な名前は異なる場合があります——現行のツールチェーンのドキュメントで確認してください——が、ルールは「ソースは入れる、ビルド成果物は入れない」です。
パッケージを共有する
Zero は pre-1.0 で、パッケージレジストリはまだ安定した表面の一部ではありません。今のところ、パッケージを共有する現実的な方法は次の通りです。
- Git: リポジトリをクローンして
zero checkを実行する。 - ベンダリングしたコピー: ソースのコピーを別のプロジェクトに落とす。
レジストリが登場したら、パッケージ参照はおそらく zero.json の dependencies フィールドに移ります。今日のスクリプトに織り込むのではなく、先を見据えた機能として扱ってください。
次回: 言語の基礎
これで実際の Zero プロジェクトを整理するために必要なものはすべて揃いました。続く章では言語そのものにズームインし、let バインディング ——Zero の値に名前を付ける方法——から始めます。
よくある質問
Zero パッケージとは?
Zero パッケージは、zero.json マニフェストと .0 ソースを格納する src/ フォルダーを含むディレクトリです。マニフェストはパッケージの名前、バージョン、そして 1 つ以上の「ターゲット」を宣言します——各ターゲットは、ソースから何(実行ファイル、ライブラリ、テストバイナリ)をどうビルドするかをコンパイラーに伝えます。
新しい Zero パッケージはどう作りますか?
zero new <template> <name> を実行します。例: zero new cli hello。CLI は zero.json、src/main.0、そして選んだテンプレートに必要なファイルを持つディレクトリをスキャフォールドします。そこからパッケージ内で zero check、zero run、zero build を実行できます。
zero.json には何を書きますか?
zero.json には何を書きますか?最低限、name と version を持つ package オブジェクト、そしてパッケージがビルドする各ものを記述する targets オブジェクトです。ターゲットは kind(実行ファイルなら exe など)と、エントリーソースファイルを指す main を持ちます。1 つのマニフェストに複数のターゲットを宣言できます。
1 つの Zero パッケージに複数のターゲットを持てますか?
はい。パッケージは任意の数のターゲットを宣言できます——たとえば CLI 用の exe ターゲット 1 つ、再利用可能なライブラリ用の lib ターゲット 1 つ、1 つ以上のテストターゲット、というように。各ターゲットは src/ 配下に独自のエントリーポイントを持ち、CLI から個別にビルド・実行できます。
コンパイラーはビルド出力をどこに置きますか?
ビルド成果物はパッケージ内のビルドディレクトリに着地します(正確なパスは実装依存で、Zero が pre-1.0 のうちは変更される可能性があります)。src/ 配下のソースツリーは決して変更されません。ビルドディレクトリは使い捨て可能なものとして扱いましょう——git にチェックインするのは悪い考えです。