From 2385fb99a76c4281f034287623cf5d144fc4bd42 Mon Sep 17 00:00:00 2001 From: nejdetkadir Date: Tue, 20 Oct 2026 21:20:33 +0300 Subject: [PATCH 1/2] Link a default for the embedded-assets prepare hook core now references gea_embedded_assets_prepare through GEA_PROGRAM_HOOK, which this target compiles as an ordinary reference. build-windows.mjs adds the generated assets unit only when it exists, and without it nothing defines the hook, so it gets an /alternatename default like the other hooks. The default returns true: with no file-backed assets there is nothing to prepare. --- .../targets/win32/main/win32_hook_defaults.cpp | 3 +++ .../targets/win32/test/fixtures/hook-defaults/framework.cpp | 2 ++ .../targets/win32/test/fixtures/hook-defaults/program.cpp | 1 + .../targets/win32/test/hook-defaults.test.mjs | 6 +++--- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp b/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp index 513145e..bf031a4 100644 --- a/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp +++ b/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp @@ -15,6 +15,9 @@ extern "C" void gea_win32_default_cycle_collection_defer() {} extern "C" bool gea_win32_default_embedded_asset_lookup(const char *, const unsigned char **, unsigned long *) { return false; } +extern "C" bool gea_win32_default_embedded_assets_prepare() { return true; } + #pragma comment(linker, "/alternatename:gea_cycle_collection_defer_begin=gea_win32_default_cycle_collection_defer") #pragma comment(linker, "/alternatename:gea_cycle_collection_defer_end=gea_win32_default_cycle_collection_defer") #pragma comment(linker, "/alternatename:gea_embedded_asset_lookup=gea_win32_default_embedded_asset_lookup") +#pragma comment(linker, "/alternatename:gea_embedded_assets_prepare=gea_win32_default_embedded_assets_prepare") diff --git a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/framework.cpp b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/framework.cpp index ffc8cc2..44fefd3 100644 --- a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/framework.cpp +++ b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/framework.cpp @@ -2,9 +2,11 @@ #include extern "C" void gea_cycle_collection_defer_begin(); extern "C" bool gea_embedded_asset_lookup(const char *path, const unsigned char **data, unsigned long *length); +extern "C" bool gea_embedded_assets_prepare(); int main() { gea_cycle_collection_defer_begin(); + std::printf("prepare %d\n", gea_embedded_assets_prepare() ? 1 : 0); const unsigned char *data = nullptr; unsigned long length = 0; const bool found = gea_embedded_asset_lookup("a.png", &data, &length); diff --git a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/program.cpp b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/program.cpp index 22f942e..46d38aa 100644 --- a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/program.cpp +++ b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/program.cpp @@ -2,3 +2,4 @@ #include extern "C" __attribute__((weak)) void gea_cycle_collection_defer_begin() { std::printf("program defer\n"); } extern "C" __attribute__((weak)) bool gea_embedded_asset_lookup(const char *, const unsigned char **, unsigned long *length) { *length = 7; return true; } +extern "C" __attribute__((weak)) bool gea_embedded_assets_prepare() { return false; } diff --git a/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs b/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs index 2f2895f..c115af6 100644 --- a/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs +++ b/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs @@ -52,9 +52,9 @@ test('linked hook defaults yield to program and app definitions, and duplicates assert.equal(run.status, 0, run.stderr) return { linked: true, lines: run.stdout.split(/\r?\n/).filter(Boolean) } } - assert.deepEqual(link('defaults', [framework, defaults]).lines, ['lookup 0 0']) - assert.deepEqual(link('program', [framework, defaults, program]).lines, ['program defer', 'lookup 1 7']) - assert.deepEqual(link('override', [framework, defaults, program, override]).lines, ['program defer', 'lookup 1 42']) + assert.deepEqual(link('defaults', [framework, defaults]).lines, ['prepare 1', 'lookup 0 0']) + assert.deepEqual(link('program', [framework, defaults, program]).lines, ['program defer', 'prepare 0', 'lookup 1 7']) + assert.deepEqual(link('override', [framework, defaults, program, override]).lines, ['program defer', 'prepare 0', 'lookup 1 42']) const clash = link('duplicate', [framework, defaults, override, duplicate]) assert.equal(clash.linked, false) assert.match(clash.output, /duplicate symbol: gea_embedded_asset_lookup/) From 856ba96ed4d16fc9a9d2761acd9f199f9b85475f Mon Sep 17 00:00:00 2001 From: nejdetkadir Date: Tue, 20 Oct 2026 23:37:46 +0300 Subject: [PATCH 2/2] Cover the prepare hook's bundle and duplicate cases The generator now defines a weak gea_embedded_assets_prepare for apps without file-backed assets (core 81cbe9f) and a strong one for apps with them. A bundle fixture stands in for the strong definition, which must replace the program's weak one, the app override now defines it too, and two strong definitions must still fail to link. Also drop an unused include. --- .../targets/win32/main/win32_hook_defaults.cpp | 2 -- .../win32/test/fixtures/hook-defaults/app_duplicate.cpp | 1 + .../win32/test/fixtures/hook-defaults/app_override.cpp | 1 + .../win32/test/fixtures/hook-defaults/bundle_prepare.cpp | 2 ++ .../targets/win32/test/hook-defaults.test.mjs | 8 ++++++-- 5 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/bundle_prepare.cpp diff --git a/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp b/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp index bf031a4..0e75733 100644 --- a/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp +++ b/packages/geastack-windows/targets/win32/main/win32_hook_defaults.cpp @@ -9,8 +9,6 @@ // only while the symbol has no definition. A program's definition (weak or // not) or an app's replaces the default; two strong definitions remain a // duplicate-symbol error. -#include - extern "C" void gea_win32_default_cycle_collection_defer() {} extern "C" bool gea_win32_default_embedded_asset_lookup(const char *, const unsigned char **, unsigned long *) { return false; } diff --git a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_duplicate.cpp b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_duplicate.cpp index 8d492c2..0e3be5e 100644 --- a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_duplicate.cpp +++ b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_duplicate.cpp @@ -1,2 +1,3 @@ // A second, different strong definition of the same hook: a genuine duplicate. extern "C" bool gea_embedded_asset_lookup(const char *, const unsigned char **, unsigned long *length) { *length = 43; return true; } +extern "C" bool gea_embedded_assets_prepare() { return true; } diff --git a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_override.cpp b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_override.cpp index 8ce330f..e2a87ea 100644 --- a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_override.cpp +++ b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/app_override.cpp @@ -1,2 +1,3 @@ // An app's own definition of a hook. extern "C" bool gea_embedded_asset_lookup(const char *, const unsigned char **, unsigned long *length) { *length = 42; return true; } +extern "C" bool gea_embedded_assets_prepare() { return true; } diff --git a/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/bundle_prepare.cpp b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/bundle_prepare.cpp new file mode 100644 index 0000000..cfe6ed9 --- /dev/null +++ b/packages/geastack-windows/targets/win32/test/fixtures/hook-defaults/bundle_prepare.cpp @@ -0,0 +1,2 @@ +// Stands in for the generated assets unit of an app with file-backed assets: a strong prepare hook. +extern "C" bool gea_embedded_assets_prepare() { return true; } diff --git a/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs b/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs index c115af6..5a4f019 100644 --- a/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs +++ b/packages/geastack-windows/targets/win32/test/hook-defaults.test.mjs @@ -43,7 +43,7 @@ test('linked hook defaults yield to program and app definitions, and duplicates return file } const defaults = object(path.join(targetDir, 'main', 'win32_hook_defaults.cpp')) - const [framework, program, override, duplicate] = ['framework', 'program', 'app_override', 'app_duplicate'].map((name) => object(path.join(fixtures, `${name}.cpp`))) + const [framework, program, bundle, override, duplicate] = ['framework', 'program', 'bundle_prepare', 'app_override', 'app_duplicate'].map((name) => object(path.join(fixtures, `${name}.cpp`))) const link = (name, objects) => { const executable = path.join(out, `${name}.exe`) const result = spawnSync(lldLink, ['/nologo', `/out:${executable}`, '/subsystem:console', ...objects], { encoding: 'utf8' }) @@ -54,8 +54,12 @@ test('linked hook defaults yield to program and app definitions, and duplicates } assert.deepEqual(link('defaults', [framework, defaults]).lines, ['prepare 1', 'lookup 0 0']) assert.deepEqual(link('program', [framework, defaults, program]).lines, ['program defer', 'prepare 0', 'lookup 1 7']) - assert.deepEqual(link('override', [framework, defaults, program, override]).lines, ['program defer', 'prepare 0', 'lookup 1 42']) + assert.deepEqual(link('bundle', [framework, defaults, program, bundle]).lines, ['program defer', 'prepare 1', 'lookup 1 7']) + assert.deepEqual(link('override', [framework, defaults, program, override]).lines, ['program defer', 'prepare 1', 'lookup 1 42']) const clash = link('duplicate', [framework, defaults, override, duplicate]) assert.equal(clash.linked, false) assert.match(clash.output, /duplicate symbol: gea_embedded_asset_lookup/) + const prepareClash = link('prepare-duplicate', [framework, defaults, bundle, duplicate]) + assert.equal(prepareClash.linked, false) + assert.match(prepareClash.output, /duplicate symbol: gea_embedded_assets_prepare/) })