emsdk-env 0.10.0 → 0.11.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/dist/build-BbwVl0T6.js +1379 -0
- package/dist/build-BbwVl0T6.js.map +1 -0
- package/dist/build-TpHGBYTu.cjs +1388 -0
- package/dist/build-TpHGBYTu.cjs.map +1 -0
- package/dist/build.d.ts +22 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/commands.d.ts +14 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/emsdk.d.ts +22 -0
- package/dist/emsdk.d.ts.map +1 -0
- package/dist/env.d.ts +16 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/fs-utils.d.ts +13 -0
- package/dist/fs-utils.d.ts.map +1 -0
- package/dist/generated/packageMetadata.d.ts +18 -0
- package/dist/generated/packageMetadata.d.ts.map +1 -0
- package/dist/index.cjs +11 -14
- package/dist/index.d.ts +17 -338
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +10 -15
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/{vite.d.ts → types.d.ts} +299 -268
- package/dist/types.d.ts.map +1 -0
- package/dist/vite/index.d.ts +24 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/logger.d.ts +14 -0
- package/dist/vite/logger.d.ts.map +1 -0
- package/dist/vite/types.d.ts +17 -0
- package/dist/vite/types.d.ts.map +1 -0
- package/dist/vite.cjs +735 -712
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +729 -712
- package/dist/vite.mjs.map +1 -1
- package/package.json +22 -21
- package/dist/build-BE9Z95iJ.js +0 -1668
- package/dist/build-BE9Z95iJ.js.map +0 -1
- package/dist/build-BGtsNe6D.cjs +0 -1689
- package/dist/build-BGtsNe6D.cjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/build-BGtsNe6D.cjs
DELETED
|
@@ -1,1689 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* name: emsdk-env
|
|
3
|
-
* version: 0.10.0
|
|
4
|
-
* description: Emscripten environment builder
|
|
5
|
-
* author: Kouji Matsui (@kekyo@mi.kekyo.net)
|
|
6
|
-
* license: MIT
|
|
7
|
-
* repository.url: https://github.com/kekyo/emsdk-env
|
|
8
|
-
* git.commit.hash: 7ee173408d930a3cc7444806156538a24a617b55
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
"use strict";
|
|
12
|
-
var __create = Object.create;
|
|
13
|
-
var __defProp = Object.defineProperty;
|
|
14
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
15
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
16
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
17
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
18
|
-
var __copyProps = (to, from, except, desc) => {
|
|
19
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
-
for (let key of __getOwnPropNames(from))
|
|
21
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
-
}
|
|
24
|
-
return to;
|
|
25
|
-
};
|
|
26
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
27
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
28
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
29
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
30
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
31
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
32
|
-
mod
|
|
33
|
-
));
|
|
34
|
-
const promises = require("fs/promises");
|
|
35
|
-
const os = require("os");
|
|
36
|
-
const glob = require("glob");
|
|
37
|
-
const path = require("path");
|
|
38
|
-
const child_process = require("child_process");
|
|
39
|
-
const __NOOP_HANDLER = () => {
|
|
40
|
-
};
|
|
41
|
-
const __NOOP_RELEASABLE = {
|
|
42
|
-
release: __NOOP_HANDLER,
|
|
43
|
-
[Symbol.dispose]: __NOOP_HANDLER
|
|
44
|
-
};
|
|
45
|
-
const toAbortError = (reason) => {
|
|
46
|
-
if (reason instanceof Error) {
|
|
47
|
-
return reason;
|
|
48
|
-
}
|
|
49
|
-
if (typeof reason === "string") {
|
|
50
|
-
return new Error(reason);
|
|
51
|
-
}
|
|
52
|
-
return new Error("Operation aborted");
|
|
53
|
-
};
|
|
54
|
-
const onAbort = (signal, callback) => {
|
|
55
|
-
if (!signal) {
|
|
56
|
-
return __NOOP_RELEASABLE;
|
|
57
|
-
}
|
|
58
|
-
if (signal.aborted) {
|
|
59
|
-
try {
|
|
60
|
-
callback(toAbortError(signal.reason));
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.warn("AbortHook callback error: ", error);
|
|
63
|
-
}
|
|
64
|
-
return __NOOP_RELEASABLE;
|
|
65
|
-
}
|
|
66
|
-
let abortHandler;
|
|
67
|
-
abortHandler = () => {
|
|
68
|
-
if (abortHandler) {
|
|
69
|
-
const reason = signal.reason;
|
|
70
|
-
signal.removeEventListener("abort", abortHandler);
|
|
71
|
-
abortHandler = void 0;
|
|
72
|
-
try {
|
|
73
|
-
callback(toAbortError(reason));
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.warn("AbortHook callback error: ", error);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
const release = () => {
|
|
80
|
-
if (abortHandler) {
|
|
81
|
-
signal.removeEventListener("abort", abortHandler);
|
|
82
|
-
abortHandler = void 0;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
signal.addEventListener("abort", abortHandler, { once: true });
|
|
86
|
-
const handle = {
|
|
87
|
-
release,
|
|
88
|
-
[Symbol.dispose]: release
|
|
89
|
-
};
|
|
90
|
-
return handle;
|
|
91
|
-
};
|
|
92
|
-
const defer = (fn) => {
|
|
93
|
-
if (typeof setImmediate === "function") {
|
|
94
|
-
setImmediate(fn);
|
|
95
|
-
} else {
|
|
96
|
-
setTimeout(fn, 0);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
const ABORTED_ERROR$2 = () => new Error("Lock acquisition was aborted");
|
|
100
|
-
const createLockHandle = (releaseCallback) => {
|
|
101
|
-
let isActive = true;
|
|
102
|
-
const release = () => {
|
|
103
|
-
if (!isActive) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
isActive = false;
|
|
107
|
-
releaseCallback();
|
|
108
|
-
};
|
|
109
|
-
return {
|
|
110
|
-
get isActive() {
|
|
111
|
-
return isActive;
|
|
112
|
-
},
|
|
113
|
-
release,
|
|
114
|
-
[Symbol.dispose]: release
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
const createMutex = (maxConsecutiveCalls = 20) => {
|
|
118
|
-
let isLocked = false;
|
|
119
|
-
const queue = [];
|
|
120
|
-
let count = 0;
|
|
121
|
-
const processQueue = () => {
|
|
122
|
-
var _a;
|
|
123
|
-
if (isLocked || queue.length === 0) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const item = queue.shift();
|
|
127
|
-
if ((_a = item.signal) == null ? void 0 : _a.aborted) {
|
|
128
|
-
item.reject(ABORTED_ERROR$2());
|
|
129
|
-
scheduleNextProcess();
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
isLocked = true;
|
|
133
|
-
const lockHandle = createLockHandle(releaseLock);
|
|
134
|
-
item.resolve(lockHandle);
|
|
135
|
-
};
|
|
136
|
-
const scheduleNextProcess = () => {
|
|
137
|
-
count++;
|
|
138
|
-
if (count >= maxConsecutiveCalls) {
|
|
139
|
-
count = 0;
|
|
140
|
-
defer(processQueue);
|
|
141
|
-
} else {
|
|
142
|
-
processQueue();
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
const releaseLock = () => {
|
|
146
|
-
if (!isLocked) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
isLocked = false;
|
|
150
|
-
scheduleNextProcess();
|
|
151
|
-
};
|
|
152
|
-
const removeFromQueue = (item) => {
|
|
153
|
-
const index = queue.indexOf(item);
|
|
154
|
-
if (index !== -1) {
|
|
155
|
-
queue.splice(index, 1);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
const lock = async (signal) => {
|
|
159
|
-
if (signal) {
|
|
160
|
-
if (signal.aborted) {
|
|
161
|
-
throw ABORTED_ERROR$2();
|
|
162
|
-
}
|
|
163
|
-
return new Promise((resolve, reject) => {
|
|
164
|
-
const queueItem = {
|
|
165
|
-
resolve: void 0,
|
|
166
|
-
reject: void 0,
|
|
167
|
-
signal
|
|
168
|
-
};
|
|
169
|
-
const abortHandle = onAbort(signal, () => {
|
|
170
|
-
removeFromQueue(queueItem);
|
|
171
|
-
reject(ABORTED_ERROR$2());
|
|
172
|
-
});
|
|
173
|
-
queueItem.resolve = (handle) => {
|
|
174
|
-
abortHandle.release();
|
|
175
|
-
resolve(handle);
|
|
176
|
-
};
|
|
177
|
-
queueItem.reject = (error) => {
|
|
178
|
-
abortHandle.release();
|
|
179
|
-
reject(error);
|
|
180
|
-
};
|
|
181
|
-
queue.push(queueItem);
|
|
182
|
-
processQueue();
|
|
183
|
-
});
|
|
184
|
-
} else {
|
|
185
|
-
return new Promise((resolve, reject) => {
|
|
186
|
-
queue.push({
|
|
187
|
-
resolve,
|
|
188
|
-
reject
|
|
189
|
-
});
|
|
190
|
-
processQueue();
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
const result = {
|
|
195
|
-
lock,
|
|
196
|
-
waiter: {
|
|
197
|
-
wait: lock
|
|
198
|
-
},
|
|
199
|
-
get isLocked() {
|
|
200
|
-
return isLocked;
|
|
201
|
-
},
|
|
202
|
-
get pendingCount() {
|
|
203
|
-
return queue.length;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
return result;
|
|
207
|
-
};
|
|
208
|
-
const createAbortError = () => {
|
|
209
|
-
const error = new Error("The operation was aborted.");
|
|
210
|
-
error.name = "AbortError";
|
|
211
|
-
return error;
|
|
212
|
-
};
|
|
213
|
-
const runCommand = async (command, args, cwd, signal) => {
|
|
214
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
215
|
-
return new Promise((resolvePromise, rejectPromise) => {
|
|
216
|
-
const child = child_process.spawn(command, args, {
|
|
217
|
-
cwd,
|
|
218
|
-
stdio: "inherit"
|
|
219
|
-
});
|
|
220
|
-
let settled = false;
|
|
221
|
-
const onAbort2 = () => {
|
|
222
|
-
if (settled) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
settled = true;
|
|
226
|
-
child.kill();
|
|
227
|
-
rejectPromise(createAbortError());
|
|
228
|
-
};
|
|
229
|
-
signal == null ? void 0 : signal.addEventListener("abort", onAbort2, { once: true });
|
|
230
|
-
const cleanup = () => {
|
|
231
|
-
signal == null ? void 0 : signal.removeEventListener("abort", onAbort2);
|
|
232
|
-
};
|
|
233
|
-
child.once("error", (error) => {
|
|
234
|
-
if (settled) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
settled = true;
|
|
238
|
-
cleanup();
|
|
239
|
-
rejectPromise(error);
|
|
240
|
-
});
|
|
241
|
-
child.once("close", (code) => {
|
|
242
|
-
if (settled) {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
settled = true;
|
|
246
|
-
cleanup();
|
|
247
|
-
if (code === 0) {
|
|
248
|
-
resolvePromise();
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
rejectPromise(
|
|
252
|
-
new Error(
|
|
253
|
-
`Command failed: ${command} ${args.join(" ")} (exit code ${code})`
|
|
254
|
-
)
|
|
255
|
-
);
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
};
|
|
259
|
-
const runCommandWithEnv = async (command, args, cwd, env, signal) => {
|
|
260
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
261
|
-
return new Promise((resolvePromise, rejectPromise) => {
|
|
262
|
-
const child = child_process.spawn(command, args, {
|
|
263
|
-
cwd,
|
|
264
|
-
env,
|
|
265
|
-
stdio: "inherit"
|
|
266
|
-
});
|
|
267
|
-
let settled = false;
|
|
268
|
-
const onAbort2 = () => {
|
|
269
|
-
if (settled) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
settled = true;
|
|
273
|
-
child.kill();
|
|
274
|
-
rejectPromise(createAbortError());
|
|
275
|
-
};
|
|
276
|
-
signal == null ? void 0 : signal.addEventListener("abort", onAbort2, { once: true });
|
|
277
|
-
const cleanup = () => {
|
|
278
|
-
signal == null ? void 0 : signal.removeEventListener("abort", onAbort2);
|
|
279
|
-
};
|
|
280
|
-
child.once("error", (error) => {
|
|
281
|
-
if (settled) {
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
settled = true;
|
|
285
|
-
cleanup();
|
|
286
|
-
rejectPromise(error);
|
|
287
|
-
});
|
|
288
|
-
child.once("close", (code) => {
|
|
289
|
-
if (settled) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
settled = true;
|
|
293
|
-
cleanup();
|
|
294
|
-
if (code === 0) {
|
|
295
|
-
resolvePromise();
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
rejectPromise(
|
|
299
|
-
new Error(
|
|
300
|
-
`Command failed: ${command} ${args.join(" ")} (exit code ${code})`
|
|
301
|
-
)
|
|
302
|
-
);
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
const runCommandCapture = async (command, args, cwd, signal) => {
|
|
307
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
308
|
-
return new Promise((resolvePromise, rejectPromise) => {
|
|
309
|
-
const stdoutChunks = [];
|
|
310
|
-
const stderrChunks = [];
|
|
311
|
-
const child = child_process.spawn(command, args, {
|
|
312
|
-
cwd,
|
|
313
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
314
|
-
});
|
|
315
|
-
let settled = false;
|
|
316
|
-
const onAbort2 = () => {
|
|
317
|
-
if (settled) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
settled = true;
|
|
321
|
-
child.kill();
|
|
322
|
-
rejectPromise(createAbortError());
|
|
323
|
-
};
|
|
324
|
-
signal == null ? void 0 : signal.addEventListener("abort", onAbort2, { once: true });
|
|
325
|
-
const cleanup = () => {
|
|
326
|
-
signal == null ? void 0 : signal.removeEventListener("abort", onAbort2);
|
|
327
|
-
};
|
|
328
|
-
child.stdout.on("data", (chunk) => {
|
|
329
|
-
stdoutChunks.push(chunk);
|
|
330
|
-
});
|
|
331
|
-
child.stderr.on("data", (chunk) => {
|
|
332
|
-
stderrChunks.push(chunk);
|
|
333
|
-
});
|
|
334
|
-
child.once("error", (error) => {
|
|
335
|
-
if (settled) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
settled = true;
|
|
339
|
-
cleanup();
|
|
340
|
-
rejectPromise(error);
|
|
341
|
-
});
|
|
342
|
-
child.once("close", (code) => {
|
|
343
|
-
if (settled) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
settled = true;
|
|
347
|
-
cleanup();
|
|
348
|
-
if (code === 0) {
|
|
349
|
-
resolvePromise(Buffer.concat(stdoutChunks));
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
const stderrText = Buffer.concat(stderrChunks).toString("utf8");
|
|
353
|
-
rejectPromise(
|
|
354
|
-
new Error(
|
|
355
|
-
`Command failed: ${command} ${args.join(" ")} (exit code ${code})${stderrText ? `
|
|
356
|
-
${stderrText}` : ""}`
|
|
357
|
-
)
|
|
358
|
-
);
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
};
|
|
362
|
-
const pathExists = async (targetPath) => {
|
|
363
|
-
try {
|
|
364
|
-
await promises.access(targetPath, promises.constants.F_OK);
|
|
365
|
-
return true;
|
|
366
|
-
} catch (e) {
|
|
367
|
-
return false;
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
const ensureDirectory = async (targetPath) => {
|
|
371
|
-
await promises.mkdir(targetPath, { recursive: true });
|
|
372
|
-
};
|
|
373
|
-
const DEFAULT_REPO_URL = "https://github.com/emscripten-core/emsdk.git";
|
|
374
|
-
const DEFAULT_GIT_REF = "main";
|
|
375
|
-
const DEFAULT_CACHE_DIR = path.join(os.homedir(), ".cache", "emsdk-env");
|
|
376
|
-
const DEFAULT_TARGET_VERSION = "latest";
|
|
377
|
-
const versionMutexes = /* @__PURE__ */ new Map();
|
|
378
|
-
const getVersionMutex = (key) => {
|
|
379
|
-
let mutex = versionMutexes.get(key);
|
|
380
|
-
if (!mutex) {
|
|
381
|
-
mutex = createMutex();
|
|
382
|
-
versionMutexes.set(key, mutex);
|
|
383
|
-
}
|
|
384
|
-
return mutex;
|
|
385
|
-
};
|
|
386
|
-
const ensureNonEmpty = (value, label) => {
|
|
387
|
-
if (value.trim().length === 0) {
|
|
388
|
-
throw new TypeError(`${label} must be a non-empty string.`);
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
const sanitizeSegment = (value) => {
|
|
392
|
-
const trimmed = value.trim();
|
|
393
|
-
ensureNonEmpty(trimmed, "targetVersion");
|
|
394
|
-
const sanitized = trimmed.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
395
|
-
if (sanitized === "." || sanitized === ".." || sanitized.length === 0) {
|
|
396
|
-
throw new TypeError("targetVersion results in an unsafe path segment.");
|
|
397
|
-
}
|
|
398
|
-
return sanitized;
|
|
399
|
-
};
|
|
400
|
-
const resolveEmsdkCommand = () => process.platform === "win32" ? "emsdk.bat" : "./emsdk";
|
|
401
|
-
const runEmsdk = async (repoDir, args, signal) => {
|
|
402
|
-
if (process.platform === "win32") {
|
|
403
|
-
await runCommand("cmd", ["/c", "emsdk.bat", ...args], repoDir, signal);
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
await runCommand(resolveEmsdkCommand(), args, repoDir, signal);
|
|
407
|
-
};
|
|
408
|
-
const runGitClone = async (gitPath, repoUrl, targetDir, cwd, signal) => {
|
|
409
|
-
await runCommand(
|
|
410
|
-
gitPath,
|
|
411
|
-
["clone", repoUrl, targetDir, "--depth", "1", "--branch", DEFAULT_GIT_REF],
|
|
412
|
-
cwd,
|
|
413
|
-
signal
|
|
414
|
-
);
|
|
415
|
-
};
|
|
416
|
-
const isAlreadyExistsError = (error) => error instanceof Error && "code" in error && error.code !== void 0 && ["EEXIST", "ENOTEMPTY", "EISDIR"].includes(
|
|
417
|
-
String(error.code)
|
|
418
|
-
);
|
|
419
|
-
const prepareEmsdk = async (options) => {
|
|
420
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
421
|
-
if (!options) {
|
|
422
|
-
throw new TypeError("options must be provided.");
|
|
423
|
-
}
|
|
424
|
-
if (options.targetVersion !== void 0 && typeof options.targetVersion !== "string") {
|
|
425
|
-
throw new TypeError("targetVersion must be a string.");
|
|
426
|
-
}
|
|
427
|
-
const targetVersion = (_a = options.targetVersion) != null ? _a : DEFAULT_TARGET_VERSION;
|
|
428
|
-
ensureNonEmpty(targetVersion, "targetVersion");
|
|
429
|
-
(_b = options.signal) == null ? void 0 : _b.throwIfAborted();
|
|
430
|
-
const cacheDir = path.resolve((_c = options.cacheDir) != null ? _c : DEFAULT_CACHE_DIR);
|
|
431
|
-
const repoUrl = (_d = options.repoUrl) != null ? _d : DEFAULT_REPO_URL;
|
|
432
|
-
const gitPath = (_e = options.gitPath) != null ? _e : "git";
|
|
433
|
-
const versionDir = sanitizeSegment(targetVersion);
|
|
434
|
-
const finalDir = path.resolve(cacheDir, versionDir);
|
|
435
|
-
const mutex = getVersionMutex(finalDir);
|
|
436
|
-
const lock = await mutex.lock(options.signal);
|
|
437
|
-
try {
|
|
438
|
-
(_f = options.signal) == null ? void 0 : _f.throwIfAborted();
|
|
439
|
-
if (await pathExists(finalDir)) {
|
|
440
|
-
return finalDir;
|
|
441
|
-
}
|
|
442
|
-
await ensureDirectory(cacheDir);
|
|
443
|
-
const tempRoot = await promises.mkdtemp(path.join(cacheDir, ".tmp-"));
|
|
444
|
-
const tempRepoDir = path.join(tempRoot, "emsdk");
|
|
445
|
-
try {
|
|
446
|
-
await runGitClone(
|
|
447
|
-
gitPath,
|
|
448
|
-
repoUrl,
|
|
449
|
-
tempRepoDir,
|
|
450
|
-
cacheDir,
|
|
451
|
-
options.signal
|
|
452
|
-
);
|
|
453
|
-
(_g = options.signal) == null ? void 0 : _g.throwIfAborted();
|
|
454
|
-
await runEmsdk(tempRepoDir, ["install", targetVersion], options.signal);
|
|
455
|
-
try {
|
|
456
|
-
await promises.rename(tempRepoDir, finalDir);
|
|
457
|
-
} catch (error) {
|
|
458
|
-
if (isAlreadyExistsError(error)) {
|
|
459
|
-
return finalDir;
|
|
460
|
-
}
|
|
461
|
-
throw error;
|
|
462
|
-
}
|
|
463
|
-
} finally {
|
|
464
|
-
await promises.rm(tempRoot, { recursive: true, force: true });
|
|
465
|
-
}
|
|
466
|
-
(_h = options.signal) == null ? void 0 : _h.throwIfAborted();
|
|
467
|
-
await runEmsdk(finalDir, ["activate", targetVersion], options.signal);
|
|
468
|
-
return finalDir;
|
|
469
|
-
} finally {
|
|
470
|
-
lock.release();
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
const shellQuote = (value) => `'${String(value).replace(/'/g, `'"'"'`)}'`;
|
|
474
|
-
const parseEnvBuffer = (buffer) => {
|
|
475
|
-
const entries = buffer.toString("utf8").split("\0");
|
|
476
|
-
const env = {};
|
|
477
|
-
for (const entry of entries) {
|
|
478
|
-
if (!entry) {
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
const delimiterIndex = entry.indexOf("=");
|
|
482
|
-
if (delimiterIndex <= 0) {
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
485
|
-
const key = entry.slice(0, delimiterIndex);
|
|
486
|
-
const value = entry.slice(delimiterIndex + 1);
|
|
487
|
-
env[key] = value;
|
|
488
|
-
}
|
|
489
|
-
return env;
|
|
490
|
-
};
|
|
491
|
-
const loadEmsdkEnv = async (emsdkRoot, logger, signal) => {
|
|
492
|
-
if (process.platform === "win32") {
|
|
493
|
-
throw new Error(
|
|
494
|
-
"Emscripten environment extraction on Windows is not implemented yet."
|
|
495
|
-
);
|
|
496
|
-
}
|
|
497
|
-
const envScript = path.resolve(emsdkRoot, "emsdk_env.sh");
|
|
498
|
-
if (!await pathExists(envScript)) {
|
|
499
|
-
throw new Error(`emsdk_env.sh not found: ${envScript}`);
|
|
500
|
-
}
|
|
501
|
-
const command = `. ${shellQuote(envScript)} >/dev/null 2>&1; env -0`;
|
|
502
|
-
logger.debug(`Loading emsdk environment: ${envScript}`);
|
|
503
|
-
const output = await runCommandCapture(
|
|
504
|
-
"bash",
|
|
505
|
-
["-lc", command],
|
|
506
|
-
emsdkRoot,
|
|
507
|
-
signal
|
|
508
|
-
);
|
|
509
|
-
return parseEnvBuffer(output);
|
|
510
|
-
};
|
|
511
|
-
const resolveEmccCommand = async (env, emsdkRoot) => {
|
|
512
|
-
if (env.EMCC) {
|
|
513
|
-
return env.EMCC;
|
|
514
|
-
}
|
|
515
|
-
if (env.EMSCRIPTEN) {
|
|
516
|
-
const candidate = path.join(env.EMSCRIPTEN, "emcc");
|
|
517
|
-
if (await pathExists(candidate)) {
|
|
518
|
-
return candidate;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
const fallback = path.join(emsdkRoot, "upstream", "emscripten", "emcc");
|
|
522
|
-
if (await pathExists(fallback)) {
|
|
523
|
-
return fallback;
|
|
524
|
-
}
|
|
525
|
-
return "emcc";
|
|
526
|
-
};
|
|
527
|
-
const resolveEmarCommand = async (env, emsdkRoot) => {
|
|
528
|
-
if (env.EMAR) {
|
|
529
|
-
return env.EMAR;
|
|
530
|
-
}
|
|
531
|
-
if (env.EMSCRIPTEN) {
|
|
532
|
-
const candidate = path.join(env.EMSCRIPTEN, "emar");
|
|
533
|
-
if (await pathExists(candidate)) {
|
|
534
|
-
return candidate;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
const fallback = path.join(emsdkRoot, "upstream", "emscripten", "emar");
|
|
538
|
-
if (await pathExists(fallback)) {
|
|
539
|
-
return fallback;
|
|
540
|
-
}
|
|
541
|
-
return "emar";
|
|
542
|
-
};
|
|
543
|
-
const resolveWasmOptCommand = async (env, emsdkRoot) => {
|
|
544
|
-
var _a;
|
|
545
|
-
if (env.WASM_OPT) {
|
|
546
|
-
return env.WASM_OPT;
|
|
547
|
-
}
|
|
548
|
-
const binaryenRoot = (_a = env.BINARYEN_ROOT) != null ? _a : env.BINARYEN;
|
|
549
|
-
if (binaryenRoot) {
|
|
550
|
-
const candidate = path.join(binaryenRoot, "bin", "wasm-opt");
|
|
551
|
-
if (await pathExists(candidate)) {
|
|
552
|
-
return candidate;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
const fallback = path.join(emsdkRoot, "upstream", "bin", "wasm-opt");
|
|
556
|
-
if (await pathExists(fallback)) {
|
|
557
|
-
return fallback;
|
|
558
|
-
}
|
|
559
|
-
return "wasm-opt";
|
|
560
|
-
};
|
|
561
|
-
const createConsoleLogger = (prefix) => {
|
|
562
|
-
return {
|
|
563
|
-
debug: (msg) => console.debug(`[${prefix}]: ${msg}`),
|
|
564
|
-
info: (msg) => console.info(`[${prefix}]: ${msg}`),
|
|
565
|
-
warn: (msg) => console.warn(`[${prefix}]: ${msg}`),
|
|
566
|
-
error: (msg) => console.error(`[${prefix}]: ${msg}`)
|
|
567
|
-
};
|
|
568
|
-
};
|
|
569
|
-
const DEFAULT_WASM_SRC_DIR = "wasm";
|
|
570
|
-
const DEFAULT_WASM_INCLUDE_DIR = "include";
|
|
571
|
-
const DEFAULT_WASM_OUT_DIR = path.join("src", "wasm");
|
|
572
|
-
const DEFAULT_WASM_LIB_DIR = "lib";
|
|
573
|
-
const DEFAULT_IMPORT_INCLUDE_DIR = "include";
|
|
574
|
-
const DEFAULT_IMPORT_LIB_DIR = "lib";
|
|
575
|
-
const DEFAULT_WASM_BUILD_DIR = path.join(os.tmpdir(), "emsdk-env");
|
|
576
|
-
const DEFAULT_EMSDK_TARGET_VERSION = "latest";
|
|
577
|
-
const DEFAULT_WASM_OPT_ARGS = ["-Oz"];
|
|
578
|
-
const DEFAULT_GENERATED_LOADER_OUT_FILE = path.join(
|
|
579
|
-
"src",
|
|
580
|
-
"generated",
|
|
581
|
-
"wasm-loader.ts"
|
|
582
|
-
);
|
|
583
|
-
let buildSequence = 0;
|
|
584
|
-
const padNumber = (value, length = 2) => String(value).padStart(length, "0");
|
|
585
|
-
const formatTimestamp = (date) => {
|
|
586
|
-
const year = date.getFullYear();
|
|
587
|
-
const month = padNumber(date.getMonth() + 1);
|
|
588
|
-
const day = padNumber(date.getDate());
|
|
589
|
-
const hour = padNumber(date.getHours());
|
|
590
|
-
const minute = padNumber(date.getMinutes());
|
|
591
|
-
const second = padNumber(date.getSeconds());
|
|
592
|
-
return `${year}${month}${day}_${hour}${minute}${second}`;
|
|
593
|
-
};
|
|
594
|
-
const createBuildId = () => {
|
|
595
|
-
buildSequence += 1;
|
|
596
|
-
const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
|
|
597
|
-
const seq = String(buildSequence).padStart(4, "0");
|
|
598
|
-
return `${timestamp}_${seq}_${process.pid}`;
|
|
599
|
-
};
|
|
600
|
-
const ensureArray = (value) => value != null ? value : [];
|
|
601
|
-
const resolveTargetType = (value) => value != null ? value : "wasm";
|
|
602
|
-
const normalizePrepareOptions = (options) => {
|
|
603
|
-
const { targetVersion, ...rest } = options != null ? options : {};
|
|
604
|
-
return {
|
|
605
|
-
targetVersion: targetVersion != null ? targetVersion : DEFAULT_EMSDK_TARGET_VERSION,
|
|
606
|
-
...rest
|
|
607
|
-
};
|
|
608
|
-
};
|
|
609
|
-
const parseStringKeyValueInput = (values) => {
|
|
610
|
-
const parsed = {};
|
|
611
|
-
for (const entry of values) {
|
|
612
|
-
const index = entry.indexOf("=");
|
|
613
|
-
if (index === -1) {
|
|
614
|
-
parsed[entry] = void 0;
|
|
615
|
-
continue;
|
|
616
|
-
}
|
|
617
|
-
const key = entry.slice(0, index);
|
|
618
|
-
const value = entry.slice(index + 1);
|
|
619
|
-
parsed[key] = value;
|
|
620
|
-
}
|
|
621
|
-
return parsed;
|
|
622
|
-
};
|
|
623
|
-
const isDefineMap = (input) => input instanceof Map;
|
|
624
|
-
const normalizeDefineInput = (input) => {
|
|
625
|
-
if (!input) {
|
|
626
|
-
return {};
|
|
627
|
-
}
|
|
628
|
-
if (Array.isArray(input)) {
|
|
629
|
-
return parseStringKeyValueInput(input);
|
|
630
|
-
}
|
|
631
|
-
if (isDefineMap(input)) {
|
|
632
|
-
return Object.fromEntries(input);
|
|
633
|
-
}
|
|
634
|
-
return { ...input };
|
|
635
|
-
};
|
|
636
|
-
const isLinkDirectiveMap = (input) => input instanceof Map;
|
|
637
|
-
const normalizeLinkDirectiveInput = (input) => {
|
|
638
|
-
if (!input) {
|
|
639
|
-
return {};
|
|
640
|
-
}
|
|
641
|
-
if (Array.isArray(input)) {
|
|
642
|
-
return parseStringKeyValueInput(input);
|
|
643
|
-
}
|
|
644
|
-
if (isLinkDirectiveMap(input)) {
|
|
645
|
-
return Object.fromEntries(input);
|
|
646
|
-
}
|
|
647
|
-
return { ...input };
|
|
648
|
-
};
|
|
649
|
-
const mergeDefines = (common, target) => ({
|
|
650
|
-
...normalizeDefineInput(common),
|
|
651
|
-
...normalizeDefineInput(target)
|
|
652
|
-
});
|
|
653
|
-
const mergeLinkDirectives = (common, target) => ({
|
|
654
|
-
...normalizeLinkDirectiveInput(common),
|
|
655
|
-
...normalizeLinkDirectiveInput(target)
|
|
656
|
-
});
|
|
657
|
-
const resolveWasmOptEnabled = (common, target) => {
|
|
658
|
-
var _a, _b;
|
|
659
|
-
return (_b = (_a = target == null ? void 0 : target.enable) != null ? _a : common == null ? void 0 : common.enable) != null ? _b : false;
|
|
660
|
-
};
|
|
661
|
-
const resolveWasmOptArgs = (common, target, env) => {
|
|
662
|
-
var _a, _b;
|
|
663
|
-
const commonArgs = (_a = common == null ? void 0 : common.options) != null ? _a : DEFAULT_WASM_OPT_ARGS;
|
|
664
|
-
const targetArgs = (_b = target == null ? void 0 : target.options) != null ? _b : [];
|
|
665
|
-
const mergedArgs = [...commonArgs, ...targetArgs];
|
|
666
|
-
return expandArray(mergedArgs, env, "wasmOpt.options");
|
|
667
|
-
};
|
|
668
|
-
const stripOuterQuotes = (value) => {
|
|
669
|
-
const trimmed = value.trim();
|
|
670
|
-
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
671
|
-
return trimmed.slice(1, -1);
|
|
672
|
-
}
|
|
673
|
-
return trimmed;
|
|
674
|
-
};
|
|
675
|
-
const extractWasmBinaryFile = (value) => {
|
|
676
|
-
if (value.startsWith("WASM_BINARY_FILE=")) {
|
|
677
|
-
return value.slice("WASM_BINARY_FILE=".length);
|
|
678
|
-
}
|
|
679
|
-
const match = value.match(/^(?:-s|--settings)(?:=)?WASM_BINARY_FILE=(.+)$/);
|
|
680
|
-
if (match) {
|
|
681
|
-
return match[1];
|
|
682
|
-
}
|
|
683
|
-
return void 0;
|
|
684
|
-
};
|
|
685
|
-
const resolveWasmBinaryFileFromLinkOptions = (linkOptions) => {
|
|
686
|
-
for (let index = 0; index < linkOptions.length; index += 1) {
|
|
687
|
-
const option = linkOptions[index];
|
|
688
|
-
if (!option) {
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
691
|
-
if (option === "-s" || option === "--settings") {
|
|
692
|
-
const next = linkOptions[index + 1];
|
|
693
|
-
if (!next) {
|
|
694
|
-
continue;
|
|
695
|
-
}
|
|
696
|
-
const extracted2 = extractWasmBinaryFile(next);
|
|
697
|
-
if (extracted2) {
|
|
698
|
-
return stripOuterQuotes(extracted2);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
const extracted = extractWasmBinaryFile(option);
|
|
702
|
-
if (extracted) {
|
|
703
|
-
return stripOuterQuotes(extracted);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
return void 0;
|
|
707
|
-
};
|
|
708
|
-
const resolveWasmOptInputFile = (resolvedOutFile, resolvedLinkOptions) => {
|
|
709
|
-
const wasmBinaryFile = resolveWasmBinaryFileFromLinkOptions(resolvedLinkOptions);
|
|
710
|
-
if (wasmBinaryFile) {
|
|
711
|
-
return path.isAbsolute(wasmBinaryFile) ? wasmBinaryFile : path.resolve(path.dirname(resolvedOutFile), wasmBinaryFile);
|
|
712
|
-
}
|
|
713
|
-
const parsed = path.parse(resolvedOutFile);
|
|
714
|
-
if (parsed.ext.toLowerCase() === ".wasm") {
|
|
715
|
-
return resolvedOutFile;
|
|
716
|
-
}
|
|
717
|
-
const baseName = parsed.name.toLowerCase().endsWith(".wasm") ? parsed.name : `${parsed.name}.wasm`;
|
|
718
|
-
return path.join(parsed.dir, baseName);
|
|
719
|
-
};
|
|
720
|
-
const resolvePath = (rootDir, value) => path.isAbsolute(value) ? value : path.resolve(rootDir, value);
|
|
721
|
-
const expandPlaceholders = (value, env, label) => value.replace(/\{([A-Z0-9_]+)\}/g, (_match, key) => {
|
|
722
|
-
const replacement = env[key];
|
|
723
|
-
if (replacement === void 0) {
|
|
724
|
-
throw new Error(`Unknown placeholder {${key}} in ${label}.`);
|
|
725
|
-
}
|
|
726
|
-
return replacement;
|
|
727
|
-
});
|
|
728
|
-
const expandArray = (values, env, label) => values.map((value) => expandPlaceholders(value, env, label));
|
|
729
|
-
const resolveDefines = (defines, env) => {
|
|
730
|
-
const resolved = {};
|
|
731
|
-
for (const [key, value] of Object.entries(defines)) {
|
|
732
|
-
if (typeof value === "string") {
|
|
733
|
-
resolved[key] = expandPlaceholders(value, env, `defines.${key}`);
|
|
734
|
-
} else {
|
|
735
|
-
resolved[key] = value;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
return resolved;
|
|
739
|
-
};
|
|
740
|
-
const resolveLinkDirectiveValue = (value, env, label) => {
|
|
741
|
-
if (typeof value === "string") {
|
|
742
|
-
return expandPlaceholders(value, env, label);
|
|
743
|
-
}
|
|
744
|
-
if (Array.isArray(value)) {
|
|
745
|
-
return value.map(
|
|
746
|
-
(entry, index) => expandPlaceholders(entry, env, `${label}[${index}]`)
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
return value;
|
|
750
|
-
};
|
|
751
|
-
const resolveLinkDirectives = (directives, env) => {
|
|
752
|
-
const resolved = {};
|
|
753
|
-
for (const [key, value] of Object.entries(directives)) {
|
|
754
|
-
resolved[key] = resolveLinkDirectiveValue(
|
|
755
|
-
value,
|
|
756
|
-
env,
|
|
757
|
-
`linkDirectives.${key}`
|
|
758
|
-
);
|
|
759
|
-
}
|
|
760
|
-
return resolved;
|
|
761
|
-
};
|
|
762
|
-
const resolveIncludeDirs = (includeDirs, env, rootDir) => {
|
|
763
|
-
const expanded = expandArray(includeDirs, env, "includeDirs");
|
|
764
|
-
return expanded.map((value) => resolvePath(rootDir, value));
|
|
765
|
-
};
|
|
766
|
-
const resolveOutFile = (outFile, env, outDir) => {
|
|
767
|
-
const expanded = expandPlaceholders(outFile, env, "outFile");
|
|
768
|
-
return resolvePath(outDir, expanded);
|
|
769
|
-
};
|
|
770
|
-
const resolveSourcesFromPatterns = async (patterns, env, srcDir, label) => {
|
|
771
|
-
const expanded = expandArray(patterns, env, label);
|
|
772
|
-
const resolvedPatterns = expanded.map((value) => resolvePath(srcDir, value));
|
|
773
|
-
const results = await Promise.all(
|
|
774
|
-
resolvedPatterns.map((pattern) => glob.glob(pattern, { nodir: true }))
|
|
775
|
-
);
|
|
776
|
-
const sources = results.flat();
|
|
777
|
-
sources.sort();
|
|
778
|
-
return sources;
|
|
779
|
-
};
|
|
780
|
-
const buildDefineFlags = (defines) => Object.entries(defines).flatMap(
|
|
781
|
-
([key, value]) => value === null || value === void 0 ? [`-D${key}`] : [`-D${key}=${String(value)}`]
|
|
782
|
-
);
|
|
783
|
-
const serializeLinkDirectiveValue = (value) => Array.isArray(value) ? JSON.stringify(value) : String(value);
|
|
784
|
-
const buildLinkDirectiveFlags = (directives) => {
|
|
785
|
-
if (Object.keys(directives).length === 0) {
|
|
786
|
-
return [];
|
|
787
|
-
}
|
|
788
|
-
return Object.entries(directives).flatMap(
|
|
789
|
-
([key, value]) => value === null || value === void 0 ? ["-s", key] : ["-s", `${key}=${serializeLinkDirectiveValue(value)}`]
|
|
790
|
-
);
|
|
791
|
-
};
|
|
792
|
-
const buildExportFlags = (exports$1) => {
|
|
793
|
-
if (exports$1.length === 0) {
|
|
794
|
-
return [];
|
|
795
|
-
}
|
|
796
|
-
return ["-s", `EXPORTED_FUNCTIONS=${JSON.stringify(exports$1)}`];
|
|
797
|
-
};
|
|
798
|
-
const createEnvForBuild = (baseEnv, overrides) => ({
|
|
799
|
-
...process.env,
|
|
800
|
-
...baseEnv,
|
|
801
|
-
...overrides
|
|
802
|
-
});
|
|
803
|
-
const resolveTargetOutFile = (targetName, targetOutFile, env, baseDir, extension) => {
|
|
804
|
-
if (targetOutFile) {
|
|
805
|
-
return resolveOutFile(targetOutFile, env, baseDir);
|
|
806
|
-
}
|
|
807
|
-
return path.resolve(baseDir, `${targetName}.${extension}`);
|
|
808
|
-
};
|
|
809
|
-
const resolveTargetSources = async (targetSources, env, srcDir) => {
|
|
810
|
-
const patterns = targetSources && targetSources.length > 0 ? targetSources : [path.join(srcDir, "**", "*.c"), path.join(srcDir, "**", "*.cpp")];
|
|
811
|
-
return resolveSourcesFromPatterns(patterns, env, srcDir, "sources");
|
|
812
|
-
};
|
|
813
|
-
const toSafeObjectName = (rootDir, sourcePath, groupIndex) => {
|
|
814
|
-
const baseName = path.relative(rootDir, sourcePath).replace(/[\\/]/g, "_").replace(/[^A-Za-z0-9._-]/g, "_");
|
|
815
|
-
if (groupIndex === void 0) {
|
|
816
|
-
return baseName;
|
|
817
|
-
}
|
|
818
|
-
return `${baseName}__g${groupIndex}`;
|
|
819
|
-
};
|
|
820
|
-
const dedupeSources = (sources) => {
|
|
821
|
-
const seen = /* @__PURE__ */ new Set();
|
|
822
|
-
const deduped = [];
|
|
823
|
-
for (const source of sources) {
|
|
824
|
-
if (seen.has(source)) {
|
|
825
|
-
continue;
|
|
826
|
-
}
|
|
827
|
-
seen.add(source);
|
|
828
|
-
deduped.push(source);
|
|
829
|
-
}
|
|
830
|
-
return deduped;
|
|
831
|
-
};
|
|
832
|
-
const dedupeValues = (values) => {
|
|
833
|
-
const seen = /* @__PURE__ */ new Set();
|
|
834
|
-
const deduped = [];
|
|
835
|
-
for (const value of values) {
|
|
836
|
-
if (seen.has(value)) {
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
seen.add(value);
|
|
840
|
-
deduped.push(value);
|
|
841
|
-
}
|
|
842
|
-
return deduped;
|
|
843
|
-
};
|
|
844
|
-
const isSubPath = (parentDir, targetPath) => {
|
|
845
|
-
const rel = path.relative(parentDir, targetPath);
|
|
846
|
-
if (rel === "") {
|
|
847
|
-
return true;
|
|
848
|
-
}
|
|
849
|
-
return !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
850
|
-
};
|
|
851
|
-
const readTextIfExists = async (filePath) => {
|
|
852
|
-
try {
|
|
853
|
-
return await promises.readFile(filePath, "utf8");
|
|
854
|
-
} catch (error) {
|
|
855
|
-
const nodeError = error;
|
|
856
|
-
if (nodeError.code === "ENOENT") {
|
|
857
|
-
return void 0;
|
|
858
|
-
}
|
|
859
|
-
throw error;
|
|
860
|
-
}
|
|
861
|
-
};
|
|
862
|
-
const writeTextIfChanged = async (filePath, content) => {
|
|
863
|
-
const existing = await readTextIfExists(filePath);
|
|
864
|
-
if (existing === content) {
|
|
865
|
-
return false;
|
|
866
|
-
}
|
|
867
|
-
await ensureDirectory(path.dirname(filePath));
|
|
868
|
-
await promises.writeFile(filePath, content, "utf8");
|
|
869
|
-
return true;
|
|
870
|
-
};
|
|
871
|
-
const toPascalCaseIdentifier = (value) => {
|
|
872
|
-
const tokens = value.split(/[^A-Za-z0-9]+/).map((token) => token.trim()).filter((token) => token.length > 0);
|
|
873
|
-
if (tokens.length === 0) {
|
|
874
|
-
throw new Error(`Cannot derive loader function name from target: ${value}`);
|
|
875
|
-
}
|
|
876
|
-
const pascal = tokens.map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join("");
|
|
877
|
-
return /^[0-9]/.test(pascal) ? `Target${pascal}` : pascal;
|
|
878
|
-
};
|
|
879
|
-
const toRelativeImportSpecifier = (fromFile, toFile) => {
|
|
880
|
-
const rel = path.relative(path.dirname(fromFile), toFile).replace(/\\/g, "/");
|
|
881
|
-
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
882
|
-
};
|
|
883
|
-
const buildGeneratedLoaderContent = (generatedLoaderFile, targets) => {
|
|
884
|
-
const targetBlocks = targets.map((target) => {
|
|
885
|
-
const specifier = JSON.stringify(
|
|
886
|
-
toRelativeImportSpecifier(generatedLoaderFile, target.outFile)
|
|
887
|
-
);
|
|
888
|
-
return `export const ${target.functionName} = async <T extends object>(
|
|
889
|
-
options?: TargetWasmLoadOptions
|
|
890
|
-
): Promise<WasmInstance<T>> => {
|
|
891
|
-
const source = options?.url ?? new URL(${specifier}, import.meta.url);
|
|
892
|
-
return await loadWasm<T>(source, createWasmLoadOptions(options?.imports));
|
|
893
|
-
};`;
|
|
894
|
-
}).join("\n\n");
|
|
895
|
-
return `// Generated by emsdk-env. DO NOT EDIT.
|
|
896
|
-
|
|
897
|
-
export type WasmSource =
|
|
898
|
-
| string
|
|
899
|
-
| URL
|
|
900
|
-
| ArrayBuffer
|
|
901
|
-
| ArrayBufferView
|
|
902
|
-
| Response;
|
|
903
|
-
|
|
904
|
-
export interface WasmLoadOptions {
|
|
905
|
-
readonly imports?: WebAssembly.Imports;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
export interface TargetWasmLoadOptions extends WasmLoadOptions {
|
|
909
|
-
readonly url?: string | URL;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
const isResponse = (value: WasmSource): value is Response =>
|
|
913
|
-
typeof Response !== 'undefined' && value instanceof Response;
|
|
914
|
-
|
|
915
|
-
const createWasmLoadOptions = (
|
|
916
|
-
imports: WebAssembly.Imports | undefined
|
|
917
|
-
): WasmLoadOptions | undefined => (imports ? { imports } : undefined);
|
|
918
|
-
|
|
919
|
-
export interface WasmInstance<T extends object> {
|
|
920
|
-
readonly exports: T;
|
|
921
|
-
readonly memory: WebAssembly.Memory;
|
|
922
|
-
readonly table: WebAssembly.Table | undefined;
|
|
923
|
-
readonly rawExports: WebAssembly.Exports;
|
|
924
|
-
readonly module: WebAssembly.Module;
|
|
925
|
-
readonly instance: WebAssembly.Instance;
|
|
926
|
-
readonly initialize: (() => unknown) | undefined;
|
|
927
|
-
readonly start: (() => unknown) | undefined;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
const resolveWasmBytes = async (source: WasmSource): Promise<ArrayBuffer> => {
|
|
931
|
-
if (isResponse(source)) {
|
|
932
|
-
return await source.arrayBuffer();
|
|
933
|
-
}
|
|
934
|
-
if (source instanceof URL || typeof source === 'string') {
|
|
935
|
-
const response = await fetch(source);
|
|
936
|
-
if (!response.ok) {
|
|
937
|
-
throw new Error(\`Failed to fetch wasm: \${response.url}\`);
|
|
938
|
-
}
|
|
939
|
-
return await response.arrayBuffer();
|
|
940
|
-
}
|
|
941
|
-
if (source instanceof ArrayBuffer) {
|
|
942
|
-
return source;
|
|
943
|
-
}
|
|
944
|
-
if (ArrayBuffer.isView(source)) {
|
|
945
|
-
const view = new Uint8Array(
|
|
946
|
-
source.buffer,
|
|
947
|
-
source.byteOffset,
|
|
948
|
-
source.byteLength
|
|
949
|
-
);
|
|
950
|
-
return view.slice().buffer;
|
|
951
|
-
}
|
|
952
|
-
throw new TypeError('Unsupported wasm source.');
|
|
953
|
-
};
|
|
954
|
-
|
|
955
|
-
const getImportValue = (
|
|
956
|
-
imports: WebAssembly.Imports | undefined,
|
|
957
|
-
moduleName: string,
|
|
958
|
-
name: string
|
|
959
|
-
) => {
|
|
960
|
-
const moduleImports = imports?.[moduleName];
|
|
961
|
-
if (!moduleImports || typeof moduleImports !== 'object') {
|
|
962
|
-
return undefined;
|
|
963
|
-
}
|
|
964
|
-
return (moduleImports as Record<string, unknown>)[name];
|
|
965
|
-
};
|
|
966
|
-
|
|
967
|
-
const resolveMemory = (
|
|
968
|
-
module: WebAssembly.Module,
|
|
969
|
-
instance: WebAssembly.Instance,
|
|
970
|
-
imports: WebAssembly.Imports | undefined
|
|
971
|
-
) => {
|
|
972
|
-
let memory: WebAssembly.Memory | undefined;
|
|
973
|
-
for (const entry of WebAssembly.Module.exports(module)) {
|
|
974
|
-
if (entry.kind !== 'memory') {
|
|
975
|
-
continue;
|
|
976
|
-
}
|
|
977
|
-
if (memory) {
|
|
978
|
-
throw new Error('Multiple wasm memories are not supported.');
|
|
979
|
-
}
|
|
980
|
-
const value = instance.exports[entry.name];
|
|
981
|
-
if (!(value instanceof WebAssembly.Memory)) {
|
|
982
|
-
throw new Error(\`Export is not a WebAssembly.Memory: \${entry.name}\`);
|
|
983
|
-
}
|
|
984
|
-
memory = value;
|
|
985
|
-
}
|
|
986
|
-
if (memory) {
|
|
987
|
-
return memory;
|
|
988
|
-
}
|
|
989
|
-
for (const entry of WebAssembly.Module.imports(module)) {
|
|
990
|
-
if (entry.kind !== 'memory') {
|
|
991
|
-
continue;
|
|
992
|
-
}
|
|
993
|
-
if (memory) {
|
|
994
|
-
throw new Error('Multiple wasm memories are not supported.');
|
|
995
|
-
}
|
|
996
|
-
const value = getImportValue(imports, entry.module, entry.name);
|
|
997
|
-
if (!(value instanceof WebAssembly.Memory)) {
|
|
998
|
-
throw new Error(
|
|
999
|
-
\`Imported value is not a WebAssembly.Memory: \${entry.module}.\${entry.name}\`
|
|
1000
|
-
);
|
|
1001
|
-
}
|
|
1002
|
-
memory = value;
|
|
1003
|
-
}
|
|
1004
|
-
if (!memory) {
|
|
1005
|
-
throw new Error('WASM memory export/import was not resolved.');
|
|
1006
|
-
}
|
|
1007
|
-
return memory;
|
|
1008
|
-
};
|
|
1009
|
-
|
|
1010
|
-
const resolveTable = (
|
|
1011
|
-
module: WebAssembly.Module,
|
|
1012
|
-
instance: WebAssembly.Instance,
|
|
1013
|
-
imports: WebAssembly.Imports | undefined
|
|
1014
|
-
) => {
|
|
1015
|
-
let table: WebAssembly.Table | undefined;
|
|
1016
|
-
for (const entry of WebAssembly.Module.exports(module)) {
|
|
1017
|
-
if (entry.kind !== 'table') {
|
|
1018
|
-
continue;
|
|
1019
|
-
}
|
|
1020
|
-
if (table) {
|
|
1021
|
-
throw new Error('Multiple wasm tables are not supported.');
|
|
1022
|
-
}
|
|
1023
|
-
const value = instance.exports[entry.name];
|
|
1024
|
-
if (!(value instanceof WebAssembly.Table)) {
|
|
1025
|
-
throw new Error(\`Export is not a WebAssembly.Table: \${entry.name}\`);
|
|
1026
|
-
}
|
|
1027
|
-
table = value;
|
|
1028
|
-
}
|
|
1029
|
-
if (table) {
|
|
1030
|
-
return table;
|
|
1031
|
-
}
|
|
1032
|
-
for (const entry of WebAssembly.Module.imports(module)) {
|
|
1033
|
-
if (entry.kind !== 'table') {
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
if (table) {
|
|
1037
|
-
throw new Error('Multiple wasm tables are not supported.');
|
|
1038
|
-
}
|
|
1039
|
-
const value = getImportValue(imports, entry.module, entry.name);
|
|
1040
|
-
if (!(value instanceof WebAssembly.Table)) {
|
|
1041
|
-
throw new Error(
|
|
1042
|
-
\`Imported value is not a WebAssembly.Table: \${entry.module}.\${entry.name}\`
|
|
1043
|
-
);
|
|
1044
|
-
}
|
|
1045
|
-
table = value;
|
|
1046
|
-
}
|
|
1047
|
-
return table;
|
|
1048
|
-
};
|
|
1049
|
-
|
|
1050
|
-
export const loadWasm = async <T extends object>(
|
|
1051
|
-
source: WasmSource,
|
|
1052
|
-
options?: WasmLoadOptions
|
|
1053
|
-
): Promise<WasmInstance<T>> => {
|
|
1054
|
-
const bytes = await resolveWasmBytes(source);
|
|
1055
|
-
const module = await WebAssembly.compile(bytes);
|
|
1056
|
-
const instance = await WebAssembly.instantiate(module, options?.imports ?? {});
|
|
1057
|
-
|
|
1058
|
-
const functionExports: Record<string, (...args: unknown[]) => unknown> = {};
|
|
1059
|
-
for (const entry of WebAssembly.Module.exports(module)) {
|
|
1060
|
-
if (entry.kind !== 'function') {
|
|
1061
|
-
continue;
|
|
1062
|
-
}
|
|
1063
|
-
const value = instance.exports[entry.name];
|
|
1064
|
-
if (typeof value !== 'function') {
|
|
1065
|
-
throw new Error(\`Export is not a function: \${entry.name}\`);
|
|
1066
|
-
}
|
|
1067
|
-
functionExports[entry.name] = value as (...args: unknown[]) => unknown;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
const initialize =
|
|
1071
|
-
typeof instance.exports._initialize === 'function'
|
|
1072
|
-
? (instance.exports._initialize as () => unknown)
|
|
1073
|
-
: undefined;
|
|
1074
|
-
const start =
|
|
1075
|
-
typeof instance.exports._start === 'function'
|
|
1076
|
-
? (instance.exports._start as () => unknown)
|
|
1077
|
-
: undefined;
|
|
1078
|
-
|
|
1079
|
-
return {
|
|
1080
|
-
exports: functionExports as T,
|
|
1081
|
-
memory: resolveMemory(module, instance, options?.imports),
|
|
1082
|
-
table: resolveTable(module, instance, options?.imports),
|
|
1083
|
-
rawExports: instance.exports,
|
|
1084
|
-
module,
|
|
1085
|
-
instance,
|
|
1086
|
-
initialize,
|
|
1087
|
-
start,
|
|
1088
|
-
};
|
|
1089
|
-
};
|
|
1090
|
-
|
|
1091
|
-
${targetBlocks}
|
|
1092
|
-
`;
|
|
1093
|
-
};
|
|
1094
|
-
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1095
|
-
const resolvePackageJsonPath = async (startPath, packageName) => {
|
|
1096
|
-
let current = path.dirname(startPath);
|
|
1097
|
-
for (; ; ) {
|
|
1098
|
-
const candidate = path.join(current, "package.json");
|
|
1099
|
-
if (await pathExists(candidate)) {
|
|
1100
|
-
return candidate;
|
|
1101
|
-
}
|
|
1102
|
-
const parent = path.dirname(current);
|
|
1103
|
-
if (parent === current) {
|
|
1104
|
-
throw new Error(`package.json not found for import: ${packageName}`);
|
|
1105
|
-
}
|
|
1106
|
-
current = parent;
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
const loadPackageJson = async (packageJsonPath, packageName) => {
|
|
1110
|
-
try {
|
|
1111
|
-
const raw = await promises.readFile(packageJsonPath, "utf8");
|
|
1112
|
-
const parsed = JSON.parse(raw);
|
|
1113
|
-
if (!isRecord(parsed)) {
|
|
1114
|
-
throw new Error("package.json must be an object.");
|
|
1115
|
-
}
|
|
1116
|
-
return parsed;
|
|
1117
|
-
} catch (error) {
|
|
1118
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1119
|
-
throw new Error(
|
|
1120
|
-
`Failed to read package.json for import ${packageName}: ${message}`
|
|
1121
|
-
);
|
|
1122
|
-
}
|
|
1123
|
-
};
|
|
1124
|
-
const resolveImportPaths = async (resolver, packageName) => {
|
|
1125
|
-
let resolvedEntry;
|
|
1126
|
-
try {
|
|
1127
|
-
resolvedEntry = resolver.resolve(packageName);
|
|
1128
|
-
} catch (error) {
|
|
1129
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1130
|
-
throw new Error(`Failed to resolve import ${packageName}: ${message}`);
|
|
1131
|
-
}
|
|
1132
|
-
const packageJsonPath = await resolvePackageJsonPath(
|
|
1133
|
-
resolvedEntry,
|
|
1134
|
-
packageName
|
|
1135
|
-
);
|
|
1136
|
-
const packageRoot = path.dirname(packageJsonPath);
|
|
1137
|
-
const packageJson = await loadPackageJson(packageJsonPath, packageName);
|
|
1138
|
-
const emsdkConfigRaw = packageJson["emsdk-env"];
|
|
1139
|
-
if (emsdkConfigRaw !== void 0 && !isRecord(emsdkConfigRaw)) {
|
|
1140
|
-
throw new Error(
|
|
1141
|
-
`Invalid emsdk-env config for import ${packageName}: expected an object.`
|
|
1142
|
-
);
|
|
1143
|
-
}
|
|
1144
|
-
const includeRaw = isRecord(emsdkConfigRaw) ? emsdkConfigRaw.include : void 0;
|
|
1145
|
-
if (includeRaw !== void 0 && typeof includeRaw !== "string") {
|
|
1146
|
-
throw new Error(
|
|
1147
|
-
`Invalid emsdk-env include for import ${packageName}: expected a string.`
|
|
1148
|
-
);
|
|
1149
|
-
}
|
|
1150
|
-
const libRaw = isRecord(emsdkConfigRaw) ? emsdkConfigRaw.lib : void 0;
|
|
1151
|
-
if (libRaw !== void 0 && typeof libRaw !== "string") {
|
|
1152
|
-
throw new Error(
|
|
1153
|
-
`Invalid emsdk-env lib for import ${packageName}: expected a string.`
|
|
1154
|
-
);
|
|
1155
|
-
}
|
|
1156
|
-
const includeRel = includeRaw != null ? includeRaw : DEFAULT_IMPORT_INCLUDE_DIR;
|
|
1157
|
-
const libRel = libRaw != null ? libRaw : DEFAULT_IMPORT_LIB_DIR;
|
|
1158
|
-
const includeDir = path.resolve(packageRoot, includeRel);
|
|
1159
|
-
const libDir = path.resolve(packageRoot, libRel);
|
|
1160
|
-
const includeExists = await pathExists(includeDir);
|
|
1161
|
-
const libExists = await pathExists(libDir);
|
|
1162
|
-
if (!includeExists && !libExists) {
|
|
1163
|
-
throw new Error(
|
|
1164
|
-
`Import ${packageName} does not provide include or lib directories.`
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
return {
|
|
1168
|
-
includeDir: includeExists ? includeDir : void 0,
|
|
1169
|
-
libDir: libExists ? libDir : void 0
|
|
1170
|
-
};
|
|
1171
|
-
};
|
|
1172
|
-
const resolveImportDirectories = async (rootDir, imports) => {
|
|
1173
|
-
if (imports.length === 0) {
|
|
1174
|
-
return { includeDirs: [], libDirs: [] };
|
|
1175
|
-
}
|
|
1176
|
-
const moduleApi = await import("node:module");
|
|
1177
|
-
const resolver = moduleApi.createRequire(path.resolve(rootDir, "package.json"));
|
|
1178
|
-
const includeDirs = [];
|
|
1179
|
-
const libDirs = [];
|
|
1180
|
-
for (const packageName of imports) {
|
|
1181
|
-
const resolved = await resolveImportPaths(resolver, packageName);
|
|
1182
|
-
if (resolved.includeDir) {
|
|
1183
|
-
includeDirs.push(resolved.includeDir);
|
|
1184
|
-
}
|
|
1185
|
-
if (resolved.libDir) {
|
|
1186
|
-
libDirs.push(resolved.libDir);
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
return {
|
|
1190
|
-
includeDirs: dedupeValues(includeDirs),
|
|
1191
|
-
libDirs: dedupeValues(libDirs)
|
|
1192
|
-
};
|
|
1193
|
-
};
|
|
1194
|
-
const resolveGeneratedLoaderOutFile = (rootDir, env, generatedLoader) => {
|
|
1195
|
-
var _a;
|
|
1196
|
-
if (!(generatedLoader == null ? void 0 : generatedLoader.enable)) {
|
|
1197
|
-
return void 0;
|
|
1198
|
-
}
|
|
1199
|
-
const rawOutFile = expandPlaceholders(
|
|
1200
|
-
(_a = generatedLoader.outFile) != null ? _a : DEFAULT_GENERATED_LOADER_OUT_FILE,
|
|
1201
|
-
env,
|
|
1202
|
-
"generatedLoader.outFile"
|
|
1203
|
-
);
|
|
1204
|
-
return resolvePath(rootDir, rawOutFile);
|
|
1205
|
-
};
|
|
1206
|
-
const resolveGeneratedLoaderWatchDirs = (rootDir, srcDir, commonIncludeDirs, env, targetEntries, importIncludeDirs) => {
|
|
1207
|
-
const dirs = [srcDir, ...resolveIncludeDirs(commonIncludeDirs, env, rootDir)];
|
|
1208
|
-
for (const [targetName, target] of targetEntries) {
|
|
1209
|
-
if (!target.includeDirs || target.includeDirs.length === 0) {
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
const targetEnv = {
|
|
1213
|
-
...env,
|
|
1214
|
-
TARGET_NAME: targetName
|
|
1215
|
-
};
|
|
1216
|
-
dirs.push(...resolveIncludeDirs(target.includeDirs, targetEnv, rootDir));
|
|
1217
|
-
}
|
|
1218
|
-
dirs.push(...importIncludeDirs);
|
|
1219
|
-
return dedupeValues(dirs);
|
|
1220
|
-
};
|
|
1221
|
-
const validateGeneratedLoaderOutFile = (generatedLoaderFile, watchDirs) => {
|
|
1222
|
-
for (const dir of watchDirs) {
|
|
1223
|
-
if (isSubPath(dir, generatedLoaderFile)) {
|
|
1224
|
-
throw new Error(
|
|
1225
|
-
`generatedLoader.outFile must not be placed under watched directory: ${generatedLoaderFile}`
|
|
1226
|
-
);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
};
|
|
1230
|
-
const buildCompileArgs = (options, includeDirs, defines, env, rootDir) => {
|
|
1231
|
-
const resolvedOptions = expandArray(options, env, "options");
|
|
1232
|
-
const includeArgs = resolveIncludeDirs(includeDirs, env, rootDir).map(
|
|
1233
|
-
(dir) => `-I${dir}`
|
|
1234
|
-
);
|
|
1235
|
-
const defineArgs = buildDefineFlags(resolveDefines(defines, env));
|
|
1236
|
-
return { resolvedOptions, includeArgs, defineArgs };
|
|
1237
|
-
};
|
|
1238
|
-
const buildWasm = async (options) => {
|
|
1239
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1240
|
-
if (!options) {
|
|
1241
|
-
throw new TypeError("options must be provided.");
|
|
1242
|
-
}
|
|
1243
|
-
if (!options.rule || !options.rule.targets) {
|
|
1244
|
-
throw new TypeError("rule targets must be provided.");
|
|
1245
|
-
}
|
|
1246
|
-
const targetEntries = Object.entries(options.rule.targets);
|
|
1247
|
-
if (targetEntries.length === 0) {
|
|
1248
|
-
throw new TypeError("rule targets must not be empty.");
|
|
1249
|
-
}
|
|
1250
|
-
const logger = (_a = options.logger) != null ? _a : createConsoleLogger("emsdk-env");
|
|
1251
|
-
const rootDir = path.resolve((_b = options.root) != null ? _b : process.cwd());
|
|
1252
|
-
const emsdkOptions = normalizePrepareOptions(options.emsdk);
|
|
1253
|
-
const emsdkRoot = await prepareEmsdk(emsdkOptions);
|
|
1254
|
-
const emsdkEnv = await loadEmsdkEnv(emsdkRoot, logger, emsdkOptions.signal);
|
|
1255
|
-
const baseEnv = {
|
|
1256
|
-
...emsdkEnv,
|
|
1257
|
-
ROOT: rootDir
|
|
1258
|
-
};
|
|
1259
|
-
const rawSrcDir = expandPlaceholders(
|
|
1260
|
-
(_c = options.srcDir) != null ? _c : DEFAULT_WASM_SRC_DIR,
|
|
1261
|
-
baseEnv,
|
|
1262
|
-
"srcDir"
|
|
1263
|
-
);
|
|
1264
|
-
const rawIncludeDir = expandPlaceholders(
|
|
1265
|
-
(_d = options.includeDir) != null ? _d : DEFAULT_WASM_INCLUDE_DIR,
|
|
1266
|
-
baseEnv,
|
|
1267
|
-
"includeDir"
|
|
1268
|
-
);
|
|
1269
|
-
const rawOutDir = expandPlaceholders(
|
|
1270
|
-
(_e = options.outDir) != null ? _e : DEFAULT_WASM_OUT_DIR,
|
|
1271
|
-
baseEnv,
|
|
1272
|
-
"outDir"
|
|
1273
|
-
);
|
|
1274
|
-
const rawLibDir = expandPlaceholders(
|
|
1275
|
-
(_f = options.libDir) != null ? _f : DEFAULT_WASM_LIB_DIR,
|
|
1276
|
-
baseEnv,
|
|
1277
|
-
"libDir"
|
|
1278
|
-
);
|
|
1279
|
-
const rawBuildDir = expandPlaceholders(
|
|
1280
|
-
(_g = options.buildDir) != null ? _g : DEFAULT_WASM_BUILD_DIR,
|
|
1281
|
-
baseEnv,
|
|
1282
|
-
"buildDir"
|
|
1283
|
-
);
|
|
1284
|
-
const srcDir = resolvePath(rootDir, rawSrcDir);
|
|
1285
|
-
const includeDir = resolvePath(rootDir, rawIncludeDir);
|
|
1286
|
-
const outDir = resolvePath(rootDir, rawOutDir);
|
|
1287
|
-
const libDir = resolvePath(rootDir, rawLibDir);
|
|
1288
|
-
const buildDir = resolvePath(rootDir, rawBuildDir);
|
|
1289
|
-
const buildId = createBuildId();
|
|
1290
|
-
const buildRunDir = path.resolve(buildDir, buildId);
|
|
1291
|
-
const cleanupBuildDir = (_h = options.cleanupBuildDir) != null ? _h : true;
|
|
1292
|
-
const parallel = (_i = options.parallel) != null ? _i : true;
|
|
1293
|
-
const envWithDirs = {
|
|
1294
|
-
...emsdkEnv,
|
|
1295
|
-
ROOT: rootDir,
|
|
1296
|
-
SRC_DIR: srcDir,
|
|
1297
|
-
INCLUDE_DIR: includeDir,
|
|
1298
|
-
OUT_DIR: outDir,
|
|
1299
|
-
LIB_DIR: libDir,
|
|
1300
|
-
BUILD_DIR: buildDir
|
|
1301
|
-
};
|
|
1302
|
-
const emccCommand = await resolveEmccCommand(envWithDirs, emsdkRoot);
|
|
1303
|
-
const common = (_j = options.rule.common) != null ? _j : {};
|
|
1304
|
-
const commonIncludeDirs = common.includeDirs === void 0 ? [includeDir] : common.includeDirs;
|
|
1305
|
-
const importDirectories = await resolveImportDirectories(
|
|
1306
|
-
rootDir,
|
|
1307
|
-
ensureArray(options.imports)
|
|
1308
|
-
);
|
|
1309
|
-
const importIncludeDirs = importDirectories.includeDirs;
|
|
1310
|
-
const importLibDirs = importDirectories.libDirs;
|
|
1311
|
-
const linkLibDirs = dedupeValues([libDir, ...importLibDirs]);
|
|
1312
|
-
const generatedLoaderFile = resolveGeneratedLoaderOutFile(
|
|
1313
|
-
rootDir,
|
|
1314
|
-
envWithDirs,
|
|
1315
|
-
options.generatedLoader
|
|
1316
|
-
);
|
|
1317
|
-
if (generatedLoaderFile) {
|
|
1318
|
-
const watchDirs = resolveGeneratedLoaderWatchDirs(
|
|
1319
|
-
rootDir,
|
|
1320
|
-
srcDir,
|
|
1321
|
-
commonIncludeDirs,
|
|
1322
|
-
envWithDirs,
|
|
1323
|
-
targetEntries,
|
|
1324
|
-
importIncludeDirs
|
|
1325
|
-
);
|
|
1326
|
-
validateGeneratedLoaderOutFile(generatedLoaderFile, watchDirs);
|
|
1327
|
-
}
|
|
1328
|
-
logger.debug(`Detected rootDir: '${rootDir}'`);
|
|
1329
|
-
logger.debug(`Detected srcDir: '${srcDir}'`);
|
|
1330
|
-
logger.debug(`Detected outDir: '${outDir}'`);
|
|
1331
|
-
logger.debug(`Detected libDir: '${libDir}'`);
|
|
1332
|
-
logger.debug(`Detected buildDir: '${buildDir}'`);
|
|
1333
|
-
logger.debug(`Detected buildId: '${buildId}'`);
|
|
1334
|
-
logger.debug(`Detected buildRunDir: '${buildRunDir}'`);
|
|
1335
|
-
logger.debug(`Detected cleanupBuildDir: ${cleanupBuildDir}`);
|
|
1336
|
-
logger.debug(`Detected parallel: ${parallel}`);
|
|
1337
|
-
logger.debug(`Detected emccCommand: '${emccCommand}'`);
|
|
1338
|
-
logger.debug(
|
|
1339
|
-
`Detected importIncludeDirs: [${importIncludeDirs.map((p) => `'${p}'`).join(",")}]`
|
|
1340
|
-
);
|
|
1341
|
-
logger.debug(
|
|
1342
|
-
`Detected importLibDirs: [${importLibDirs.map((p) => `'${p}'`).join(",")}]`
|
|
1343
|
-
);
|
|
1344
|
-
if (generatedLoaderFile) {
|
|
1345
|
-
logger.debug(`Detected generatedLoaderFile: '${generatedLoaderFile}'`);
|
|
1346
|
-
}
|
|
1347
|
-
await ensureDirectory(outDir);
|
|
1348
|
-
await ensureDirectory(libDir);
|
|
1349
|
-
await ensureDirectory(buildDir);
|
|
1350
|
-
await promises.rm(buildRunDir, { recursive: true, force: true });
|
|
1351
|
-
await ensureDirectory(buildRunDir);
|
|
1352
|
-
const hasArchiveTargets = targetEntries.some(
|
|
1353
|
-
([, target]) => resolveTargetType(target.type) === "archive"
|
|
1354
|
-
);
|
|
1355
|
-
const emarCommand = hasArchiveTargets ? await resolveEmarCommand(envWithDirs, emsdkRoot) : void 0;
|
|
1356
|
-
if (emarCommand) {
|
|
1357
|
-
logger.debug(`Detected emarCommand: '${emarCommand}'`);
|
|
1358
|
-
}
|
|
1359
|
-
let wasmOptCommand;
|
|
1360
|
-
const getWasmOptCommand = async () => {
|
|
1361
|
-
if (wasmOptCommand) {
|
|
1362
|
-
return wasmOptCommand;
|
|
1363
|
-
}
|
|
1364
|
-
wasmOptCommand = await resolveWasmOptCommand(envWithDirs, emsdkRoot);
|
|
1365
|
-
logger.debug(`Detected wasmOptCommand: '${wasmOptCommand}'`);
|
|
1366
|
-
return wasmOptCommand;
|
|
1367
|
-
};
|
|
1368
|
-
const outFiles = {};
|
|
1369
|
-
let resultGeneratedLoaderFile;
|
|
1370
|
-
const buildTargets = async (expectedType) => {
|
|
1371
|
-
var _a2;
|
|
1372
|
-
for (const [targetName, target] of targetEntries) {
|
|
1373
|
-
const targetType = resolveTargetType(target.type);
|
|
1374
|
-
if (targetType !== expectedType) {
|
|
1375
|
-
continue;
|
|
1376
|
-
}
|
|
1377
|
-
if (targetType === "archive") {
|
|
1378
|
-
if (target.linkOptions !== void 0) {
|
|
1379
|
-
throw new Error(
|
|
1380
|
-
`linkOptions is not supported for archive target: ${targetName}`
|
|
1381
|
-
);
|
|
1382
|
-
}
|
|
1383
|
-
if (target.linkDirectives !== void 0) {
|
|
1384
|
-
throw new Error(
|
|
1385
|
-
`linkDirectives is not supported for archive target: ${targetName}`
|
|
1386
|
-
);
|
|
1387
|
-
}
|
|
1388
|
-
if (target.exports !== void 0) {
|
|
1389
|
-
throw new Error(
|
|
1390
|
-
`exports is not supported for archive target: ${targetName}`
|
|
1391
|
-
);
|
|
1392
|
-
}
|
|
1393
|
-
if (target.wasmOpt !== void 0) {
|
|
1394
|
-
throw new Error(
|
|
1395
|
-
`wasmOpt is not supported for archive target: ${targetName}`
|
|
1396
|
-
);
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
const mergedLinkOptions = targetType === "archive" ? [] : [
|
|
1400
|
-
...ensureArray(common.linkOptions),
|
|
1401
|
-
...ensureArray(target.linkOptions)
|
|
1402
|
-
];
|
|
1403
|
-
const mergedLinkDirectives = targetType === "archive" ? {} : mergeLinkDirectives(common.linkDirectives, target.linkDirectives);
|
|
1404
|
-
const mergedExports = targetType === "archive" ? [] : [...ensureArray(common.exports), ...ensureArray(target.exports)];
|
|
1405
|
-
const wasmOptEnabled = targetType === "archive" ? false : resolveWasmOptEnabled(common.wasmOpt, target.wasmOpt);
|
|
1406
|
-
const baseCompileOptions = [
|
|
1407
|
-
...ensureArray(common.options),
|
|
1408
|
-
...ensureArray(target.options)
|
|
1409
|
-
];
|
|
1410
|
-
const baseIncludeDirs = [
|
|
1411
|
-
...ensureArray(commonIncludeDirs),
|
|
1412
|
-
...ensureArray(target.includeDirs),
|
|
1413
|
-
...importIncludeDirs
|
|
1414
|
-
];
|
|
1415
|
-
const baseDefines = mergeDefines(common.defines, target.defines);
|
|
1416
|
-
const sourceGroups = (_a2 = target.sourceGroups) != null ? _a2 : [];
|
|
1417
|
-
const targetEnv = {
|
|
1418
|
-
...envWithDirs,
|
|
1419
|
-
TARGET_NAME: targetName
|
|
1420
|
-
};
|
|
1421
|
-
const buildEnv = createEnvForBuild(targetEnv, {});
|
|
1422
|
-
const resolvedOutFile = resolveTargetOutFile(
|
|
1423
|
-
targetName,
|
|
1424
|
-
target.outFile,
|
|
1425
|
-
targetEnv,
|
|
1426
|
-
targetType === "archive" ? libDir : outDir,
|
|
1427
|
-
targetType === "archive" ? "a" : "wasm"
|
|
1428
|
-
);
|
|
1429
|
-
const sources = await resolveTargetSources(
|
|
1430
|
-
target.sources,
|
|
1431
|
-
targetEnv,
|
|
1432
|
-
srcDir
|
|
1433
|
-
);
|
|
1434
|
-
const groupSources = sourceGroups.map(() => []);
|
|
1435
|
-
const groupSourceSet = /* @__PURE__ */ new Set();
|
|
1436
|
-
for (let index = 0; index < sourceGroups.length; index += 1) {
|
|
1437
|
-
const group = sourceGroups[index];
|
|
1438
|
-
if (!group) {
|
|
1439
|
-
continue;
|
|
1440
|
-
}
|
|
1441
|
-
const resolved = await resolveSourcesFromPatterns(
|
|
1442
|
-
group.sources,
|
|
1443
|
-
targetEnv,
|
|
1444
|
-
srcDir,
|
|
1445
|
-
`sourceGroups[${index}].sources`
|
|
1446
|
-
);
|
|
1447
|
-
const deduped = dedupeSources(resolved);
|
|
1448
|
-
groupSources[index] = deduped;
|
|
1449
|
-
for (const source of deduped) {
|
|
1450
|
-
groupSourceSet.add(source);
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
const baseSources = sources.filter(
|
|
1454
|
-
(source) => !groupSourceSet.has(source)
|
|
1455
|
-
);
|
|
1456
|
-
const groupedSources = groupSources.flat();
|
|
1457
|
-
if (baseSources.length + groupedSources.length === 0) {
|
|
1458
|
-
throw new Error(`No sources matched for target: ${targetName}`);
|
|
1459
|
-
}
|
|
1460
|
-
const targetBuildDir = path.resolve(buildRunDir, targetName);
|
|
1461
|
-
await promises.rm(targetBuildDir, { recursive: true, force: true });
|
|
1462
|
-
await ensureDirectory(targetBuildDir);
|
|
1463
|
-
const resolvedLinkDirectives = targetType === "archive" ? {} : resolveLinkDirectives(mergedLinkDirectives, targetEnv);
|
|
1464
|
-
const linkDirectiveArgs = buildLinkDirectiveFlags(resolvedLinkDirectives);
|
|
1465
|
-
const resolvedLinkOptions = targetType === "archive" ? [] : [
|
|
1466
|
-
...linkDirectiveArgs,
|
|
1467
|
-
...expandArray(mergedLinkOptions, targetEnv, "linkOptions")
|
|
1468
|
-
];
|
|
1469
|
-
const resolvedExports = targetType === "archive" ? [] : expandArray(mergedExports, targetEnv, "exports");
|
|
1470
|
-
const exportArgs = buildExportFlags(resolvedExports);
|
|
1471
|
-
const resolvedWasmOptArgs = wasmOptEnabled ? resolveWasmOptArgs(common.wasmOpt, target.wasmOpt, targetEnv) : [];
|
|
1472
|
-
const baseCompileArgs = buildCompileArgs(
|
|
1473
|
-
baseCompileOptions,
|
|
1474
|
-
baseIncludeDirs,
|
|
1475
|
-
baseDefines,
|
|
1476
|
-
targetEnv,
|
|
1477
|
-
rootDir
|
|
1478
|
-
);
|
|
1479
|
-
const groupCompileArgs = sourceGroups.map((group) => {
|
|
1480
|
-
const groupOptions = [
|
|
1481
|
-
...baseCompileOptions,
|
|
1482
|
-
...ensureArray(group == null ? void 0 : group.options)
|
|
1483
|
-
];
|
|
1484
|
-
const groupIncludeDirs = [
|
|
1485
|
-
...baseIncludeDirs,
|
|
1486
|
-
...ensureArray(group == null ? void 0 : group.includeDirs)
|
|
1487
|
-
];
|
|
1488
|
-
const groupDefines = mergeDefines(baseDefines, group == null ? void 0 : group.defines);
|
|
1489
|
-
return buildCompileArgs(
|
|
1490
|
-
groupOptions,
|
|
1491
|
-
groupIncludeDirs,
|
|
1492
|
-
groupDefines,
|
|
1493
|
-
targetEnv,
|
|
1494
|
-
rootDir
|
|
1495
|
-
);
|
|
1496
|
-
});
|
|
1497
|
-
const compileSource = async (source, args, groupIndex) => {
|
|
1498
|
-
const objectName = toSafeObjectName(rootDir, source, groupIndex);
|
|
1499
|
-
const outputObject = path.resolve(targetBuildDir, `${objectName}.o`);
|
|
1500
|
-
const compileArgs = [
|
|
1501
|
-
"-c",
|
|
1502
|
-
source,
|
|
1503
|
-
"-o",
|
|
1504
|
-
outputObject,
|
|
1505
|
-
...args.resolvedOptions,
|
|
1506
|
-
...args.includeArgs,
|
|
1507
|
-
...args.defineArgs
|
|
1508
|
-
];
|
|
1509
|
-
const sourcePath = path.relative(rootDir, source);
|
|
1510
|
-
logger.info(`Compiling source: ${sourcePath} --> $tmp/${objectName}.o`);
|
|
1511
|
-
logger.debug(`emcc ${compileArgs.join(" ")}`);
|
|
1512
|
-
await runCommandWithEnv(
|
|
1513
|
-
emccCommand,
|
|
1514
|
-
compileArgs,
|
|
1515
|
-
rootDir,
|
|
1516
|
-
buildEnv,
|
|
1517
|
-
emsdkOptions.signal
|
|
1518
|
-
);
|
|
1519
|
-
return outputObject;
|
|
1520
|
-
};
|
|
1521
|
-
const buildObjectsSequential = async () => {
|
|
1522
|
-
const objectFiles2 = [];
|
|
1523
|
-
for (const source of baseSources) {
|
|
1524
|
-
objectFiles2.push(
|
|
1525
|
-
await compileSource(source, baseCompileArgs, void 0)
|
|
1526
|
-
);
|
|
1527
|
-
}
|
|
1528
|
-
for (let index = 0; index < groupSources.length; index += 1) {
|
|
1529
|
-
const sourcesInGroup = groupSources[index];
|
|
1530
|
-
if (!sourcesInGroup) {
|
|
1531
|
-
continue;
|
|
1532
|
-
}
|
|
1533
|
-
const groupArgs = groupCompileArgs[index];
|
|
1534
|
-
if (!groupArgs) {
|
|
1535
|
-
continue;
|
|
1536
|
-
}
|
|
1537
|
-
for (const source of sourcesInGroup) {
|
|
1538
|
-
objectFiles2.push(await compileSource(source, groupArgs, index));
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
return objectFiles2;
|
|
1542
|
-
};
|
|
1543
|
-
const compileJobs = [];
|
|
1544
|
-
for (const source of baseSources) {
|
|
1545
|
-
compileJobs.push({
|
|
1546
|
-
source,
|
|
1547
|
-
args: baseCompileArgs,
|
|
1548
|
-
groupIndex: void 0
|
|
1549
|
-
});
|
|
1550
|
-
}
|
|
1551
|
-
for (let index = 0; index < groupSources.length; index += 1) {
|
|
1552
|
-
const sourcesInGroup = groupSources[index];
|
|
1553
|
-
if (!sourcesInGroup) {
|
|
1554
|
-
continue;
|
|
1555
|
-
}
|
|
1556
|
-
const groupArgs = groupCompileArgs[index];
|
|
1557
|
-
if (!groupArgs) {
|
|
1558
|
-
continue;
|
|
1559
|
-
}
|
|
1560
|
-
for (const source of sourcesInGroup) {
|
|
1561
|
-
compileJobs.push({ source, args: groupArgs, groupIndex: index });
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
logger.info(
|
|
1565
|
-
parallel ? `Building target: '${targetName}' [${compileJobs.length} files, in parallel]` : `Building target: '${targetName}' [${compileJobs.length} files]`
|
|
1566
|
-
);
|
|
1567
|
-
const objectFiles = parallel ? await Promise.all(
|
|
1568
|
-
compileJobs.map(
|
|
1569
|
-
(job) => compileSource(job.source, job.args, job.groupIndex)
|
|
1570
|
-
)
|
|
1571
|
-
) : await buildObjectsSequential();
|
|
1572
|
-
if (targetType === "archive") {
|
|
1573
|
-
if (!emarCommand) {
|
|
1574
|
-
throw new Error("emar command is required for archive targets.");
|
|
1575
|
-
}
|
|
1576
|
-
logger.info(`Archiving target: ${targetName}.a`);
|
|
1577
|
-
const archiveArgs = ["rcs", resolvedOutFile, ...objectFiles];
|
|
1578
|
-
logger.debug(`emar ${archiveArgs.join(" ")}`);
|
|
1579
|
-
await runCommandWithEnv(
|
|
1580
|
-
emarCommand,
|
|
1581
|
-
archiveArgs,
|
|
1582
|
-
rootDir,
|
|
1583
|
-
buildEnv,
|
|
1584
|
-
emsdkOptions.signal
|
|
1585
|
-
);
|
|
1586
|
-
} else {
|
|
1587
|
-
logger.info(`Linking target: ${targetName}.wasm`);
|
|
1588
|
-
const linkArgs = [
|
|
1589
|
-
...objectFiles,
|
|
1590
|
-
"-o",
|
|
1591
|
-
resolvedOutFile,
|
|
1592
|
-
...linkLibDirs.map((dir) => `-L${dir}`),
|
|
1593
|
-
...resolvedLinkOptions,
|
|
1594
|
-
...exportArgs
|
|
1595
|
-
];
|
|
1596
|
-
logger.debug(`emcc ${linkArgs.join(" ")}`);
|
|
1597
|
-
await runCommandWithEnv(
|
|
1598
|
-
emccCommand,
|
|
1599
|
-
linkArgs,
|
|
1600
|
-
rootDir,
|
|
1601
|
-
buildEnv,
|
|
1602
|
-
emsdkOptions.signal
|
|
1603
|
-
);
|
|
1604
|
-
if (wasmOptEnabled) {
|
|
1605
|
-
const wasmOptInput = resolveWasmOptInputFile(
|
|
1606
|
-
resolvedOutFile,
|
|
1607
|
-
resolvedLinkOptions
|
|
1608
|
-
);
|
|
1609
|
-
if (!await pathExists(wasmOptInput)) {
|
|
1610
|
-
throw new Error(
|
|
1611
|
-
`wasm-opt enabled but wasm binary not found: ${wasmOptInput}`
|
|
1612
|
-
);
|
|
1613
|
-
}
|
|
1614
|
-
const tempOutFile = `${wasmOptInput}.opt`;
|
|
1615
|
-
const wasmOptArgs = [
|
|
1616
|
-
wasmOptInput,
|
|
1617
|
-
"-o",
|
|
1618
|
-
tempOutFile,
|
|
1619
|
-
...resolvedWasmOptArgs
|
|
1620
|
-
];
|
|
1621
|
-
const wasmOptCommand2 = await getWasmOptCommand();
|
|
1622
|
-
logger.info(`Optimizing target: ${targetName}.wasm`);
|
|
1623
|
-
logger.debug(`wasm-opt ${wasmOptArgs.join(" ")}`);
|
|
1624
|
-
await runCommandWithEnv(
|
|
1625
|
-
wasmOptCommand2,
|
|
1626
|
-
wasmOptArgs,
|
|
1627
|
-
rootDir,
|
|
1628
|
-
buildEnv,
|
|
1629
|
-
emsdkOptions.signal
|
|
1630
|
-
);
|
|
1631
|
-
await promises.rm(wasmOptInput, { force: true });
|
|
1632
|
-
await promises.rename(tempOutFile, wasmOptInput);
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
outFiles[targetName] = resolvedOutFile;
|
|
1636
|
-
}
|
|
1637
|
-
};
|
|
1638
|
-
try {
|
|
1639
|
-
await buildTargets("archive");
|
|
1640
|
-
await buildTargets("wasm");
|
|
1641
|
-
if (generatedLoaderFile) {
|
|
1642
|
-
const generatedTargets = [];
|
|
1643
|
-
const functionNames = /* @__PURE__ */ new Set();
|
|
1644
|
-
for (const [targetName, target] of targetEntries) {
|
|
1645
|
-
if (resolveTargetType(target.type) !== "wasm") {
|
|
1646
|
-
continue;
|
|
1647
|
-
}
|
|
1648
|
-
const outFile = outFiles[targetName];
|
|
1649
|
-
if (!outFile) {
|
|
1650
|
-
continue;
|
|
1651
|
-
}
|
|
1652
|
-
const functionName = `load${toPascalCaseIdentifier(targetName)}Wasm`;
|
|
1653
|
-
if (functionNames.has(functionName)) {
|
|
1654
|
-
throw new Error(
|
|
1655
|
-
`Generated loader function name collision: ${functionName}`
|
|
1656
|
-
);
|
|
1657
|
-
}
|
|
1658
|
-
functionNames.add(functionName);
|
|
1659
|
-
generatedTargets.push({
|
|
1660
|
-
targetName,
|
|
1661
|
-
functionName,
|
|
1662
|
-
outFile
|
|
1663
|
-
});
|
|
1664
|
-
}
|
|
1665
|
-
const content = buildGeneratedLoaderContent(
|
|
1666
|
-
generatedLoaderFile,
|
|
1667
|
-
generatedTargets
|
|
1668
|
-
);
|
|
1669
|
-
const didWrite = await writeTextIfChanged(generatedLoaderFile, content);
|
|
1670
|
-
logger.info(
|
|
1671
|
-
didWrite ? `Generated loader: ${path.relative(rootDir, generatedLoaderFile)}` : `Generated loader unchanged: ${path.relative(rootDir, generatedLoaderFile)}`
|
|
1672
|
-
);
|
|
1673
|
-
resultGeneratedLoaderFile = generatedLoaderFile;
|
|
1674
|
-
}
|
|
1675
|
-
} finally {
|
|
1676
|
-
if (cleanupBuildDir) {
|
|
1677
|
-
await promises.rm(buildRunDir, { recursive: true, force: true });
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
return {
|
|
1681
|
-
emsdkRoot,
|
|
1682
|
-
outFiles,
|
|
1683
|
-
...resultGeneratedLoaderFile ? { generatedLoaderFile: resultGeneratedLoaderFile } : {}
|
|
1684
|
-
};
|
|
1685
|
-
};
|
|
1686
|
-
exports.buildWasm = buildWasm;
|
|
1687
|
-
exports.createConsoleLogger = createConsoleLogger;
|
|
1688
|
-
exports.prepareEmsdk = prepareEmsdk;
|
|
1689
|
-
//# sourceMappingURL=build-BGtsNe6D.cjs.map
|