@gjsify/napi 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -0
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/types/index.d.ts +25 -0
- package/meson.build +126 -0
- package/package.json +100 -0
- package/prebuilds/linux-x86_64/GjsifyNapi-1.0.gir +19 -0
- package/prebuilds/linux-x86_64/GjsifyNapi-1.0.typelib +0 -0
- package/prebuilds/linux-x86_64/libgjsifynapi.so +0 -0
- package/src/cc/arraybuffer.cc +772 -0
- package/src/cc/async_work.cc +439 -0
- package/src/cc/common.h +519 -0
- package/src/cc/env.cc +262 -0
- package/src/cc/error.cc +300 -0
- package/src/cc/function.cc +358 -0
- package/src/cc/module.cc +625 -0
- package/src/cc/napi.def +22 -0
- package/src/cc/napi.export.map +16 -0
- package/src/cc/napi.exported-symbols.txt +15 -0
- package/src/cc/object.cc +728 -0
- package/src/cc/ref.cc +510 -0
- package/src/cc/stubs.cc +100 -0
- package/src/cc/tsfn.cc +602 -0
- package/src/cc/value.cc +656 -0
- package/src/cc/wrap.cc +321 -0
- package/src/napi-headers/js_native_api.h +639 -0
- package/src/napi-headers/js_native_api_types.h +249 -0
- package/src/napi-headers/node_api.h +270 -0
- package/src/napi-headers/node_api_types.h +63 -0
- package/src/vala/gjs-1.0.vapi +6 -0
- package/src/vala/mozjs-140.vapi +6 -0
- package/src/vala/napi.vala +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# @gjsify/napi
|
|
2
|
+
|
|
3
|
+
**Node-API (N-API) host for GJS** — implements the Node-API C ABI over GJS's
|
|
4
|
+
SpiderMonkey (mozjs-140) so GJS can load unmodified compiled `.node` addons.
|
|
5
|
+
|
|
6
|
+
It is the forward mirror of [`@gjsify/node-gi`](../../node-gi/node-gi) ("GI in
|
|
7
|
+
Node"): where node-gi runs GObject-Introspection code IN Node via Node's N-API,
|
|
8
|
+
this runs Node's **N-API `.node` addons IN GJS** ("N-API in GJS"). A consumer
|
|
9
|
+
addon built with stock `node-gyp` — including its bundled native code — loads and
|
|
10
|
+
runs inside GJS byte-identically to Node (see the gjsify `AGENTS.md`
|
|
11
|
+
`### N-API host in GJS`).
|
|
12
|
+
|
|
13
|
+
> **Status: experimental (Tier 3 — [ADR 0011](../../../docs/adr/0011-napi-host-in-gjs.md)).**
|
|
14
|
+
> No stability promise; new axes start here. **Phase 0 is complete:** the full
|
|
15
|
+
> `js_native_api.h` surface + the module loader/version/fatal bits are
|
|
16
|
+
> implemented; the async / threadsafe-function / event-loop group of
|
|
17
|
+
> `node_api.h` is intentionally loud-stubbed and deferred. First consumer:
|
|
18
|
+
> **better-sqlite3 v13.0.1 (incl. its bundled SQLite) runs unmodified, byte-identical
|
|
19
|
+
> to Node**, valgrind-clean. Conformance oracle (node's own `js-native-api`
|
|
20
|
+
> addons, golden-diff vs Node): **13 pass / 8 Phase-0-deferred ledgered / 0 fail**.
|
|
21
|
+
|
|
22
|
+
## How it works
|
|
23
|
+
|
|
24
|
+
Packaged like the `@gjsify/*-native` bridges (`@gjsify/tls-native`): meson builds
|
|
25
|
+
a thin Vala GI surface (`GjsifyNapi.init()`) plus the C++ napi-over-mozjs-140
|
|
26
|
+
implementation into ONE `.so` + `.gir` + `.typelib`, loaded from GJS via
|
|
27
|
+
`imports.gi`. `init()` reaches the running `JSContext`
|
|
28
|
+
(`gjs_context_get_current` / `gjs_context_get_native_context`) and installs one
|
|
29
|
+
JSNative, `loadAddon(path)`; thereafter the addon's `exports` is a normal JS
|
|
30
|
+
return value and load failures are normal JS exceptions. `napi_value` is a
|
|
31
|
+
GC-traced `JS::Heap<JS::Value>` arena slot (SpiderMonkey's moving GC forbids the
|
|
32
|
+
raw-boxed-value trick and `JS::Rooted` scopes). The shim `dlopen`s the addon
|
|
33
|
+
`RTLD_LOCAL` and self-promotes its own `napi_*` / `node_api_*` into global scope,
|
|
34
|
+
so an addon's undefined napi symbols bind to ours — exactly as Node/Bun export
|
|
35
|
+
the ABI from the main binary, which is why **consumers need no special build**.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
gjsify install @gjsify/napi
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Published on the `@gjsify/*` release train. The tarball ships the shim
|
|
44
|
+
**prebuilt** for the platforms in [Platforms](#platforms) below —
|
|
45
|
+
`prebuilds/linux-x86_64/` and `prebuilds/darwin-arm64/`, each a `.so`/`.dylib`
|
|
46
|
+
plus its `.gir` and `.typelib`, rebuilt from the released source by the
|
|
47
|
+
`napi-prebuild-*` jobs in `.github/workflows/release.yml` — so an install brings
|
|
48
|
+
the shim itself, not just a build recipe. Installing through the `gjsify` CLI
|
|
49
|
+
puts the prebuild dir on `GI_TYPELIB_PATH`/`LD_LIBRARY_PATH` for you.
|
|
50
|
+
|
|
51
|
+
The tarball ALSO ships the build inputs (`meson.build`, `src/vala`, `src/cc`,
|
|
52
|
+
`src/napi-headers`), so on a platform with no prebuild — or against a GJS built
|
|
53
|
+
on a different SpiderMonkey major (see [the mozjs-140 pin](#the-mozjs-140-pin))
|
|
54
|
+
— you can rebuild in place: `cd node_modules/@gjsify/napi && meson setup build .
|
|
55
|
+
&& meson compile -C build`, then point `GI_TYPELIB_PATH` (plus
|
|
56
|
+
`LD_LIBRARY_PATH`, or `DYLD_LIBRARY_PATH` on macOS) at `build/`. See
|
|
57
|
+
[Requirements](#requirements) for the toolchain that needs.
|
|
58
|
+
|
|
59
|
+
## Usage — transparent (primary)
|
|
60
|
+
|
|
61
|
+
After `gjsify install @gjsify/napi`, a normal native-addon import **just works**
|
|
62
|
+
in a `gjsify build --app gjs` build — no wrapper, no manual `loadAddon`:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import Database from 'better-sqlite3'; // require('bufferutil') / etc.
|
|
66
|
+
|
|
67
|
+
const db = new Database(':memory:');
|
|
68
|
+
db.exec('CREATE TABLE t (n INT)');
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The `napiNodeAddonPlugin` in `@gjsify/rolldown-plugin-gjsify` (the forward mirror
|
|
72
|
+
of the `gjsGiNodePlugin` `gi://`→`requireGi` rewrite) intercepts the addon's own
|
|
73
|
+
acquisition helper — `bindings`, `node-gyp-build`, a direct `.node` import, a
|
|
74
|
+
napi-rs `@scope/pkg-<triple>` platform sibling, or a napi-rs **generated loader
|
|
75
|
+
entry** (`@node-rs/*`) — and rewrites it to `loadAddon('<abs .node>')`. For the
|
|
76
|
+
node-gyp-build/bindings case it locates the compiled `.node` using
|
|
77
|
+
node-gyp-build's own probe order (`build/Release` → `build/Debug` →
|
|
78
|
+
`prebuilds/<platform>-<arch>`), so the GJS build routes the SAME binary Node
|
|
79
|
+
loads; for a napi-rs package it detects the generated loader (package.json
|
|
80
|
+
`napi`/optionalDependencies signal + native-`main` match) and replaces the whole
|
|
81
|
+
module with `module.exports = loadAddon(<current-platform sibling .node>)`, so the
|
|
82
|
+
generated `createRequire` loader body never reaches the bundle. Always-on for
|
|
83
|
+
`--app gjs`, inert when no native addon is in the graph.
|
|
84
|
+
|
|
85
|
+
**Escape hatch — explicit `loadAddon`.** When you want to load a `.node` by an
|
|
86
|
+
arbitrary runtime path (not a static import), call it directly:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { loadAddon, hasNapi } from '@gjsify/napi';
|
|
90
|
+
|
|
91
|
+
if (hasNapi()) {
|
|
92
|
+
const addon = loadAddon('/abs/path/to/build/Release/addon.node');
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
All four addon conventions — node-gyp-build, bindings, a direct `.node`, and
|
|
97
|
+
napi-rs generated loaders (`@node-rs/*`) — are transparent; the explicit
|
|
98
|
+
`loadAddon` escape hatch remains for loading a `.node` by an arbitrary runtime
|
|
99
|
+
path.
|
|
100
|
+
|
|
101
|
+
## Requirements
|
|
102
|
+
|
|
103
|
+
- A C++ toolchain (`g++`/`clang`), `meson`, `vala`, `g-ir-compiler`
|
|
104
|
+
- Development headers for `glib-2.0`, `gobject-2.0`, `gio-2.0`, **`gjs-1.0`** and
|
|
105
|
+
**`mozjs-140`**
|
|
106
|
+
- Fedora: `gjs-devel mozjs140-devel glib2-devel gobject-introspection-devel
|
|
107
|
+
vala meson gcc-c++`
|
|
108
|
+
- macOS (Homebrew): `brew install gjs gobject-introspection vala meson ninja
|
|
109
|
+
pkgconf` — `gjs` pulls `spidermonkey` (mozjs-140) transitively, the SAME
|
|
110
|
+
pairing Fedora pins (gjs 1.88.x ↔ mozjs-140)
|
|
111
|
+
- Node.js + `node-gyp` to build the test/consumer addons (`.node` files)
|
|
112
|
+
|
|
113
|
+
## Platforms
|
|
114
|
+
|
|
115
|
+
Ships as a prebuilt `.dylib`/`.so` + `.gir` + `.typelib` per platform. Both
|
|
116
|
+
supported triples are rebuilt on their own native runner for every release
|
|
117
|
+
(`napi-prebuild-linux` / `napi-prebuild-darwin-arm64` in `release.yml`) and
|
|
118
|
+
staged into the one published tarball, so a single `@gjsify/napi` version serves
|
|
119
|
+
both:
|
|
120
|
+
|
|
121
|
+
| Platform | Prebuild dir | Status |
|
|
122
|
+
| --- | --- | --- |
|
|
123
|
+
| Linux x86_64 | `prebuilds/linux-x86_64/` | Supported (full gate + conformance + consumer CI) |
|
|
124
|
+
| macOS arm64 | `prebuilds/darwin-arm64/` | Supported (build + load + P0.x value-model + **P1 tsfn** gates); the earlier tsfn exit-segfault (a UAF — the tsfn was freed while foreign claimants still held claims) is **fixed** (join-before-free, both abort + teardown paths); conformance/consumer/valgrind widening deferred |
|
|
125
|
+
| Windows x64 | — | **Attempted, blocked at gjs-on-Windows** (shim-side portability done; see below) |
|
|
126
|
+
|
|
127
|
+
**Windows is attempted, blocked at gjs-on-Windows.** The shim-side portability
|
|
128
|
+
is complete and Linux-verified: `meson.build` has a `windows` branch (a `.def`
|
|
129
|
+
EXPORTS file — MSVC `link.exe` takes no globs — plus the `gjsifynapi.dll` leaf
|
|
130
|
+
and MSVC-syntax cpp_args), and `src/cc/module.cc`'s POSIX `dlfcn` loader is
|
|
131
|
+
`#ifdef _WIN32`-ported to `LoadLibraryEx`/`GetProcAddress`/`GetModuleHandleEx`.
|
|
132
|
+
A manual-dispatch (`workflow_dispatch`) `windows` job in `napi.yml` drives the
|
|
133
|
+
from-source attempt. **Re-checking the blocker harder overturned one half:** a
|
|
134
|
+
prebuilt MSVC-ABI **mozjs-140 now exists** — `servo/mozjs` ships
|
|
135
|
+
`libmozjs-x86_64-pc-windows-msvc` at `mozjs-sys-v140.13.0-0` (SpiderMonkey ESR
|
|
136
|
+
140.13). **The remaining wall is `libgjs` itself:** no prebuilt libgjs exists for
|
|
137
|
+
Windows (gvsbuild has no gjs/spidermonkey module, GNOME/gjs CI is Linux-only),
|
|
138
|
+
and the servo prebuilt is a patched Rust static-lib layout, not the pkg-config
|
|
139
|
+
`mozjs-140` gjs's meson wants — so gjs must still be source-built with clang-cl.
|
|
140
|
+
A **second wall** waits behind it: an unmodified node-gyp `.node` on Windows
|
|
141
|
+
binds `napi_*` via a delay-load hook against the host `.exe`, which `gjs.exe`
|
|
142
|
+
does not export (there is no POSIX global-namespace self-promotion analog). See
|
|
143
|
+
`STATUS.md` → *N-API host in GJS* → cross-platform prebuilds. This is the key
|
|
144
|
+
difference from [`@gjsify/node-gi`](../../node-gi/node-gi), which links the
|
|
145
|
+
portable girepository stack and so runs on all three OSes.
|
|
146
|
+
|
|
147
|
+
## Build
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
meson setup build . # or: gjsify run init:meson
|
|
151
|
+
meson compile -C build # builds libgjsifynapi.so + GjsifyNapi-1.0.{gir,typelib}
|
|
152
|
+
|
|
153
|
+
# stage the prebuild the loader/gates resolve from:
|
|
154
|
+
gjsify run build:prebuilds # meson build + copy into prebuilds/linux-x86_64/
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Test
|
|
158
|
+
|
|
159
|
+
The gates, conformance oracle and consumer proof all load the addon through the
|
|
160
|
+
staged shim, with `GI_TYPELIB_PATH`/`LD_LIBRARY_PATH` pointed at `build/`. Build
|
|
161
|
+
the addons first, then run the legs:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
gjsify run build:test-addons # node-gyp rebuild of test/*-addon/*.node
|
|
165
|
+
|
|
166
|
+
gjsify run test:gate # smoke: load a minimal addon under gjs
|
|
167
|
+
gjsify run test:gate:p01 # env + value model + scopes
|
|
168
|
+
gjsify run test:gate:p02 # js_native_api core
|
|
169
|
+
gjsify run test:gate:p03 # wrap + lifetime
|
|
170
|
+
gjsify run test:mem # valgrind leak/UAF leg for the gates
|
|
171
|
+
|
|
172
|
+
gjsify run test:conformance # golden-diff vs Node over node's js-native-api addons
|
|
173
|
+
gjsify run test:consumer # better-sqlite3 v13.0.1 runs on GJS, byte-vs-Node
|
|
174
|
+
|
|
175
|
+
gjsify run test:addons:setup # vendor + source-build the real-addon matrix
|
|
176
|
+
gjsify run test:addons # pinned baseline: loadAddon({addonPath}), byte-vs-Node
|
|
177
|
+
gjsify run test:addons:transparent # transparent: napiNodeAddonPlugin auto-resolves, byte-vs-Node
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`test:addons:transparent` is the end-to-end proof of the transparent path: it
|
|
181
|
+
builds each real addon `--app gjs` through `napiNodeAddonPlugin`'s
|
|
182
|
+
auto-resolution (no hand-pinned addonPath) and requires byte-identical output vs
|
|
183
|
+
Node. All four pass byte-identical: bufferutil + utf-8-validate (node-gyp-build),
|
|
184
|
+
sqlite3 (bindings), and `@node-rs/argon2` (napi-rs generated-loader
|
|
185
|
+
entry-replacement).
|
|
186
|
+
|
|
187
|
+
`gjsify run test:conformance:update` regenerates the golden files;
|
|
188
|
+
`conformance/ledger.json` records each Phase-0-deferred program with a precise
|
|
189
|
+
reason (an unlisted failure fails the harness; a listed program that starts
|
|
190
|
+
passing also fails — stale entry). `test:conformance:mem` / `test:consumer:mem`
|
|
191
|
+
are the valgrind variants.
|
|
192
|
+
|
|
193
|
+
## The mozjs-140 pin
|
|
194
|
+
|
|
195
|
+
The pin is intrinsic and by design: the **shim** links GJS's SpiderMonkey (built
|
|
196
|
+
`-fno-rtti -fno-exceptions`, matching GJS) and must be rebuilt when GJS bumps its
|
|
197
|
+
mozjs major — mozjs has no stable C++ ABI. The **addon** is untouched by mozjs
|
|
198
|
+
churn: it speaks only the stable napi C ABI. That asymmetry is the whole point.
|
|
199
|
+
|
|
200
|
+
## License
|
|
201
|
+
|
|
202
|
+
MIT. See [ADR 0011](../../../docs/adr/0011-napi-host-in-gjs.md) for the full
|
|
203
|
+
rationale, alternatives, and consequences.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});export{__name};
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";let e=null;const t=globalThis.imports?.gi;if(t)try{e=t.GjsifyNapi}catch{}const n=e;function hasNapi(){return e!==null}let r=null;function ensureInstalled(){if(r)return r;if(!e)throw Error(`@gjsify/napi: native typelib not loaded. Check hasNapi() first.`);if(!e.init())throw Error(`@gjsify/napi: GjsifyNapi.init() failed — no running GJS JSContext.`);let t=globalThis,n=t.__gjsifyNapiLoadAddon;if(typeof n!=`function`)throw Error(`@gjsify/napi: bootstrap native __gjsifyNapiLoadAddon was not installed.`);return delete t.__gjsifyNapiLoadAddon,r=n,n}function loadAddon(e){return ensureInstalled()(e)}export{hasNapi,loadAddon,n as nativeNapi};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Introspected shape of the `GjsifyNapi` GI namespace (GjsifyNapi-1.0.gir). */
|
|
2
|
+
export interface GjsifyNapiModule {
|
|
3
|
+
/**
|
|
4
|
+
* Install the N-API host into the running GJS context. Idempotent.
|
|
5
|
+
* Returns `false` when there is no current GjsContext/JSContext.
|
|
6
|
+
*/
|
|
7
|
+
init(): boolean;
|
|
8
|
+
/** Probe that the native typelib is loaded. */
|
|
9
|
+
is_available(): boolean;
|
|
10
|
+
}
|
|
11
|
+
/** The native GjsifyNapi module, or `null` if not installed. */
|
|
12
|
+
export declare const nativeNapi: GjsifyNapiModule | null;
|
|
13
|
+
/** Returns `true` when the GjsifyNapi native shim is available. */
|
|
14
|
+
export declare function hasNapi(): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Load a compiled Node-API addon (`.node`) into the running GJS context.
|
|
17
|
+
*
|
|
18
|
+
* The addon must be a pure Node-API module (e.g. a stock node-gyp build);
|
|
19
|
+
* legacy NAN/V8 addons are rejected with a clear error. A second load of the
|
|
20
|
+
* same (real)path returns the cached `exports` object.
|
|
21
|
+
*
|
|
22
|
+
* @param path Filesystem path to the `.node` shared object.
|
|
23
|
+
* @returns The addon's `exports` object.
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadAddon(path: string): Record<string, unknown>;
|
package/meson.build
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# @gjsify/napi — N-API host shim over GJS's SpiderMonkey (mozjs-140).
|
|
3
|
+
# Mirrors the @gjsify/tls-native meson pipeline: Vala (GI surface) + native
|
|
4
|
+
# code compiled into ONE shared library + GIR + typelib. The native part here
|
|
5
|
+
# is C++ (JSAPI is C++); the shim is intrinsically pinned to GJS's mozjs
|
|
6
|
+
# major and must be rebuilt when GJS bumps (ADR 0011).
|
|
7
|
+
project('GjsifyNapi', ['c', 'cpp', 'vala'],
|
|
8
|
+
version: '1.0',
|
|
9
|
+
# Match GJS's own build (refs/gjs/meson.build): C++17, no RTTI, no
|
|
10
|
+
# exceptions — mozjs-140 has no stable C++ ABI and is built the same way.
|
|
11
|
+
default_options: ['cpp_std=c++17'])
|
|
12
|
+
|
|
13
|
+
dependencies = [
|
|
14
|
+
dependency('glib-2.0'),
|
|
15
|
+
dependency('gobject-2.0'),
|
|
16
|
+
dependency('gio-2.0'),
|
|
17
|
+
dependency('gjs-1.0'), # gjs_context_get_current / get_native_context
|
|
18
|
+
dependency('mozjs-140'), # JSAPI
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
cc = meson.get_compiler('c')
|
|
22
|
+
dl_dep = cc.find_library('dl', required: false) # dlopen/dlsym/dladdr
|
|
23
|
+
if dl_dep.found()
|
|
24
|
+
dependencies += dl_dep
|
|
25
|
+
endif
|
|
26
|
+
|
|
27
|
+
vala_sources = files(
|
|
28
|
+
'src/vala/napi.vala',
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# node-gi TU-split idiom: one common.h owning cross-TU decls, functional
|
|
32
|
+
# .cc slices. The vendored Node-API headers live in src/napi-headers/.
|
|
33
|
+
cc_sources = files(
|
|
34
|
+
'src/cc/arraybuffer.cc',
|
|
35
|
+
'src/cc/async_work.cc',
|
|
36
|
+
'src/cc/env.cc',
|
|
37
|
+
'src/cc/error.cc',
|
|
38
|
+
'src/cc/function.cc',
|
|
39
|
+
'src/cc/module.cc',
|
|
40
|
+
'src/cc/object.cc',
|
|
41
|
+
'src/cc/ref.cc',
|
|
42
|
+
'src/cc/stubs.cc',
|
|
43
|
+
'src/cc/tsfn.cc',
|
|
44
|
+
'src/cc/value.cc',
|
|
45
|
+
'src/cc/wrap.cc',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# §3b export hygiene: only napi_*/node_api_* (the ABI) + gjsify_napi_* (the
|
|
49
|
+
# GI/Vala surface) are visible; everything else is local. The mechanism is
|
|
50
|
+
# linker-specific, so branch on the host toolchain:
|
|
51
|
+
# - GNU ld / lld (Linux): --version-script (glob patterns, ABI-only export)
|
|
52
|
+
# - ld64 (macOS): -exported_symbols_list (leading-underscore globs)
|
|
53
|
+
# - MSVC link.exe / lld-link (Windows): a .def EXPORTS file (no glob support).
|
|
54
|
+
# On Windows the napi_*/node_api_* ABI is already exported via the vendored
|
|
55
|
+
# headers' __declspec(dllexport) (js_native_api.h NAPI_EXTERN on _WIN32), and
|
|
56
|
+
# MSVC hides every non-dllexport symbol by DEFAULT — so the .def only has to add
|
|
57
|
+
# the Vala GI surface (gjsify_napi_init/is_available/install) that g_module
|
|
58
|
+
# resolves from the typelib. That closes the same hygiene contract the
|
|
59
|
+
# version-script/exported-symbols-list enforce elsewhere. The Windows build
|
|
60
|
+
# still requires a from-source gjs + mozjs-140 toolchain (clang-cl/MSVC; see
|
|
61
|
+
# STATUS.md "N-API host in GJS" cross-platform prebuilds + the `windows` job in
|
|
62
|
+
# napi.yml) — mozjs-140 is now obtainable (servo/mozjs prebuilt
|
|
63
|
+
# libmozjs-x86_64-pc-windows-msvc), the open wall is gjs-on-Windows itself.
|
|
64
|
+
host_system = host_machine.system()
|
|
65
|
+
if host_system == 'darwin'
|
|
66
|
+
export_symbols = meson.current_source_dir() / 'src/cc/napi.exported-symbols.txt'
|
|
67
|
+
export_link_args = ['-Wl,-exported_symbols_list,' + export_symbols]
|
|
68
|
+
export_link_depends = files('src/cc/napi.exported-symbols.txt')
|
|
69
|
+
# meson names the shared library libgjsifynapi.dylib on macOS; the typelib
|
|
70
|
+
# must record that exact leaf so gjs' g_module_open resolves it at load.
|
|
71
|
+
shared_lib_name = 'libgjsifynapi.dylib'
|
|
72
|
+
elif host_system == 'windows'
|
|
73
|
+
# MSVC/clang-cl consume /DEF:<file>; the DLL has no `lib` prefix, so the
|
|
74
|
+
# typelib must record `gjsifynapi.dll` as the leaf g_module_open resolves.
|
|
75
|
+
def_file = meson.current_source_dir() / 'src/cc/napi.def'
|
|
76
|
+
export_link_args = ['/DEF:' + def_file]
|
|
77
|
+
export_link_depends = files('src/cc/napi.def')
|
|
78
|
+
shared_lib_name = 'gjsifynapi.dll'
|
|
79
|
+
else
|
|
80
|
+
version_script = meson.current_source_dir() / 'src/cc/napi.export.map'
|
|
81
|
+
export_link_args = ['-Wl,--version-script,' + version_script]
|
|
82
|
+
export_link_depends = files('src/cc/napi.export.map')
|
|
83
|
+
shared_lib_name = 'libgjsifynapi.so'
|
|
84
|
+
endif
|
|
85
|
+
|
|
86
|
+
# GJS/mozjs-140 are built C++17, no RTTI, no exceptions (mozjs has no stable
|
|
87
|
+
# C++ ABI and is built the same way — ADR 0011). Spell that per argument syntax
|
|
88
|
+
# so the shim matches on every toolchain: GNU/Clang take -fno-*, MSVC/clang-cl
|
|
89
|
+
# take /GR- (no RTTI) and default to no C++ exceptions (no /EHsc).
|
|
90
|
+
cpp = meson.get_compiler('cpp')
|
|
91
|
+
if cpp.get_argument_syntax() == 'msvc'
|
|
92
|
+
shim_cpp_args = ['/GR-']
|
|
93
|
+
else
|
|
94
|
+
shim_cpp_args = ['-fno-rtti', '-fno-exceptions']
|
|
95
|
+
endif
|
|
96
|
+
|
|
97
|
+
libGjsifyNapi = library('gjsifynapi', vala_sources + cc_sources,
|
|
98
|
+
dependencies: dependencies,
|
|
99
|
+
include_directories: include_directories('src/napi-headers'),
|
|
100
|
+
cpp_args: shim_cpp_args,
|
|
101
|
+
# Stub vapis for the C++-only deps (mozjs-140, gjs-1.0): meson forwards
|
|
102
|
+
# every dependency() to valac as --pkg; Vala itself never uses them.
|
|
103
|
+
vala_args: [
|
|
104
|
+
'--vapidir=' + meson.current_source_dir() / 'src/vala',
|
|
105
|
+
],
|
|
106
|
+
link_args: export_link_args,
|
|
107
|
+
link_depends: export_link_depends,
|
|
108
|
+
vala_gir: meson.project_name() + '-1.0.gir',
|
|
109
|
+
install: true,
|
|
110
|
+
install_dir: [true, true, true, true],
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
g_ir_compiler = find_program('g-ir-compiler')
|
|
114
|
+
|
|
115
|
+
custom_target(meson.project_name() + '-1.0.typelib',
|
|
116
|
+
command: [
|
|
117
|
+
g_ir_compiler,
|
|
118
|
+
'--shared-library', shared_lib_name,
|
|
119
|
+
'--output', '@OUTPUT@',
|
|
120
|
+
meson.current_build_dir() / meson.project_name() + '-1.0.gir',
|
|
121
|
+
],
|
|
122
|
+
output: meson.project_name() + '-1.0.typelib',
|
|
123
|
+
depends: libGjsifyNapi,
|
|
124
|
+
install: true,
|
|
125
|
+
install_dir: get_option('libdir') / 'girepository-1.0',
|
|
126
|
+
)
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gjsify/napi",
|
|
3
|
+
"version": "0.22.0",
|
|
4
|
+
"description": "Node-API (N-API) host for GJS — implements the napi C ABI over SpiderMonkey (mozjs-140) so GJS can load unmodified compiled .node addons. The forward mirror of @gjsify/node-gi (GI in Node); this is N-API in GJS. Vala/C++ shim as .so+.gir+.typelib prebuild, loaded via imports.gi.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/esm/index.js",
|
|
7
|
+
"module": "lib/esm/index.js",
|
|
8
|
+
"types": "lib/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/types/index.d.ts",
|
|
12
|
+
"default": "./lib/esm/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"prebuilds",
|
|
18
|
+
"meson.build",
|
|
19
|
+
"src/vala",
|
|
20
|
+
"src/cc",
|
|
21
|
+
"src/napi-headers"
|
|
22
|
+
],
|
|
23
|
+
"gjsify": {
|
|
24
|
+
"platforms": [
|
|
25
|
+
"linux-x86_64",
|
|
26
|
+
"darwin-arm64"
|
|
27
|
+
],
|
|
28
|
+
"prebuilds": "prebuilds",
|
|
29
|
+
"runtimes": {
|
|
30
|
+
"gjs": "polyfill",
|
|
31
|
+
"node": "none",
|
|
32
|
+
"browser": "none",
|
|
33
|
+
"nativescript": "none"
|
|
34
|
+
},
|
|
35
|
+
"tier": 3
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"gjs",
|
|
39
|
+
"napi",
|
|
40
|
+
"node-api",
|
|
41
|
+
"n-api",
|
|
42
|
+
"native-addon",
|
|
43
|
+
"node",
|
|
44
|
+
"spidermonkey",
|
|
45
|
+
"mozjs",
|
|
46
|
+
"vala",
|
|
47
|
+
"native"
|
|
48
|
+
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"clear": "rm -rf lib build tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs || exit 0",
|
|
51
|
+
"check": "gjsify tsc --noEmit",
|
|
52
|
+
"build": "gjsify run build:gjsify && gjsify run build:types",
|
|
53
|
+
"build:gjsify": "gjsify build --library 'src/ts/**/*.{ts,js}'",
|
|
54
|
+
"build:types": "gjsify tsc",
|
|
55
|
+
"init:meson": "meson setup build .",
|
|
56
|
+
"init:meson:wipe": "gjsify run init:meson --wipe",
|
|
57
|
+
"build:meson": "gjsify run init:meson && meson compile -C build",
|
|
58
|
+
"build:prebuilds": "gjsify run build:meson && mkdir -p prebuilds/linux-x86_64 && cp build/libgjsifynapi.so build/GjsifyNapi-1.0.gir build/GjsifyNapi-1.0.typelib prebuilds/linux-x86_64/",
|
|
59
|
+
"build:test-addons": "for d in test/*-addon; do (cd \"$d\" && npm exec -- node-gyp rebuild) || exit 1; done",
|
|
60
|
+
"build:stubs": "python3 scripts/gen-stubs.py",
|
|
61
|
+
"test:gate": "GI_TYPELIB_PATH=build LD_LIBRARY_PATH=build gjs test/load-gate.js test/hello-addon/build/Release/hello.node",
|
|
62
|
+
"test:gate:p01": "GI_TYPELIB_PATH=build LD_LIBRARY_PATH=build gjs test/p01-gate.js",
|
|
63
|
+
"test:gate:p02": "GI_TYPELIB_PATH=build LD_LIBRARY_PATH=build gjs test/p02-gate.js",
|
|
64
|
+
"test:gate:p03": "sh test/run-p03-gate.sh",
|
|
65
|
+
"test:gate:p1": "GI_TYPELIB_PATH=build LD_LIBRARY_PATH=build gjs test/p1-tsfn-gate.js",
|
|
66
|
+
"test:nodegi": "node test/nodegi-gate.mjs",
|
|
67
|
+
"test:nodegi:mem": "node test/nodegi-gate.mjs --valgrind",
|
|
68
|
+
"test:mem": "sh test/p03-mem.sh",
|
|
69
|
+
"test:consumer": "node test/consumer-gate.mjs",
|
|
70
|
+
"test:consumer:mem": "sh test/consumer-mem.sh",
|
|
71
|
+
"test:addons:setup": "sh test/addons/setup.sh",
|
|
72
|
+
"test:addons": "sh test/run-addon-matrix.sh",
|
|
73
|
+
"test:addons:transparent": "sh test/run-transparent-matrix.sh",
|
|
74
|
+
"test:conformance": "node scripts/conformance.mjs",
|
|
75
|
+
"test:conformance:update": "node scripts/conformance.mjs --update-golden",
|
|
76
|
+
"test:conformance:mem": "sh scripts/conformance-mem.sh"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@girs/glib-2.0": "^4.1.0",
|
|
80
|
+
"@girs/gobject-2.0": "^4.1.0"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@girs/gjs": "^4.1.0",
|
|
84
|
+
"@gjsify/cli": "^0.22.0",
|
|
85
|
+
"@gjsify/unit": "^0.22.0",
|
|
86
|
+
"@ts-for-gir/cli": "^4.1.0",
|
|
87
|
+
"@types/node": "^25.9.2",
|
|
88
|
+
"typescript": "^6.0.3"
|
|
89
|
+
},
|
|
90
|
+
"license": "MIT",
|
|
91
|
+
"repository": {
|
|
92
|
+
"type": "git",
|
|
93
|
+
"url": "git+https://github.com/gjsify/gjsify.git",
|
|
94
|
+
"directory": "packages/napi/napi"
|
|
95
|
+
},
|
|
96
|
+
"bugs": {
|
|
97
|
+
"url": "https://github.com/gjsify/gjsify/issues"
|
|
98
|
+
},
|
|
99
|
+
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/napi/napi#readme"
|
|
100
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<!-- GjsifyNapi-1.0.gir generated by valac 0.56.19, do not modify. -->
|
|
3
|
+
<repository version="1.2" xmlns="http://www.gtk.org/introspection/core/1.0" xmlns:c="http://www.gtk.org/introspection/c/1.0" xmlns:doc="http://www.gtk.org/introspection/doc/1.0" xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
|
|
4
|
+
<package name="gjsifynapi"/>
|
|
5
|
+
<c:include name="gjsifynapi.h"/>
|
|
6
|
+
<doc:format name="unknown"/>
|
|
7
|
+
<namespace name="GjsifyNapi" version="1.0" shared-library="libgjsifynapi.so" c:prefix="GjsifyNapi" c:identifier-prefixes="GjsifyNapi" c:symbol-prefixes="gjsify_napi">
|
|
8
|
+
<function name="init" c:identifier="gjsify_napi_init">
|
|
9
|
+
<return-value transfer-ownership="full">
|
|
10
|
+
<type name="gboolean" c:type="gboolean"/>
|
|
11
|
+
</return-value>
|
|
12
|
+
</function>
|
|
13
|
+
<function name="is_available" c:identifier="gjsify_napi_is_available">
|
|
14
|
+
<return-value transfer-ownership="full">
|
|
15
|
+
<type name="gboolean" c:type="gboolean"/>
|
|
16
|
+
</return-value>
|
|
17
|
+
</function>
|
|
18
|
+
</namespace>
|
|
19
|
+
</repository>
|
|
Binary file
|
|
Binary file
|