オフィスアワーがそろそろ始まるよ!()

ビルドスクリプト

Zenでビルドプロセスを自動化するには、ビルドスクリプトを使用します。従来では、このような目的でmakecmakeが利用されていました。Zenでは、外部ビルドシステムに依存せず、ビルドプロセスをZen言語で記述します。

Zenのビルドスクリプトは、次のようなユースケースで利用できます。

  • ビルド前処理
    • ホストシステム内にある依存ライブラリの検出
    • 依存ライブラリのビルド
    • プラットフォーム固有の設定
  • ビルド
    • オプションの指定 (リリースモード、ターゲットなど)
  • ビルド後処理
    • バイナリ形式の変換 (ELFからIntel HEX形式への変換)
    • バイナリの検査と編集 (binutilsの使用など)
  • テスト実行
  • コードフォーマッタ実行

このような異なるユースケースに対して、Zenのビルドシステムで対応可能です。

用語解説

具体的な説明に入る前に、ステップオプションという2つの概念について説明します。

ステップ

ビルドプロセスの1つのステージをステップと呼びます。ステップはビルドスクリプト内で自由に追加することができます。また、ステップ同士に依存関係を持たせることができます。

例えば、build-exerundebugという3つのステップがあるとします。build-exeステップが完了しないと、runステップおよびdebugステップは実行できません。そこで、「build-exe -> run」という依存関係と、「build-exe -> debug」という依存関係をビルドスクリプト内で記述します。

下記に示す3つのコマンドは、指定されたステップと依存するステップだけを実行します。

# `build-exe`ステップのみ実行
$ zen build build-exe
# `build-exe`ステップと`run`ステップを実行
$ zen build run
# `build-exe`ステップと`debug`ステップを実行
$ zen build debug

このように、ステップごとの依存関係を記述しながら、柔軟なビルドプロセスを組み上げることができるようになっています。

オプション

ビルドスクリプトを実行する際に、コマンドラインから与えられるオプションです。現在、ブール値 (true / false) と文字列とをオプションとして受け取り、ビルドスクリプト内で使用することができます。

コマンドラインからオプションを与えるには、-Dの後にオプションを続けます。

ブール値の場合、-D<オプション>で該当オプションがtrueになります。文字列の場合、-D<オプション>=<文字列>の形式でオプションを与えます。

ビルドスクリプトを作成してみよう!

順を追ってビルドスクリプトを作成しましょう。 Hello Worldを表示するプログラムをzen build runで実行できるようにします。

新しい作業ディレクトリを作成し、src/main.zenを次の内容で作成します。

const std = @import("std");

pub fn main() void {
    std.debug.warn("Hello World\n", .{});
}

build.zen の作成

まず、コンパイル可能な最小限のbuild.zenを作成します。

const std = @import("std");
const Builder = std.build.Builder;

pub fn build(b: *mut Builder) void {
    // ここにビルドスクリプトを書く
}

通常、Zenのプログラムはmain()関数から実行を開始しますが、ビルドスクリプトはbuild()関数から実行を開始します。 build()関数は、引数に初期化済みのBuilderインスタンスを受け取ります。 戻り値型は、voidもしくはError!void (Errorは任意のエラー型) です。

lib/std/special/build_runner.zenにビルドスクリプトのmain()関数が存在しており、Builderインスタンスの初期化を行った後、build()関数を呼ぶようになっています。

これで、zen buildコマンドを実行すると、ビルドスクリプトのビルドはできますが、zen-cacheディレクトリが作成される以外、何も起こりません。 この時点でビルドスクリプトとして最低限の機能を使うことができます。

例えば、zen build --helpを実行すると利用可能なステップやオプションが表示されます。

$ zen build --help
Usage: zen build [steps] [options]

Steps:
  install (default)      Copy build artifacts to prefix path
  uninstall              Remove build artifacts from prefix path

General Options:
  --help                 Print this help and exit
  --verbose              Print commands before executing them
  --prefix [path]        Override default install prefix
  --search-prefix [path] Add a path to look for binaries, libraries, headers
  --sign [identity]      Sign binary files with a signing identity

Project-Specific Options:
  (none)

Advanced Options:
  --build-file [file]      Override path to build.zen
  --sign [identity]        Sign binary files with a signing identity
  --cache-dir [path]       Override path to Zen cache directory
  --override-lib-dir [arg] Override path to Zen lib directory
  --verbose-tokenize       Enable compiler debug output for tokenization
  --verbose-ast            Enable compiler debug output for parsing into an AST
  --verbose-link           Enable compiler debug output for linking
  --verbose-ir             Enable compiler debug output for Zen IR
  --verbose-llvm-ir        Enable compiler debug output for LLVM IR
  --verbose-cimport        Enable compiler debug output for C imports
  --verbose-cc             Enable compiler debug output for C compilation
  --dump-graph             Dump the dependency graph and exit

実行ファイルをビルドするステップの作成

さて、用語説明でステップという概念を説明しました。 さきほど、zen build --helpで出力されたメッセージの中に、デフォルトで作成されるステップが表示されていました。 すなわち、installuninstallです。

$ zen build --help
Usage: zen build [steps] [options]

Steps:
  install (default)      Copy build artifacts to prefix path
  uninstall              Remove build artifacts from prefix path

今の時点でzen build installを実行することが可能ですが、やはり何も起こりません。 これは、installステップに紐づくステップが一切存在していないためです。

そこで、src/main.zenをビルドしてインストールするステップを、installステップに紐付けます。

pub fn build(b: *mut Builder) void {
    const exe = b.addExecutable("hello", "src/main.zen");
    exe.install();
}

b.addExecutable("hello", "src/main.zen")の第一引数helloは実行ファイル名で、src/main.zenはソースファイル名です。

addExecutableは、実行ファイルをビルドするステップであるLibExeObjStepのインスタンスをヒープ領域に作成し、そのポインタを返します。 LibExeObjStepBuilderと並び、ビルドスクリプト内で重要な役割を果たします。 なんらかのソースファイルをビルドする場合、このLibExeObjStepを使用します。

さて、addExecutableLibExeObjStepを作成した時点では、このステップは何とも関連していません。 今、デフォルトでinstallステップがあるので、installステップと紐付けます。

exe.install()は、installステップがexeに依存する関係性を追加します。 つまり、installステップを実行する前に、exeを実行します。

ここでzen build installを実行すると、zen-cache/bin/helloの実行ファイルが作成されます。

$ zen build install
$ ./zen-cache/bin/hello
Hello World

正確には、exe.install()は、InstallArtifactStepという新しいステップを作成し、install -> InstallArtifactStep -> LibExeObjStepという依存関係を構築します。 InstallArtifactStepは、LibExeObjStepでビルドする対象ごとに一定のルールに基づいたパスに成果物をインストールします。 デフォルトでは、実行ファイルはzen-cache/bin下にインストールされます。 この依存関係はzen build --dump-graphコマンドで可視化できます。

$ zen build --dump-graph
digraph graphname {
"install140313468919696" -> "InstallArtifactStep140313468923320";
"InstallArtifactStep140313468923320" -> "LibExeObjStep140313468921888";
}

実行ファイルを実行するステップの追加

zen build runでビルドしたファイルを実行できるように、runステップを追加します。

まずは、実行ファイルを実行するRunStepを作成します。

pub fn build(b: *mut Builder) void {
    const exe = b.addExecutable("hello", "src/main.zen");
    exe.install();

    const run_cmd = exe.run();
}

exe.run()は、exeステップでビルドしたファイルを実行するRunStepのインスタンスをヒープ領域に作成し、そのポインタを返します。 現時点では、まだzen build runコマンドを実行することができません。 runステップがない、と怒られてしまいます。

$ zen build run
Cannot run step 'run' because it does not exist

runステップを追加するには、次の2行を追加します。

    const run_step = b.step("run", "Run the app");
    b.addStepDependency(run_step, run_cmd);

b.stepzen buildに指定できるステップを追加します。 b.stepの第一引数はステップ名、第二引数はステップの説明でzen build --helpを実行した時に表示されます。 b.addStepDependency(run_step, run_cmd);で、run_stepが先ほど作成したrun_cmd (RunStep)に依存するようにします。 addStepDependencyは、2つのステップを引数に取ります。 今回の場合、run_step -> run_cmdという依存関係を追加しています。

ここで、zen build --helpを実行するとrunステップが追加されていることが確認できます。

$ zen build --help
Usage: zen build [steps] [options]

Steps:
  install (default)      Copy build artifacts to prefix path
  uninstall              Remove build artifacts from prefix path
  run                    Run the app

では、zen build runを実行してみましょう。

$ zen build run
Hello World

Hello Worldが表示されました!

これまでいくつかのステップを作成しましたが、runステップだけがzen buildで指定できます。 これはなぜでしょうか? 実は、ステップの中でもトップレベルステップだけが、zen buildで指定できるステップになります。 トップレベルステップはBuilderstep()関数で作成することができます。

ビルドスクリプトにおけるステップの関係の俯瞰図は次のようになります。

これで実行ファイルをビルドして実行することができますが、1つ問題があります。 一度、zen-cacheを削除して、もう一度zen build runを実行して下さい。

$ rm -r zen-cache
$ zen build run

zen-cache下にbinディレクトリが存在せず、どこにhello実行ファイルがあるのかが、わかりません。 ディレクトリ以下を探すと、キャッシュ内に実行ファイルが存在していることはわかります。

$ find . -name "hello"
./zen-cache/o/AXoKD7r5s9g4SDmV64FuRaYeI2MaYSfe7ikFIDe6niRvs1DuZ2rvWkopc2KlKI6K/hello

最新の実行ファイルがどれかわからないのでは、具合が悪いです。 runステップ実行時にも、zen-cache/bin下に実行ファイルをインストールするようにしておきましょう。

そのためには、run_cmdinstallステップに依存するように、次の1行を追加します。

    b.addStepDependency(run_cmd, b.getInstallStep());

getInstallStep()はビルドスクリプトデフォルトのinstallステップを取得します。

これで、zen build run実行時にもzen-cache/binhelloがインストールされます。

ここまでのビルドスクリプトをまとめると、次のようになります。

examples/ch10-compilation/build-script/basic/build.zen:1:12

const std = @import("std");
const Builder = std.build.Builder;

pub fn build(b: *mut Builder) void {
    const exe = b.addExecutable("hello", "src/main.zen");
    exe.install();

    const run_cmd = exe.run();
    b.addStepDependency(run_cmd, b.getInstallStep());

    const run_step = b.step("run", "Run the app");
    b.addStepDependency(run_step, run_cmd);
}

テストを実行するステップの追加

Zenにおけるテストの重要性は、本ドキュメント内でも繰り返し述べてきました。 では、ビルドスクリプトからテストを実行するにはどうすれば良いでしょうか?

次のテストをsrc/main.zenに追加し、このテストをビルドスクリプトから実行してみましょう。

test "first test" {
    std.testing.ok(true);
}

ビルドスクリプトでテストを実行するには、testステップを追加します。

examples/ch10-compilation/build-script/basic/build.zen:14:17

    const test_exe = b.addTest("src/main.zen");
    const test_step = b.step("test", "Run all tests");
    b.addStepDependency(test_step, test_exe);

addTest()関数は、テストをビルドするLibExeObjStepのインスタンスをヒープ領域に作成し、そのポインタを返します。 後は、runステップを追加した時と同じ要領です。

$ zen build test
1/1 test "first test"...OK
All 1 tests have succesfully passed.

プロジェクトテンプレートのビルドスクリプト

さらに、感覚を掴むために、プロジェクトテンプレートのビルドスクリプトを見てみましょう。

新しくプロジェクトテンプレートを作成します。

$ mkdir template && cd $_
$ zen init-exe

build.zenは以下の内容になっています。

examples/ch10-compilation/build-script/template/build.zen:1:24

const Builder = @import("std").build.Builder;

pub fn build(b: *mut Builder) void {
    // standardTargetOptions を使用すると、`zen build`を実行する人が、ビルドするターゲットを選択できます。
    // .{}はデフォルトを上書きせず、任意のターゲットが許可されます。
    // デフォルトではネイティブがターゲットになります。
    // ターゲットを制限するオプションを指定することも可能です。
    const target = b.standardTargetOptions(.{});
    // standardReleaseOptions を使用すると、`zen build`を実行する人が、
    // Debug、 ReleaseSafe、 ReleaseFast、 ReleaseSmall から選択できます.
    const mode = b.standardReleaseOptions();

    const exe = b.addExecutable("template", "src/main.zen");
    exe.setTarget(target);
    exe.setBuildMode(mode);
    exe.install();

    const run_cmd = exe.run();
    b.addStepDependency(run_cmd, b.getInstallStep());

    const run_step = b.step("run", "Run the app");
    b.addStepDependency(run_step, run_cmd);
}

ビルドスクリプトの内容を説明する前に、このビルドスクリプトによってできることを見てみましょう。次のコマンドで、ビルドスクリプトのヘルプを表示することができます。

$ zen build --help

次のようなヘルプが表示されます。

Usage: zen build [steps] [options]

Steps:
  install (default)      Copy build artifacts to prefix path
  uninstall              Remove build artifacts from prefix path
  run                    Run the app

General Options:
  --help                 Print this help and exit
  --verbose              Print commands before executing them
...

Project-Specific Options:
  -Dmattr=[string]       set build CPU features
  -Dmcpu=[string]        set build CPU
  -Dtarget=[string]      set build CPU architecture, OS and ABI
  -Drelease-safe=[bool]  optimizations on and safety on
  -Drelease-fast=[bool]  optimizations on and safety off
  -Drelease-small=[bool] size optimizations on and safety off

Advanced Options:
  --build-file [file]      Override path to build.zen
  --sign [identity]        Sign binary files with a signing identity
...

ビルドステップにはinstall / uninstall / runという3つのステップがあり、installがデフォルトになっています。zen buildの後に何もステップを指定しなければ、installが実行されます。プロジェクトテンプレートでは、installはビルドキャッシュ (zen-cache) 内にbinというディレクトリを作って、その下にアプリケーションバイナリをコピーします。

runステップはビルドしたアプリケーションバイナリを実行します。

$ zen build
# ビルド生成物を確認
$ ./zen-cache/bin/template
Congratulations on your first step to writing perfect software in Zen.

# 下は、上記2つのコマンドを実行したことと同義
$ zen build run
Congratulations on your first step to writing perfect software in Zen.

# リリースモードをオプションとして与える
$ zen build run -Drelease-safe
Congratulations on your first step to writing perfect software in Zen.

さて、使い方がわかったところで、ビルドスクリプトの中身に戻りましょう。

ビルドスクリプトではstd.buildモジュール内のBuilder構造体を使用するので、インポートします。

const Builder = @import("std").build.Builder;

ビルドスクリプトのエントリポイントは、pub fn build(*mut Builder) void、もしくは、エラーを返す場合pub fn build(*mut Builder) !voidでなければなりません。プロジェクトテンプレートでは、bという変数名で*Builderを受け取っています。

pub fn build(b: *mut Builder) void {

コマンドラインオプションからビルドターゲットを指定したい場合、standardTargetOptions 関数を使用できます。コマンドラインから -Dtarget-Dmcpu-Dmattr オプションでそれぞれターゲットトリプル、特定のCPUタイプ、アーキテクチャの属性を指定できるようになります。コマンドラインで指定がない場合は、ビルドを実行しているホスト環境がビルドターゲットになります。オプションに指定する値の詳細は 第10章 ビルドオプション-target-mcpu-mattr を参照して下さい。

    const target = b.standardTargetOptions(.{});

コマンドラインオプションからビルドモードを指定したい場合、standardReleaseOptions関数を使用できます。コマンドラインから-Drelease-safe / -Drelease-fast / -Drelease-safeのいずれかを選択できるようになります。コマンドラインで指定がない場合は、ビルドモードはデバッグモードになります。

    const mode = b.standardReleaseOptions();

addExecutable関数では、アプリケーション名とルートソースファイルを指定して、アプリケーションバイナリをビルドするためのexeステップを得ます。Builderはいくつかの頻出ステップを作成する関数を有しています。addExecutableはそのうちの1つです。

    const exe = b.addExecutable("template", "src/main.zen");

exe.setTargetexe.setBuildModeで、それぞれ exeステップのビルドターゲットとビルドモードを設定し、exe.installinstallステップでexeステップが実行されるようにします。

    exe.setTarget(target);
    exe.setBuildMode(mode);
    exe.install();

ここまでで、zen buildもしくはzen build installでアプリケーションバイナリがビルドされ、zen-cache/binにビルドされたバイナリがコピーされます。

exe.run関数は、exeステップでの生成物を実行するrun_cmdステップを返します。バイナリを実行するステップは、installステップに依存するため、addStepDependencyinstallステップとの依存関係を作成しています。

    const run_cmd = exe.run();
    b.addStepDependency(run_cmd, b.getInstallStep());

最後にコマンドラインから選択できるステップにrunステップ (コード内ではrun_step) を追加します。これには、Builderstep関数を使用します。引数は、ステップ名とそのステップの説明です。このrun_stepは、コマンドラインでrunが入力された時に実行します。run_cmdステップとの依存関係を作成することで、runステップ実行によって、run_cmdステップが実行されることになります。

    const run_step = b.step("run", "Run the app");
    b.addStepDependency(run_step, run_cmd);

これでプロジェクトテンプレートのビルドスクリプトを一通り解説しました。ビルドスクリプトは最初はとっつきにくく感じるかもしれません。しかし基本は、ステップを作って、ステップ間の依存関係を接続していくだけです。

std.build内にあるステップ

ビルドスクリプトでは自由にステップを追加することが可能ですが、よく使うステップは、std.buildの中で定義されています。

  • LibExeObjStep
  • RunStep
  • InstallArtifactStep
  • InstallFileStep
  • InstallDirStep
  • WriteFileStep
  • LogStep
  • RemoveDirStep
  • CodeSignStep

これらのステップで目的のビルドプロセスが実現できない場合、ビルドステップを追加すると良いでしょう。

LibExeObjStep

ビルドスクリプト内で最も頻繁に利用するステップです。 その名前の通り、ライブラリ、実行ファイル、オブジェクトをビルドするステップです。

LibExeObjStepの役割は多岐にわたりますが、共通する目的はZenコンパイラの実行コマンドを生成することです (例えば、zen build-exe src/main.zen) 。

例えば、次のsrc/main.zenがあるとします。

const std = @import("std");

pub fn main() void {
    std.debug.warn("Hello World\n", .{});
}

このソースコードをリリースモードでビルドするためには、次のコマンドを使います。

$ zen build-exe src/main.zen --release-safe

同じことをビルドスクリプトで行うためには、次のようにします。

examples/ch10-compilation/build-script/release/build.zen:1:7

const Builder = @import("std").build.Builder;

pub fn build(b: *mut Builder) void {
    const exe = b.addExecutable("release", "src/main.zen");
    exe.setBuildMode(.ReleaseSafe);
    exe.install();
}

addExecutableで実行ファイルをビルドするLibExeObjStepを作成し、ビルドモードを設定しています。

どのようなビルドコマンドが最終的に実行されているか見るためには、zen build --verboseを使います。

$ zen build --verbose
zen build-exe <path to project>/src/main.zen --release-safe --cache-dir <path to project>/zen-cache --name release --cache on
cp <path to project>/zen-cache/o/2atoU0fWyeSJzhrW8N-Mgjg1w-ABBsXHd_O70hYvQQ6PQJiILzgVpxyUtGlnfFFy/release <path to project>/zen-cache/bin/release

1つ目のコマンドがzen build-exe src/main.zen --release-safeとなっていることがわかります。 ビルドスクリプトは、キャッシュを有効にするなど、その他のオプションもデフォルトで設定するので、それ以外のオプションも付いています。

ライブラリ用のLibExeObjStepを作成するとzen build-libが、オブジェクト用ではzen build-objが、テスト用ではzen testが、それぞれコマンドとして実行されます。

このように、LibExeObjStepはZenコンパイラの実行コマンドを生成します。 LibExeObjStepは、他にも様々なコンパイラオプションを設定するためのAPIを提供します。

ステップを自作する

ステップは自作することができます。 次のStepインタフェースを満たすように、構造体を宣言します。

pub const Step = interface {
    fn getName() []u8;
    fn make(builder: *mut Builder) anyerror!void;
};

make()関数はステップが実行する処理を記述します。

例として、新しいディレクトリを作成するCreateDirStepは次のようになります。

examples/ch10-compilation/build-script/custom_step/build.zen:14:54

/// 新しいディレクトリを作成するステップです
const CreateDirStep = struct {
    const Self = @This();
    // ビルドルートディレクトリからの相対パスで作成するディレクトリを指定します
    dir_path: []u8,
    // すでにディレクトリが存在していることを許可するかどうかのフラグです
    allow_existing: bool,

    /// ヒープ領域にインスタンスを新規作成し、そのポインタを返します
    pub fn create(allocator: std.heap.Allocator, dir_path: []u8, allow_existing: bool) *mut Self {
        const create_dir_step = std.heap.create(allocator, Self) catch unreachable;
        create_dir_step.* = Self.init(dir_path, allow_existing);
        return create_dir_step;
    }

    /// インスタンスを初期化します。`create`から呼ばれることを想定しています
    fn init(dir_path: []u8, allow_existing: bool) Self {
        return Self{
            .dir_path = dir_path,
            .allow_existing = allow_existing,
        };
    }

    /// ステップの名前を取得します
    fn getName(_: Self) []u8 {
        return @typeName(Self);
    }

    /// ディレクトリを作成します
    /// この関数は標準ライブラリ内のコードから呼ばれることを想定しています
    fn make(self: *mut Self, builder: *mut Builder) !void {
        const full_path = builder.pathFromRoot(self.dir_path);
        std.fs.cwd().makeDir(full_path) catch |err| {
            if (self.allow_existing and err == error.PathAlreadyExists) {
                return;
            }

            std.debug.warn("Unable to create {}: {}\n", .{ full_path, @errorName(err) });
            return err;
        };
    }
};

ステップを自作するにあたり、1つ重要なポイントがあります。 それは、ステップのインスタンスはヒープ領域に確保しなければならないことです。 そのため上の例では、init()関数とは別にcreate()関数を用意して、ヒープ領域にインスタンスを作成しています。

ノート ステップインスタンスのmakeは、ビルドスクリプトのエントリ関数であるbuild()関数から、呼び出し元に制御が移った後に実行されます。 そのため、build()関数内でスタックにインスタンスを作成すると、解放済みのメモリを操作することになり、未定義動作を引き起こします。

APIリファレンス

Builder

Builderのインスタンスは、build関数の引数として、渡されます。以下はインスタンスから利用できるメソッドです。

  • addExecutable(name: []u8, root_src: ?[]u8) *mut LibExeObjStep: 実行バイナリをビルドするステップを作成します。nameは実行ファイル名、root_srcは最も上位の関数があるソースファイルです。Cソースファイルをビルドする場合は、root_srcnullでもかまいません。
  • addObject(name: []u8, root_src: ?[]u8) *mut LibExeObjStep: オブジェクトファイルをビルドするステップを作成します。
  • addSharedLibrary(name: []u8, root_src: ?[]u8, ver: builtin.Version) *mut LibExeObjStep: 共有ライブラリをビルドするステップを作成します。
  • addStaticLibrary(name: []u8, root_src: ?[]u8) *mut LibExeObjStep: 静的ライブラリをビルドするステップを作成します。
  • addTest(root_src: []u8) *mut LibExeObjStep: テストバイナリを生成するステップを追加します。
  • addAssemble(name: []u8, src: []u8) *mut LibExeObjStep: アセンブリからオブジェクトファイルをビルドするステップを作成します。
  • addSystemCommand(argv: [][]u8) *mut RunStep: システムコマンドを実行するステップを作成します。
  • addStepDependency(dependant: *mut vtable Step, dependecy: *mut vtable Step) void: ステップの依存関係を作成します。
  • addWriteFile(file_path: []u8, data: []u8) *mut WriteFilesStep: ファイルにデータを書き込むステップを作成します。
  • addLog(comptime format: []u8, args: anytype) *mut LogStep: ログ出力するステップを作成します。
  • addRemoveDirTree(dir_path: []u8) *mut RemoveDirStep: ディレクトリを削除するステップを作成します。
  • addFmt(paths: [][]u8) *mut FmtStep: コードフォーマッタを実行するステップを作成します。
  • option(comptime T: type, name: []u8, description: []u8) ?T: ビルドスクリプトでビルドする際に、コマンドラインから与えられるオプションを追加します。
  • step(name: []u8, description: []u8) *mut vtable Step: 新しくステップを作成します。
  • setPreferredReleaseMode(mode: builtin.Mode) void: ユーザーがビルドモードを指定しなかった場合に使われるデフォルトのビルドモードです。
  • standardReleaseOptions() builtin.Mode: release-saferelease-fastrelease-smallをビルドオプションとして追加し、コマンドラインで指定されたビルドモードを返します。
  • standardTargetOptions(args: StandardTargetOptionsArgs) CrossTarget: targetmcpumattr をビルドオプションとして追加し、コマンドラインで指定されたビルドターゲットを返します。
  • installArtifact(artifact: *mut LibExeObjStep) void: 成果物をインストールします。
  • addInstallArtifact(artifact: *mut LibExeObjStep) *mut InstallArtifactStep: 成果物をインストールするステップを追加します。
  • exec(argv: [][]u8) ![]mut u8: コマンドを実行します。

LibExeObjStep

実行バイナリやライブラリ、オブジェクトファイルをビルドするステップです。

  • setTarget(target: CrossTarget) void: ビルドターゲットを設定します。
  • setOutputDir(dir: []u8) void: ビルド成果物を配置するディレクトリを設定します。
  • install() void: 成果物をインストールします。
  • run() *mut RunStep: 実行ステップを追加します。コマンドライン引数にrunステップを追加します。
  • setLinkerScriptPath(path: []u8) void: リンカスクリプトのパスを設定します。
  • linkLibrary(lib: *mut LibExeObjStep) void: 他ステップでビルドされるライブラリをリンクします。
  • linkSystemLibrary(name: []u8) void: システムライブラリをリンクします。
  • addCSourceFile(file: []u8, args: [][]u8) void: Cソースファイルをビルド対象として追加します。argsにはCソースコードのビルドオプション (clangのオプション) を複数設定できます。
  • setBuildMode(mode: builtin.Mode) void: ビルドモードを設定します。
  • getOutputPath() []u8: 成果物が出力されるパスを取得します。成果物にさらに加工を加えたい場合に使います。
  • addAssemblyFile(path: []u8) void: アセンブリファイルをビルド対象として追加します。
  • addObjectFile(path: []u8) void: オブジェクトファイルをビルド対象として追加します。
  • addObject(obj: *mut LibExeObjStep) void: 他ステップでビルドされるオブジェクトを追加します。
  • addIncludeDir(path: []u8) void: インクルードパスを追加します。
  • addLibPath(path: []u8) void: ライブラリのサーチパスを追加します。

クロスビルド

クロスビルドを行なう際はターゲット情報を設定した CrossTarget 構造体のインスタンスを引数に渡して setTarget を呼び出します。 CrossTarget 構造体のインスタンスは ParseOptions 構造体 (ターゲットトリプルの文字列、特定のCPUタイプ、アーキテクチャの属性など) を指定して CrossTarget.parse 関数を実行することで作成します。

例えば次のコードのように実行します。

const target = try std.zen.CrossTarget.parse(.{
    .arch_os_abi = "thumb-freestanding-eabihf",
    .mcpu = "cortex-m4",
    .mattr = "vfp4",
    });

const firmware = builder.addExecutable("firmware", "src/boot.zen");
firmware.setTarget(target);

parse 関数は次のように定義されています。

fn parse(args: ParseOptions) !CrossTarget

ParseOptions 構造体に指定する、ターゲットトリプルの文字列、特定のCPUタイプ、アーキテクチャの属性については 第10章 ビルドオプション-target-mcpu-mattr を参照して下さい。

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6

Chapter 7

Chapter 8

Chapter 9

Chapter 10

Chapter 11

Chapter 12

Chapter 13

Chapter 14

Chapter 15

Appendix

Error Explanation

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2020 connectFree Corporation. All rights reserved. | 特定商取引法に基づく表示
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.