Zig: Zig and Node.js N-API example

Created on 3 Aug 2019  路  3Comments  路  Source: ziglang/zig

Given Zig's promise of C header includes, it would be cool for the docs or blog to have an example of writing a "Hello Node.js" native addon for Node.js using N-API and Zig.

Node's N-API is fairly recent, and many existing native addons for Node written using Nan etc. are probably being ported. Now might be a great time for some of these native Node modules to consider using Zig instead of C/C++.

Most helpful comment

@andrewrk this issue is a good example use case for why we need the ability to support constructors. The workaround found is linux and elf specific.

All 3 comments

It seems like n-api requires that modules register themselves from constructors that run when their dll is opened. If you don't then node's process.dlopen fails with:

Error: Module did not self-register.

This issue will require a way to register a dynamic library constructor.


The code I was playing with:

// https://nodejs.org/api/n-api.html

const std = @import("std");

const napi = @cImport({
    @cInclude("node_api.h");
});

fn NAPI_MODULE_X(modname: []const u8, regfunc: napi.napi_addon_register_func, priv: ?*c_void, flags: c_uint) void {
    napi_module_register(&napi_module {
        .nm_version = napi.NAPI_MODULE_VERSION,
        .nm_flags = flags,
        .nm_filename = null,
        .nm_register_func = regfunc,
        .nm_modname = modname,
        .nm_priv = priv,
        .reserved = c_void(null) ** 4,
    });
}

fn NAPI_MODULE(modname: []const u8, regfunc: napi.napi_addon_register_func) void {
    return NAPI_MODULE_X(modname, regfunc, null, 0);
}

extern fn myfunc(env: napi.napi_env, exports: napi.napi_value) napi.napi_value {
    var answer: napi.napi_value = undefined;
    var status: napi.napi_status = undefined;

    status = napi.napi_create_int64(env, 42, &answer);
    if (status != .napi_ok) return null;

    status = napi.napi_set_named_property(env, exports, &"answer", answer);
    if (status != .napi_ok) return null;

    return exports;
}
comptime {
    @export("napi_register_module_v1", myfunc, .Strong);
}
zig build-lib -dynamic --library c -isystem /usr/include/node/ n-api.zig

I have managed to do exactly that thanks to the help of the nice zig people in freenode by doing that on linux:

export const init_array linksection(".init_array") = [_]extern fn () void {
  myFunc
};

@andrewrk this issue is a good example use case for why we need the ability to support constructors. The workaround found is linux and elf specific.

Was this page helpful?
0 / 5 - 0 ratings