Skip to content

Commit 763ea3b

Browse files
authored
[wasm-esm-integration] Fix EMSCRIPETEN_KEEPALIVE (#24108)
As part of this change we re-export all wasm symbols from the support JS file. Going forward this also means we can support things like JS wrappers. Fixes: #24083
1 parent ba06aca commit 763ea3b

File tree

5 files changed

+43
-26
lines changed

5 files changed

+43
-26
lines changed

test/core/test_esm_integration.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdio.h>
2+
#include <emscripten.h>
3+
4+
EMSCRIPTEN_KEEPALIVE void foo() {
5+
printf("foo called\n");
6+
}
7+
8+
int main(int argc, char* argv[]) {
9+
printf("hello, world! (%d)\n", argc);
10+
return 0;
11+
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
export { __main_argc_argv as main } from './hello_world.wasm';
2-
export { default, err, stringToNewUTF8 } from './hello_world.support.mjs';
1+
// The wasm module must be imported here first before the support file
2+
// in order to avoid issues with circular dependencies.
3+
import * as unused from './hello_world.wasm';
4+
export { default, _foo, _main, err, stringToNewUTF8 } from './hello_world.support.mjs';

test/test_core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9568,9 +9568,9 @@ def test_esm_integration(self):
95689568
# TODO(sbc): WASM_ESM_INTEGRATION doesn't currently work with closure.
95699569
# self.maybe_closure()
95709570
self.node_args += ['--experimental-wasm-modules', '--no-warnings']
9571-
self.run_process([EMCC, '-o', 'hello_world.mjs', '-sEXPORTED_RUNTIME_METHODS=err', '-sEXPORTED_FUNCTIONS=_main,stringToNewUTF8', '-sWASM_ESM_INTEGRATION', '-Wno-experimental', test_file('hello_world_argv.c')] + self.get_emcc_args())
9571+
self.run_process([EMCC, '-o', 'hello_world.mjs', '-sEXPORTED_RUNTIME_METHODS=err', '-sEXPORTED_FUNCTIONS=_main,stringToNewUTF8', '-sWASM_ESM_INTEGRATION', '-Wno-experimental', test_file('core/test_esm_integration.c')] + self.get_emcc_args())
95729572
create_file('runner.mjs', '''
9573-
import init, { err, stringToNewUTF8, main } from "./hello_world.mjs";
9573+
import init, { err, stringToNewUTF8, _main, _foo } from "./hello_world.mjs";
95749574
await init({arguments: ['foo', 'bar']});
95759575
err('this is a pointer:', stringToNewUTF8('hello'));
95769576
''')

tools/emscripten.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ def emscript(in_wasm, out_wasm, outfile_js, js_syms, finalize=True, base_metadat
433433
receiving = create_receiving(function_exports)
434434
if settings.WASM_ESM_INTEGRATION:
435435
sending = create_sending(metadata, forwarded_json['librarySymbols'])
436-
parts += [sending, receiving]
436+
reexports = create_reexports()
437+
parts += [sending, receiving, reexports]
437438
else:
438439
parts += create_module(receiving, metadata, global_exports, forwarded_json['librarySymbols'])
439440
parts.append(post)
@@ -858,7 +859,10 @@ def create_sending(metadata, library_symbols):
858859
elems = []
859860
for k, v in sorted_items:
860861
elems.append(f'{v} as {k}')
861-
return f"export {{ {', '.join(elems)} }};\n\n"
862+
elems = ',\n '.join(elems)
863+
exports = '// Export JS functions to the wasm module with demangled names.\n'
864+
exports += f"export {{\n {elems}\n}};\n\n"
865+
return exports
862866

863867
prefix = ''
864868
if settings.MAYBE_CLOSURE_COMPILER:
@@ -876,6 +880,21 @@ def create_sending(metadata, library_symbols):
876880
return '{\n ' + ',\n '.join(elems) + '\n}'
877881

878882

883+
def create_reexports():
884+
assert settings.WASM_ESM_INTEGRATION
885+
exports = '// Re-export imported wasm functions to the JS entry point. These are user-facing and underscore mangled.\n'
886+
wasm_exports = []
887+
for exp in building.user_requested_exports:
888+
if shared.is_c_symbol(exp):
889+
demangled = shared.demangle_c_symbol_name(exp)
890+
if demangled in settings.WASM_EXPORTS:
891+
wasm_exports.append(exp)
892+
if demangled == 'main' and '__main_argc_argv' in settings.WASM_EXPORTS:
893+
wasm_exports.append('_main')
894+
exports += f"export {{ {', '.join(wasm_exports)} }};\n\n"
895+
return exports
896+
897+
879898
def can_use_await():
880899
return settings.MODULARIZE
881900

tools/link.py

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,28 +2116,13 @@ def create_worker_file(input_file, target_dir, output_file, options):
21162116

21172117

21182118
def create_esm_wrapper(wrapper_file, support_target, wasm_target):
2119-
wasm_exports = []
2120-
js_exports = list(settings.EXPORTED_RUNTIME_METHODS)
2121-
for f in settings.USER_EXPORTS:
2122-
if f == '_main' and '__main_argc_argv' in settings.WASM_EXPORTS:
2123-
wasm_exports.append('__main_argc_argv as main')
2124-
elif f in settings.WASM_EXPORTS:
2125-
wasm_exports.append(shared.demangle_c_symbol_name(f))
2126-
else:
2127-
js_exports.append(f)
2128-
wasm_exports = ', '.join(wasm_exports)
2129-
js_exports = ', '.join(js_exports)
2119+
js_exports = settings.EXPORTED_RUNTIME_METHODS + list(building.user_requested_exports)
2120+
js_exports = ', '.join(sorted(js_exports))
21302121

21312122
wrapper = []
2132-
if wasm_exports:
2133-
wrapper.append(f"export {{ {wasm_exports} }} from './{settings.WASM_BINARY_FILE}';")
2134-
# Because of the wasm ESM integration worker we need to make sure we import
2135-
# the wasm module here, before we import the support.js file.
2136-
# So, if there are no other exports we at least export the `memory`.
2137-
else:
2138-
wrapper.append('// The wasm module must be imported here first before the support file')
2139-
wrapper.append('// in order to avoid issues with circullr dependencies.')
2140-
wrapper.append(f"import * as unused from './{settings.WASM_BINARY_FILE}';")
2123+
wrapper.append('// The wasm module must be imported here first before the support file')
2124+
wrapper.append('// in order to avoid issues with circular dependencies.')
2125+
wrapper.append(f"import * as unused from './{settings.WASM_BINARY_FILE}';")
21412126
support_url = f'./{os.path.basename(support_target)}'
21422127
if js_exports:
21432128
wrapper.append(f"export {{ default, {js_exports} }} from '{support_url}';")

0 commit comments

Comments
 (0)