@gjsify/node-gi 0.30.0 → 0.32.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/gtk-runtime.js +174 -3
- package/index.js +15 -1
- package/load-diagnostics.js +83 -0
- package/package.json +2 -1
- package/prebuilds/darwin-arm64/node_gi.node +0 -0
- package/prebuilds/darwin-x64/node_gi.node +0 -0
- package/prebuilds/win32-x64/node_gi.node +0 -0
- package/system-gi.js +10 -1
package/gtk-runtime.js
CHANGED
|
@@ -12,6 +12,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
12
12
|
import { dirname, join } from 'node:path';
|
|
13
13
|
import { existsSync } from 'node:fs';
|
|
14
14
|
import { pathCovers, splitSearchPath, systemGiLibraryDirs } from './system-gi.js';
|
|
15
|
+
import { nativeCandidates, prebuildAddonPath } from './native-paths.js';
|
|
15
16
|
|
|
16
17
|
// NB: node:child_process is intentionally NOT imported at module top level. It is
|
|
17
18
|
// pulled in lazily (via `require` below) ONLY on the darwin re-exec path — importing
|
|
@@ -63,6 +64,167 @@ export function resolveGtkRuntimeBundle() {
|
|
|
63
64
|
return null;
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
// ---- WHICH GTK WINS ---------------------------------------------------------
|
|
68
|
+
//
|
|
69
|
+
// Two GTKs can be reachable at once: a batteries-included bundle
|
|
70
|
+
// (@gjsify/gtk-runtime-<os>-<arch>) and the host's own. Until now the answer was
|
|
71
|
+
// implicit — "a bundle, if one is present" — and the rule keeping that safe was
|
|
72
|
+
// "a bundle must NEVER be a dependency of @gjsify/node-gi", because #910 made it
|
|
73
|
+
// one and a CI job that had COMPILED the addon against Homebrew GTK then re-exec'd
|
|
74
|
+
// onto the BUNDLE's typelibs: wrong method entries, then a 29-minute timeout
|
|
75
|
+
// (#920 reverted it). That rule protected the from-source case and left every end
|
|
76
|
+
// user on Windows with no GTK at all (#1063) — nothing installs the bundle there
|
|
77
|
+
// and Windows ships no system GTK.
|
|
78
|
+
//
|
|
79
|
+
// The repair separates two things that were tangled:
|
|
80
|
+
//
|
|
81
|
+
// • WHO INSTALLS IT is not this package's business. node-gi still declares no
|
|
82
|
+
// bundle — whoever SHIPS an app declares it (for the showcases that is the
|
|
83
|
+
// gjsify CLI, which already supplies @gjsify/node-gi the same way). A
|
|
84
|
+
// from-source build therefore never receives a bundle it did not ask for,
|
|
85
|
+
// which is #910's accident removed at the source rather than caught later.
|
|
86
|
+
//
|
|
87
|
+
// • WHICH ONE WINS when both are present is a POLICY — stated per-OS, and
|
|
88
|
+
// overridable.
|
|
89
|
+
//
|
|
90
|
+
// PER-OS DEFAULTS, and why they are spelled out rather than derived. The cheaper
|
|
91
|
+
// rule "prefer a bundle wherever we ship one" gives identical answers today,
|
|
92
|
+
// since bundles exist exactly for the platforms without a dependable system
|
|
93
|
+
// stack. It is a trap: the day someone builds a Linux bundle (Flatpak, a CI
|
|
94
|
+
// image) that rule would SILENTLY flip Linux from system-first to bundle-first
|
|
95
|
+
// with nobody deciding it. Stating each default now means a new bundle cannot
|
|
96
|
+
// move an existing platform's behaviour.
|
|
97
|
+
//
|
|
98
|
+
// linux → system first. dnf/apt/pacman resolve GTK *and* its typelibs
|
|
99
|
+
// correctly; that is the combination the distro tested.
|
|
100
|
+
// win32 → bundle first. There is no system GTK; a host with gvsbuild has it
|
|
101
|
+
// deliberately and stays reachable as the fallback.
|
|
102
|
+
// darwin → bundle first. Homebrew is usually present yet measurably NOT
|
|
103
|
+
// findable (gjs's own rpath points into glib's keg alone), which is
|
|
104
|
+
// the reason the darwin bundle exists at all.
|
|
105
|
+
//
|
|
106
|
+
// `GJSIFY_GTK_PREFER=bundle|system` overrides. Deliberately NOT the same knob as
|
|
107
|
+
// `GJSIFY_GTK_RUNTIME`, which names a bundle DIRECTORY: where a bundle is and
|
|
108
|
+
// which source wins are two questions, and one variable answering both leaves a
|
|
109
|
+
// user unable to say "I have a bundle, use the system anyway".
|
|
110
|
+
|
|
111
|
+
/** @typedef {'bundle' | 'system' | 'none'} GtkSource */
|
|
112
|
+
/** @typedef {'prebuild' | 'source' | 'unknown'} AddonProvenance */
|
|
113
|
+
|
|
114
|
+
/** Per-OS default: which source is consulted FIRST. See the note above. */
|
|
115
|
+
export const DEFAULT_GTK_PREFERENCE = Object.freeze({
|
|
116
|
+
linux: 'system',
|
|
117
|
+
win32: 'bundle',
|
|
118
|
+
darwin: 'bundle',
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Decide which GTK this process should use. PURE — every input is a parameter,
|
|
123
|
+
* so all three platforms' branches are executable from any host.
|
|
124
|
+
*
|
|
125
|
+
* The result is an ordered preference filtered by availability, never an
|
|
126
|
+
* exclusion: "prefer system" on a host with no system GTK still falls back to a
|
|
127
|
+
* bundle, because a preference that silently also means "and nothing else" turns
|
|
128
|
+
* a working setup into a hard failure.
|
|
129
|
+
*
|
|
130
|
+
* THE ONE HARD PART. A `source` addon was linked against whatever GTK the builder
|
|
131
|
+
* had, so pairing it with a bundle is not a preference but an ABI error — it is
|
|
132
|
+
* #910 exactly. The bundle is therefore dropped from the order for a from-source
|
|
133
|
+
* addon. `GJSIFY_GTK_PREFER=bundle` can still lift it, because building against a
|
|
134
|
+
* bundle on purpose is legitimate and an explicitly-set variable is consent;
|
|
135
|
+
* what #910 was is an accident nobody chose, and the DEFAULT must never
|
|
136
|
+
* reproduce it.
|
|
137
|
+
*
|
|
138
|
+
* @param {object} opts
|
|
139
|
+
* @param {NodeJS.Platform | string} opts.platform
|
|
140
|
+
* @param {boolean} opts.hasBundle a complete bundle is installed
|
|
141
|
+
* @param {boolean} opts.hasSystem a host GTK is worth trying (`hostGtkIsWorthTrying`)
|
|
142
|
+
* @param {AddonProvenance} [opts.provenance] which addon binary will load
|
|
143
|
+
* @param {string} [opts.override] raw `GJSIFY_GTK_PREFER` value, if any
|
|
144
|
+
* @returns {GtkSource}
|
|
145
|
+
*/
|
|
146
|
+
export function decideGtkSource({ platform, hasBundle, hasSystem, provenance = 'unknown', override }) {
|
|
147
|
+
const bundleFirst =
|
|
148
|
+
override === 'bundle' ? true : override === 'system' ? false : DEFAULT_GTK_PREFERENCE[platform] !== 'system';
|
|
149
|
+
let order = bundleFirst ? ['bundle', 'system'] : ['system', 'bundle'];
|
|
150
|
+
|
|
151
|
+
if (provenance === 'source' && override !== 'bundle') {
|
|
152
|
+
order = order.filter((source) => source !== 'bundle');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const available = { bundle: hasBundle, system: hasSystem };
|
|
156
|
+
for (const source of order) {
|
|
157
|
+
if (available[source]) return source;
|
|
158
|
+
}
|
|
159
|
+
return 'none';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Which binary `loadNative()` will pick, WITHOUT loading it.
|
|
164
|
+
*
|
|
165
|
+
* Load-bearing on Windows: the DLL search path must be set BEFORE the addon is
|
|
166
|
+
* dlopen'd, so the provenance question cannot wait until we hold the loaded
|
|
167
|
+
* module. `nativeCandidates()` is a pure, ordered list and the same one the
|
|
168
|
+
* loader walks, so probing it here cannot disagree with what actually loads.
|
|
169
|
+
*
|
|
170
|
+
* An explicit `NODE_GI_NATIVE=<path>` pin answers `unknown`, not `source`: the
|
|
171
|
+
* caller named a binary and we cannot tell what it was built against, so the safe
|
|
172
|
+
* reading is that a deliberate choice does not get the from-source veto.
|
|
173
|
+
* @returns {AddonProvenance}
|
|
174
|
+
*/
|
|
175
|
+
export function addonProvenance() {
|
|
176
|
+
const pinned = process.env.NODE_GI_NATIVE;
|
|
177
|
+
if (pinned && pinned !== 'build' && pinned !== 'prebuild') return 'unknown';
|
|
178
|
+
const prebuild = prebuildAddonPath();
|
|
179
|
+
for (const candidate of nativeCandidates()) {
|
|
180
|
+
if (!existsSync(candidate)) continue;
|
|
181
|
+
return candidate === prebuild ? 'prebuild' : 'source';
|
|
182
|
+
}
|
|
183
|
+
return 'unknown';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Is the HOST's own GI stack worth trying?
|
|
188
|
+
*
|
|
189
|
+
* Deliberately cheap and conservative rather than a probe that pretends to know.
|
|
190
|
+
* On linux and win32 "system" means "change nothing and let the OS loader do its
|
|
191
|
+
* job", which is always worth attempting — and on win32 the failure that follows
|
|
192
|
+
* is what produces the actionable diagnosis in `index.js` instead of a raw OS
|
|
193
|
+
* string. Only darwin has a real question, because there the loader needs the
|
|
194
|
+
* libdirs handed to it and `systemGiLibraryDirs()` is what finds them.
|
|
195
|
+
* @param {NodeJS.Platform | string} [platform]
|
|
196
|
+
* @returns {boolean}
|
|
197
|
+
*/
|
|
198
|
+
export function hostGtkIsWorthTrying(platform = process.platform) {
|
|
199
|
+
if (platform !== 'darwin') return true;
|
|
200
|
+
return systemGiLibraryDirs().length > 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let decidedSource = null;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The decision for THIS process, memoized — every entry point below must reach
|
|
207
|
+
* the same answer, and re-deciding per call is how two of them drift apart.
|
|
208
|
+
* @returns {GtkSource}
|
|
209
|
+
*/
|
|
210
|
+
export function gtkSource() {
|
|
211
|
+
if (decidedSource === null) {
|
|
212
|
+
decidedSource = decideGtkSource({
|
|
213
|
+
platform: process.platform,
|
|
214
|
+
hasBundle: resolveGtkRuntimeBundle() !== null,
|
|
215
|
+
hasSystem: hostGtkIsWorthTrying(),
|
|
216
|
+
provenance: addonProvenance(),
|
|
217
|
+
override: process.env.GJSIFY_GTK_PREFER,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return decidedSource;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** TEST-ONLY: drop the memoized decision so a spec can vary the environment. */
|
|
224
|
+
export function resetGtkSourceForTests() {
|
|
225
|
+
decidedSource = null;
|
|
226
|
+
}
|
|
227
|
+
|
|
66
228
|
/**
|
|
67
229
|
* Make GTK genuinely env-free on macOS by RE-EXECING this process once with
|
|
68
230
|
* `DYLD_FALLBACK_LIBRARY_PATH` pointing at the dylibs a typelib names by bare
|
|
@@ -127,9 +289,11 @@ export function maybeReexecForGtkRuntime() {
|
|
|
127
289
|
if (typeof globalThis.imports !== 'undefined' && typeof globalThis.print === 'function') return;
|
|
128
290
|
if (process.env[REEXEC_SENTINEL]) return; // already re-exec'd — the child path
|
|
129
291
|
|
|
130
|
-
// A bundle
|
|
131
|
-
// the #920 note above).
|
|
132
|
-
|
|
292
|
+
// A bundle THE POLICY CHOSE is the whole answer and stays the ONLY entry (see
|
|
293
|
+
// the #920 note above). Otherwise the host's own GI libdirs are the answer —
|
|
294
|
+
// which is also what a from-source addon gets, since `gtkSource()` refuses it
|
|
295
|
+
// a bundle by default.
|
|
296
|
+
const bundle = gtkSource() === 'bundle' ? resolveGtkRuntimeBundle() : null;
|
|
133
297
|
const libDirs = bundle ? [bundle.libDir] : systemGiLibraryDirs();
|
|
134
298
|
if (libDirs.length === 0) return; // no bundle and no host GI stack — nothing to point at
|
|
135
299
|
|
|
@@ -180,6 +344,9 @@ export function maybeReexecForGtkRuntime() {
|
|
|
180
344
|
*/
|
|
181
345
|
export function maybePrependGtkRuntimeDllPath() {
|
|
182
346
|
if (process.platform !== 'win32') return; // strict no-op on every non-win32 runtime
|
|
347
|
+
// Gated on the POLICY, not on mere presence: an installed bundle does not win
|
|
348
|
+
// for a from-source addon, and `GJSIFY_GTK_PREFER=system` opts out entirely.
|
|
349
|
+
if (gtkSource() !== 'bundle') return;
|
|
183
350
|
const bundle = resolveGtkRuntimeBundle();
|
|
184
351
|
if (!bundle) return; // strict no-op when no bundle is present
|
|
185
352
|
const binDir = bundle.libDir; // on win32 the native-code dir is gtk/bin (the DLLs)
|
|
@@ -213,6 +380,9 @@ export function maybeWireGtkWindowingEnv() {
|
|
|
213
380
|
// so setting them in-process works on both. The only platform difference is the
|
|
214
381
|
// XDG_DATA_DIRS separator (';' on win32, ':' on unix/darwin).
|
|
215
382
|
if (process.platform !== 'win32' && process.platform !== 'darwin') return;
|
|
383
|
+
// Same gate as the DLL/dylib path: the runtime DATA belongs to the bundle, so
|
|
384
|
+
// it is wired only when the bundle is the source the policy picked.
|
|
385
|
+
if (gtkSource() !== 'bundle') return;
|
|
216
386
|
const bundle = resolveGtkRuntimeBundle();
|
|
217
387
|
if (!bundle) return; // strict no-op when no bundle is present
|
|
218
388
|
|
|
@@ -284,6 +454,7 @@ export function activateBundledGtkRuntime(native) {
|
|
|
284
454
|
if (activated !== null) return activated || null;
|
|
285
455
|
activated = false;
|
|
286
456
|
if (process.platform !== 'darwin' && process.platform !== 'win32') return null;
|
|
457
|
+
if (gtkSource() !== 'bundle') return null; // the policy chose the host's GTK
|
|
287
458
|
|
|
288
459
|
const bundle = resolveGtkRuntimeBundle();
|
|
289
460
|
if (!bundle) return null;
|
package/index.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { createRequire } from 'node:module';
|
|
14
14
|
import { existsSync } from 'node:fs';
|
|
15
15
|
import { hostTarget, nativeCandidates, packageRoot } from './native-paths.js';
|
|
16
|
+
import { describeAddonLoadFailure } from './load-diagnostics.js';
|
|
16
17
|
import {
|
|
17
18
|
activateBundledGtkRuntime,
|
|
18
19
|
maybePrependGtkRuntimeDllPath,
|
|
@@ -100,7 +101,20 @@ function gjsLoadAddon(path) {
|
|
|
100
101
|
function loadNative() {
|
|
101
102
|
for (const candidate of nativeCandidates()) {
|
|
102
103
|
if (existsSync(candidate)) {
|
|
103
|
-
|
|
104
|
+
try {
|
|
105
|
+
return RUNTIME === 'gjs' ? gjsLoadAddon(candidate) : require(candidate);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
// The addon FILE is here and still would not load. On win32 and
|
|
108
|
+
// darwin that means its GTK dependency closure was not found, and
|
|
109
|
+
// the raw error names only the .node — in the OS's language, about
|
|
110
|
+
// a file that plainly exists. Reported from a clean Windows host as
|
|
111
|
+
// `Error: Das angegebene Modul wurde nicht gefunden.` pointing at a
|
|
112
|
+
// present node_gi.node (#1063), which names nothing a user can act
|
|
113
|
+
// on. Same class as PR #994, where a missing load-time library
|
|
114
|
+
// surfaced as "Unsupported type void, deriving from fundamental
|
|
115
|
+
// void". The cause is knowable here, so say it.
|
|
116
|
+
throw new Error(describeAddonLoadFailure(candidate, err), { cause: err });
|
|
117
|
+
}
|
|
104
118
|
}
|
|
105
119
|
}
|
|
106
120
|
throw new Error(
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// @gjsify/node-gi/load-diagnostics — what a user is told when the addon FILE is
|
|
3
|
+
// present and still will not load.
|
|
4
|
+
//
|
|
5
|
+
// A MODULE OF ITS OWN, and that is the point: `index.js` loads the native addon
|
|
6
|
+
// at evaluation time, so anything living there can only be imported by a process
|
|
7
|
+
// that already succeeded at the thing being diagnosed. The message has to be
|
|
8
|
+
// reachable — and testable — without a working addon.
|
|
9
|
+
//
|
|
10
|
+
// Pure over its inputs (platform, decided GTK source, target are parameters), so
|
|
11
|
+
// the Windows and macOS wording is assertable from a Linux host. Neither has ever
|
|
12
|
+
// been printed by a job in this repository.
|
|
13
|
+
import { hostTarget } from './native-paths.js';
|
|
14
|
+
import { gtkSource } from './gtk-runtime.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Turn a failed addon load into something the reader can act on.
|
|
18
|
+
*
|
|
19
|
+
* PURE over its inputs (platform + the decided GTK source are parameters) so all
|
|
20
|
+
* three platforms' wording is assertable from any host — the Windows message in
|
|
21
|
+
* particular is the one no CI job on this project has ever printed.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} addonPath the .node that failed to load
|
|
24
|
+
* @param {unknown} err the original loader error
|
|
25
|
+
* @param {object} [ctx]
|
|
26
|
+
* @param {NodeJS.Platform | string} [ctx.platform]
|
|
27
|
+
* @param {'bundle' | 'system' | 'none'} [ctx.source] which GTK the policy picked
|
|
28
|
+
* @param {string} [ctx.target] the `<os>-<arch>` tag
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
export function describeAddonLoadFailure(addonPath, err, ctx = {}) {
|
|
32
|
+
const platform = ctx.platform ?? process.platform;
|
|
33
|
+
const source = ctx.source ?? gtkSource();
|
|
34
|
+
const target = ctx.target ?? hostTarget();
|
|
35
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
36
|
+
|
|
37
|
+
const lines = [
|
|
38
|
+
`@gjsify/node-gi: the native addon exists but could not be loaded.`,
|
|
39
|
+
` addon: ${addonPath}`,
|
|
40
|
+
` cause: ${reason}`,
|
|
41
|
+
'',
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
if (platform === 'win32' || platform === 'darwin') {
|
|
45
|
+
const libs = platform === 'win32' ? 'DLLs' : 'dylibs';
|
|
46
|
+
lines.push(
|
|
47
|
+
`The file is present, so this is almost always its GTK/GObject-Introspection`,
|
|
48
|
+
`dependency closure (glib, gobject, gio, girepository, …) not being found —`,
|
|
49
|
+
`not the addon itself. GTK source selected for this process: ${source}.`,
|
|
50
|
+
'',
|
|
51
|
+
);
|
|
52
|
+
if (source !== 'bundle') {
|
|
53
|
+
lines.push(
|
|
54
|
+
`Install the batteries-included runtime, which ships those ${libs}:`,
|
|
55
|
+
` npm install @gjsify/gtk-runtime-${target}`,
|
|
56
|
+
`or point GJSIFY_GTK_RUNTIME at an existing bundle directory.`,
|
|
57
|
+
'',
|
|
58
|
+
);
|
|
59
|
+
} else {
|
|
60
|
+
lines.push(
|
|
61
|
+
`A bundle WAS selected, so it is likely incomplete for this target.`,
|
|
62
|
+
`Reinstall @gjsify/gtk-runtime-${target}, or set GJSIFY_GTK_PREFER=system`,
|
|
63
|
+
`to use the host's own GTK instead.`,
|
|
64
|
+
'',
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (platform === 'win32') {
|
|
68
|
+
lines.push(
|
|
69
|
+
`Also required on Windows and easy to miss: the Visual C++ redistributable`,
|
|
70
|
+
`(vcruntime140.dll / vcruntime140_1.dll / msvcp140.dll). \`gjsify system-check\``,
|
|
71
|
+
`reports whether it is present.`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
lines.push(
|
|
76
|
+
`Install your distribution's GTK4 + GObject-Introspection runtime`,
|
|
77
|
+
`(e.g. \`dnf install gtk4 gobject-introspection\`). \`gjsify system-check\``,
|
|
78
|
+
`lists what is missing.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return lines.join('\n');
|
|
83
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/node-gi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "GObject-Introspection runtime for Node.js — load gi:// namespaces (GLib/GObject/Gio/…) with GJS-compatible semantics. Vendored + rewritten from node-gtk under MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"gi.d.ts",
|
|
45
45
|
"gtk-runtime.js",
|
|
46
46
|
"gtk-runtime.d.ts",
|
|
47
|
+
"load-diagnostics.js",
|
|
47
48
|
"system-gi.js",
|
|
48
49
|
"system-gi.d.ts",
|
|
49
50
|
"globals.js",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/system-gi.js
CHANGED
|
@@ -55,7 +55,16 @@
|
|
|
55
55
|
// eventual lift to a shared package is tracked in `status/open-todos.md`.
|
|
56
56
|
import { statSync } from 'node:fs';
|
|
57
57
|
import { createRequire } from 'node:module';
|
|
58
|
-
|
|
58
|
+
// POSIX path semantics, not the HOST's. This function answers a question about
|
|
59
|
+
// a darwin filesystem — `platform` is a PARAMETER, so the host running the code
|
|
60
|
+
// may be any of the three. Node's default `join`/`dirname`/`basename` follow the
|
|
61
|
+
// host, so on win32 `join('/usr/local/lib', 'girepository-1.0')` becomes
|
|
62
|
+
// `\usr\local\lib\girepository-1.0` and never matches the darwin path the
|
|
63
|
+
// caller (or the injected `existsDir`) is holding. Measured on the Windows leg:
|
|
64
|
+
// three `systemGiLibraryDirs` specs returned `[]` where they assert a prefix.
|
|
65
|
+
// `PROBED_GI_LIBDIRS` is darwin-only, so POSIX is always the right dialect here.
|
|
66
|
+
import { posix } from 'node:path';
|
|
67
|
+
const { basename, dirname, join } = posix;
|
|
59
68
|
|
|
60
69
|
const require = createRequire(import.meta.url);
|
|
61
70
|
|