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

組込み定数

Zenコンパイラに組み込まれている型や列挙型の情報です。Zenのプログラム内では、builtinをインポートすることで、これらの情報にアクセスできます。

コンパイラビルトインは、マルチプラットフォーム対応、クロスビルド、アトミック操作、リフレクションなどで利用します。これらのトピックに現時点で興味がない場合は、この節はスキップしても問題ありません。

コンパイラが組込みで持っている情報を全てを見たい場合、次のコマンドを実行します。

$ zen builtin

ここでは、その中から特によく利用するものについて解説を行います。

  • ターゲット環境
    • アーキテクチャ
    • OS
    • ABI
  • 命令セットアーキテクチャ
    • 浮動小数点ABI
    • 浮動小数点モード
    • エンディアン
  • リンカ
    • グローバルリンケージ
  • アトミック
    • オーダ
    • 命令
  • ビルドオプション
  • 型情報
    • 整数、浮動小数点、ポインタ、配列、構造体、オプション型、エラー型、列挙型
  • ターゲット環境定数

組込み定数の利用方法

コンパイラビルトインの用途の1つとして、コンパイル時にターゲット環境に合わせて分岐を実行する、というものが挙げられます。ビルドターゲットのOSごとに異なるメッセージを表示する例を示します。

まずbuiltinをインポートします。ターゲットのOS情報は、builtin.osに格納されており、その値はbuiltin.Os (大文字O) で定義されている列挙型です。そこで、switchのパターンは、各列挙型のヴァリアントとします。

examples/ch07-builtins/src/builtin.zen:2:10

const builtin = @import("builtin");

const message = switch(builtin.os) {
    builtin.Os.windows => "hello Windows!",
    builtin.Os.macosx => "hello MacOSX!",
    builtin.Os.linux => "hello Linux!",
    else => "hello others!",
};

これでmessageにはターゲット環境に合わせた文字列が格納されます。ためしに表示してみます。

examples/ch07-builtins/src/builtin.zen:12:14

test "simple builtin usage" {
    std.debug.warn("{}\n", message);
}

著者の環境は、Linuxなので、次の結果になりました。

hello Linux!

ビルトインは、コンパイル時計算可能です。そのため、実行時には余分なコストがかかりません。

examples/ch07-builtins/src/builtin.zen:16:21

const equal = std.testing.equal;
test "builtin is comptime known" {
    comptime {
        equal("hello Linux!", message);
    }
}

注意: 上記コードの期待値hello Linux!は、お使いのOSに合わせて変更して下さい。

ターゲット環境

Zenコンパイラがサポートしているターゲット環境です。プロセッサ (CPU) アーキテクチャ、OS、ABIの3つを組み合わせます。著者の環境は、x86_64-linux-gnuです。これは、プロセッサアーキテクチャがx86_64 (Intel) 、OSがLinux、ABIがGNUであることを意味します。

アーキテクチャ

Zenがサポートするプロセッサアーキテクチャです。タグ付き共用体builtin.Archにまとめられています。

pub const Arch = union(enum) {
    arm: Arm32,
    armeb: Arm32,
    aarch64: Arm64,
    aarch64_be: Arm64,
    arc,
    avr,
    bpfel,
    bpfeb,
    hexagon,
    mips,
    mipsel,
    mips64,
    mips64el,
    msp430,
    powerpc,
    powerpc64,
    powerpc64le,
    r600,
    amdgcn,
    riscv32,
    riscv64,
    sparc,
    sparcv9,
    sparcel,
    s390x,
    tce,
    tcele,
    thumb: Arm32,
    thumbeb: Arm32,
    i386,
    x86_64,
    xcore,
    nvptx,
    nvptx64,
    le32,
    le64,
    amdil,
    amdil64,
    hsail,
    hsail64,
    spir,
    spir64,
    kalimba: Kalimba,
    shave,
    lanai,
    wasm32,
    wasm64,
    renderscript32,
    renderscript64,
...
};

ARMは32ビット / 64ビットのアーキテクチャがさらに細分化されています。これは、Cortex-A / Cortex-R / Cortex-Mの違いや命令セットアーキテクチャバージョンの違いを識別するためのものです。

ビルドターゲットのアーキテクチャは、builtin.archに格納されています。著者のネイティブ環境ではx86_64です。

test "builtin arch" {
    comptime ok(builtin.arch == builtin.Arch.x86_64);
}

OS

ZenがサポートするOSです。列挙型builtin.Osにまとめられています。

pub const Os = enum {
    freestanding,
    ananas,
    cloudabi,
    dragonfly,
    freebsd,
    fuchsia,
    ios,
    kfreebsd,
    linux,
    lv2,
    macosx,
    netbsd,
    openbsd,
    solaris,
    windows,
    haiku,
    minix,
    rtems,
    nacl,
    cnk,
    aix,
    cuda,
    nvcl,
    amdhsa,
    ps4,
    elfiamcu,
    tvos,
    watchos,
    mesa3d,
    contiki,
    amdpal,
    hermit,
    hurd,
    wasi,
    zen,
    uefi,
};

ビルドターゲットのOSは、builtin.osに格納されています。著者のネイティブ環境ではlinuxです。

test "builtin os" {
    comptime ok(builtin.os == builtin.Os.linux);
}

ABI

ZenがサポートするOSです。列挙型builtin.Abiにまとめられています。

pub const Abi = enum {
    none,
    gnu,
    gnuabin32,
    gnuabi64,
    gnueabi,
    gnueabihf,
    gnux32,
    code16,
    eabi,
    eabihf,
    android,
    musl,
    musleabi,
    musleabihf,
    msvc,
    itanium,
    cygnus,
    coreclr,
    simulator,
};

ビルドターゲットのABIは、builtin.abiに格納されています。著者のネイティブ環境ではgnuです。

test "builtin abi" {
    comptime ok(builtin.abi == builtin.Abi.gnu);
}

命令セットアーキテクチャ

命令セットアーキテクチャの浮動小数点ABI、浮動小数点モード、バイトエンディアンに関連する列挙型です。

pub const FloatABI = enum {
    Soft,
    SoftFp,
    Hard,
};

pub const FloatMode = enum {
    Strict,
    Optimized,
};

pub const Endian = enum {
    Big,
    Little,
};

リンカ

リンク時のグローバルリンケージに関する列挙型です。組込み関数@exportでシンボルをエスクポートするときに、グローバルリンケージを指定するために利用します。

pub const GlobalLinkage = enum {
    Internal,
    Strong,
    Weak,
    LinkOnce,
};

アトミック

アトミックな操作とオーダーに関連する列挙型です。

pub const AtomicRmwOp = enum {
    Xchg,
    Add,
    Sub,
    And,
    Nand,
    Or,
    Xor,
    Max,
    Min,
};

pub const AtomicOrder = enum {
    Unordered,
    Monotonic,
    Acquire,
    Release,
    AcqRel,
    SeqCst,
};

ビルドオプション

ビルドモードに関連する列挙型です。

pub const Mode = enum {
    Debug,
    ReleaseSafe,
    ReleaseFast,
    ReleaseSmall,
};

型情報

TypeInfoは、Zenの型に関するメタ情報が定義されています。

例えば、配列のArrayは次のような型情報を持っています。

    pub const Array = struct {
        len: comptime_int,
        child: type,
    };
test "array child" {
    const a = [_]u32{0} ** 10;
    ok(@typeOf(a).len == 10);
    ok(@typeOf(a).Child == u32);
}

ターゲット環境定数

ビルドターゲットの環境を知るためにはどうすれば良いのでしょうか?特にオプションを指定せずに、zen builtinコマンドを実行すると、ネイティブ環境のデフォルト設定が取得できます。

著者のネイティブ環境のデフォルト設定は次の通りでした。

pub const endian = Endian.Little;
pub const is_test = false;
pub const single_threaded = false;
pub const os = Os.linux;
pub const arch = Arch.x86_64;
pub const abi = Abi.gnu;
pub const float_abi = FloatABI.Hard;
pub const glibc_version: ?Version = null;
pub const object_format = ObjectFormat.elf;
pub const mode = Mode.Debug;
pub const link_libc = false;
pub const have_error_return_tracing = true;
pub const valgrind_support = true;
pub const position_independent_code = false;
pub const strip_debug_info = false;
pub const lib_dir = "<path to zen>/lib/zen";
pub const std_dir = "<path to zen>/lib/zen/std";
pub const special_dir = "<path to zen>/lib/zen/std/special";

これらの設定は、コマンドラインオプションや、ビルドスクリプトの設定によって変更することが可能です。例えば、クロスビルドのターゲットとして、ARM Cortex-M3 (--target thumbv7em-freestanding-eabi) を指定して、ビルドモードをリリースセーフモード (--release-safe) にすると、次のようになります。

ターゲットアーキテクチャや浮動小数点ABI、リリースモードなどがネイティブ環境とは異なってきます。上のネイティブ環境をターゲットとした出力と見比べて見て下さい。

$ zen builtin --release-safe --target thumbv7em-freestanding-eabi
pub const endian = Endian.Little;
pub const is_test = false;
pub const single_threaded = false;
pub const os = Os.freestanding;
pub const arch = Arch{ .thumb = Arch.Arm32.v7em };
pub const abi = Abi.eabi;
pub const float_abi = FloatABI.SoftFp;
pub const glibc_version: ?Version = null;
pub const object_format = ObjectFormat.elf;
pub const mode = Mode.ReleaseSafe;
pub const link_libc = false;
pub const have_error_return_tracing = false;
pub const valgrind_support = false;
pub const position_independent_code = false;
pub const strip_debug_info = false;
pub const lib_dir = "<path to zen>/lib/zen";
pub const std_dir = "<path to zen>/lib/zen/std";
pub const special_dir = "<path to zen>/lib/zen/std/special";

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 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.