xbintsc 0.3.14 → 0.3.16
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 +22 -22
- package/README.zh-CN.md +20 -19
- package/bin/xbintsc.js +1 -2
- package/dist/src/cli/main.js +8 -5
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +5 -6
- package/dist/src/codegen/generator/tables.js +13 -6
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/graph.d.ts +8 -0
- package/dist/src/driver/bundler/graph.js +85 -0
- package/dist/src/driver/bundler/graph.js.map +1 -0
- package/dist/src/driver/bundler/merge.d.ts +11 -0
- package/dist/src/driver/bundler/merge.js +288 -0
- package/dist/src/driver/bundler/merge.js.map +1 -0
- package/dist/src/driver/bundler/resolve.d.ts +12 -0
- package/dist/src/driver/bundler/resolve.js +246 -0
- package/dist/src/driver/bundler/resolve.js.map +1 -0
- package/dist/src/driver/bundler/symbols.d.ts +15 -0
- package/dist/src/driver/bundler/symbols.js +51 -0
- package/dist/src/driver/bundler/symbols.js.map +1 -0
- package/dist/src/driver/bundler/types.d.ts +36 -0
- package/dist/src/driver/bundler/types.js +5 -0
- package/dist/src/driver/bundler/types.js.map +1 -0
- package/dist/src/driver/index.d.ts +1 -2
- package/dist/src/driver/index.js +1 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/modules.d.ts +9 -16
- package/dist/src/driver/modules.js +8 -644
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/paths.d.ts +0 -9
- package/dist/src/driver/paths.js +0 -31
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/toolchain-provider.d.ts +10 -10
- package/dist/src/driver/toolchain-provider.js +9 -38
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.js +8 -2
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/catalog.js +2 -1
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/index.d.ts +24 -0
- package/dist/src/extensions/gui/index.js +101 -0
- package/dist/src/extensions/gui/index.js.map +1 -0
- package/dist/src/extensions/native.d.ts +2 -3
- package/dist/src/extensions/native.js +2 -3
- package/dist/src/extensions/native.js.map +1 -1
- package/dist/tests/driver/paths.test.js +1 -9
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +12 -79
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
- package/dist/tests/e2e/compile-basics.test.js +134 -0
- package/dist/tests/e2e/compile-basics.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
- package/dist/tests/e2e/compile-builtins.test.js +191 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
- package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
- package/dist/tests/e2e/compile-control-flow.test.js +190 -0
- package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
- package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
- package/dist/tests/e2e/compile-modules.test.js +48 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
- package/dist/tests/e2e/differential-helpers.d.ts +12 -0
- package/dist/tests/e2e/differential-helpers.js +16 -0
- package/dist/tests/e2e/differential-helpers.js.map +1 -0
- package/dist/tests/e2e/differential-language.test.d.ts +4 -0
- package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
- package/dist/tests/e2e/differential-language.test.js.map +1 -0
- package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
- package/dist/tests/e2e/differential-symbols.test.js +92 -0
- package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.d.ts +4 -0
- package/dist/tests/e2e/differential-values.test.js +197 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -0
- package/dist/tests/e2e/gui.test.d.ts +12 -0
- package/dist/tests/e2e/gui.test.js +493 -0
- package/dist/tests/e2e/gui.test.js.map +1 -0
- package/dist/tests/e2e/native-extensions.test.d.ts +4 -5
- package/dist/tests/e2e/native-extensions.test.js +6 -7
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
- package/dist/tests/e2e/timers.test.d.ts +7 -0
- package/dist/tests/e2e/timers.test.js +63 -0
- package/dist/tests/e2e/timers.test.js.map +1 -0
- package/package.json +2 -2
- package/runtime/ext_gui/css.cpp +743 -0
- package/runtime/ext_gui/css.h +98 -0
- package/runtime/ext_gui/document.cpp +264 -0
- package/runtime/ext_gui/document.h +89 -0
- package/runtime/ext_gui/dom.cpp +472 -0
- package/runtime/ext_gui/dom.h +71 -0
- package/runtime/ext_gui/gui.cpp +457 -0
- package/runtime/ext_gui/gui_engine.h +81 -0
- package/runtime/ext_gui/image.cpp +125 -0
- package/runtime/ext_gui/image.h +42 -0
- package/runtime/ext_gui/layout.cpp +748 -0
- package/runtime/ext_gui/layout.h +93 -0
- package/runtime/ext_gui/paint.cpp +137 -0
- package/runtime/ext_gui/paint.h +75 -0
- package/runtime/ext_gui/renderer.cpp +959 -0
- package/runtime/ext_gui/renderer.h +68 -0
- package/runtime/ext_gui/stb_image.h +7988 -0
- package/runtime/ext_gui/style.cpp +771 -0
- package/runtime/ext_gui/style.h +117 -0
- package/runtime/ext_gui/text.cpp +378 -0
- package/runtime/ext_gui/text.h +78 -0
- package/runtime/ext_gui/window.cpp +405 -0
- package/runtime/ext_node/fs/fs_common.h +13 -527
- package/runtime/ext_node/fs/meta_ops.c +3 -3
- package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
- package/runtime/ext_node/fs/parts/builtins.inc +69 -0
- package/runtime/ext_node/fs/parts/dir.inc +47 -0
- package/runtime/ext_node/fs/parts/encoding.inc +186 -0
- package/runtime/ext_node/fs/parts/errors.inc +66 -0
- package/runtime/ext_node/fs/parts/flags.inc +39 -0
- package/runtime/ext_node/fs/parts/platform.inc +86 -0
- package/runtime/ext_node/fs/parts/promisify.inc +15 -0
- package/runtime/ext_node/fs/parts/time.inc +9 -0
- package/runtime/rt.h +36 -4
- package/runtime/rt_internal.h +10 -23
- package/runtime/xt_builtins.c +4 -0
- package/runtime/xt_containers/access.inc +168 -0
- package/runtime/xt_containers/arrays.inc +108 -0
- package/runtime/xt_containers/boxes.inc +11 -0
- package/runtime/xt_containers/objects.inc +326 -0
- package/runtime/xt_containers.c +8 -618
- package/runtime/xt_ext.h +0 -1
- package/runtime/xt_io/base64.inc +87 -0
- package/runtime/xt_io/console.inc +119 -0
- package/runtime/xt_io/exception.inc +142 -0
- package/runtime/xt_io/inspect.inc +212 -0
- package/runtime/xt_io.c +11 -556
- package/runtime/xt_loop.c +262 -24
- package/runtime/xt_regex/api.inc +58 -0
- package/runtime/xt_regex/helpers.inc +68 -0
- package/runtime/xt_regex/matcher.inc +248 -0
- package/runtime/xt_regex/parser.inc +236 -0
- package/runtime/xt_regex/types.inc +58 -0
- package/runtime/xt_regex.h +9 -672
- package/runtime/xt_stdlib2/helpers.inc +2 -4
- package/runtime/xt_values/arithmetic.inc +150 -0
- package/runtime/xt_values/comparison.inc +112 -0
- package/runtime/xt_values/constructors.inc +41 -0
- package/runtime/xt_values/conversions.inc +115 -0
- package/runtime/xt_values/number-format.inc +180 -0
- package/runtime/xt_values/strings.inc +22 -0
- package/runtime/xt_values.c +10 -626
- package/scripts/build-gui.ts +317 -0
- package/scripts/build-runtime.ts +7 -8
- package/scripts/coverage-runtime.ts +4 -4
- package/scripts/package-release.ts +12 -84
- package/src/cli/main.ts +8 -4
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/tables.ts +13 -6
- package/src/driver/bundler/graph.ts +95 -0
- package/src/driver/bundler/merge.ts +312 -0
- package/src/driver/bundler/resolve.ts +240 -0
- package/src/driver/bundler/symbols.ts +55 -0
- package/src/driver/bundler/types.ts +37 -0
- package/src/driver/index.ts +1 -9
- package/src/driver/modules.ts +9 -693
- package/src/driver/paths.ts +0 -31
- package/src/driver/toolchain-provider.ts +12 -45
- package/src/driver/toolchain.ts +7 -2
- package/src/extensions/catalog.ts +2 -1
- package/src/extensions/gui/index.ts +107 -0
- package/src/extensions/native.ts +2 -3
- package/dist/src/driver/toolchain-download.d.ts +0 -50
- package/dist/src/driver/toolchain-download.js +0 -102
- package/dist/src/driver/toolchain-download.js.map +0 -1
- package/dist/tests/driver/toolchain-download.test.d.ts +0 -1
- package/dist/tests/driver/toolchain-download.test.js +0 -53
- package/dist/tests/driver/toolchain-download.test.js.map +0 -1
- package/dist/tests/e2e/compile.test.d.ts +0 -8
- package/dist/tests/e2e/compile.test.js +0 -893
- package/dist/tests/e2e/compile.test.js.map +0 -1
- package/dist/tests/e2e/differential.test.d.ts +0 -7
- package/dist/tests/e2e/differential.test.js.map +0 -1
- package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
- package/dist/tests/e2e/runtime-coverage.test.js +0 -646
- package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
- package/scripts/fetch-toolchain.ts +0 -101
- package/src/driver/toolchain-download.ts +0 -135
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build the GUI extension archive:
|
|
4
|
+
*
|
|
5
|
+
* runtime/lib/<os>-<arch>/gui.a
|
|
6
|
+
*
|
|
7
|
+
* The archive bundles the engine (`runtime/ext_gui/*.cpp`) together with a
|
|
8
|
+
* statically built SDL3, so a released compiler links GUI programs with no
|
|
9
|
+
* external dependency beyond the OS frameworks declared by
|
|
10
|
+
* `src/extensions/gui/index.ts`.
|
|
11
|
+
*
|
|
12
|
+
* Steps:
|
|
13
|
+
* 1. fetch the pinned SDL3 source into `vendor/SDL` (gitignored),
|
|
14
|
+
* 2. build `libSDL3.a` with CMake,
|
|
15
|
+
* 2b. fetch + build static FreeType and HarfBuzz for text,
|
|
16
|
+
* 3. compile the engine translation units,
|
|
17
|
+
* 4. merge everything into `gui.a` (libtool on macOS, `ar -M` elsewhere;
|
|
18
|
+
* `gui.lib` on Windows, built from MSVC-compatible COFF objects).
|
|
19
|
+
*
|
|
20
|
+
* Environment:
|
|
21
|
+
* xbintsc_CXX C++ compiler override (default: clang++/c++/g++)
|
|
22
|
+
* xbintsc_CMAKE CMake override (default: a vendored CMake, then `cmake`)
|
|
23
|
+
* xbintsc_AR archiver override (default: llvm-ar, then ar)
|
|
24
|
+
* SDL3_TAG SDL3 git tag to check out (default: release-3.2.10)
|
|
25
|
+
* FREETYPE_VERSION FreeType version (default: 2.13.3)
|
|
26
|
+
* HARFBUZZ_VERSION HarfBuzz version (default: 10.1.0)
|
|
27
|
+
*
|
|
28
|
+
* On Windows the engine is compiled with `clang++` against the MSVC ABI (run
|
|
29
|
+
* from a Visual Studio developer prompt so `INCLUDE`/`LIB` are set) and merged
|
|
30
|
+
* into a COFF `gui.lib` with `llvm-ar`.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "node:fs";
|
|
34
|
+
import { spawnSync, type SpawnSyncReturns } from "node:child_process";
|
|
35
|
+
import { dirname, join, resolve } from "node:path";
|
|
36
|
+
import { fileURLToPath } from "node:url";
|
|
37
|
+
import { platformSlug } from "../src/driver/paths.js";
|
|
38
|
+
|
|
39
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
40
|
+
const runtimeDir = join(root, "runtime");
|
|
41
|
+
const engineDir = join(runtimeDir, "ext_gui");
|
|
42
|
+
const vendorDir = join(root, "vendor");
|
|
43
|
+
const sdlSrc = join(vendorDir, "SDL");
|
|
44
|
+
const sdlBuild = join(sdlSrc, "build");
|
|
45
|
+
const freetypeSrc = join(vendorDir, "freetype");
|
|
46
|
+
const freetypeBuild = join(vendorDir, "freetype-build");
|
|
47
|
+
const harfbuzzSrc = join(vendorDir, "harfbuzz");
|
|
48
|
+
const harfbuzzBuild = join(vendorDir, "harfbuzz-build");
|
|
49
|
+
const objDir = join(root, "build", "gui-obj");
|
|
50
|
+
const outDir = join(runtimeDir, "lib", platformSlug());
|
|
51
|
+
|
|
52
|
+
const isWindows = process.platform === "win32";
|
|
53
|
+
const objectSuffix = isWindows ? ".obj" : ".o";
|
|
54
|
+
const output = join(outDir, isWindows ? "gui.lib" : "gui.a");
|
|
55
|
+
|
|
56
|
+
const SDL_TAG = process.env.SDL3_TAG || "release-3.2.10";
|
|
57
|
+
const FREETYPE_VERSION = process.env.FREETYPE_VERSION || "2.13.3";
|
|
58
|
+
const HARFBUZZ_VERSION = process.env.HARFBUZZ_VERSION || "10.1.0";
|
|
59
|
+
const FREETYPE_URL = `https://download.savannah.gnu.org/releases/freetype/freetype-${FREETYPE_VERSION}.tar.xz`;
|
|
60
|
+
const HARFBUZZ_URL = `https://github.com/harfbuzz/harfbuzz/releases/download/${HARFBUZZ_VERSION}/harfbuzz-${HARFBUZZ_VERSION}.tar.xz`;
|
|
61
|
+
|
|
62
|
+
function fail(message: string): never {
|
|
63
|
+
console.error(`xbintsc: ${message}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function run(
|
|
68
|
+
command: string,
|
|
69
|
+
args: readonly string[],
|
|
70
|
+
options: { input?: string; quietStderr?: boolean } = {},
|
|
71
|
+
): SpawnSyncReturns<string> {
|
|
72
|
+
const quiet = options.quietStderr === true;
|
|
73
|
+
const result = spawnSync(command, args, {
|
|
74
|
+
stdio: options.input !== undefined ? ["pipe", "inherit", "inherit"] : quiet ? ["ignore", "inherit", "pipe"] : "inherit",
|
|
75
|
+
encoding: "utf8",
|
|
76
|
+
input: options.input,
|
|
77
|
+
});
|
|
78
|
+
if (result.status !== 0) {
|
|
79
|
+
if (quiet && result.stderr) process.stderr.write(result.stderr);
|
|
80
|
+
fail(`${command} ${args.join(" ")} failed with status ${result.status ?? "?"}`);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isRunnable(candidate: string): boolean {
|
|
86
|
+
return !spawnSync(candidate, ["--version"], { encoding: "utf8" }).error;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function firstAvailable(candidates: readonly (string | undefined)[]): string | undefined {
|
|
90
|
+
for (const candidate of candidates) {
|
|
91
|
+
if (candidate && isRunnable(candidate)) return candidate;
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Vendored CMake from `vendor/tools`, then `cmake` on PATH. */
|
|
97
|
+
function findCmake(): string {
|
|
98
|
+
const candidates: string[] = [];
|
|
99
|
+
if (process.env.xbintsc_CMAKE) candidates.push(process.env.xbintsc_CMAKE);
|
|
100
|
+
if (existsSync(join(vendorDir, "tools"))) {
|
|
101
|
+
for (const entry of readdirSync(join(vendorDir, "tools"))) {
|
|
102
|
+
if (!entry.startsWith("cmake-")) continue;
|
|
103
|
+
candidates.push(join(vendorDir, "tools", entry, "CMake.app", "Contents", "bin", "cmake"));
|
|
104
|
+
candidates.push(join(vendorDir, "tools", entry, "bin", "cmake"));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
candidates.push("cmake");
|
|
108
|
+
const cmake = firstAvailable(candidates);
|
|
109
|
+
if (!cmake) fail("no CMake found; install it or set xbintsc_CMAKE");
|
|
110
|
+
return cmake;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function findCxx(): string {
|
|
114
|
+
const cxx = firstAvailable([process.env.xbintsc_CXX, "clang++", "c++", "g++"]);
|
|
115
|
+
if (!cxx) fail("no C++ compiler found; install clang++ or set xbintsc_CXX");
|
|
116
|
+
return cxx;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function findArchiver(): string {
|
|
120
|
+
const ar = firstAvailable([process.env.xbintsc_AR, "llvm-ar", "ar"]);
|
|
121
|
+
if (!ar) fail("no archiver found; set xbintsc_AR to llvm-ar or ar");
|
|
122
|
+
return ar;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** First of `candidates` that exists on disk (CMake generators place static
|
|
126
|
+
* libraries either at the build root or under `Release/`). */
|
|
127
|
+
function firstExisting(candidates: readonly string[]): string | undefined {
|
|
128
|
+
for (const candidate of candidates) {
|
|
129
|
+
if (existsSync(candidate)) return candidate;
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Locate a library CMake produced, accepting the POSIX and MSVC names and
|
|
135
|
+
* falling back to a version-suffixed MSVC name (e.g. `freetype-2.13.3.lib`). */
|
|
136
|
+
function builtLibrary(buildDir: string, names: readonly string[], pattern?: RegExp): string | undefined {
|
|
137
|
+
const candidates: string[] = [];
|
|
138
|
+
for (const name of names) {
|
|
139
|
+
candidates.push(join(buildDir, name));
|
|
140
|
+
candidates.push(join(buildDir, "Release", name));
|
|
141
|
+
candidates.push(join(buildDir, "Debug", name));
|
|
142
|
+
}
|
|
143
|
+
const exact = firstExisting(candidates);
|
|
144
|
+
if (exact || !pattern) return exact;
|
|
145
|
+
for (const dir of [buildDir, join(buildDir, "Release"), join(buildDir, "Debug")]) {
|
|
146
|
+
if (!existsSync(dir)) continue;
|
|
147
|
+
for (const entry of readdirSync(dir)) {
|
|
148
|
+
if (pattern.test(entry)) return join(dir, entry);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function sdlArchive(): string | undefined {
|
|
155
|
+
return builtLibrary(sdlBuild, ["libSDL3.a", "SDL3-static.lib", "SDL3.lib"], /^SDL3[-\w.]*\.lib$/);
|
|
156
|
+
}
|
|
157
|
+
function freetypeArchive(): string | undefined {
|
|
158
|
+
return builtLibrary(freetypeBuild, ["libfreetype.a", "freetype.lib"], /^freetype[-\d.]*\.lib$/);
|
|
159
|
+
}
|
|
160
|
+
function harfbuzzArchive(): string | undefined {
|
|
161
|
+
return builtLibrary(harfbuzzBuild, ["libharfbuzz.a", "harfbuzz.lib"], /^harfbuzz[-\d.]*\.lib$/);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* -- 1. SDL3 source ------------------------------------------------------- */
|
|
165
|
+
|
|
166
|
+
if (!existsSync(join(sdlSrc, "CMakeLists.txt"))) {
|
|
167
|
+
console.log(`xbintsc: fetching SDL3 ${SDL_TAG} into vendor/SDL`);
|
|
168
|
+
mkdirSync(vendorDir, { recursive: true });
|
|
169
|
+
run("git", ["clone", "--depth", "1", "--branch", SDL_TAG, "https://github.com/libsdl-org/SDL.git", sdlSrc]);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* -- 2. static SDL3 ------------------------------------------------------- */
|
|
173
|
+
|
|
174
|
+
const existingSdlArchive = sdlArchive();
|
|
175
|
+
if (!existingSdlArchive) {
|
|
176
|
+
const cmake = findCmake();
|
|
177
|
+
console.log(`xbintsc: building static SDL3 with ${cmake}`);
|
|
178
|
+
const configureArgs = [
|
|
179
|
+
"-S", sdlSrc,
|
|
180
|
+
"-B", sdlBuild,
|
|
181
|
+
"-DCMAKE_BUILD_TYPE=Release",
|
|
182
|
+
"-DSDL_SHARED=OFF",
|
|
183
|
+
"-DSDL_STATIC=ON",
|
|
184
|
+
"-DSDL_TESTS=OFF",
|
|
185
|
+
"-DSDL_EXAMPLES=OFF",
|
|
186
|
+
];
|
|
187
|
+
run(cmake, configureArgs);
|
|
188
|
+
run(cmake, ["--build", sdlBuild, "--config", "Release", "--target", "SDL3-static", "--parallel"]);
|
|
189
|
+
} else {
|
|
190
|
+
console.log(`xbintsc: reusing existing ${existingSdlArchive}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* -- 2b. FreeType + HarfBuzz (text) --------------------------------------- */
|
|
194
|
+
|
|
195
|
+
/** Download a release tarball into `vendor/` and extract it under `name`.
|
|
196
|
+
* Release tarballs are used (not git clones) because they ship generated
|
|
197
|
+
* sources, so no ragel/autotools step is needed. */
|
|
198
|
+
function ensureTarballSource(name: string, url: string, extractedName: string): string {
|
|
199
|
+
const destination = join(vendorDir, name);
|
|
200
|
+
if (existsSync(join(destination, "CMakeLists.txt"))) return destination;
|
|
201
|
+
const tarball = join(vendorDir, `${name}.tar.xz`);
|
|
202
|
+
console.log(`xbintsc: fetching ${name} from ${url}`);
|
|
203
|
+
mkdirSync(vendorDir, { recursive: true });
|
|
204
|
+
run("curl", ["-sL", "--fail", "-o", tarball, url]);
|
|
205
|
+
run("tar", ["-xf", tarball, "-C", vendorDir]);
|
|
206
|
+
const extracted = join(vendorDir, extractedName);
|
|
207
|
+
if (!existsSync(extracted)) fail(`expected ${extractedName} after extracting ${name}`);
|
|
208
|
+
rmSync(destination, { recursive: true, force: true });
|
|
209
|
+
renameSync(extracted, destination);
|
|
210
|
+
rmSync(tarball, { force: true });
|
|
211
|
+
return destination;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
ensureTarballSource("freetype", FREETYPE_URL, `freetype-${FREETYPE_VERSION}`);
|
|
215
|
+
ensureTarballSource("harfbuzz", HARFBUZZ_URL, `harfbuzz-${HARFBUZZ_VERSION}`);
|
|
216
|
+
|
|
217
|
+
if (!existsSync(freetypeArchive() ?? "")) {
|
|
218
|
+
const cmake = findCmake();
|
|
219
|
+
console.log("xbintsc: building static FreeType");
|
|
220
|
+
run(cmake, [
|
|
221
|
+
"-S", freetypeSrc,
|
|
222
|
+
"-B", freetypeBuild,
|
|
223
|
+
"-DCMAKE_BUILD_TYPE=Release",
|
|
224
|
+
"-DBUILD_SHARED_LIBS=OFF",
|
|
225
|
+
/* We only need TrueType/OpenType outlines; skip the optional codecs. */
|
|
226
|
+
"-DFT_DISABLE_ZLIB=TRUE",
|
|
227
|
+
"-DFT_DISABLE_BZIP2=TRUE",
|
|
228
|
+
"-DFT_DISABLE_PNG=TRUE",
|
|
229
|
+
"-DFT_DISABLE_HARFBUZZ=TRUE",
|
|
230
|
+
"-DFT_DISABLE_BROTLI=TRUE",
|
|
231
|
+
]);
|
|
232
|
+
run(cmake, ["--build", freetypeBuild, "--config", "Release", "--parallel"]);
|
|
233
|
+
} else {
|
|
234
|
+
console.log(`xbintsc: reusing existing ${freetypeArchive()}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (!existsSync(harfbuzzArchive() ?? "")) {
|
|
238
|
+
const cmake = findCmake();
|
|
239
|
+
console.log("xbintsc: building static HarfBuzz");
|
|
240
|
+
run(cmake, [
|
|
241
|
+
"-S", harfbuzzSrc,
|
|
242
|
+
"-B", harfbuzzBuild,
|
|
243
|
+
"-DCMAKE_BUILD_TYPE=Release",
|
|
244
|
+
"-DBUILD_SHARED_LIBS=OFF",
|
|
245
|
+
"-DHB_BUILD_UTILS=OFF",
|
|
246
|
+
"-DHB_BUILD_TESTS=OFF",
|
|
247
|
+
"-DHB_BUILD_SUBSET=OFF",
|
|
248
|
+
"-DHB_HAVE_FREETYPE=OFF",
|
|
249
|
+
"-DHB_HAVE_GLIB=OFF",
|
|
250
|
+
"-DHB_HAVE_ICU=OFF",
|
|
251
|
+
"-DHB_HAVE_GRAPHITE2=OFF",
|
|
252
|
+
]);
|
|
253
|
+
run(cmake, ["--build", harfbuzzBuild, "--config", "Release", "--parallel"]);
|
|
254
|
+
} else {
|
|
255
|
+
console.log(`xbintsc: reusing existing ${harfbuzzArchive()}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* -- 3. engine objects ---------------------------------------------------- */
|
|
259
|
+
|
|
260
|
+
const cxx = findCxx();
|
|
261
|
+
mkdirSync(objDir, { recursive: true });
|
|
262
|
+
const includeFlags = [
|
|
263
|
+
"-I", runtimeDir,
|
|
264
|
+
"-I", join(sdlSrc, "include"),
|
|
265
|
+
"-I", join(freetypeSrc, "include"),
|
|
266
|
+
"-I", join(freetypeBuild, "include"),
|
|
267
|
+
"-I", join(harfbuzzSrc, "src"),
|
|
268
|
+
];
|
|
269
|
+
const sources = readdirSync(engineDir)
|
|
270
|
+
.filter((entry) => entry.endsWith(".cpp"))
|
|
271
|
+
.sort();
|
|
272
|
+
|
|
273
|
+
const objects: string[] = [];
|
|
274
|
+
const cxxFlags = ["-std=c++17", "-O2", "-Wall", "-Wextra", ...includeFlags];
|
|
275
|
+
/* The MSVC ABI rejects `-fPIC`; position independence is the default elsewhere. */
|
|
276
|
+
if (!isWindows) cxxFlags.splice(3, 0, "-fPIC");
|
|
277
|
+
for (const source of sources) {
|
|
278
|
+
const object = join(objDir, source.replace(/\.cpp$/, objectSuffix));
|
|
279
|
+
console.log(`xbintsc: compiling ${source}`);
|
|
280
|
+
run(cxx, [...cxxFlags, "-c", join(engineDir, source), "-o", object]);
|
|
281
|
+
objects.push(object);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* -- 4. merge into gui.a / gui.lib ---------------------------------------- */
|
|
285
|
+
|
|
286
|
+
const sdl = sdlArchive();
|
|
287
|
+
const freetype = freetypeArchive();
|
|
288
|
+
const harfbuzz = harfbuzzArchive();
|
|
289
|
+
if (!sdl || !freetype || !harfbuzz) {
|
|
290
|
+
fail("one of the SDL3/FreeType/HarfBuzz archives was not found after building");
|
|
291
|
+
}
|
|
292
|
+
const libraries = [sdl, freetype, harfbuzz];
|
|
293
|
+
|
|
294
|
+
mkdirSync(outDir, { recursive: true });
|
|
295
|
+
rmSync(output, { force: true });
|
|
296
|
+
if (process.platform === "darwin") {
|
|
297
|
+
/* libtool warns about the empty object files SDL3's archive carries; hide it
|
|
298
|
+
* unless the merge actually fails. */
|
|
299
|
+
run("libtool", ["-static", "-o", output, ...objects, ...libraries], {
|
|
300
|
+
quietStderr: true,
|
|
301
|
+
});
|
|
302
|
+
} else {
|
|
303
|
+
/* `ar -M` (GNU/LLVM) merges archives through an MRI script. Windows paths are
|
|
304
|
+
* normalised to `/` so the MRI parser does not read `\` as an escape. */
|
|
305
|
+
const mri = (path: string): string => path.replace(/\\/g, "/");
|
|
306
|
+
const ar = findArchiver();
|
|
307
|
+
const script = [
|
|
308
|
+
`create ${mri(output)}`,
|
|
309
|
+
...objects.map((object) => `addmod ${mri(object)}`),
|
|
310
|
+
...libraries.map((library) => `addlib ${mri(library)}`),
|
|
311
|
+
"save",
|
|
312
|
+
"end",
|
|
313
|
+
].join("\n");
|
|
314
|
+
run(ar, ["-M"], { input: script });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
console.log(`xbintsc: wrote ${output}`);
|
package/scripts/build-runtime.ts
CHANGED
|
@@ -29,16 +29,15 @@ const outDir = join(runtimeDir, "lib", platformSlug());
|
|
|
29
29
|
const objDir = join(root, "build", "runtime-obj");
|
|
30
30
|
|
|
31
31
|
if (process.platform === "win32") {
|
|
32
|
-
// The
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
console.log("xbintsc:
|
|
32
|
+
// The driver links with the MSVC ABI on Windows, where the prebuilt archives
|
|
33
|
+
// are unnecessary: `build` compiles the runtime C sources on demand with the
|
|
34
|
+
// user's clang. (Producing MSVC-compatible COFF `.lib` archives is possible
|
|
35
|
+
// but not worth the extra step.)
|
|
36
|
+
console.log("xbintsc: skipping runtime archives on Windows; the driver compiles the C sources on demand");
|
|
37
37
|
process.exit(0);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// Use the same toolchain the driver will
|
|
41
|
-
// `LD_LIBRARY_PATH` (the legacy `libtinfo.so.5` on Linux) threaded through.
|
|
40
|
+
// Use the same toolchain the driver will.
|
|
42
41
|
const toolchain = resolveToolchain();
|
|
43
42
|
const clang = toolchain.clang;
|
|
44
43
|
const childEnv = Object.assign({}, process.env, toolchain.env);
|
|
@@ -54,7 +53,7 @@ function findArchiver(clangPath: string): string {
|
|
|
54
53
|
const exe = process.platform === "win32" ? ".exe" : "";
|
|
55
54
|
const candidates = [
|
|
56
55
|
process.env.xbintsc_AR,
|
|
57
|
-
// A
|
|
56
|
+
// A clang install usually ships `llvm-ar` next to the driver.
|
|
58
57
|
dir === "." ? undefined : join(dir, `llvm-ar${exe}`),
|
|
59
58
|
"llvm-ar",
|
|
60
59
|
"ar",
|
|
@@ -160,9 +160,9 @@ function runs(command: string): boolean {
|
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
162
|
* Locate the LLVM tool `name` (`llvm-profdata`/`llvm-cov`) that matches the
|
|
163
|
-
* clang the driver resolved.
|
|
164
|
-
*
|
|
165
|
-
*
|
|
163
|
+
* clang the driver resolved. Prefer the tool next to clang, then the
|
|
164
|
+
* version-suffixed system installs: mixing versions makes `llvm-profdata`
|
|
165
|
+
* reject the profile format.
|
|
166
166
|
*/
|
|
167
167
|
function findTool(clang: string, name: string): string | undefined {
|
|
168
168
|
const exe = process.platform === "win32" ? ".exe" : "";
|
|
@@ -282,7 +282,7 @@ function main(): void {
|
|
|
282
282
|
profdataTool ? undefined : "llvm-profdata",
|
|
283
283
|
covTool ? undefined : "llvm-cov",
|
|
284
284
|
].filter(Boolean).join(", ");
|
|
285
|
-
skip(`${missing} not found for ${clang}; install LLVM
|
|
285
|
+
skip(`${missing} not found for ${clang}; install the LLVM tools (llvm-profdata, llvm-cov)`, options.strict);
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
if (!options.reportOnly) runTests(options);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Assemble a
|
|
3
|
+
* Assemble a release archive for the current platform:
|
|
4
4
|
*
|
|
5
5
|
* dist/release/xbintsc-<version>-<os>-<arch>.tar.gz (or .tar.zst)
|
|
6
6
|
* dist/release/xbintsc-<version>-<os>-<arch>.tar.gz.sha256
|
|
@@ -10,23 +10,24 @@
|
|
|
10
10
|
*
|
|
11
11
|
* The unpacked staging tree is built under `build/release-stage/`, never under
|
|
12
12
|
* `dist/release/`, so an upload glob over `dist/release/*` cannot accidentally
|
|
13
|
-
* ship the (
|
|
13
|
+
* ship the (large) tree alongside the archive.
|
|
14
|
+
*
|
|
15
|
+
* xbintsc does not bundle a compiler: the archive holds only the self-hosted
|
|
16
|
+
* binary and the C runtime sources plus prebuilt archives. Users provide the
|
|
17
|
+
* toolchain themselves (see `doc/requirements.md`).
|
|
14
18
|
*
|
|
15
19
|
* Layout inside the archive:
|
|
16
20
|
*
|
|
17
21
|
* xbintsc-<os>-<arch>/
|
|
18
22
|
* bin/xbintsc[.exe] the self-hosted compiler
|
|
19
23
|
* runtime/ C runtime sources + prebuilt runtime/lib/<slug>
|
|
20
|
-
* vendor/<slug>/ the bundled clang+lld toolchain (Linux/Windows)
|
|
21
24
|
* README.md
|
|
22
25
|
*
|
|
23
|
-
* The compiler locates `runtime/`
|
|
24
|
-
*
|
|
25
|
-
* toolchain installed.
|
|
26
|
+
* The compiler locates `runtime/` relative to its own executable (see
|
|
27
|
+
* `findRuntimeDir`), so this tree runs without any bundled toolchain.
|
|
26
28
|
*
|
|
27
29
|
* Inputs:
|
|
28
30
|
* - the self-hosted binary staged at `dist/xbintsc[.exe]` (CI copies it there)
|
|
29
|
-
* - `vendor/<slug>/`, fetched by `scripts/fetch-toolchain.ts`
|
|
30
31
|
* - `runtime/lib/<slug>/`, built by `scripts/build-runtime.ts`
|
|
31
32
|
*/
|
|
32
33
|
|
|
@@ -37,9 +38,7 @@ import {
|
|
|
37
38
|
chmodSync,
|
|
38
39
|
existsSync,
|
|
39
40
|
mkdirSync,
|
|
40
|
-
readdirSync,
|
|
41
41
|
readFileSync,
|
|
42
|
-
realpathSync,
|
|
43
42
|
rmSync,
|
|
44
43
|
statSync,
|
|
45
44
|
writeFileSync,
|
|
@@ -49,14 +48,12 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
49
48
|
import { fileURLToPath } from "node:url";
|
|
50
49
|
import {
|
|
51
50
|
findRuntimeDir,
|
|
52
|
-
platformSlug,
|
|
53
51
|
releaseArchiveBase,
|
|
54
52
|
releaseArchiveExtension,
|
|
55
53
|
releaseArchiveFileName,
|
|
56
54
|
} from "../src/driver/paths.js";
|
|
57
55
|
|
|
58
56
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
59
|
-
const slug = platformSlug();
|
|
60
57
|
const base = releaseArchiveBase();
|
|
61
58
|
const version = (
|
|
62
59
|
JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as { version: string }
|
|
@@ -77,55 +74,6 @@ function firstExisting(candidates: readonly string[]): string | undefined {
|
|
|
77
74
|
return undefined;
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
/**
|
|
81
|
-
* Copy only the parts of the fetched toolchain that xbintsc actually runs.
|
|
82
|
-
*
|
|
83
|
-
* The official LLVM release unpacks to ~7 GB: every MLIR/Flang/lldb tool, the
|
|
84
|
-
* static archives and the full C++ headers. The compiler only shells out to the
|
|
85
|
-
* clang driver, the lld linker and llvm-ar, and clang additionally needs its own
|
|
86
|
-
* resource directory (`lib/clang/<version>`, the builtin headers and
|
|
87
|
-
* compiler-rt). Copying just those keeps the archive ~100x smaller.
|
|
88
|
-
*/
|
|
89
|
-
function stageToolchain(vendor: string, dest: string): void {
|
|
90
|
-
const exe = process.platform === "win32" ? ".exe" : "";
|
|
91
|
-
mkdirSync(join(dest, "bin"), { recursive: true });
|
|
92
|
-
|
|
93
|
-
const real = (...candidates: readonly string[]): string | undefined => {
|
|
94
|
-
const found = firstExisting(candidates.map((candidate) => join(vendor, candidate)));
|
|
95
|
-
return found ? realpathSync(found) : undefined;
|
|
96
|
-
};
|
|
97
|
-
const copyAs = (source: string | undefined, name: string): void => {
|
|
98
|
-
if (!source) return;
|
|
99
|
-
const target = join(dest, "bin", name);
|
|
100
|
-
copyFileSync(source, target);
|
|
101
|
-
if (process.platform !== "win32") chmodSync(target, 0o755);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// In the official release `clang`/`ld.lld` are symlinks into the bin/ dir;
|
|
105
|
-
// copy the resolved targets under the names the toolchain provider (and
|
|
106
|
-
// clang's `-fuse-ld=lld`) expect next to `bin/clang`.
|
|
107
|
-
copyAs(real(`bin/clang${exe}`, `bin/clang-18${exe}`), `clang${exe}`);
|
|
108
|
-
copyAs(real(`bin/ld.lld${exe}`, `bin/lld${exe}`), `ld.lld${exe}`);
|
|
109
|
-
copyAs(real(`bin/llvm-ar${exe}`, "bin/llvm-ar"), `llvm-ar${exe}`);
|
|
110
|
-
|
|
111
|
-
// clang's resource directory: builtin headers + compiler-rt archives.
|
|
112
|
-
const resourceDir = join(vendor, "lib", "clang");
|
|
113
|
-
if (existsSync(resourceDir)) {
|
|
114
|
-
cpSync(resourceDir, join(dest, "lib", "clang"), { recursive: true });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Shared libraries the fetch placed next to the toolchain (on Linux that is
|
|
118
|
-
// the legacy `libtinfo.so.5` the official build still links).
|
|
119
|
-
const libDir = join(vendor, "lib");
|
|
120
|
-
if (existsSync(libDir)) {
|
|
121
|
-
for (const entry of readdirSync(libDir, { withFileTypes: true })) {
|
|
122
|
-
if (/^(.*\.so(\.\d+)*|.*\.dylib|.*\.dll)$/.test(entry.name)) {
|
|
123
|
-
cpSync(join(libDir, entry.name), join(dest, "lib", entry.name), { recursive: true });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
77
|
const distDir = join(root, "dist");
|
|
130
78
|
const binary = firstExisting([
|
|
131
79
|
join(distDir, `xbintsc${exeSuffix}`),
|
|
@@ -138,7 +86,7 @@ if (!binary) {
|
|
|
138
86
|
|
|
139
87
|
// Archives go to `dist/release/`; the unpacked staging tree goes to
|
|
140
88
|
// `build/release-stage/` so the upload glob over `dist/release/*` cannot pick up
|
|
141
|
-
// the raw tree
|
|
89
|
+
// the raw tree.
|
|
142
90
|
const releaseRoot = join(distDir, "release");
|
|
143
91
|
const stageRoot = join(root, "build", "release-stage");
|
|
144
92
|
const stage = join(stageRoot, base);
|
|
@@ -156,33 +104,13 @@ console.log(`xbintsc: packaged binary ${basename(binary)} (${statSync(binary).si
|
|
|
156
104
|
cpSync(findRuntimeDir(), join(stage, "runtime"), { recursive: true });
|
|
157
105
|
console.log("xbintsc: packaged runtime/");
|
|
158
106
|
|
|
159
|
-
// 3.
|
|
160
|
-
const vendor = join(root, "vendor", slug);
|
|
161
|
-
if (existsSync(join(vendor, "bin"))) {
|
|
162
|
-
if (process.platform === "win32") {
|
|
163
|
-
// llvm-mingw spreads its MinGW-w64 CRT/import libraries across the tree, so
|
|
164
|
-
// bundling it whole is the safe default there for now.
|
|
165
|
-
cpSync(vendor, join(stage, "vendor", slug), { recursive: true });
|
|
166
|
-
} else {
|
|
167
|
-
stageToolchain(vendor, join(stage, "vendor", slug));
|
|
168
|
-
}
|
|
169
|
-
console.log(`xbintsc: packaged vendor/${slug}/`);
|
|
170
|
-
} else if (process.platform === "linux" || process.platform === "win32") {
|
|
171
|
-
console.warn(
|
|
172
|
-
`xbintsc: warning: no vendor/${slug}/ found; the release will rely on a system toolchain. ` +
|
|
173
|
-
"Run `npm run fetch-toolchain` first for a self-contained archive.",
|
|
174
|
-
);
|
|
175
|
-
} else {
|
|
176
|
-
console.log(`xbintsc: no bundled toolchain for ${slug}; relying on the system SDK (macOS)`);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// 4. Human-facing notes.
|
|
107
|
+
// 3. Human-facing notes.
|
|
180
108
|
for (const name of ["README.md", "LICENSE"]) {
|
|
181
109
|
const source = join(root, name);
|
|
182
110
|
if (existsSync(source)) copyFileSync(source, join(stage, name));
|
|
183
111
|
}
|
|
184
112
|
|
|
185
|
-
//
|
|
113
|
+
// 4. Archive it. Prefer zstd when available, otherwise gzip.
|
|
186
114
|
const hasZstd = !spawnSync("zstd", ["--version"], { stdio: "ignore" }).error;
|
|
187
115
|
const extension = releaseArchiveExtension(hasZstd);
|
|
188
116
|
const archive = join(releaseRoot, `${archiveBase}${extension}`);
|
|
@@ -192,7 +120,7 @@ const tar = spawnSync("tar", tarArgs, { stdio: "inherit" });
|
|
|
192
120
|
if (tar.error) fail(`failed to run tar: ${tar.error.message}`);
|
|
193
121
|
if (tar.status !== 0) fail(`tar exited with ${tar.status}`);
|
|
194
122
|
|
|
195
|
-
//
|
|
123
|
+
// 5. Checksum, so users can verify the download.
|
|
196
124
|
const digest = createHash("sha256").update(readFileSync(archive)).digest("hex");
|
|
197
125
|
writeFileSync(`${archive}.sha256`, `${digest} ${basename(archive)}\n`);
|
|
198
126
|
|
package/src/cli/main.ts
CHANGED
|
@@ -24,7 +24,6 @@ import { resolveToolchain } from "../driver/toolchain-provider.js";
|
|
|
24
24
|
import { realRunner } from "../driver/toolchain.js";
|
|
25
25
|
import { createDefaultRegistry, type ExtensionRegistry } from "../extensions/registry.js";
|
|
26
26
|
import { bundledExtensions } from "../extensions/catalog.js";
|
|
27
|
-
import { nodeExtension } from "../extensions/node/index.js";
|
|
28
27
|
import { nativeExtensionFromManifest } from "../extensions/native.js";
|
|
29
28
|
|
|
30
29
|
export interface CliIo {
|
|
@@ -100,9 +99,11 @@ function buildRegistry(flags: Map<string, string | boolean>): ExtensionRegistry
|
|
|
100
99
|
const registry = createDefaultRegistry();
|
|
101
100
|
const requested = flags.get("ext");
|
|
102
101
|
if (typeof requested === "string") {
|
|
102
|
+
const bundled = bundledExtensions();
|
|
103
103
|
for (const name of requested.split(",").map((n) => n.trim()).filter(Boolean)) {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const extension = bundled.find((candidate) => candidate.name === name);
|
|
105
|
+
if (!extension) throw new Error(`Unknown extension '${name}'`);
|
|
106
|
+
registry.register(extension);
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
// Each `--ext-native` value is a manifest path describing a pre-built C++ or
|
|
@@ -172,7 +173,10 @@ function doctor(io: CliIo): number {
|
|
|
172
173
|
io.stdout(`toolchain : ${toolchain.clang} (${toolchain.source})\n`);
|
|
173
174
|
io.stdout(`compiler : ${firstLine(version) || "unknown"}\n`);
|
|
174
175
|
} catch {
|
|
175
|
-
io.stdout("toolchain : not found
|
|
176
|
+
io.stdout("toolchain : not found\n");
|
|
177
|
+
io.stdout(" install one of: Xcode Command Line Tools (`xcode-select --install`) on macOS,\n");
|
|
178
|
+
io.stdout(" clang+lld (apt/dnf/pacman) on Linux, or LLVM + Visual Studio C++ build tools on Windows,\n");
|
|
179
|
+
io.stdout(" then re-run; or set xbintsc_CLANG to a clang binary. See doc/requirements.md.\n");
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
try {
|
|
@@ -215,6 +215,10 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
215
215
|
"declare i64 @xt_decode_uri(i32, i64*)",
|
|
216
216
|
"declare i64 @xt_btoa(i32, i64*)",
|
|
217
217
|
"declare i64 @xt_atob(i32, i64*)",
|
|
218
|
+
"declare i64 @xt_set_timeout(i32, i64*)",
|
|
219
|
+
"declare i64 @xt_clear_timeout(i32, i64*)",
|
|
220
|
+
"declare i64 @xt_set_interval(i32, i64*)",
|
|
221
|
+
"declare i64 @xt_clear_interval(i32, i64*)",
|
|
218
222
|
"declare i64 @xt_number_ctor(i32, i64*)",
|
|
219
223
|
"declare i64 @xt_bigint_ctor(i32, i64*)",
|
|
220
224
|
"declare i64 @xt_bigint_static(i64, i32, i64*)",
|
|
@@ -246,6 +250,10 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
246
250
|
"declare i64 @xt_builtin_value_encodeURI(i64, i64, i32, i64*)",
|
|
247
251
|
"declare i64 @xt_builtin_value_decodeURIComponent(i64, i64, i32, i64*)",
|
|
248
252
|
"declare i64 @xt_builtin_value_decodeURI(i64, i64, i32, i64*)",
|
|
253
|
+
"declare i64 @xt_builtin_value_setTimeout(i64, i64, i32, i64*)",
|
|
254
|
+
"declare i64 @xt_builtin_value_clearTimeout(i64, i64, i32, i64*)",
|
|
255
|
+
"declare i64 @xt_builtin_value_setInterval(i64, i64, i32, i64*)",
|
|
256
|
+
"declare i64 @xt_builtin_value_clearInterval(i64, i64, i32, i64*)",
|
|
249
257
|
"declare i64 @xt_builtin_value_number(i64, i64, i32, i64*)",
|
|
250
258
|
"declare i64 @xt_builtin_value_string(i64, i64, i32, i64*)",
|
|
251
259
|
"declare i64 @xt_builtin_value_boolean(i64, i64, i32, i64*)",
|
|
@@ -12,12 +12,11 @@ import {
|
|
|
12
12
|
/**
|
|
13
13
|
* True when a `try` frame must be saved with `_setjmpex` rather than `_setjmp`.
|
|
14
14
|
*
|
|
15
|
-
* 64-bit Windows on ARM has no `_setjmp`:
|
|
16
|
-
* `
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* its own host.
|
|
15
|
+
* 64-bit Windows on ARM has no `_setjmp`: the UCRT declares `setjmp` as
|
|
16
|
+
* `_setjmpex(buf, sponentry)` there, so the linker expects `_setjmpex` (with the
|
|
17
|
+
* caller's stack pointer at entry, `llvm.sponentry`, instead of its frame
|
|
18
|
+
* pointer). clang lowers a C `setjmp` on this target to exactly that pair.
|
|
19
|
+
* Checked at code-generation time because xbintsc builds for its own host.
|
|
21
20
|
*/
|
|
22
21
|
export function requiresSetjmpex(platform: string, arch: string): boolean {
|
|
23
22
|
return platform === "win32" && arch === "arm64";
|
|
@@ -124,6 +123,10 @@ export const GLOBAL_FUNCTIONS: Record<string, string> = {
|
|
|
124
123
|
decodeURI: "xt_decode_uri",
|
|
125
124
|
btoa: "xt_btoa",
|
|
126
125
|
atob: "xt_atob",
|
|
126
|
+
setTimeout: "xt_set_timeout",
|
|
127
|
+
clearTimeout: "xt_clear_timeout",
|
|
128
|
+
setInterval: "xt_set_interval",
|
|
129
|
+
clearInterval: "xt_clear_interval",
|
|
127
130
|
Number: "xt_number_ctor",
|
|
128
131
|
String: "xt_string_ctor",
|
|
129
132
|
Boolean: "xt_boolean_ctor",
|
|
@@ -143,6 +146,10 @@ export const BUILTIN_FUNCTION_VALUES: Record<string, string> = {
|
|
|
143
146
|
encodeURI: "xt_builtin_value_encodeURI",
|
|
144
147
|
decodeURIComponent: "xt_builtin_value_decodeURIComponent",
|
|
145
148
|
decodeURI: "xt_builtin_value_decodeURI",
|
|
149
|
+
setTimeout: "xt_builtin_value_setTimeout",
|
|
150
|
+
clearTimeout: "xt_builtin_value_clearTimeout",
|
|
151
|
+
setInterval: "xt_builtin_value_setInterval",
|
|
152
|
+
clearInterval: "xt_builtin_value_clearInterval",
|
|
146
153
|
Number: "xt_builtin_value_number",
|
|
147
154
|
String: "xt_builtin_value_string",
|
|
148
155
|
Boolean: "xt_builtin_value_boolean",
|