Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions test/modularize_post_js.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#preprocess

// This file gets included via `--extern-post-js` in order to run tests
// that are built with `-sMODULARIZE`.

#if PTHREADS
// Avoid instantiating the module on pthreads.
if (!isPthread)
#endif
{{{ EXPORT_NAME }}}();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a general thing that all users will want, but I don't have a good idea for how to provide that. We could make Module() do nothing at all on pthreads, in theory, but that seems risky, even if I can't think of a use for it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thank that might make sense, but doesn't have to be part of this change. We can consider that as followup.

2 changes: 1 addition & 1 deletion test/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def check_js_engines():

def get_and_import_modules():
modules = []
for filename in glob.glob(os.path.join(os.path.dirname(__file__), 'test*.py')):
for filename in glob.glob(os.path.join(common.TEST_ROOT, 'test*.py')):
module_dir, module_file = os.path.split(filename)
module_name, module_ext = os.path.splitext(module_file)
__import__(module_name)
Expand Down
14 changes: 4 additions & 10 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2468,10 +2468,7 @@ def test_pthread_proxying(self, modularize):
if modularize:
self.set_setting('MODULARIZE')
self.set_setting('EXPORT_NAME=ModuleFactory')
# Only instantiate the module on the main thread.
create_file('extern-post.js',
'if (typeof importScripts != "function") ModuleFactory();')
args = ['--extern-post-js=extern-post.js']
args = ['--extern-post-js', test_file('modularize_post_js.js')]
self.do_run_in_out_file_test('pthread/test_pthread_proxying.c',
interleaved_output=False, emcc_args=args)

Expand Down Expand Up @@ -6266,8 +6263,7 @@ def test_unicode_js_library(self):
err = self.expect_fail([PYTHON, 'expect_fail.py'], expect_traceback=True)
self.assertContained('UnicodeDecodeError', err)

create_file('modularize_post.js', '(async function main(){await Module();})()')
self.emcc_args += ['-sMODULARIZE', '--js-library', test_file('unicode_library.js'), '--extern-post-js', 'modularize_post.js', '--post-js', test_file('unicode_postjs.js')]
self.emcc_args += ['-sMODULARIZE', '--js-library', test_file('unicode_library.js'), '--extern-post-js', test_file('modularize_post_js.js'), '--post-js', test_file('unicode_postjs.js')]
self.do_run_in_out_file_test('test_unicode_js_library.c')

def test_funcptr_import_type(self):
Expand Down Expand Up @@ -7924,14 +7920,13 @@ def get_wat_addr(call_index):
def test_modularize_closure_pre(self):
# test that the combination of modularize + closure + pre-js works. in that mode,
# closure should not minify the Module object in a way that the pre-js cannot use it.
create_file('post.js', 'var TheModule = Module();\n')
if self.is_wasm2js():
# TODO(sbc): Fix closure warnings with MODULARIZE + WASM=0
self.ldflags.append('-Wno-error=closure')

self.emcc_args += [
'--pre-js', test_file('core/modularize_closure_pre.js'),
'--extern-post-js=post.js',
'--extern-post-js', test_file('modularize_post_js.js'),
'--closure=1',
'-g1',
'-sMODULARIZE',
Expand Down Expand Up @@ -9222,8 +9217,7 @@ def test_pthread_offset_converter_modularize(self):
self.set_setting('USE_OFFSET_CONVERTER')
self.set_setting('MODULARIZE')
self.set_setting('EXPORT_NAME', 'foo')
create_file('post.js', 'if (!isPthread) foo();')
self.emcc_args += ['--extern-post-js', 'post.js']
self.emcc_args += ['--extern-post-js', test_file('modularize_post_js.js')]
if '-g' in self.emcc_args:
self.emcc_args += ['-DDEBUG']
self.do_runf('core/test_return_address.c', 'passed')
Expand Down
61 changes: 28 additions & 33 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,8 @@ def test_emcc_generate_config(self, compiler):
'node': (['-sENVIRONMENT=node'],),
})
def test_emcc_output_mjs(self, args):
create_file('extern-post.js', 'await Module();')
self.run_process([EMCC, '-o', 'hello_world.mjs',
'--extern-post-js', 'extern-post.js',
'--extern-post-js', test_file('modularize_post_js.js'),
test_file('hello_world.c')] + args)
src = read_file('hello_world.mjs')
self.assertContained('export default Module;', src)
Expand All @@ -363,11 +362,10 @@ def test_emcc_output_mjs(self, args):
})
@node_pthreads
def test_emcc_output_worker_mjs(self, args):
create_file('extern-post.js', 'if (!isPthread) await Module();')
os.mkdir('subdir')
self.run_process([EMCC, '-o', 'subdir/hello_world.mjs',
'-sEXIT_RUNTIME', '-sPROXY_TO_PTHREAD', '-pthread', '-O1',
'--extern-post-js', 'extern-post.js',
'--extern-post-js', test_file('modularize_post_js.js'),
test_file('hello_world.c')] + args)
src = read_file('subdir/hello_world.mjs')
self.assertContained("new URL('hello_world.wasm', import.meta.url)", src)
Expand All @@ -377,19 +375,17 @@ def test_emcc_output_worker_mjs(self, args):

@node_pthreads
def test_emcc_output_worker_mjs_single_file(self):
create_file('extern-post.js', 'await Module();')
self.run_process([EMCC, '-o', 'hello_world.mjs', '-pthread',
'--extern-post-js', 'extern-post.js',
'--extern-post-js', test_file('modularize_post_js.js'),
test_file('hello_world.c'), '-sSINGLE_FILE'])
src = read_file('hello_world.mjs')
self.assertNotContained("new URL('data:", src)
self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), workerOptions)", src)
self.assertContained('hello, world!', self.run_js('hello_world.mjs'))

def test_emcc_output_mjs_closure(self):
create_file('extern-post.js', 'await Module();')
self.run_process([EMCC, '-o', 'hello_world.mjs',
'--extern-post-js', 'extern-post.js',
'--extern-post-js', test_file('modularize_post_js.js'),
test_file('hello_world.c'), '--closure=1'])
src = read_file('hello_world.mjs')
self.assertContained('new URL("hello_world.wasm", import.meta.url)', src)
Expand Down Expand Up @@ -1577,25 +1573,20 @@ def test_minimal_modularize_export_keepalive(self):
EMSCRIPTEN_KEEPALIVE int libf1() { return 42; }
''')

def write_js_main():
"""
With MINIMAL_RUNTIME, the module instantiation function isn't exported neither as a UMD nor as an ES6 module.
Thus, it's impossible to use `require` or `import`.

This function simply appends the instantiation code to the generated code.
"""
runtime = read_file('test.js')
write_file('main.js', f'{runtime}\nModule().then((mod) => console.log(mod._libf1()));')
# With MINIMAL_RUNTIME, the module instantiation function isn't exported neither as a UMD nor as
# an ES6 module.
# Thus, it's impossible to use `require` or `import` and instead run the module
# as part of --extern-post-js.
create_file('post.js', 'Module().then((mod) => console.log(mod._libf1()));')
self.emcc_args += ['--extern-post-js=post.js']

# By default, no symbols should be exported when using MINIMAL_RUNTIME.
self.emcc('main.c', [], output_filename='test.js')
write_js_main()
self.assertContained('TypeError: mod._libf1 is not a function', self.run_js('main.js', assert_returncode=NON_ZERO))
self.emcc('main.c', [])
self.assertContained('TypeError: mod._libf1 is not a function', self.run_js('a.out.js', assert_returncode=NON_ZERO))

# Ensures that EXPORT_KEEPALIVE=1 exports the symbols.
self.emcc('main.c', ['-sEXPORT_KEEPALIVE=1'], output_filename='test.js')
write_js_main()
self.assertContained('42\n', self.run_js('main.js'))
self.emcc('main.c', ['-sEXPORT_KEEPALIVE=1'])
self.assertContained('42\n', self.run_js('a.out.js'))

@crossplatform
def test_minimal_runtime_export_all_modularize(self):
Expand Down Expand Up @@ -6682,7 +6673,12 @@ def test_define_modularize(self):
create_file('a.out.js', src)
self.assertContained("define([], () => Module);", src)

create_file('run_module.js', 'var m; (global.define = (deps, factory) => { m = factory(); }).amd = true; require("./a.out.js"); m();')
create_file('run_module.js', '''
var m;
(global.define = (deps, factory) => { m = factory(); }).amd = true;
require("./a.out.js");
m();
''')
output = self.run_js('run_module.js')
self.assertContained('hello, world!\n', output)

Expand Down Expand Up @@ -10385,15 +10381,15 @@ def test_node_js_pthread_module(self, es6):
create_file('moduleLoader.mjs', '''
import test_module from "./subdir/module.mjs";
test_module().then((test_module_instance) => {
test_module_instance._main();
console.log("done");
});
''')
else:
ext = '.js'
create_file('moduleLoader.js', '''
const test_module = require("./subdir/module.js");
test_module().then((test_module_instance) => {
test_module_instance._main();
console.log("done");
});
''')
ensure_dir('subdir')
Expand All @@ -10403,7 +10399,7 @@ def test_node_js_pthread_module(self, es6):

# run the module
ret = self.run_js('moduleLoader' + ext)
self.assertContained('hello, world!', ret)
self.assertContained('hello, world!\ndone\n', ret)

create_file('workerLoader.js', f'''
const {{ Worker, isMainThread }} = require('worker_threads');
Expand All @@ -10412,7 +10408,7 @@ def test_node_js_pthread_module(self, es6):

# run the same module, but inside of a worker
ret = self.run_js('workerLoader.js')
self.assertContained('hello, world!', ret)
self.assertContained('hello, world!\ndone\n', ret)

@no_windows('node system() does not seem to work, see https://github.com/emscripten-core/emscripten/pull/10547')
@requires_node
Expand Down Expand Up @@ -12180,15 +12176,14 @@ def test_standalone_syscalls(self):
self.assertContained(expected, self.run_js('test.wasm', engine))

@parameterized({
'wasm2js': (['-sWASM=0'], ''),
'modularize': (['-sMODULARIZE'], 'Module()'),
'wasm2js': (['-sWASM=0'],),
'modularize': (['-sMODULARIZE', '--extern-post-js', test_file('modularize_post_js.js')],),
})
def test_promise_polyfill(self, constant_args, extern_post_js):
def test_promise_polyfill(self, constant_args):
def test(args, expect_fail):
# legacy browsers may lack Promise, which wasm2js depends on. see what
# happens when we kill the global Promise function.
create_file('extern-post.js', extern_post_js)
self.run_process([EMCC, test_file('hello_world.c')] + constant_args + args + ['--extern-post-js', 'extern-post.js'])
self.run_process([EMCC, test_file('hello_world.c')] + constant_args + args)
js = read_file('a.out.js')
create_file('a.out.js', 'Promise = undefined;\n' + js)
return self.run_js('a.out.js', assert_returncode=NON_ZERO if expect_fail else 0)
Expand Down
9 changes: 8 additions & 1 deletion tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,14 @@ def fix_windows_newlines(text):


def read_js_files(files):
contents = '\n'.join(read_file(f) for f in files)
contents = []
for f in files:
content = read_file(f)
if content.startswith('#preprocess\n'):
contents.append(shared.read_and_preprocess(f, expand_macros=True))
else:
contents.append(content)
contents = '\n'.join(contents)
return fix_windows_newlines(contents)


Expand Down
Loading