Skip to content

Commit 6ede0b8

Browse files
authored
Fix regression with Safari and EXPORT_NAME (#19656)
Fixes: #18357
1 parent e295d29 commit 6ede0b8

File tree

10 files changed

+49
-20
lines changed

10 files changed

+49
-20
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ jobs:
601601
echo "JSC_ENGINE = [os.path.expanduser('~/.jsvu/bin/javascriptcore')]" >> ~/emsdk/.emscripten
602602
echo "JS_ENGINES = [JSC_ENGINE]" >> ~/emsdk/.emscripten
603603
- run-tests:
604-
test_targets: "core0.test_hello_world"
604+
test_targets: "core0.test_hello_world other.test_modularize_incoming other.test_modularize_incoming_export_name"
605605
test-spidermonkey:
606606
executor: linux-python
607607
steps:

emcc.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3229,8 +3229,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile):
32293229

32303230
if settings.MODULARIZE:
32313231
modularize()
3232-
3233-
if settings.USE_CLOSURE_COMPILER:
3232+
elif settings.USE_CLOSURE_COMPILER:
32343233
module_export_name_substitution()
32353234

32363235
# Run a final optimization pass to clean up items that were not possible to
@@ -3863,7 +3862,10 @@ def modularize():
38633862
shared.target_environment_may_be('web'):
38643863
async_emit = 'async '
38653864

3866-
return_value = settings.EXPORT_NAME
3865+
# Return the incoming `moduleArg`. This is is equeivielt to the `Module` var within the
3866+
# generated code but its not run through closure minifiection so we can reference it in
3867+
# the the return statement.
3868+
return_value = 'moduleArg'
38673869
if settings.WASM_ASYNC_COMPILATION:
38683870
return_value += '.ready'
38693871
if not settings.EXPORT_READY_PROMISE:
@@ -3874,7 +3876,7 @@ def modularize():
38743876
diagnostics.warning('emcc', 'EXPORT_NAME should not be named "config" when targeting Safari')
38753877

38763878
src = '''
3877-
%(maybe_async)sfunction(%(EXPORT_NAME)s = {}) {
3879+
%(maybe_async)sfunction(moduleArg = {}) {
38783880
38793881
%(src)s
38803882
@@ -3883,7 +3885,6 @@ def modularize():
38833885
%(capture_module_function_for_audio_worklet)s
38843886
''' % {
38853887
'maybe_async': async_emit,
3886-
'EXPORT_NAME': settings.EXPORT_NAME,
38873888
'src': src,
38883889
'return_value': return_value,
38893890
# Given the async nature of how the Module function and Module object come into existence in AudioWorkletGlobalScope,
@@ -3945,6 +3946,7 @@ def modularize():
39453946

39463947

39473948
def module_export_name_substitution():
3949+
assert not settings.MODULARIZE
39483950
global final_js
39493951
logger.debug(f'Private module export name substitution with {settings.EXPORT_NAME}')
39503952
src = read_file(final_js)

src/closure-externs/closure-externs.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,5 @@ var sampleRate;
261261
* Avoid closure minifying anything to "id". See #13965
262262
*/
263263
var id;
264+
265+
var moduleArg;

src/preamble.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,11 @@ if (Module['locateFile']) {
630630
}
631631
#if EXPORT_ES6 && USE_ES6_IMPORT_META && !SINGLE_FILE // in single-file mode, repeating WASM_BINARY_FILE would emit the contents again
632632
} else {
633+
#if ENVIRONMENT_MAY_BE_SHELL
634+
if (ENVIRONMENT_IS_SHELL)
635+
wasmBinaryFile = '{{{ WASM_BINARY_FILE }}}';
636+
else
637+
#endif
633638
// Use bundler-friendly `new URL(..., import.meta.url)` pattern; works in browsers too.
634639
wasmBinaryFile = new URL('{{{ WASM_BINARY_FILE }}}', import.meta.url).href;
635640
}

src/shell.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
// after the generated code, you will need to define var Module = {};
2121
// before the code. Then that object will be used in the code, and you
2222
// can continue to use Module afterwards as well.
23-
#if USE_CLOSURE_COMPILER
23+
#if MODULARIZE
24+
var Module = moduleArg;
25+
#elif USE_CLOSURE_COMPILER
2426
// if (!Module)` is crucial for Closure Compiler here as it will otherwise replace every `Module` occurrence with a string
2527
var /** @type {{
2628
noImageDecoding: boolean,

src/shell_minimal.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* SPDX-License-Identifier: MIT
55
*/
66

7-
#if USE_CLOSURE_COMPILER
8-
7+
#if MODULARIZE
8+
var Module = moduleArg;
9+
#elif USE_CLOSURE_COMPILER
910
// if (!Module)` is crucial for Closure Compiler here as it will
1011
// otherwise replace every `Module` occurrence with the object below
1112
var /** @type{Object} */ Module;
@@ -15,7 +16,7 @@ if (!Module) /** @suppress{checkTypes}*/Module =
1516
#endif
1617
{"__EMSCRIPTEN_PRIVATE_MODULE_EXPORT_NAME_SUBSTITUTION__":1};
1718

18-
#elif !MODULARIZE && (ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL)
19+
#elif ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
1920

2021
// When running on the web we expect Module to be defined externally, in the
2122
// HTML. Otherwise we must define it here before its first use
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 567,
33
"a.html.gz": 379,
4-
"a.js": 18209,
5-
"a.js.gz": 8055,
4+
"a.js": 18218,
5+
"a.js.gz": 8059,
66
"a.mem": 3171,
77
"a.mem.gz": 2713,
8-
"total": 21947,
9-
"total_gz": 11147
8+
"total": 21956,
9+
"total_gz": 11151
1010
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 567,
33
"a.html.gz": 379,
4-
"a.js": 17681,
5-
"a.js.gz": 7872,
4+
"a.js": 17689,
5+
"a.js.gz": 7874,
66
"a.mem": 3171,
77
"a.mem.gz": 2713,
8-
"total": 21419,
9-
"total_gz": 10964
8+
"total": 21427,
9+
"total_gz": 10966
1010
}

test/test_core.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7770,6 +7770,7 @@ def test_webidl(self, mode, allow_memory_growth):
77707770
if self.maybe_closure():
77717771
# avoid closure minified names competing with our test code in the global name space
77727772
self.set_setting('MODULARIZE')
7773+
self.set_setting('EXPORT_NAME', 'createModule')
77737774
else:
77747775
self.set_setting('WASM_ASYNC_COMPILATION', 0)
77757776

@@ -7781,7 +7782,7 @@ def test_webidl(self, mode, allow_memory_growth):
77817782

77827783
post_js = '\n\n'
77837784
if self.get_setting('MODULARIZE'):
7784-
post_js += 'var TheModule = Module();\n'
7785+
post_js += 'var TheModule = createModule();\n'
77857786
else:
77867787
post_js += 'var TheModule = Module;\n'
77877788
post_js += '\n\n'
@@ -9129,7 +9130,7 @@ def test_asan_api(self):
91299130
def test_asan_modularized_with_closure(self):
91309131
# the bug is that createModule() returns undefined, instead of the
91319132
# proper Promise object.
9132-
create_file('post.js', 'if (!(createModule() instanceof Promise)) throw "Promise was not returned :(";\n')
9133+
create_file('post.js', 'if (!(createModule() instanceof Promise)) throw `Promise was not returned (${typeof createModule()})`;\n')
91339134
self.emcc_args += ['-fsanitize=address', '--extern-post-js=post.js']
91349135
self.set_setting('MODULARIZE')
91359136
self.set_setting('EXPORT_NAME', 'createModule')

test/test_other.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5928,6 +5928,22 @@ def test_modularize_strict(self):
59285928
output = self.run_js('run.js')
59295929
self.assertEqual(output, 'hello, world!\n')
59305930

5931+
@parameterized({
5932+
'': ([],),
5933+
'export_name': (['-sEXPORT_NAME=Foo'],),
5934+
'closure': (['-sEXPORT_NAME=Foo', '--closure=1'],),
5935+
})
5936+
@crossplatform
5937+
def test_modularize_incoming(self, args):
5938+
self.run_process([EMCC, test_file('hello_world.c'), '-o', 'out.mjs'] + self.get_emcc_args() + args)
5939+
create_file('run.mjs', '''
5940+
import Module from './out.mjs';
5941+
await Module({onRuntimeInitialized: () => console.log('done init')})
5942+
.then(() => console.log('got module'));
5943+
''')
5944+
output = self.run_js('run.mjs')
5945+
self.assertContained('done init\nhello, world!\ngot module\n', output)
5946+
59315947
@crossplatform
59325948
@node_pthreads
59335949
@no_mac('https://github.com/emscripten-core/emscripten/issues/19683')

0 commit comments

Comments
 (0)