Global module options

View Source

ignore

Public functions can be ignored and not converted into nifs by filling out the :ignore option in use Zig directive.

defmodule IgnoreTest do
  use ExUnit.Case, async: true

  use Zig, 
    otp_app: :zigler,
    ignore: [:ignored]

  ~Z"""
  pub fn ignored(number: u32) u32 {
      return number + 1;
  }

  pub fn available(number: u32) u32 {
      return ignored(number);
  }
  """

  test "available function works" do
    assert 48 = available(47)
  end

  test "ignored function is not available" do
    refute function_exported?(__MODULE__, :ignored, 0)
  end
end

attributes

Attributes from your module can be used as compile-time constants communicated from elixir. All attributes of the following types will be automatically available through the attributes module import:

  • integer (as comptime int values)
  • float (as comptime float values)
  • nil (as null)
  • boolean (as bool values)
  • binary (as comptime [:0]u8 values)
  • atom (as enum literal values)
  • tuple of only the above types (as tuple)
defmodule Attribute do
  use ExUnit.Case, async: true
  use Zig, otp_app: :zigler

  @supplied_value Mix.env()

  ~Z"""
  const beam = @import("beam");
  const attribs = @import("attributes");

  pub fn get_attrib() beam.term {
    return beam.make(.{.ok, attribs.supplied_value}, .{});
  }
  """

  test "getting an attribute" do
    assert {:ok, :test} = get_attrib()
  end
end

adding modules

It's possible to add zig files as modules using the extra_modules keyword option. The name of the module is the key, and the value is a tuple of the path to the zig file that acts as the module and a list of transitive module dependencies.

Example extra.zig

pub const value = 47;
defmodule PackageFile do
  use ExUnit.Case, async: true
  use Zig, 
    otp_app: :zigler,
    extra_modules: [extra: {"./test/_support/module/extra.zig", [:beam]}]

  ~Z"""
  const extra = @import("extra");

  pub fn extra_value() u64 {
    return extra.value;
  }
  """

  test "module file" do
    assert 47 = extra_value()
  end
end

Release Mode

Zig has several release modes, and you can specify which release mode to build your program under using the optimize option. This option defaults to :debug if you are in :dev or :test and :safe otherwise (or if the Mix module is not available). You may also specify :env which reades the ZIGLER_RELEASE_MODE environment variable, or {:env, default} which lets you specify a different default mode if ZIGLER_RELEASE_MODE is not set.

defmodule ReleaseMode do
  use ExUnit.Case, async: true

  use Zig, otp_app: :zigler, optimize: :fast

  ~Z"""
  const beam = @import("beam");
  pub fn get_mode() beam.term {
      return beam.make(@import("builtin").mode, .{});
  }
  """

  test "release mode" do
    assert :ReleaseFast == get_mode()
  end
end

Error Traces

By default, zigler will provide error traces in Debug and ReleaseSafe modes. You may override this in ReleaseSafe by supplying the error_tracing option

defmodule ErrorTraces do
  use ExUnit.Case, async: true

  use Zig, otp_app: :zigler, error_tracing: false, optimize: :safe

  ~Z"""
  pub fn add_one(x: u32) !u32 {
      if (x == 42) return error.BadNumber;
      return x + 1;
  }
  """

  test "error traces can be overridden" do
    assert 48 == add_one(47)

    stacktrace = try do
      add_one(42)
    rescue
      _ ->
        __STACKTRACE__
    end

    assert [{__MODULE__, :add_one, 1, _} | _] = stacktrace
  end
end

# module

dump options

Zigler lets you dump various compile-time assets to the console for debugging purposes, which can be enabled by setting any given one of the following options to true:

  • dump: dumps the rendered elixir code generated by use Zig.
  • dump_sema: dumps the json data emitted by the semantic analysis pass.
  • dump_build_zig: dumps the autogenerated build.zig file