Skip to content

feat: Zig 0.16.0 compatibility#225

Open
gilbertwong96 wants to merge 6 commits into
burrito-elixir:mainfrom
gilbertwong96:zig-0.16.0
Open

feat: Zig 0.16.0 compatibility#225
gilbertwong96 wants to merge 6 commits into
burrito-elixir:mainfrom
gilbertwong96:zig-0.16.0

Conversation

@gilbertwong96

@gilbertwong96 gilbertwong96 commented Jun 12, 2026

Copy link
Copy Markdown

Updates the Zig wrapper to compile and run on Zig 0.16.0.

Zig 0.16.0 API changes:

  • std.c.statIo.Dir.cwd().statFile (cross-compile fix)
  • Permissions.unixNewPermissions.fromMode
  • Guard Permissions.toMode() on Windows (enum, no POSIX mode bits)
  • Drop unused arena parameter from maybe_install_musl_runtime

Process spawning:

  • Replace std.process.replace with spawn + child.wait (replace hangs on macOS arm64 in 0.16.0)
  • Unify Windows/Unix code paths

Bug fix:

  • Split "-elixir ansi_enabled true" and "-s elixir start_cli" into separate argv entries — passing them as single strings caused the BEAM to hang in __select on macOS

CI:

  • Add Zig 0.16.0 + macOS arm64 (macos-14) to cross-build matrix

Builds on #224 by @jsmestad. Closes #221.

Brezn and others added 3 commits May 29, 2026 12:12
The Zig standard library had a major restructuring in 0.16.0, primarily
around the new Io abstraction. This updates all source files to use the
new APIs:

- std.process.getEnvVarOwned → b.graph.environ_map.get (build.zig) and
  std.process.Environ (runtime)
- std.fs.cwd() → std.Io.Dir.cwd()
- File methods (close, stat, writer, reader) now take io: Io parameter
- std.fs.getAppDataDir removed; replaced with manual XDG/platform logic
- std.process.execve → std.process.replace
- Build module methods (addIncludePath, addCSourceFile, linkSystemLibrary)
  moved from Compile step to root_module
- main() accepts std.process.Init for Io and Environ access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jsmestad

Copy link
Copy Markdown

Any reason you dropped support for glibc and went musl only?

@gilbertwong96

Copy link
Copy Markdown
Author

Any reason you dropped support for glibc and went musl only?

Yeah, this branch still contains non-sense change for debug and test purposes, I will sort out branch to remove non sense changes and then force push them.

@gilbertwong96

Copy link
Copy Markdown
Author

Force pushed

@gilbertwong96 gilbertwong96 changed the title Update Zig compatibility from 0.15.2 to 0.16.0 — additional fixes + CI matrix feat: Zig 0.16.0 compatibility Jun 27, 2026
Cross-compilation fixes (Zig 0.16.0 API changes):
- Replace std.c.stat with Io.Dir.cwd().statFile
- Rename Permissions.unixNew → Permissions.fromMode
- Remove unused arena parameter from maybe_install_musl_runtime
- Comptime-guard the musl runtime call site on macOS
- Guard Permissions.toMode() on Windows (enum, no POSIX mode bits)

Process spawning (cross-platform):
- Replace std.process.replace with std.process.spawn + child.wait
  (std.process.replace does not work reliably on macOS arm64)
- Unify Windows/Unix code paths via the same spawn+wait pattern

CI:
- Add Zig 0.16.0 to the cross-build matrix
- Add macOS arm64 (macos-14) runner
Passing '-elixir ansi_enabled true' and '-s elixir start_cli' as single
argv entries (with embedded spaces) caused the BEAM to hang in __select
when spawned via std.process.spawn on macOS. erlexec passes them through
to beam.smp as-is, and beam.smp doesn't split space-delimited args.

Splitting them into separate argv entries fixes the hang.
@doawoo

doawoo commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

I'll have to update the runner jobs for this, but it's looking good to me. Let me run a few tests offline and then I'll merge and update CI to be correct lol

On macOS, `brew install elixir xz` installed Elixir 1.20.2 (OTP 29)
which shadowed setup-beam's Elixir 1.18.3 (OTP 27), causing a Hex ABI
mismatch (`beam_load.c` errors) at `mix deps.get`. Only `xz` is needed
via brew since setup-beam already provides Elixir.

Drop the 0.15.2 Zig matrix entries since lib/burrito.ex hardcodes
`@zig_version_expected` to 0.16.0 with a strict equality check, making
0.15.2 builds fail the version guard.
@joshrotenberg

Copy link
Copy Markdown

Tested this branch on macOS 26.5 (Tahoe) / Apple Silicon with zig 0.16.0. Packaging works: it builds a self-contained binary that boots the BEAM with no Elixir on PATH. Thanks for tackling this.

One regression: elixir:start_cli/0 now runs and consumes the application's CLI arguments.

Minimal repro, a burrito app that just prints what it sees:

# lib/argv_probe/application.ex
def start(_type, _args) do
  IO.puts(:stderr, "running_standalone? = #{Burrito.Util.running_standalone?()}")
  IO.puts(:stderr, "get_arguments()     = #{inspect(Burrito.Util.Args.get_arguments())}")
  Supervisor.start_link([], strategy: :one_for_one, name: ArgvProbe.Sup)
end

Built with this branch and run:

$ ./argv_probe hello world
running_standalone? = true
get_arguments()     = ["hello", "world"]     # the app receives args correctly
No file named hello                          # ...but start_cli also runs, treats "hello" as a script
# exit 1

So argument delivery is fine (get_arguments/0 returns them, __BURRITO is set). The problem is that elixir:start_cli/0 executes and interprets the same -extra plain arguments (which Burrito.Util.Args.get_arguments/0 reads via :init.get_plain_arguments/0) as Elixir CLI arguments, then halts the VM. --version prints the Erlang/Elixir banner; any other first argument becomes "No file named ".

This traces to the -s elixir start_cli change in src/erlang_launcher.zig. In 1.5.0 it was a single argv token, so start_cli never actually ran and the app's own arg-reading was the only consumer. Split into -s, elixir, start_cli, it runs for real. The split does fix the macOS boot hang, so this looks like a side effect rather than a reason to drop it. Happy to test any patch on this macOS 26 host.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Zig 0.16.x (macOS 26 compatibility blocker)

4 participants