feat: Zig 0.16.0 compatibility - #225
Conversation
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>
9536c44 to
1ac8e20
Compare
37db26f to
4cd733b
Compare
|
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. |
4f5a854 to
0b950fe
Compare
|
Force pushed |
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.
0b950fe to
0f9761b
Compare
|
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.
|
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: 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)
endBuilt with this branch and run: So argument delivery is fine ( This traces to the |
|
@joshrotenberg Thanks for testing this out, and reporting the regression there... I'll try and look into that |
7a3abbb to
30be1e1
Compare
|
Hi, @doawoo, push one more commit to fix the bug EPIPE hang when piping output to head/less. |
30be1e1 to
da6e45d
Compare
When stdout is piped to a command that exits early (e.g. `app cmd | head -5`), the BEAM's standard_io group leader crashes on EPIPE and the VM hangs indefinitely trying to flush IO during shutdown. The wrapper now pipes child stdout through itself via a copy thread. When the downstream pipe breaks (EPIPE on write), the copy thread kills the child process, allowing the wrapper to exit cleanly instead of blocking on child.wait() forever.
da6e45d to
0a246a2
Compare
|
@gilbertwong96 Thank you for this massively helpful contribution! All tests look good! |
|
Will appreciate it if you publish a new release on hex.pm :) |
|
Released! |
The bug is Burrito 1.6’s new stdout relay from PR #225 (burrito-elixir/burrito#225). It made the wrapper a second owner of stdout. Issue #234 (burrito-elixir/burrito#234) and PR #235 (burrito-elixir/burrito#235) use the practical fix: when stdout is a TTY, let BEAM inherit it directly; retain the relay only for pipes. I ported that fix: - app/mix.exs:1 installs the release hook. - app/release/burrito_patches.exs:1 applies the upstream patch and fails closed if Burrito changes. - app/test/linear_cli/release/burrito_patches_test.exs:1 verifies it. - Linux Burrito binary compiled successfully. - A throttled pseudo-terminal emitted all 5,000 rows, including the final row, then exited 0. - Full suite: 312 tests passed. - Formatter check passed. Need a follow-up on this when burrito gets the patch into mainstream
Updates the Zig wrapper to compile and run on Zig 0.16.0.
Zig 0.16.0 API changes:
std.c.stat→Io.Dir.cwd().statFile(cross-compile fix)Permissions.unixNew→Permissions.fromModePermissions.toMode()on Windows (enum, no POSIX mode bits)arenaparameter frommaybe_install_musl_runtimeProcess spawning:
std.process.replacewithspawn+child.wait(replace hangs on macOS arm64 in 0.16.0)Bug fixes:
"-elixir ansi_enabled true"and"-s elixir start_cli"into separate argv entries — passing them as single strings caused the BEAM to hang in__selecton macOShead/less. When stdout is piped to a command that exits early, the BEAM'sstandard_iogroup leader crashes on EPIPE and the VM hangs indefinitely trying to flush IO during shutdown. The wrapper now pipes child stdout through itself via a copy thread; when the downstream pipe breaks (EPIPE on write), the copy thread kills the child process, allowing the wrapper to exit cleanly instead of blocking onchild.wait()forever.CI:
Builds on #224 by @jsmestad. Closes #221.