xbintsc 0.5.45 → 0.5.52
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/AGENTS.md +1 -1
- package/README.md +5 -4
- package/README.zh-CN.md +4 -3
- package/dist/src/cli/extensions.d.ts +24 -0
- package/dist/src/cli/extensions.js +62 -0
- package/dist/src/cli/extensions.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/help.js +3 -1
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hints.js +8 -3
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +21 -28
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +2 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/driver/build-key.d.ts +2 -0
- package/dist/src/driver/build-key.js +1 -0
- package/dist/src/driver/build-key.js.map +1 -1
- package/dist/src/driver/compiler.js +61 -8
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +4 -0
- package/dist/src/driver/config.js +2 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/link-features.d.ts +37 -0
- package/dist/src/driver/link-features.js +123 -0
- package/dist/src/driver/link-features.js.map +1 -0
- package/dist/src/driver/options.d.ts +10 -0
- package/dist/src/driver/runtime-objects.d.ts +5 -0
- package/dist/src/driver/runtime-objects.js +20 -1
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/usage.d.ts +23 -0
- package/dist/src/driver/usage.js +353 -0
- package/dist/src/driver/usage.js.map +1 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/catalog.js +1 -2
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/features.d.ts +34 -0
- package/dist/src/extensions/gui/features.js +165 -0
- package/dist/src/extensions/gui/features.js.map +1 -0
- package/dist/src/extensions/gui/index.js +10 -4
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/link-feature.d.ts +70 -0
- package/dist/src/extensions/link-feature.js +18 -0
- package/dist/src/extensions/link-feature.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +24 -4
- package/dist/src/extensions/registry.js +26 -3
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tests/cli/hints.test.js +5 -7
- package/dist/tests/cli/hints.test.js.map +1 -1
- package/dist/tests/driver/link-features.test.js +105 -0
- package/dist/tests/driver/link-features.test.js.map +1 -0
- package/dist/tests/driver/usage.test.d.ts +1 -0
- package/dist/tests/driver/usage.test.js +88 -0
- package/dist/tests/driver/usage.test.js.map +1 -0
- package/dist/tests/e2e/gui-audio.test.js +4 -4
- package/dist/tests/e2e/gui-audio.test.js.map +1 -1
- package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
- package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
- package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
- package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
- package/dist/tests/e2e/gui-css-features.test.js +270 -0
- package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.js +92 -11
- package/dist/tests/e2e/gui-effects.test.js.map +1 -1
- package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
- package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
- package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
- package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
- package/dist/tests/e2e/gui-font-face.test.js +142 -0
- package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
- package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
- package/dist/tests/e2e/gui-fonts.test.js +150 -0
- package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +10 -1
- package/dist/tests/e2e/gui-helpers.js +6 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +7 -3
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
- package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media.test.js +9 -9
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-paint.test.js +5 -2
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
- package/dist/tests/e2e/gui-shaping.test.js +47 -0
- package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
- package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
- package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
- package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.js +3 -2
- package/dist/tests/e2e/gui-transform.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
- package/dist/tests/extensions/gui-features.test.d.ts +1 -0
- package/dist/tests/extensions/gui-features.test.js +175 -0
- package/dist/tests/extensions/gui-features.test.js.map +1 -0
- package/doc/ai/cli.md +5 -1
- package/doc/ai/extensions.md +56 -26
- package/doc/ai/troubleshooting.md +10 -7
- package/doc/ai/zh-CN/cli.md +5 -1
- package/doc/ai/zh-CN/extensions.md +48 -22
- package/doc/ai/zh-CN/troubleshooting.md +6 -5
- package/doc/gui/animation.md +39 -9
- package/doc/gui/api.md +2 -1
- package/doc/gui/build.md +137 -19
- package/doc/gui/canvas.md +1 -1
- package/doc/gui/dom.md +20 -4
- package/doc/gui/known-issues.md +63 -26
- package/doc/gui/layout.md +31 -8
- package/doc/gui/media.md +13 -7
- package/doc/gui/rendering.md +114 -39
- package/doc/gui/runtime.md +5 -0
- package/doc/gui/webgl.md +24 -6
- package/doc/gui.md +110 -47
- package/doc/implemented/cli.md +2 -0
- package/doc/implemented/extensions.md +9 -3
- package/doc/npm-package.md +4 -4
- package/doc/xbintsc.config.schema.json +10 -0
- package/doc/zh-CN/gui/animation.md +33 -10
- package/doc/zh-CN/gui/api.md +2 -1
- package/doc/zh-CN/gui/build.md +110 -16
- package/doc/zh-CN/gui/canvas.md +1 -1
- package/doc/zh-CN/gui/dom.md +16 -3
- package/doc/zh-CN/gui/known-issues.md +45 -15
- package/doc/zh-CN/gui/layout.md +23 -6
- package/doc/zh-CN/gui/media.md +11 -6
- package/doc/zh-CN/gui/rendering.md +84 -26
- package/doc/zh-CN/gui/runtime.md +3 -0
- package/doc/zh-CN/gui/webgl.md +3 -3
- package/doc/zh-CN/gui.md +92 -41
- package/doc/zh-CN/implemented/cli.md +2 -0
- package/doc/zh-CN/implemented/extensions.md +9 -3
- package/doc/zh-CN/npm-package.md +4 -3
- package/package.json +7 -7
- package/runtime/ext_gui/animation_values.cpp +425 -0
- package/runtime/ext_gui/animation_values.h +64 -0
- package/runtime/ext_gui/browser.cpp +22 -15
- package/runtime/ext_gui/browser_loop.cpp +13 -1
- package/runtime/ext_gui/canvas.h +1 -1
- package/runtime/ext_gui/canvas_raster.cpp +1 -1
- package/runtime/ext_gui/canvas_text.cpp +1 -1
- package/runtime/ext_gui/css.cpp +172 -21
- package/runtime/ext_gui/css.h +75 -4
- package/runtime/ext_gui/css_match.cpp +4 -0
- package/runtime/ext_gui/css_sheet.cpp +218 -2
- package/runtime/ext_gui/document.cpp +42 -192
- package/runtime/ext_gui/document.h +25 -12
- package/runtime/ext_gui/document_animation.cpp +428 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
- package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
- package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
- package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
- package/runtime/ext_gui/dom_api_style.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
- package/runtime/ext_gui/effect_values.cpp +245 -21
- package/runtime/ext_gui/gpu_bridge.c +28 -0
- package/runtime/ext_gui/gpu_feature.cpp +30 -0
- package/runtime/ext_gui/gpu_shader.cpp +22 -0
- package/runtime/ext_gui/gpu_shader_api.h +50 -0
- package/runtime/ext_gui/gradient_values.cpp +24 -0
- package/runtime/ext_gui/grid_values.cpp +23 -0
- package/runtime/ext_gui/gui.cpp +6 -37
- package/runtime/ext_gui/gui_canvas.cpp +14 -6
- package/runtime/ext_gui/gui_cursor.cpp +50 -0
- package/runtime/ext_gui/gui_engine.h +1 -18
- package/runtime/ext_gui/gui_events.cpp +19 -6
- package/runtime/ext_gui/gui_internal.h +3 -0
- package/runtime/ext_gui/gui_webgl.cpp +25 -10
- package/runtime/ext_gui/image_api.cpp +18 -0
- package/runtime/ext_gui/image_api.h +43 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
- package/runtime/ext_gui/image_bridge.c +22 -0
- package/runtime/ext_gui/image_feature.cpp +107 -0
- package/runtime/ext_gui/inline_svg.cpp +95 -8
- package/runtime/ext_gui/inline_svg.h +5 -1
- package/runtime/ext_gui/layout.cpp +15 -9
- package/runtime/ext_gui/layout.h +8 -2
- package/runtime/ext_gui/layout_flex.cpp +134 -29
- package/runtime/ext_gui/layout_flow.cpp +58 -7
- package/runtime/ext_gui/layout_flow_internal.h +39 -4
- package/runtime/ext_gui/layout_grid.cpp +31 -0
- package/runtime/ext_gui/layout_inline.cpp +26 -2
- package/runtime/ext_gui/layout_vertical.cpp +196 -0
- package/runtime/ext_gui/media.cpp +4 -2
- package/runtime/ext_gui/media.h +3 -3
- package/runtime/ext_gui/media_api.h +7 -6
- package/runtime/ext_gui/paint.cpp +67 -9
- package/runtime/ext_gui/paint.h +61 -8
- package/runtime/ext_gui/paint_backdrop.cpp +211 -0
- package/runtime/ext_gui/paint_background.cpp +175 -97
- package/runtime/ext_gui/paint_effects.cpp +12 -6
- package/runtime/ext_gui/paint_internal.h +27 -0
- package/runtime/ext_gui/paint_outline.cpp +44 -0
- package/runtime/ext_gui/paint_shadow.cpp +368 -0
- package/runtime/ext_gui/renderer.cpp +15 -7
- package/runtime/ext_gui/renderer.h +11 -2
- package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
- package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
- package/runtime/ext_gui/renderer_gradient.cpp +51 -17
- package/runtime/ext_gui/renderer_image.cpp +19 -7
- package/runtime/ext_gui/renderer_internal.h +21 -0
- package/runtime/ext_gui/renderer_layer.cpp +37 -6
- package/runtime/ext_gui/renderer_text.cpp +2 -1
- package/runtime/ext_gui/stb_truetype.h +5077 -0
- package/runtime/ext_gui/style.cpp +62 -8
- package/runtime/ext_gui/style.h +111 -4
- package/runtime/ext_gui/style_cascade.cpp +83 -0
- package/runtime/ext_gui/style_internal.h +13 -1
- package/runtime/ext_gui/style_length.cpp +92 -0
- package/runtime/ext_gui/style_print.cpp +83 -2
- package/runtime/ext_gui/style_svg.cpp +40 -0
- package/runtime/ext_gui/style_text.cpp +302 -0
- package/runtime/ext_gui/style_ui.cpp +150 -0
- package/runtime/ext_gui/style_values.cpp +76 -62
- package/runtime/ext_gui/style_values_internal.h +23 -0
- package/runtime/ext_gui/text.cpp +27 -499
- package/runtime/ext_gui/text.h +18 -9
- package/runtime/ext_gui/text_api.h +45 -0
- package/runtime/ext_gui/text_bridge.c +23 -0
- package/runtime/ext_gui/text_cache.cpp +12 -3
- package/runtime/ext_gui/text_font_db.cpp +427 -0
- package/runtime/ext_gui/text_font_paths.cpp +250 -0
- package/runtime/ext_gui/text_font_paths.h +39 -0
- package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
- package/runtime/ext_gui/text_font_sfnt.h +44 -0
- package/runtime/ext_gui/text_fonts.cpp +348 -0
- package/runtime/ext_gui/text_fonts.h +78 -0
- package/runtime/ext_gui/text_fonts_internal.h +77 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
- package/runtime/ext_gui/text_hb.cpp +438 -0
- package/runtime/ext_gui/text_stb.cpp +369 -0
- package/runtime/ext_gui/transform.cpp +107 -9
- package/runtime/ext_gui/transform.h +5 -0
- package/runtime/ext_gui/webgl_api.cpp +19 -0
- package/runtime/ext_gui/webgl_api.h +53 -0
- package/runtime/ext_gui/webgl_bridge.c +25 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
- package/runtime/ext_gui/webgl_feature.cpp +82 -0
- package/runtime/ext_gui/webgl_feature.h +28 -0
- package/runtime/ext_gui/webgl_msl.cpp +41 -0
- package/runtime/ext_gui/webgl_msl.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +40 -32
- package/runtime/ext_gui/window.cpp +7 -7
- package/runtime/ext_media/decode_audio.cpp +1 -1
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +7 -7
- package/scripts/build-gui.ts +97 -98
- package/scripts/check-file-length.ts +1 -0
- package/scripts/gui-build-options.ts +122 -0
- package/src/cli/extensions.ts +72 -0
- package/src/cli/help.ts +3 -1
- package/src/cli/hints.ts +9 -3
- package/src/cli/main.ts +21 -27
- package/src/diagnostics/diagnostic.ts +2 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/compiler.ts +63 -8
- package/src/driver/config.ts +6 -0
- package/src/driver/link-features.ts +163 -0
- package/src/driver/options.ts +10 -0
- package/src/driver/runtime-objects.ts +26 -1
- package/src/driver/usage.ts +376 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/catalog.ts +1 -2
- package/src/extensions/gui/features.ts +166 -0
- package/src/extensions/gui/index.ts +10 -4
- package/src/extensions/link-feature.ts +72 -0
- package/src/extensions/registry.ts +45 -4
- package/src/index.ts +3 -2
- package/dist/src/extensions/media/index.d.ts +0 -28
- package/dist/src/extensions/media/index.js +0 -59
- package/dist/src/extensions/media/index.js.map +0 -1
- package/dist/tests/extensions/media.test.js +0 -63
- package/dist/tests/extensions/media.test.js.map +0 -1
- package/src/extensions/media/index.ts +0 -65
- /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
package/src/cli/main.ts
CHANGED
|
@@ -31,9 +31,7 @@ import {
|
|
|
31
31
|
toolchainPointer,
|
|
32
32
|
UNEXPECTED_FAILURE_HINT,
|
|
33
33
|
} from "./hints.js";
|
|
34
|
-
import {
|
|
35
|
-
import { bundledExtensions } from "../extensions/catalog.js";
|
|
36
|
-
import { nativeExtensionFromManifest } from "../extensions/native.js";
|
|
34
|
+
import { buildRegistry, normalizeExtensions } from "./extensions.js";
|
|
37
35
|
import { resolveResourceCompiler } from "../driver/win-icon.js";
|
|
38
36
|
import {
|
|
39
37
|
CONFIG_FILE_NAME,
|
|
@@ -80,6 +78,8 @@ const VALUE_FLAGS = new Set([
|
|
|
80
78
|
"optimize",
|
|
81
79
|
"ext",
|
|
82
80
|
"ext-native",
|
|
81
|
+
"feature",
|
|
82
|
+
"no-feature",
|
|
83
83
|
"config",
|
|
84
84
|
"icon",
|
|
85
85
|
"app-id",
|
|
@@ -138,27 +138,6 @@ function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
|
138
138
|
return { command: positionals.shift(), positionals, flags, passthrough };
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
function buildRegistry(extNames: readonly string[], nativeManifests: readonly string[]): ExtensionRegistry {
|
|
142
|
-
const registry = createDefaultRegistry();
|
|
143
|
-
const bundled = bundledExtensions();
|
|
144
|
-
for (const name of extNames) {
|
|
145
|
-
const extension = bundled.find((candidate) => candidate.name === name);
|
|
146
|
-
if (!extension) throw new Error(`Unknown extension '${name}'`);
|
|
147
|
-
registry.register(extension);
|
|
148
|
-
}
|
|
149
|
-
// Each manifest describes a pre-built C++ or Rust library.
|
|
150
|
-
for (const manifest of nativeManifests) {
|
|
151
|
-
registry.register(nativeExtensionFromManifest(manifest));
|
|
152
|
-
}
|
|
153
|
-
// Hint the extensions that ship with xbintsc but were not enabled, so a
|
|
154
|
-
// missing `import` of a known module points at the flag that enables it
|
|
155
|
-
// (`pass --ext node`) instead of failing later with a confusing error.
|
|
156
|
-
for (const extension of bundled) {
|
|
157
|
-
if (!registry.has(extension.name)) registry.hintExtension(extension);
|
|
158
|
-
}
|
|
159
|
-
return registry;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
141
|
function printDiagnostics(diagnostics: readonly Diagnostic[], fileName: string, io: CliIo): void {
|
|
163
142
|
/* A diagnostic can come from any module in a bundled program, so load (and
|
|
164
143
|
* cache) the source of the file it names instead of always using the entry:
|
|
@@ -404,7 +383,8 @@ function dispatch(argv: readonly string[], io: CliIo): number {
|
|
|
404
383
|
}
|
|
405
384
|
const extNames = listFlag(args.flags, "ext") ?? resolved.config.extensions ?? [];
|
|
406
385
|
const nativeManifests = listFlag(args.flags, "ext-native") ?? resolved.config.extNative ?? [];
|
|
407
|
-
const
|
|
386
|
+
const { extensions: registryExtensions } = normalizeExtensions(extNames, io);
|
|
387
|
+
const registry = buildRegistry(registryExtensions, nativeManifests);
|
|
408
388
|
/* Front-end only: parse, bundle, check and lower far enough to report
|
|
409
389
|
* semantic / unsupported-feature diagnostics, but never invoke clang or
|
|
410
390
|
* write output. The checker is on unless `--no-check` is passed. */
|
|
@@ -458,7 +438,8 @@ function dispatch(argv: readonly string[], io: CliIo): number {
|
|
|
458
438
|
}
|
|
459
439
|
const extNames = listFlag(args.flags, "ext") ?? resolved.config.extensions ?? [];
|
|
460
440
|
const nativeManifests = listFlag(args.flags, "ext-native") ?? resolved.config.extNative ?? [];
|
|
461
|
-
const
|
|
441
|
+
const { extensions: registryExtensions } = normalizeExtensions(extNames, io);
|
|
442
|
+
const registry = buildRegistry(registryExtensions, nativeManifests);
|
|
462
443
|
const { ir, diagnostics } = compileEntry(entry, registry, {
|
|
463
444
|
debug: Boolean(args.flags.get("debug")),
|
|
464
445
|
check: !args.flags.has("no-check"),
|
|
@@ -490,7 +471,13 @@ function dispatch(argv: readonly string[], io: CliIo): number {
|
|
|
490
471
|
const optimize = (args.flags.get("optimize") as string | undefined) ?? config.optimize ?? "2";
|
|
491
472
|
const extNames = listFlag(args.flags, "ext") ?? config.extensions ?? [];
|
|
492
473
|
const nativeManifests = listFlag(args.flags, "ext-native") ?? config.extNative ?? [];
|
|
493
|
-
const
|
|
474
|
+
const normalized = normalizeExtensions(extNames, io);
|
|
475
|
+
const registry = buildRegistry(normalized.extensions, nativeManifests);
|
|
476
|
+
const features = [
|
|
477
|
+
...normalized.features,
|
|
478
|
+
...(listFlag(args.flags, "feature") ?? config.features ?? []),
|
|
479
|
+
];
|
|
480
|
+
const noFeatures = listFlag(args.flags, "no-feature") ?? config.noFeatures ?? [];
|
|
494
481
|
const pgoGenerate = args.flags.get("pgo-generate");
|
|
495
482
|
const pgoUse = args.flags.get("pgo-use");
|
|
496
483
|
if (pgoGenerate !== undefined && pgoUse !== undefined) {
|
|
@@ -524,6 +511,8 @@ function dispatch(argv: readonly string[], io: CliIo): number {
|
|
|
524
511
|
lto: Boolean(args.flags.get("lto")) || config.lto === true,
|
|
525
512
|
...(pgo ? { pgo } : {}),
|
|
526
513
|
...(pgoDir ? { pgoDir } : {}),
|
|
514
|
+
...(features.length > 0 ? { features } : {}),
|
|
515
|
+
...(noFeatures.length > 0 ? { noFeatures } : {}),
|
|
527
516
|
});
|
|
528
517
|
|
|
529
518
|
if (result.diagnostics.some((d) => d.category === "error")) {
|
|
@@ -535,6 +524,11 @@ function dispatch(argv: readonly string[], io: CliIo): number {
|
|
|
535
524
|
return 1;
|
|
536
525
|
}
|
|
537
526
|
|
|
527
|
+
/* A detected-but-unavailable feature is a warning, not a failure: the
|
|
528
|
+
* program still links and the capability degrades at run time. */
|
|
529
|
+
const warnings = result.diagnostics.filter((d) => d.category === "warning");
|
|
530
|
+
if (warnings.length > 0) printDiagnostics(warnings, entry, io);
|
|
531
|
+
|
|
538
532
|
if (args.flags.has("time") && result.timings) printTimings(result.timings, io);
|
|
539
533
|
|
|
540
534
|
if (command === "build") {
|
|
@@ -44,6 +44,8 @@ export enum DiagnosticCode {
|
|
|
44
44
|
ToolchainError = 6003,
|
|
45
45
|
IncrementalCacheError = 6004,
|
|
46
46
|
CircularDependency = 6005,
|
|
47
|
+
/** An optional link feature was requested but its archive is unavailable. */
|
|
48
|
+
LinkFeatureUnavailable = 6006,
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export interface Diagnostic {
|
package/src/driver/build-key.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface CacheKeyInput {
|
|
|
31
31
|
readonly check?: boolean;
|
|
32
32
|
readonly pgo?: PgoMode;
|
|
33
33
|
readonly pgoDir: string;
|
|
34
|
+
/** Active optional link features; they change which objects/archives link. */
|
|
35
|
+
readonly features?: readonly string[];
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/** Hash every input that can change the produced binary. */
|
|
@@ -54,5 +56,6 @@ export function buildCacheKey(input: CacheKeyInput): string {
|
|
|
54
56
|
String(input.check !== false),
|
|
55
57
|
pgo ?? "",
|
|
56
58
|
pgo ? input.pgoDir : "",
|
|
59
|
+
[...(input.features ?? [])].sort().join(","),
|
|
57
60
|
]);
|
|
58
61
|
}
|
package/src/driver/compiler.ts
CHANGED
|
@@ -28,6 +28,8 @@ import { parseEntry } from "./frontend.js";
|
|
|
28
28
|
import { ensureRuntimeObjects } from "./runtime-objects.js";
|
|
29
29
|
import { ensureAppArtifacts } from "./app-artifacts.js";
|
|
30
30
|
import { buildCacheKey } from "./build-key.js";
|
|
31
|
+
import { collectUsage } from "./usage.js";
|
|
32
|
+
import { resolveLinkFeatures, type ResolvedLinkFeature } from "./link-features.js";
|
|
31
33
|
import type { BuildOptions, BuildResult, EmitKind, PhaseTiming } from "./options.js";
|
|
32
34
|
|
|
33
35
|
export { COMPILER_VERSION } from "./version.js";
|
|
@@ -102,8 +104,35 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
102
104
|
return { outputPath, cached: false, diagnostics: diagnostics.diagnostics, timings };
|
|
103
105
|
}
|
|
104
106
|
|
|
107
|
+
/* Optional link features are selected from the bundled program before the
|
|
108
|
+
* cache key: they change which registration objects and archives link. Only
|
|
109
|
+
* a linked `exe` has features; `emit obj`/`ir` produce toolchain input that
|
|
110
|
+
* the caller may link itself. */
|
|
105
111
|
const app: AppConfig = options.app ?? {};
|
|
106
112
|
const iconPath = options.icon ?? app.icon;
|
|
113
|
+
/* An app icon is decoded through the image pipeline, so force `images` even
|
|
114
|
+
* when the bundled HTML has no `<img>` — but only when the enabled extensions
|
|
115
|
+
* actually declare that feature (a non-GUI program may still embed an icon). */
|
|
116
|
+
const hasImagesFeature = registry.linkFeatures().some((entry) => entry.feature.name === "images");
|
|
117
|
+
const featureRequest = {
|
|
118
|
+
features: [
|
|
119
|
+
...(options.features ?? []),
|
|
120
|
+
...(iconPath !== undefined && hasImagesFeature ? ["images"] : []),
|
|
121
|
+
],
|
|
122
|
+
noFeatures: options.noFeatures,
|
|
123
|
+
};
|
|
124
|
+
const linkFeatures: readonly ResolvedLinkFeature[] =
|
|
125
|
+
emit === "exe"
|
|
126
|
+
? resolveLinkFeatures(registry, collectUsage(parsed.sourceFile), featureRequest, diagnostics)
|
|
127
|
+
: [];
|
|
128
|
+
if (diagnostics.hasErrors) {
|
|
129
|
+
return { outputPath, cached: false, diagnostics: diagnostics.diagnostics, timings };
|
|
130
|
+
}
|
|
131
|
+
if (options.verbose) {
|
|
132
|
+
const names = linkFeatures.map((feature) => feature.name);
|
|
133
|
+
process.stderr.write(`xbintsc: link features: ${names.length > 0 ? names.join(", ") : "none"}\n`);
|
|
134
|
+
}
|
|
135
|
+
|
|
107
136
|
let icon: IconInfo | undefined;
|
|
108
137
|
if (iconPath) {
|
|
109
138
|
try {
|
|
@@ -131,6 +160,7 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
131
160
|
check: options.check !== false,
|
|
132
161
|
pgo,
|
|
133
162
|
pgoDir,
|
|
163
|
+
features: linkFeatures.map((feature) => feature.name),
|
|
134
164
|
});
|
|
135
165
|
|
|
136
166
|
// A `.app` bundle is deterministic from the output path and name, so it can be
|
|
@@ -144,7 +174,14 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
144
174
|
/* PGO profile data can change without the cache key changing, so always
|
|
145
175
|
* rebuild a `--pgo-use` binary; it is an explicit optimization step. */
|
|
146
176
|
if (!options.force && pgo !== "use" && !diagnostics.hasErrors && cache.isFresh(cacheKey, outputs)) {
|
|
147
|
-
return {
|
|
177
|
+
return {
|
|
178
|
+
outputPath,
|
|
179
|
+
cached: true,
|
|
180
|
+
diagnostics: [],
|
|
181
|
+
timings,
|
|
182
|
+
features: linkFeatures.map((feature) => feature.name),
|
|
183
|
+
...(bundle ? { bundlePath: bundle } : {}),
|
|
184
|
+
};
|
|
148
185
|
}
|
|
149
186
|
|
|
150
187
|
const codegenStarted = Date.now();
|
|
@@ -220,7 +257,7 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
220
257
|
}
|
|
221
258
|
|
|
222
259
|
const runtimeStarted = Date.now();
|
|
223
|
-
const { runtimeObjects, extensionObjects, nativeObjects } = ensureRuntimeObjects({
|
|
260
|
+
const { runtimeObjects, extensionObjects, featureObjects, nativeObjects } = ensureRuntimeObjects({
|
|
224
261
|
runner,
|
|
225
262
|
clang,
|
|
226
263
|
runtimeDir,
|
|
@@ -231,6 +268,7 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
231
268
|
lto,
|
|
232
269
|
pgo,
|
|
233
270
|
pgoDir,
|
|
271
|
+
features: linkFeatures,
|
|
234
272
|
});
|
|
235
273
|
timings.push({ phase: "runtime", ms: Date.now() - runtimeStarted });
|
|
236
274
|
|
|
@@ -254,17 +292,25 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
254
292
|
clang,
|
|
255
293
|
objectPaths: [
|
|
256
294
|
objectPath,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
...
|
|
295
|
+
/* Feature archives come after their bridges (which reference the
|
|
296
|
+
* implementation) and before the extensions' own archives (`gui.a`
|
|
297
|
+
* provides symbols the bridges call back into). `Set` keeps that order
|
|
298
|
+
* and drops an archive two features or an extension share. */
|
|
299
|
+
...new Set([
|
|
300
|
+
...runtimeObjects,
|
|
301
|
+
...extensionObjects,
|
|
302
|
+
...featureObjects,
|
|
303
|
+
...nativeObjects,
|
|
304
|
+
...(artifacts.entryObject !== undefined ? [artifacts.entryObject] : []),
|
|
305
|
+
...artifacts.iconObjects,
|
|
306
|
+
]),
|
|
262
307
|
],
|
|
263
308
|
outputPath,
|
|
264
309
|
linkerFlags: [
|
|
265
310
|
...toolchain.linkerArgs,
|
|
266
311
|
...(process.platform === "win32" ? ["-lws2_32"] : ["-lm", "-pthread"]),
|
|
267
312
|
...registry.linkerFlags(),
|
|
313
|
+
...linkFeatures.flatMap((feature) => feature.linkerFlags),
|
|
268
314
|
/* A GUI program is a Windows-subsystem executable: no console window is
|
|
269
315
|
* created when it is launched. Console output (stdout/stderr) is lost in
|
|
270
316
|
* that subsystem, so a program that wants to report things opts back in
|
|
@@ -292,7 +338,16 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
292
338
|
|
|
293
339
|
cache.record(cacheKey, outputs);
|
|
294
340
|
cache.save();
|
|
295
|
-
return {
|
|
341
|
+
return {
|
|
342
|
+
outputPath,
|
|
343
|
+
irPath,
|
|
344
|
+
cached: false,
|
|
345
|
+
diagnostics: [],
|
|
346
|
+
ir,
|
|
347
|
+
timings,
|
|
348
|
+
features: linkFeatures.map((feature) => feature.name),
|
|
349
|
+
...(bundlePath ? { bundlePath } : {}),
|
|
350
|
+
};
|
|
296
351
|
}
|
|
297
352
|
|
|
298
353
|
/** Default `CFBundleIdentifier` for a bundle when none is configured. */
|
package/src/driver/config.ts
CHANGED
|
@@ -44,6 +44,10 @@ export interface ProjectConfig {
|
|
|
44
44
|
readonly pgoDir?: string;
|
|
45
45
|
readonly extensions?: readonly string[];
|
|
46
46
|
readonly extNative?: readonly string[];
|
|
47
|
+
/** Optional link features to force on (`media`, `gpu`, `images`, `shaping`, `webgl`, `all`). */
|
|
48
|
+
readonly features?: readonly string[];
|
|
49
|
+
/** Optional link features to keep out even when auto-detection finds a use. */
|
|
50
|
+
readonly noFeatures?: readonly string[];
|
|
47
51
|
readonly force?: boolean;
|
|
48
52
|
readonly app?: AppConfig;
|
|
49
53
|
}
|
|
@@ -135,6 +139,8 @@ export function parseProjectConfig(text: string, where: string = CONFIG_FILE_NAM
|
|
|
135
139
|
pgoDir: readString(root, "pgoDir", where),
|
|
136
140
|
extensions: readStringArray(root, "extensions", where),
|
|
137
141
|
extNative: readStringArray(root, "extNative", where),
|
|
142
|
+
features: readStringArray(root, "features", where),
|
|
143
|
+
noFeatures: readStringArray(root, "noFeatures", where),
|
|
138
144
|
force: readBoolean(root, "force", where),
|
|
139
145
|
app,
|
|
140
146
|
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolving optional link features for one build.
|
|
3
|
+
*
|
|
4
|
+
* The registry knows which features the *enabled* extensions can provide; this
|
|
5
|
+
* module decides which of them a program may use (from {@link ProgramUsage}),
|
|
6
|
+
* applies the `--feature` / `--no-feature` overrides, and turns an unavailable
|
|
7
|
+
* archive into either a warning (auto-detected) or an error (explicitly forced).
|
|
8
|
+
*
|
|
9
|
+
* Keeping the decision here — not in codegen — means the produced LLVM IR is
|
|
10
|
+
* independent of the feature set: the only difference is which registration
|
|
11
|
+
* objects and archives reach the linker.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { DiagnosticCode, type DiagnosticBag } from "../diagnostics/diagnostic.js";
|
|
15
|
+
import type { ExtensionRegistry } from "../extensions/registry.js";
|
|
16
|
+
import type { LinkFeature, ProgramUsage } from "../extensions/link-feature.js";
|
|
17
|
+
|
|
18
|
+
/** The user's explicit feature overrides (`--feature` / `--no-feature`). */
|
|
19
|
+
export interface LinkFeatureRequest {
|
|
20
|
+
readonly features?: readonly string[];
|
|
21
|
+
readonly noFeatures?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** One active feature, with everything the driver needs to link it. */
|
|
25
|
+
export interface ResolvedLinkFeature {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly description: string;
|
|
28
|
+
readonly runtimeSources: readonly string[];
|
|
29
|
+
readonly nativeObjects: readonly string[];
|
|
30
|
+
readonly linkerFlags: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** `--feature all` / `--no-feature all`; specific names override it. */
|
|
34
|
+
const ALL = "all";
|
|
35
|
+
|
|
36
|
+
/** Human-readable list of the features the enabled extensions provide. */
|
|
37
|
+
function availableList(names: readonly string[]): string {
|
|
38
|
+
if (names.length === 0) return "none (enable an extension that provides one, e.g. --ext gui)";
|
|
39
|
+
return names.join(", ");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Pick the active features for `usage`.
|
|
44
|
+
*
|
|
45
|
+
* Precedence: a specific `--feature x` beats `--no-feature all`, and a specific
|
|
46
|
+
* `--no-feature x` beats `--feature all`; the same name on both sides is an
|
|
47
|
+
* error. Diagnosed errors are left in `diagnostics`; the caller must stop when
|
|
48
|
+
* it has errors.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveLinkFeatures(
|
|
51
|
+
registry: ExtensionRegistry,
|
|
52
|
+
usage: ProgramUsage,
|
|
53
|
+
request: LinkFeatureRequest,
|
|
54
|
+
diagnostics: DiagnosticBag,
|
|
55
|
+
): readonly ResolvedLinkFeature[] {
|
|
56
|
+
const declarations = registry.linkFeatures();
|
|
57
|
+
const byName = new Map<string, LinkFeature>();
|
|
58
|
+
for (const declaration of declarations) byName.set(declaration.feature.name, declaration.feature);
|
|
59
|
+
const available = [...byName.keys()].sort();
|
|
60
|
+
const requested = new Set(request.features ?? []);
|
|
61
|
+
const disabled = new Set(request.noFeatures ?? []);
|
|
62
|
+
|
|
63
|
+
for (const name of [...requested, ...disabled]) {
|
|
64
|
+
if (name === ALL || byName.has(name)) continue;
|
|
65
|
+
diagnostics.error(
|
|
66
|
+
DiagnosticCode.LinkFeatureUnavailable,
|
|
67
|
+
`unknown link feature '${name}'; available: ${availableList(available)}`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (requested.has(ALL) && disabled.has(ALL)) {
|
|
71
|
+
diagnostics.error(
|
|
72
|
+
DiagnosticCode.LinkFeatureUnavailable,
|
|
73
|
+
"link features cannot be both forced and disabled with 'all' (--feature all --no-feature all)",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (diagnostics.hasErrors) return [];
|
|
77
|
+
|
|
78
|
+
const forceAll = requested.has(ALL);
|
|
79
|
+
const disableAll = disabled.has(ALL);
|
|
80
|
+
|
|
81
|
+
/* Start from the explicitly forced set, then pull in `requires`. A specific
|
|
82
|
+
* `--no-feature` wins over `--feature all`, so it is excluded from the base
|
|
83
|
+
* set; a dependency it blocks is an error rather than a silent omission. */
|
|
84
|
+
const forced = new Set<string>();
|
|
85
|
+
for (const { feature } of declarations) {
|
|
86
|
+
const specificallyForced = requested.has(feature.name);
|
|
87
|
+
const specificallyBlocked = disabled.has(feature.name);
|
|
88
|
+
if (specificallyForced && specificallyBlocked) {
|
|
89
|
+
diagnostics.error(
|
|
90
|
+
DiagnosticCode.LinkFeatureUnavailable,
|
|
91
|
+
`link feature '${feature.name}' is both forced (--feature) and disabled (--no-feature)`,
|
|
92
|
+
);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (specificallyForced || (forceAll && !specificallyBlocked)) forced.add(feature.name);
|
|
96
|
+
}
|
|
97
|
+
let changed = true;
|
|
98
|
+
while (changed) {
|
|
99
|
+
changed = false;
|
|
100
|
+
for (const { feature } of declarations) {
|
|
101
|
+
if (!forced.has(feature.name)) continue;
|
|
102
|
+
for (const dependency of feature.requires ?? []) {
|
|
103
|
+
if (!byName.has(dependency)) {
|
|
104
|
+
diagnostics.error(
|
|
105
|
+
DiagnosticCode.LinkFeatureUnavailable,
|
|
106
|
+
`link feature '${feature.name}' requires unknown feature '${dependency}'`,
|
|
107
|
+
);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (disabled.has(dependency)) {
|
|
111
|
+
diagnostics.error(
|
|
112
|
+
DiagnosticCode.LinkFeatureUnavailable,
|
|
113
|
+
`link feature '${feature.name}' requires '${dependency}', which --no-feature disables`,
|
|
114
|
+
);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!forced.has(dependency)) {
|
|
118
|
+
forced.add(dependency);
|
|
119
|
+
changed = true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (diagnostics.hasErrors) return [];
|
|
125
|
+
|
|
126
|
+
const resolved: ResolvedLinkFeature[] = [];
|
|
127
|
+
|
|
128
|
+
for (const { feature } of declarations) {
|
|
129
|
+
const specificallyBlocked = disabled.has(feature.name);
|
|
130
|
+
const forcedHere = forced.has(feature.name);
|
|
131
|
+
const blocked = specificallyBlocked || (disableAll && !requested.has(feature.name) && !forcedHere);
|
|
132
|
+
if (!forcedHere && blocked) continue;
|
|
133
|
+
if (!forcedHere && !feature.used(usage)) continue;
|
|
134
|
+
|
|
135
|
+
let runtimeSources: readonly string[];
|
|
136
|
+
let nativeObjects: readonly string[];
|
|
137
|
+
try {
|
|
138
|
+
runtimeSources = feature.runtimeSources?.() ?? [];
|
|
139
|
+
nativeObjects = feature.nativeObjects?.() ?? [];
|
|
140
|
+
} catch (error) {
|
|
141
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
142
|
+
if (forcedHere) {
|
|
143
|
+
diagnostics.error(DiagnosticCode.LinkFeatureUnavailable, message);
|
|
144
|
+
} else {
|
|
145
|
+
diagnostics.warning(
|
|
146
|
+
DiagnosticCode.LinkFeatureUnavailable,
|
|
147
|
+
`link feature '${feature.name}' was detected but is unavailable: ${message}`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
resolved.push({
|
|
154
|
+
name: feature.name,
|
|
155
|
+
description: feature.description,
|
|
156
|
+
runtimeSources: [...runtimeSources],
|
|
157
|
+
nativeObjects: [...nativeObjects],
|
|
158
|
+
linkerFlags: [...(feature.linkerFlags?.() ?? [])],
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return resolved;
|
|
163
|
+
}
|
package/src/driver/options.ts
CHANGED
|
@@ -50,6 +50,14 @@ export interface BuildOptions {
|
|
|
50
50
|
readonly pgo?: PgoMode;
|
|
51
51
|
/** Profile directory (default: `<outDir>/pgo`). */
|
|
52
52
|
readonly pgoDir?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Optional link features to force on (`media`, `gpu`, `images`, `shaping`, `webgl`, or `all`). Features are
|
|
55
|
+
* otherwise selected from a static scan of the bundled program; forcing one
|
|
56
|
+
* is the escape hatch for HTML/CSS built from runtime data.
|
|
57
|
+
*/
|
|
58
|
+
readonly features?: readonly string[];
|
|
59
|
+
/** Optional link features to keep out even when the scan detects a use. */
|
|
60
|
+
readonly noFeatures?: readonly string[];
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
/** One phase of a build, in milliseconds (reported by `--time`). */
|
|
@@ -68,6 +76,8 @@ export interface BuildResult {
|
|
|
68
76
|
readonly bundlePath?: string;
|
|
69
77
|
/** Per-phase timings, collected for `xbintsc build --time`. */
|
|
70
78
|
readonly timings?: readonly PhaseTiming[];
|
|
79
|
+
/** Active optional link features (only for a linked `exe` build). */
|
|
80
|
+
readonly features?: readonly string[];
|
|
71
81
|
}
|
|
72
82
|
|
|
73
83
|
export interface CompileStringResult {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
10
10
|
import { basename, join, resolve } from "node:path";
|
|
11
11
|
import type { ExtensionRegistry } from "../extensions/registry.js";
|
|
12
|
+
import type { ResolvedLinkFeature } from "./link-features.js";
|
|
12
13
|
import { hashParts } from "./cache.js";
|
|
13
14
|
import { findRuntimeLibrary } from "./runtime-lib.js";
|
|
14
15
|
import { compileC, optimizationFlags, RUNTIME_CFLAGS, type PgoMode, type Runner } from "./toolchain.js";
|
|
@@ -46,6 +47,8 @@ export const RUNTIME_SOURCES = [
|
|
|
46
47
|
export interface RuntimeObjects {
|
|
47
48
|
readonly runtimeObjects: readonly string[];
|
|
48
49
|
readonly extensionObjects: readonly string[];
|
|
50
|
+
/** Objects/archives contributed by active optional link features. */
|
|
51
|
+
readonly featureObjects: readonly string[];
|
|
49
52
|
/** Pre-built C++/Rust objects and archives contributed by native extensions. */
|
|
50
53
|
readonly nativeObjects: readonly string[];
|
|
51
54
|
}
|
|
@@ -61,6 +64,8 @@ export interface RuntimeObjectsOptions {
|
|
|
61
64
|
readonly lto: boolean;
|
|
62
65
|
readonly pgo: PgoMode | undefined;
|
|
63
66
|
readonly pgoDir: string;
|
|
67
|
+
/** Optional link features selected for this program. */
|
|
68
|
+
readonly features?: readonly ResolvedLinkFeature[];
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
/**
|
|
@@ -131,5 +136,25 @@ export function ensureRuntimeObjects(options: RuntimeObjectsOptions): RuntimeObj
|
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
138
|
// A native archive may be shared by several manifests; link each once.
|
|
134
|
-
|
|
139
|
+
const featureObjects: string[] = [];
|
|
140
|
+
for (const feature of options.features ?? []) {
|
|
141
|
+
/* Feature bridges are always compiled: they are not part of any prebuilt
|
|
142
|
+
* archive, and their references are what make the linker extract the
|
|
143
|
+
* feature's implementation. */
|
|
144
|
+
for (const sourcePath of feature.runtimeSources) {
|
|
145
|
+
const dedupeKey = resolve(sourcePath);
|
|
146
|
+
if (seen.has(dedupeKey)) continue;
|
|
147
|
+
seen.add(dedupeKey);
|
|
148
|
+
extensionObjects.push(
|
|
149
|
+
compileOne(sourcePath, `feature_${feature.name}_${basename(sourcePath, ".c")}`),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
featureObjects.push(...feature.nativeObjects);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
runtimeObjects,
|
|
156
|
+
extensionObjects,
|
|
157
|
+
featureObjects: [...new Set(featureObjects)],
|
|
158
|
+
nativeObjects: [...new Set(registry.nativeObjects())],
|
|
159
|
+
};
|
|
135
160
|
}
|