Skip to content

chore: upgrade to Zig 0.16.0#9

Open
lodekeeper-z wants to merge 18 commits intoChainSafe:mainfrom
lodekeeper-z:chore/zig-master
Open

chore: upgrade to Zig 0.16.0#9
lodekeeper-z wants to merge 18 commits intoChainSafe:mainfrom
lodekeeper-z:chore/zig-master

Conversation

@lodekeeper-z
Copy link
Copy Markdown

Upgrade to Zig 0.16.0-dev (master) — part of the lodestar-z Zig master upgrade effort.

Key changes:

  • std.iostd.Io migration
  • std.Io.Dir methods now require explicit io parameter
  • Build system changes for 0.16 compatibility

🤖 Generated with AI assistance

- 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
@wemeetagain wemeetagain marked this pull request as ready for review March 19, 2026 19:59
@wemeetagain wemeetagain marked this pull request as draft March 19, 2026 19:59
@wemeetagain
Copy link
Copy Markdown
Member

@lodekeeper-z please refresh this PR based on the latest main branch

…r callbacks)

Updates examples to match new wrap() signature from ChainSafe#10 (added ref parameter).

🤖 Generated with AI assistance
@lodekeeper-z
Copy link
Copy Markdown
Author

Refreshed against latest main — merged in #10 (Ref refactor), #8 (raw variant functions), and #5 (safer callbacks). Updated the type_tag and hello_world examples to match the new wrap() signature (added ref parameter).

Note: the type_tag example has a linker issue (undefined NAPI symbols) that's pre-existing from upstream — it was introduced when #7 and #10 were merged without updating the example's wrap() call site. Our branch now fixes that compilation error, but the example still can't link standalone (needs to run as a Node addon).

@nazarhussain
Copy link
Copy Markdown
Contributor

@lodekeeper-z please refresh this PR based on the latest main branch

@lodekeeper-z
Copy link
Copy Markdown
Author

Refreshed — merged latest main (napi→zapi rename, CI workflows, type_tag example). hello_world example is still TODO due to std.time.Timer/std.Io migration in 0.16.

1 similar comment
@lodekeeper-z
Copy link
Copy Markdown
Author

Refreshed — merged latest main (napi→zapi rename, CI workflows, type_tag example). hello_world example is still TODO due to std.time.Timer/std.Io migration in 0.16.

- 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.
@GrapeBaBa GrapeBaBa marked this pull request as ready for review April 17, 2026 05:00
Copilot AI review requested due to automatic review settings April 17, 2026 05:00
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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").c and update c.zig to expose pub const c = @cImport(...).
  • Replace callconv(.C) with callconv(.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.

Comment thread build.zig.zon
Comment thread build.zig
Comment thread .github/actions/setup-env/action.yml
Comment thread examples/hello_world/mod.zig Outdated
Comment thread build.zig
@GrapeBaBa GrapeBaBa changed the title chore: upgrade to Zig 0.16.0-dev (master) chore: upgrade to Zig 0.16.0 Apr 17, 2026
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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread build.zig

const run_test_example_hello_world = b.addRunArtifact(test_example_hello_world);
const tls_run_test_example_hello_world = b.step("test:example_hello_world", "Run the example_hello_world test");
tls_run_test_example_hello_world.dependOn(&run_test_example_hello_world.step);
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aggregate test step (tls_run_test) no longer depends on this example’s test run artifact, so zig build test will skip example_hello_world unless the dedicated test:example_hello_world step is invoked. Re-add tls_run_test.dependOn(&run_test_example_hello_world.step) so the top-level test step runs this test too.

Suggested change
tls_run_test_example_hello_world.dependOn(&run_test_example_hello_world.step);
tls_run_test_example_hello_world.dependOn(&run_test_example_hello_world.step);
tls_run_test.dependOn(&run_test_example_hello_world.step);

Copilot uses AI. Check for mistakes.
Comment thread build.zig

const run_test_example_type_tag = b.addRunArtifact(test_example_type_tag);
const tls_run_test_example_type_tag = b.step("test:example_type_tag", "Run the example_type_tag test");
tls_run_test_example_type_tag.dependOn(&run_test_example_type_tag.step);
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aggregate test step (tls_run_test) no longer depends on this example’s test run artifact, so zig build test will skip example_type_tag unless the dedicated test:example_type_tag step is invoked. Re-add tls_run_test.dependOn(&run_test_example_type_tag.step) so the top-level test step runs this test too.

Suggested change
tls_run_test_example_type_tag.dependOn(&run_test_example_type_tag.step);
tls_run_test_example_type_tag.dependOn(&run_test_example_type_tag.step);
tls_run_test.dependOn(&run_test_example_type_tag.step);

Copilot uses AI. Check for mistakes.
The threadlocal `init_single_threaded` instance was defensively scoped
per thread on the theory that cross-thread sharing of a single-threaded
Threaded could race. In practice stdlib already provides
`std.Io.Threaded.global_single_threaded` for exactly this scenario:

> In some cases such as debugging, it is desirable to hardcode a
> reference to this `Io` implementation.

It's a single process-wide instance, and — importantly — the only ops
this example uses (`Timestamp.now`, `random`, etc.) bottom out in OS
calls that don't touch the `Threaded` struct's internal mutable state,
so one shared instance is safe for this use case.

This removes the `threadlocal var` declaration entirely, matching the
stdlib-recommended pattern for examples.
@GrapeBaBa
Copy link
Copy Markdown

@copilot resolve the merge conflicts in this pull request

@GrapeBaBa GrapeBaBa force-pushed the chore/zig-master branch 14 times, most recently from 4ccc9d8 to fefb88e Compare April 21, 2026 05:06
GrapeBaBa added a commit to GrapeBaBa/state-transition-z that referenced this pull request Apr 21, 2026
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.
@GrapeBaBa
Copy link
Copy Markdown

@wemeetagain @nazarhussain @spiral-ladder need to check if current approach is good for injecting IO

Copy link
Copy Markdown
Contributor

@nazarhussain nazarhussain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the DSL point of view, let me rethink why we need io for a comptime layer. The only usage we have for class constructor list, might be avoided with some other pattern. I will get back to it.

Comment thread src/js/export_module.zig
const has_init = @hasField(@TypeOf(options), "init");
const has_cleanup = @hasField(@TypeOf(options), "cleanup");
const has_register = @hasField(@TypeOf(options), "register");
const has_io = @hasField(@TypeOf(options), "io");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it's changing the public facing API, so should be considered a breaking change. Let's add a ! in PR title so release-please can handle rest.

Comment thread src/js/export_module.zig
/// ```zig
/// comptime {
/// // Basic export of all `pub` functions, classes, and sub-namespaces
/// js.exportModule(@This());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update all the examples, as io is a required attribute now.

Comment thread src/js/export_module.zig
/// The DSL internally manages an atomic refcount for module instances across
/// different N-API environments.
///
/// Usage Examples:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Along with these examples, need to update the examples in README as well.

@nazarhussain
Copy link
Copy Markdown
Contributor

nazarhussain commented Apr 22, 2026

@GrapeBaBa @wemeetagain With this PR merged we will not have io dependency in the DSL, so no change would be needed.
#20

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.

5 participants