chore!: upgrade to Zig 0.16.0#9
Conversation
- Remove usingnamespace (removed in 0.15): c.zig now exports cImport as .c field - All imports updated: @import("c.zig") → @import("c.zig").c - callconv(.C) → callconv(.c) (lowercase) - napi module requires link_libc = true for @cImport - Example disabled (TODO: std.time.Timer/sleep moved to std.Io) 🤖 Generated with AI assistance
|
@lodekeeper-z please refresh this PR based on the latest main branch |
…ersion) 🤖 Generated with AI assistance
…r callbacks) Updates examples to match new wrap() signature from ChainSafe#10 (added ref parameter). 🤖 Generated with AI assistance
|
Refreshed against latest main — merged in #10 (Ref refactor), #8 (raw variant functions), and #5 (safer callbacks). Updated the Note: the |
|
@lodekeeper-z please refresh this PR based on the latest main branch |
🤖 Generated with AI assistance
|
Refreshed — merged latest main (napi→zapi rename, CI workflows, type_tag example). hello_world example is still TODO due to |
1 similar comment
|
Refreshed — merged latest main (napi→zapi rename, CI workflows, type_tag example). hello_world example is still TODO due to |
- Replace std.time.Timer with local Timer using std.c.clock_gettime - Replace std.time.sleep with std.c.nanosleep - Restore hello_world module, library, and test in build.zig - Fix b.modules.put to use b.allocator (Zig 0.16 API change) - Update minimum_zig_version to 0.16.0 - Update CI setup-env to use Zig 0.16.0 - Remove duplicate .zig-cache/ in .gitignore
Replace std.c.clock_gettime/nanosleep with std.Io.Timestamp and std.Io.sleep, using Io.Threaded.init_single_threaded for the Io instance in the NAPI callback context.
Remove module-level var and getIo() helper. Use the stdlib-provided global_single_threaded instance directly.
Per Zig author recommendation, prefer explicit one-time initialization over global_single_threaded for dynamically-loaded NAPI libraries.
The custom Timer struct was an unnecessary wrapper around Io.Timestamp. Use Io.Timestamp directly in the NAPI callbacks.
There was a problem hiding this comment.
Pull request overview
Upgrades this Zig N-API wrapper to be compatible with Zig 0.16, including updates to C interop patterns, C ABI callconv annotations, and build/CI configuration. Also updates the hello_world example to use std.Io APIs in place of std.time.
Changes:
- Switch C imports to
@import("c.zig").cand updatec.zigto exposepub const c = @cImport(...). - Replace
callconv(.C)withcallconv(.c)for C ABI callbacks. - Bump Zig toolchain requirements (build.zig.zon + GitHub Action) and adjust build script for Zig 0.16 API changes; update examples to
std.Io.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/value_types.zig | Update C import access via .c. |
| src/threadsafe_function.zig | Update C import access and C callconv to .c. |
| src/status.zig | Update C import access via .c. |
| src/root.zig | Re-export c as the @cImport result (.c). |
| src/module.zig | Update C import access and C callconv to .c for exported registration function. |
| src/finalize_callback.zig | Update C import access and finalize callback callconv to .c. |
| src/cleanup_hook.zig | Update C import access and hook callback callconv to .c. |
| src/callback_info.zig | Update C import access via .c. |
| src/callback.zig | Update C import access and callback callconv to .c. |
| src/c.zig | Change from usingnamespace @cImport to pub const c = @cImport(...). |
| src/async_work.zig | Update C import access and async callbacks callconv to .c. |
| src/async_cleanup_hook.zig | Update C import access and cleanup hook callconv to .c. |
| src/args.zig | Update C import access via .c. |
| src/Value.zig | Update C import access via .c. |
| src/Ref.zig | Update C import access via .c. |
| src/NodeVersion.zig | Update C import access via .c. |
| src/HandleScope.zig | Update C import access via .c. |
| src/EscapableHandleScope.zig | Update C import access via .c. |
| src/Env.zig | Update C import access via .c. |
| src/Deferred.zig | Update C import access via .c. |
| src/AsyncContext.zig | Update C import access via .c. |
| examples/hello_world/mod.zig | Migrate time usage to std.Io (Io.Timestamp, io().sleep). |
| build.zig.zon | Bump .minimum_zig_version to 0.16.0. |
| build.zig | Update build definitions for Zig 0.16 (modules map API + link_libc for zapi module). |
| .gitignore | Ignore zig-pkg/ directory. |
| .github/actions/setup-env/action.yml | Pin CI Zig version to 0.16.0. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Example modules reference NAPI symbols that are only available at runtime via Node.js. Running them as standalone zig tests causes linker errors. Keep them as individual test steps (test:example_hello_world, test:example_type_tag) but exclude from the global `zig build test`.
- Remove stale "generated by zbuild" comment from build.zig.zon - Update zbuild.zon minimum_zig_version to 0.16.0 - Add link_libc to zapi module in zbuild.zon for consistency with build.zig
Each thread (main, libuv worker, spawned) gets its own init_single_threaded instance, which is correct since init_single_threaded has no synchronization.
build.zig and build.zig.zon are generated by zbuild — keep the header so manual edits don't get silently overwritten on regeneration.
zapi only uses @cImport for NAPI C headers (stddef.h, stdint.h) which Zig provides natively. link_libc is only needed by the example dynamic libraries that load into Node.js at runtime.
4ccc9d8 to
fefb88e
Compare
Four of the five Zig-0.16-upgrade PRs on our dependency forks have merged into ChainSafe upstream main: * ChainSafe/blst.zig#4 → 6ad139a * ChainSafe/hashtree-z#10 → 56e406f * ChainSafe/snappy.zig#5 → 7139424 * ChainSafe/zig-yaml#1 → b74f4e8 Switch from `lodekeeper-z/<repo>?ref=chore/zig-master` to the merged commit on `ChainSafe/<repo>` main for each. Content is identical so the existing `hash` fields stay valid. `zapi` (ChainSafe/zapi#9) is still open upstream — bump the `lodekeeper-z/zapi` commit pointer to the current PR head (fefb88ebf5c9) which includes the latest port/refactor work; TODO note to switch to ChainSafe/zapi once ChainSafe#9 merges.
The merge with main brought in the js_dsl feature (ChainSafe#11) and a refactor of `src/root.zig` (napi symbols moved to `src/napi.zig`, re-exported via `pub usingnamespace`). All of that was written for 0.14.1 and hits several 0.16 breaking changes: * `b.modules.put(key, value)` → `b.modules.put(allocator, key, value)`. Two call sites in `build.zig` were missed by the previous update pass (the `napi` module and the `example_js_dsl` module). * `src/napi.zig` exported `pub const c = @import("c.zig")`, but every internal file accesses napi types through the inner `.c` namespace. Restore the `.c` on the import. * `pub usingnamespace` was removed in Zig 0.16. Replace it in `src/root.zig` with explicit `pub const foo = napi.foo;` re-exports. * `callconv(.C)` → `callconv(.c)` (6 NAPI callback shims in `src/js/wrap_class.zig` and `src/js/wrap_function.zig`). * `std.Thread.Mutex` → `std.Io.Mutex`. The DSL's per-class registry in `src/js/class_runtime.zig` needs a 0.16-compatible mutex, which requires an `Io`. The `Io` is threaded in through the DSL's entry point rather than letting zapi carry global state: - `js.exportModule` gains an optional `.io = fn () std.Io` field in `options`. The generated `moduleInit` calls it after the user's `options.init` hook and passes the result down into `registerDecls` → `class_runtime.registerClass`. If `.io` is omitted, a DSL-local `init_single_threaded` fallback keeps zero-config modules compiling. - `registerClass` caches the resolved `Io` in per-`T` `state(T).io`; `getConstructor`, `materializeClassInstance`, and `cleanupHook` all read from this cache because they execute inside napi C callbacks that can't receive user-provided `Io`. - Normal paths (`registerClass`, `getConstructor`) use cancelable `try mutex.lock(io)` so caller cancellation can propagate. - `cleanupHook` (a napi C callback with a fixed `(*Entry)` signature that cannot return errors) uses `lockUncancelable` deliberately — unwinding on cancel would leak the entry and hand napi a dangling pointer. * `Env` gains a `fromRaw(raw_env)` constructor so the 19 napi C callback sites don't all hand-roll the `Env{ .env = ... }` literal. `Env` itself stays a pure `napi_env` wrapper — no `io` field. After this commit `zig build` succeeds, and `zig build test` runs the 42 regular tests green. `example_js_dsl` has a separate, pre-existing link issue in `zig build test` (undefined `_napi_wrap` and friends, resolved by Node at runtime when loading the `.node` file) — orthogonal to the 0.16 migration.
fefb88e to
76dae72
Compare
|
@wemeetagain @nazarhussain @spiral-ladder need to check if current approach is good for injecting IO |
|
@GrapeBaBa @wemeetagain With this PR merged we will not have io dependency in the DSL, so no change would be needed. |
## Motivation Get the codebase cleanly compatible with **Zig 0.16.0** release, following the new "explicit `io` everywhere, no hidden global state" design — without changing runtime behavior. ## Description - **`std.Io`** — File/Dir operations, `Mutex`/`Condition`/`Event` (cancelable vs uncancelable split), entropy via `io.random`/`io.randomSecure`, timestamps via `std.Io.Timestamp` - **ArrayList unmanaged** — allocator threaded through `deinit`/`append`/`resize`/`ensureCapacity`/`clone`; replace `items.len = N` hacks with `resize` / `expandToCapacity` / `appendNTimesAssumeCapacity` (preserves semantics, matches `initCapacity`'s Precise allocation) - **Struct builder** — `@Type(.@"struct" = ...)` → `@Struct(names, types, attrs)` builtin in `ssz/type/container.zig` - **Copy-elision workaround** — `std.Io` 0.16 result-location semantics pre-write the union tag of the assignment target, so reads from `self.state.init_group.*` during RHS evaluation would observe the new variant. Snapshot pre-upgrade fields to locals in `state_transition.zig` fork-upgrade chain and `era/Writer.zig` - **ThreadPool** — `io` is a parameter on `init`/`deinit`/`verifyMultipleAggregateSignatures`/`aggregateVerify` (not a stored field); normal paths use cancelable `lock`; shutdown + `submitAndWait.done.wait` stay uncancelable with comments explaining the invariant - **Shared `src/time.zig`** — `timestampNow` / `since (Duration)` / `durationSeconds`, replacing four duplicated helper pairs across `state_transition` and `bench` - **IO signature convention** — `(allocator?, io, file, ...)` applied consistently to `e2s.*` and `era.*` - **Reader API polish** — `takeArray` (zero-copy) + `readSliceAll` where appropriate; drop single-buffer `readVecAll` and `catch |err| return err` - **Other**: `RefCount` comptime-reflect on wrapped T's deinit arity (1-arg vs 2-arg) so 0.16 unmanaged `ArrayList` and project types with stored allocators both work; `sanitize_c = .trap` on blst artifact so Debug fuzz builds link without `libubsan`; untrack 426 stale `test/fuzz/zig-pkg/` entries from the git index - **CI**: `ZIG_VERSION` bumped `0.14.1 → 0.16.0`; `zbuild` sync-check + `build-examples` jobs temporarily commented out pending upstream Zig 0.16 support ## Dependency PRs Each Zig 0.16 upgrade landed as a dedicated PR on the upstream repo. `build.zig.zon` points at `lodekeeper-z` forks on the `chore/zig-master` branch until these merge and cut releases: | Dependency | Upstream PR | |---|---| | `blst` | [ChainSafe/blst.zig#4](ChainSafe/blst.zig#4) | | `hashtree` | [ChainSafe/hashtree-z#10](ChainSafe/hashtree-z#10) | | `snappy` | [ChainSafe/snappy.zig#5](ChainSafe/snappy.zig#5) | | `yaml` | [ChainSafe/zig-yaml#1](ChainSafe/zig-yaml#1) | | `zapi` | [ChainSafe/zapi#9](ChainSafe/zapi#9) | | `httpz` (disabled) | [karlseguin/http.zig#191](karlseguin/http.zig#191) |
Replace the auto-generated 175-line build.zig + the deleted zbuild.zon CLI
mode with the new zbuild library-mode pattern: a 6-line wrapper invoking
`zbuild.configureBuild` over a manifest-driven build.zig.zon.
build.zig:
- shrunk from 175 lines to a wrapper that delegates to
`zbuild.configureBuild(b, @import("build.zig.zon"), .{})`.
- Post-processes the 3 example test artifacts to set
`linker_allow_shlib_undefined = true` (zbuild exposes this option only
for libraries, so we apply it post-hoc to tests that link against napi
C symbols Node provides at dlopen time).
build.zig.zon:
- Adds zbuild as a dependency (pinned to refactor/comptime-library-rewrite
@ 17c389b — same pin as lodestar-z `main`).
- Declares all modules / libraries / tests / options_modules in the
manifest; zbuild materializes them at build time.
- All build steps from the previous build.zig are preserved
(`build-lib:*`, `test:*`, `build-test:*`, `test`).
Verified: `zig build` clean, `zig build test` passes 42/42, all 3
`.node` files install correctly, `zig fmt --check` clean.
Bump zbuild to 7ec852f, which adds `linker_allow_shlib_undefined`
support for `tests` entries (previously only allowed in `libraries`).
This lets the example tests declare the flag directly in the manifest
instead of post-processing the test artifacts in build.zig:
build.zig: shrinks back to a 6-line wrapper (no post-hoc fixup loop).
build.zig.zon: 3 example test entries each set
`linker_allow_shlib_undefined = true`.
|
@lodekeeper-z Please resolve the conflicts. |
|
@copilot resolve the merge conflicts in this pull request |
|
Discussed with @GrapeBaBa the change will make this library not compatible with project using old version of zig so we are considering this a breaking change for this library to bump it's major version. |
Resolves conflicts from main's PR ChainSafe#20 (refactor: remove mutex/io dependency from the dsl) against the Zig 0.16 migration on this branch: - src/js/class_runtime.zig: take main's atomic spinlock; the std.Io.Mutex added during the 0.16 port is no longer needed. - Drop the now-dead `io` plumbing from exportModule, registerDecls, and the js_dsl example — main's intent was to keep the DSL Io-free, so the option, the panic, and the helper are removed end-to-end. - zbuild.zon: keep deleted (obsolete after the zbuild library-mode migration on this branch; release-please version info now lives in build.zig.zon).
Upgrade to Zig 0.16.0-dev (master) — part of the lodestar-z Zig master upgrade effort.
Key changes:
std.io→std.Iomigrationstd.Io.Dirmethods now require explicitioparameter🤖 Generated with AI assistance