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.
There was a problem hiding this comment.
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.
|
|
||
| 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); |
There was a problem hiding this comment.
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.
| 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); |
|
|
||
| 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); |
There was a problem hiding this comment.
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.
| 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); |
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.
|
@copilot resolve the merge conflicts in this pull request |
# Conflicts: # .gitignore # src/root.zig
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 |
| 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"); |
There was a problem hiding this comment.
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.
| /// ```zig | ||
| /// comptime { | ||
| /// // Basic export of all `pub` functions, classes, and sub-namespaces | ||
| /// js.exportModule(@This()); |
There was a problem hiding this comment.
We need to update all the examples, as io is a required attribute now.
| /// The DSL internally manages an atomic refcount for module instances across | ||
| /// different N-API environments. | ||
| /// | ||
| /// Usage Examples: |
There was a problem hiding this comment.
Along with these examples, need to update the examples in README as well.
|
@GrapeBaBa @wemeetagain With this PR merged we will not have io dependency in the DSL, so no change would be needed. |
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