Zig Lang の始め方 - 環境構築編 -


Zig Lang とは

  • 2016年登場の新しい命令型静的型付けコンパイル言語
  • 簡素で明確な言語仕様
  • GC無し(メモリはスタックにアロケート)(ヒープ管理は言語外で行い隠れたメモリアロケーション無し)
  • オーバーフロー演算などをコンパイルエラーとして捕捉

Zigの思想は zig zen コマンドで確認できます。

$ zig zen

 * Communicate intent precisely. - 意図を正確に伝える
 * Edge cases matter. - エッジケース重要
 * Favor reading code over writing code. - コードは書くことより読むことを優先
 * Only one obvious way to do things. - 明白なやり方は一つだけ
 * Runtime crashes are better than bugs. - バグよりランタイムクラッシュを好む
 * Compile errors are better than runtime crashes. - ランタイムクラッシュよりコンパイルエラーを好む
 * Incremental improvements. - インクリメンタルに改善
 * Avoid local maximums. - 局所的最大値を避ける
 * Reduce the amount one must remember. - 覚えなければならないことを減らす
 * Focus on code rather than style. - スタイルよりコードに着目
 * Resource allocation may fail; resource deallocation must succeed. - リソース割り当ては失敗するかもしれない; 解放は成功しなければならない
 * Memory is a resource. - メモリは重要な資源である
 * Together we serve the users. - 一緒にユーザに貢献しよう


インストール

WinGet

winget add zig.zig

ユーザ環境変数のパスに C:\Users\<user>\AppData\Local\Microsoft\WinGet\Links が追加され、この中に zig.exe へのシンボリックリンクが配備されます(実体は C:\Users\<user>\AppData\Local\Microsoft\WinGet\Packages\zig.zig_Microsoft.Winget.Source_xxx\zig-windows-x86_64-xx となる)。

ただし、zig 0.11.0 段階では、ライブラリパスが見つからないためうまく動かないので、直接ダウンロードしてインストールするのが良い(後述)。

Homebrew

brew install zig

手動インストール

Releasesからダウンロード解凍し、パスを通すだけです。

バージョン確認

$ zig version
0.12.0

VS Code Extension


zig コマンド

zig コマンドには以下があります。

$ zig --help
Usage: zig [command] [options]

Commands:

  build            Build project from build.zig
  fetch            Copy a package into global cache and print its hash
  init             Initialize a Zig package in the current directory

  build-exe        Create executable from source or object files
  build-lib        Create library from source or object files
  build-obj        Create object from source or object files
  test             Perform unit testing
  run              Create executable and run immediately

  ast-check        Look for simple compile errors in any set of files
  fmt              Reformat Zig source into canonical form
  reduce           Minimize a bug report
  translate-c      Convert C code to Zig code

  ar               Use Zig as a drop-in archiver
  cc               Use Zig as a drop-in C compiler
  c++              Use Zig as a drop-in C++ compiler
  dlltool          Use Zig as a drop-in dlltool.exe
  lib              Use Zig as a drop-in lib.exe
  ranlib           Use Zig as a drop-in ranlib
  objcopy          Use Zig as a drop-in objcopy
  rc               Use Zig as a drop-in rc.exe

  env              Print lib path, std path, cache directory, and version
  help             Print this help and exit
  libc             Display native libc paths file or validate one
  targets          List available compilation targets
  version          Print version number and exit
  zen              Print Zen of Zig and exit

General Options:

  -h, --help       Print command-specific usage


Hello World

main.zig を以下のように作成します。

const std = @import("std");

pub fn main() void {
    std.debug.print("Hello, {s}!\n", .{"World"});
}
  • 接頭辞に @ が付くものは、コンパイラにより提供される組み込み関数
  • @import() は指定されたパスに対応するzigファイルを検索し、(未追加の場合)ビルドに追加する
  • pub fn main() は実行時のエントリポイントとなる関数を定義
  • std.debug.print() で文字列補完したテキストを表示
  • .{"World"} はタプルリテラルであり、文字列が一つのタプルを定義


コンパイル

$ zig build-exe main.zig

$ ./main
Hello, World!

ソースから直接実行することもできます。

$ zig run main.zig
Hello, World!


Zig Build System

0.11.0 から Zig Build System が利用可能となりました。

Zig Build System では、ビルドロジックをZig Build System API を使用して build.zig に記述します。

zig init にて初期化プロジェクトを生成します(旧来は zig init-exe があったが0.12.0では無くなっている)。

$ mkdir hello
$ cd hello
$ zig init

以下のようなファイルが生成されます。

 hello
  ├ build.zig
  ├ build.zig.zon
  └ src
      ├ main.zig
      └ root.zig

build.zig にビルドロジックが記載され、build.zig.zon (Zig Object Notation)には依存情報などビルドの設定を定義します。

main.zig には以下のような初期コード(実行可能ファイル用)が生成されます。

const std = @import("std");

pub fn main() !void {
    // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
    std.debug.print("All your {s} are belong to us.\n", .{"codebase"});

    // stdout is for the actual output of your application, for example if you
    // are implementing gzip, then only the compressed bytes should be sent to
    // stdout, not any debugging messages.
    const stdout_file = std.io.getStdOut().writer();
    var bw = std.io.bufferedWriter(stdout_file);
    const stdout = bw.writer();

    try stdout.print("Run `zig build test` to run the tests.\n", .{});

    try bw.flush(); // don't forget to flush!
}

test "simple test" {
    var list = std.ArrayList(i32).init(std.testing.allocator);
    defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
    try list.append(42);
    try std.testing.expectEqual(@as(i32, 42), list.pop());
}

root.zig には以下のような初期コード(ライブラリ用)が生成されます。

const std = @import("std");
const testing = std.testing;

export fn add(a: i32, b: i32) i32 {
    return a + b;
}

test "basic add functionality" {
    try testing.expect(add(3, 7) == 10);
}


ビルドは以下で行います。

$ zig build

zig-out 以下に実行ファイルが生成されます。

 hello
  ├ build.zig
  ├ build.zig.zon
  ├ src
  │   ├ main.zig
  │   └ root.zig
  ├ zig-cache
  └ zig-out
      ├ bin
      │  ├ hello.exe
      │  └ hello.pdb
      └ lib
         └ hello.lib

実行は以下のように行います(自動生成された build.zigrun コマンドが定義されている)。

$ zig build run


次回はZigの言語仕様について見ていきます。