Livebook で Zig を実行する

## はじめに

> Zigは、堅牢、最適、および再利用可能なソフトウェアをメンテナンスするための汎用プログラミング言語およびツールチェインです

引用元

https://ziglang.org/ja-JP/

Zigler を使うことで、 Elixir から Zig のコードを呼び出すことができます

https://github.com/E-xyza/zigler

本記事では Livebook で Zigler を使い、 Zig のコードを実行します

実装したコードはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/zigler/zigler.livemd

## 前提条件

実行環境には Zig をインストールしておきます

## セットアップ

セットアップセルで Zigler をインストールします

```elixir
Mix.install([
  {:zigler, "~> 0.13.3"}
])
```

## Zig モジュールの定義

Zig 実行用のモジュールを定義します

```elixir
defmodule ExampleZig do
  use Zig, otp_app: :zigler

  ~Z"""
  const std = @import("std");
  const beam = @import("beam");

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

  pub fn multiply(a: i32, b: i32) i32 {
      return a * b;
  }

  pub fn sort(slice: []i32) []i32 {
    std.mem.sort(i32, slice, {}, comptime std.sort.asc(i32));
    return slice;
  }

  pub fn hello(name: []const u8) ![]u8 {
    const greeting = "Hello, ";
    const total_len = greeting.len + name.len;
    var buffer = try beam.allocator.alloc(u8, total_len);

    @memcpy(buffer[0..greeting.len], greeting);
    @memcpy(buffer[greeting.len..], name);

    return buffer;
  }
  """
end
```

`~Z` の[シギル](https://elixirschool.com/ja/lessons/basics/sigils) 内に Zig のコードを書きます

メモリ割り当てには `beam.allocator` を利用します

コードを実行すると、以下のような標準出力が表示されます

```
01:57:49.573 [info] searching for zig in /home/livebook/.cache/zigler/zig-linux-aarch64-0.13.0/zig

01:57:49.573 [info] system zig found in /usr/local/zig-linux/zig

01:57:49.573 [debug] running command: /usr/local/zig-linux/zig fmt /tmp/Elixir.ExampleZig/build.zig

01:57:49.583 [debug] wrote build.zig to /tmp/Elixir.ExampleZig/build.zig

01:57:49.600 [info] searching for zig in /home/livebook/.cache/zigler/zig-linux-aarch64-0.13.0/zig

01:57:49.601 [info] system zig found in /usr/local/zig-linux/zig

01:57:49.601 [debug] running command: /usr/local/zig-linux/zig run -lc --dep analyte -Mmain=/home/livebook/.cache/mix/installs/elixir-1.17.2-erts-15.0/7151676201b96057dc15ed4fdc619273/_build/dev/lib/zigler/priv/beam/sema.zig -Merl_nif=/home/livebook/.cache/mix/installs/elixir-1.17.2-erts-15.0/7151676201b96057dc15ed4fdc619273/_build/dev/lib/zigler/priv/beam/stub_erl_nif.zig --dep erl_nif -Mbeam=/home/livebook/.cache/mix/installs/elixir-1.17.2-erts-15.0/7151676201b96057dc15ed4fdc619273/_build/dev/lib/zigler/priv/beam/beam.zig -Mattributes=/tmp/Elixir.ExampleZig/attributes.zig --dep erl_nif --dep beam --dep attributes -Manalyte=/home/livebook/.local/share/livebook/autosaved/2024_12_27/01_36_j6eb/.Elixir.ExampleZig.zig

01:57:50.389 [info] searching for zig in /home/livebook/.cache/zigler/zig-linux-aarch64-0.13.0/zig

01:57:50.389 [info] system zig found in /usr/local/zig-linux/zig

01:57:50.389 [debug] running command: /usr/local/zig-linux/zig fmt /tmp/Elixir.ExampleZig/module.zig

01:57:50.394 [debug] wrote module code to /tmp/Elixir.ExampleZig/module.zig

01:57:50.395 [info] searching for zig in /home/livebook/.cache/zigler/zig-linux-aarch64-0.13.0/zig

01:57:50.395 [info] system zig found in /usr/local/zig-linux/zig

01:57:50.395 [debug] running command: /usr/local/zig-linux/zig build -Doptimize=Debug --prefix /home/livebook/.cache/mix/installs/elixir-1.17.2-erts-15.0/7151676201b96057dc15ed4fdc619273/_build/dev/lib/zigler/priv

01:57:51.511 [debug] built library at /home/livebook/.cache/mix/installs/elixir-1.17.2-erts-15.0/7151676201b96057dc15ed4fdc619273/_build/dev/lib/zigler/priv/lib/Elixir.ExampleZig.so

01:57:51.549 [debug] loaded module at Elixir.ExampleZig
```

Zシギル内に定義したコードを元として NIF が生成、ビルドされ、 NIF のロードまで実行されています

定義したモジュールは普通の Elixir モジュールと同じように呼び出すことができます

```elixir
ExampleZig.add(3, 4)
```

実行結果

```elixir
7
```

```elixir
ExampleZig.multiply(3, 4)
```

実行結果

```elixir
12
```

```elixir
ExampleZig.sort([8, 5, 6, 2])
```

実行結果

```elixir
[2, 5, 6, 8]
```

```elixir
ExampleZig.hello("Zig")
```

実行結果

```elixir
"Hello, Zig"
```

## まとめ

NIF を作るときのややこしい部分を Zigler が全てやってくれるので、簡単に Elixir から Zig のコードを実行できました