diff --git a/test/test_other.py b/test/test_other.py index 0b827f6aad0b5..2e3321bb33fa8 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -67,7 +67,7 @@ def is_bitcode(filename): return True # on macOS, there is a 20-byte prefix which starts with little endian # encoding of 0x0B17C0DE - elif b == b'\xDE\xC0\x17\x0B': + elif b == b'\xde\xc0\x17\x0b': b = bytearray(open(filename, 'rb').read(22)) return b[20:] == b'BC' except IndexError: @@ -83,6 +83,7 @@ def uses_canonical_tmp(func): This decorator takes care of cleaning the directory after the test to satisfy the leak detector. """ + @wraps(func) def decorated(self, *args, **kwargs): # Before running the test completely remove the canonical_tmp @@ -105,8 +106,7 @@ def decorated(self, *args, **kwargs): def with_both_compilers(f): assert callable(f) - parameterize(f, {'': (EMCC,), - 'emxx': (EMXX,)}) + parameterize(f, {'': (EMCC,), 'emxx': (EMXX,)}) return f @@ -120,8 +120,7 @@ def metafunc(self, backend, *args, **kwargs): self.emcc_args.append(f'-D{backend}') f(self, *args, **kwargs) - parameterize(metafunc, {'': ('WASMFS_MEMORY_BACKEND',), - 'node': ('WASMFS_NODE_BACKEND',)}) + parameterize(metafunc, {'': ('WASMFS_MEMORY_BACKEND',), 'node': ('WASMFS_NODE_BACKEND',)}) return metafunc @@ -136,9 +135,7 @@ def metafunc(self, backend, *args, **kwargs): self.emcc_args.append(f'-D{backend}') f(self, *args, **kwargs) - parameterize(metafunc, {'': (None,), - 'wasmfs': ('WASMFS_MEMORY_BACKEND',), - 'wasmfs_node': ('WASMFS_NODE_BACKEND',)}) + parameterize(metafunc, {'': (None,), 'wasmfs': ('WASMFS_MEMORY_BACKEND',), 'wasmfs_node': ('WASMFS_NODE_BACKEND',)}) return metafunc @@ -356,29 +353,52 @@ def test_emcc_generate_config(self, compiler): self.assertContained('LLVM_ROOT', config_contents) os.remove(config_path) - @parameterized({ - '': ([],), - 'node': (['-sENVIRONMENT=node'],), - }) + @parameterized( + { + '': ([],), + 'node': (['-sENVIRONMENT=node'],), + } + ) def test_emcc_output_mjs(self, args): - self.run_process([EMCC, '-o', 'hello_world.mjs', - '--extern-post-js', test_file('modularize_post_js.js'), - test_file('hello_world.c')] + args) + self.run_process( + [ + EMCC, + '-o', + 'hello_world.mjs', + '--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) self.assertContained('hello, world!', self.run_js('hello_world.mjs')) - @parameterized({ - '': ([],), - 'node': (['-sENVIRONMENT=node'],), - }) + @parameterized( + { + '': ([],), + 'node': (['-sENVIRONMENT=node'],), + } + ) @node_pthreads def test_emcc_output_worker_mjs(self, args): os.mkdir('subdir') - self.run_process([EMCC, '-o', 'subdir/hello_world.mjs', - '-sEXIT_RUNTIME', '-sPROXY_TO_PTHREAD', '-pthread', '-O1', - '--extern-post-js', test_file('modularize_post_js.js'), - test_file('hello_world.c')] + args) + self.run_process( + [ + EMCC, + '-o', + 'subdir/hello_world.mjs', + '-sEXIT_RUNTIME', + '-sPROXY_TO_PTHREAD', + '-pthread', + '-O1', + '--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) self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), workerOptions)", src) @@ -387,18 +407,35 @@ def test_emcc_output_worker_mjs(self, args): @node_pthreads def test_emcc_output_worker_mjs_single_file(self): - self.run_process([EMCC, '-o', 'hello_world.mjs', '-pthread', - '--extern-post-js', test_file('modularize_post_js.js'), - test_file('hello_world.c'), '-sSINGLE_FILE']) + self.run_process( + [ + EMCC, + '-o', + 'hello_world.mjs', + '-pthread', + '--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): - self.run_process([EMCC, '-o', 'hello_world.mjs', - '--extern-post-js', test_file('modularize_post_js.js'), - test_file('hello_world.c'), '--closure=1']) + self.run_process( + [ + EMCC, + '-o', + 'hello_world.mjs', + '--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) self.assertContained('hello, world!', self.run_js('hello_world.mjs')) @@ -406,9 +443,9 @@ def test_emcc_output_mjs_closure(self): def test_emcc_output_mjs_web_no_import_meta(self): # Ensure we don't emit import.meta.url at all for: # ENVIRONMENT=web + EXPORT_ES6 + USE_ES6_IMPORT_META=0 - self.run_process([EMCC, '-o', 'hello_world.mjs', - test_file('hello_world.c'), - '-sENVIRONMENT=web', '-sUSE_ES6_IMPORT_META=0']) + self.run_process( + [EMCC, '-o', 'hello_world.mjs', test_file('hello_world.c'), '-sENVIRONMENT=web', '-sUSE_ES6_IMPORT_META=0'] + ) src = read_file('hello_world.mjs') self.assertNotContained('import.meta.url', src) self.assertContained('export default Module;', src) @@ -423,54 +460,78 @@ def test_export_es6_requires_modularize(self): self.assertContained('EXPORT_ES6 requires MODULARIZE to be set', err) def test_export_es6_node_requires_import_meta(self): - err = self.expect_fail([EMCC, test_file('hello_world.c'), - '-sENVIRONMENT=node', '-sEXPORT_ES6', '-sUSE_ES6_IMPORT_META=0']) + err = self.expect_fail( + [EMCC, test_file('hello_world.c'), '-sENVIRONMENT=node', '-sEXPORT_ES6', '-sUSE_ES6_IMPORT_META=0'] + ) self.assertContained('EXPORT_ES6 and ENVIRONMENT=*node* requires USE_ES6_IMPORT_META to be set', err) def test_export_es6_allows_export_in_post_js(self): - self.run_process([EMCC, test_file('hello_world.c'), '-O3', '-sEXPORT_ES6', '--post-js', test_file('export_module.js')]) + self.run_process( + [EMCC, test_file('hello_world.c'), '-O3', '-sEXPORT_ES6', '--post-js', test_file('export_module.js')] + ) src = read_file('a.out.js') self.assertContained('export{doNothing};', src) - @parameterized({ - '': (False,), - 'package_json': (True,), - }) - @parameterized({ - '': ([],), - # load a worker before startup to check ES6 modules there as well - 'pthreads': (['-pthread', '-sPTHREAD_POOL_SIZE=1'],), - }) + @parameterized( + { + '': (False,), + 'package_json': (True,), + } + ) + @parameterized( + { + '': ([],), + # load a worker before startup to check ES6 modules there as well + 'pthreads': (['-pthread', '-sPTHREAD_POOL_SIZE=1'],), + } + ) def test_export_es6(self, package_json, args): - self.run_process([EMCC, test_file('hello_world.c'), '-sEXPORT_ES6', - '-o', 'hello.mjs'] + args) + self.run_process([EMCC, test_file('hello_world.c'), '-sEXPORT_ES6', '-o', 'hello.mjs'] + args) # In ES6 mode we use MODULARIZE, so we must instantiate an instance of the # module to run it. - create_file('runner.mjs', ''' + create_file( + 'runner.mjs', + ''' import Hello from "./hello.mjs"; Hello(); - ''') + ''', + ) self.assertContained('hello, world!', self.run_js('runner.mjs')) - @parameterized({ - '': ([],), - 'pthreads': (['-pthread'],), - }) + @parameterized( + { + '': ([],), + 'pthreads': (['-pthread'],), + } + ) def test_modularize_instance(self, args): - create_file('library.js', '''\ + create_file( + 'library.js', + '''\ addToLibrary({ $baz: function() { console.log('baz'); }, $qux: function() { console.log('qux'); } - });''') - self.run_process([EMCC, test_file('modularize_instance.c'), - '-sMODULARIZE=instance', - '-sEXPORTED_RUNTIME_METHODS=baz,addOnExit', - '-sEXPORTED_FUNCTIONS=_bar,_main,qux', - '--js-library', 'library.js', - '-o', 'modularize_instance.mjs'] + args) - - create_file('runner.mjs', ''' + });''', + ) + self.run_process( + [ + EMCC, + test_file('modularize_instance.c'), + '-sMODULARIZE=instance', + '-sEXPORTED_RUNTIME_METHODS=baz,addOnExit', + '-sEXPORTED_FUNCTIONS=_bar,_main,qux', + '--js-library', + 'library.js', + '-o', + 'modularize_instance.mjs', + ] + + args + ) + + create_file( + 'runner.mjs', + ''' import { strict as assert } from 'assert'; import init, { _foo as foo, _bar as bar, baz, qux, addOnExit, HEAP32 } from "./modularize_instance.mjs"; await init(); @@ -480,7 +541,8 @@ def test_modularize_instance(self, args): qux(); // exported library function with EXPORTED_FUNCTIONS assert(typeof addOnExit === 'function'); // exported runtime function with EXPORTED_RUNTIME_METHODS assert(typeof HEAP32 === 'object'); // exported runtime value by default - ''') + ''', + ) self.assertContained('main1\nmain2\nfoo\nbar\nbaz\n', self.run_js('runner.mjs')) @@ -491,10 +553,12 @@ def test_emcc_out_file(self): self.run_process([EMCC, '-ofoo.js', 'foo.o']) self.assertExists('foo.js') - @parameterized({ - 'c': [EMCC, '.c'], - 'cxx': [EMXX, '.cpp'], - }) + @parameterized( + { + 'c': [EMCC, '.c'], + 'cxx': [EMXX, '.cpp'], + } + ) def test_emcc_basics(self, compiler, suffix): # emcc src.cpp ==> writes a.out.js and a.out.wasm self.run_process([compiler, test_file('hello_world' + suffix)]) @@ -506,10 +570,13 @@ def test_emcc_basics(self, compiler, suffix): output = self.run_process([compiler, '--version'], stdout=PIPE, stderr=PIPE) output = output.stdout.replace('\r', '') self.assertContained('emcc (Emscripten gcc/clang-like replacement', output) - self.assertContained('''Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt) + self.assertContained( + '''Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt) This is free and open source software under the MIT license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -''', output) +''', + output, + ) # --help output = self.run_process([compiler, '--help'], stdout=PIPE, stderr=PIPE) @@ -523,8 +590,8 @@ def test_emcc_basics(self, compiler, suffix): # properly report source code errors, and stop there self.clear() stderr = self.expect_fail([compiler, test_file('hello_world_error' + suffix)]) - self.assertNotContained('IOError', stderr) # no python stack - self.assertNotContained('Traceback', stderr) # no python stack + self.assertNotContained('IOError', stderr) # no python stack + self.assertNotContained('Traceback', stderr) # no python stack self.assertContained('error: invalid preprocessing directive', stderr) self.assertContained(["error: use of undeclared identifier 'cheez", "error: unknown type name 'cheez'"], stderr) self.assertContained('errors generated.', stderr.splitlines()[-2]) @@ -544,10 +611,7 @@ def test_dumpmachine(self): output = self.run_process([EMCC, '-sMEMORY64', '-dumpmachine'], stdout=PIPE, stderr=PIPE).stdout self.assertContained('wasm64-unknown-emscripten', output) - @parameterized({ - 'c': [EMCC, '.c'], - 'cxx': [EMXX, '.cpp'] - }) + @parameterized({'c': [EMCC, '.c'], 'cxx': [EMXX, '.cpp']}) def test_emcc_2(self, compiler, suffix): # emcc src.cpp -c and emcc -c src.cpp -o src.[o|foo|so] ==> should always give an object file for args in ([], ['-o', 'src.o'], ['-o', 'src.foo'], ['-o', 'src.so']): @@ -572,10 +636,7 @@ def test_bc_as_archive(self): self.run_process([EMCC, '-c', test_file('hello_world.c'), '-flto', '-o', 'out.a']) self.run_process([EMCC, 'out.a']) - @parameterized({ - 'c': [EMCC, '.c'], - 'cxx': [EMXX, '.cpp'] - }) + @parameterized({'c': [EMCC, '.c'], 'cxx': [EMXX, '.cpp']}) def test_emcc_3(self, compiler, suffix): # handle singleton archives self.run_process([compiler, '-c', test_file('hello_world' + suffix), '-o', 'a.o']) @@ -605,37 +666,37 @@ def test_emcc_4(self, compiler): # Optimization: emcc src.cpp -o something.js [-Ox]. -O0 is the same as not specifying any optimization setting # link_param are used after compiling first for params, opt_level, link_params, closure, has_malloc in [ - (['-o', 'something.js'], 0, None, 0, 1), - (['-o', 'something.js', '-O0', '-g'], 0, None, 0, 0), - (['-o', 'something.js', '-O1'], 1, None, 0, 0), - (['-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), # no closure since debug - (['-o', 'something.js', '-O2'], 2, None, 0, 1), - (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), - (['-o', 'something.js', '-Os'], 2, None, 0, 1), - (['-o', 'something.js', '-O3'], 3, None, 0, 1), + (['-o', 'something.js'], 0, None, 0, 1), + (['-o', 'something.js', '-O0', '-g'], 0, None, 0, 0), + (['-o', 'something.js', '-O1'], 1, None, 0, 0), + (['-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), # no closure since debug + (['-o', 'something.js', '-O2'], 2, None, 0, 1), + (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), + (['-o', 'something.js', '-Os'], 2, None, 0, 1), + (['-o', 'something.js', '-O3'], 3, None, 0, 1), # and, test compiling first - (['-c', '-o', 'something.o'], 0, [], 0, 0), - (['-c', '-o', 'something.o', '-O0'], 0, [], 0, 0), + (['-c', '-o', 'something.o'], 0, [], 0, 0), + (['-c', '-o', 'something.o', '-O0'], 0, [], 0, 0), (['-c', '-o', 'something.o', '-O1'], 1, ['-O1'], 0, 0), (['-c', '-o', 'something.o', '-O2'], 2, ['-O2'], 0, 0), (['-c', '-o', 'something.o', '-O3'], 3, ['-O3'], 0, 0), - (['-O1', '-c', '-o', 'something.o'], 1, [], 0, 0), + (['-O1', '-c', '-o', 'something.o'], 1, [], 0, 0), # non-wasm - (['-sWASM=0', '-o', 'something.js'], 0, None, 0, 1), - (['-sWASM=0', '-o', 'something.js', '-O0', '-g'], 0, None, 0, 0), - (['-sWASM=0', '-o', 'something.js', '-O1'], 1, None, 0, 0), - (['-sWASM=0', '-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), # no closure since debug - (['-sWASM=0', '-o', 'something.js', '-O2'], 2, None, 0, 1), - (['-sWASM=0', '-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), - (['-sWASM=0', '-o', 'something.js', '-Os'], 2, None, 0, 1), - (['-sWASM=0', '-o', 'something.js', '-O3'], 3, None, 0, 1), + (['-sWASM=0', '-o', 'something.js'], 0, None, 0, 1), + (['-sWASM=0', '-o', 'something.js', '-O0', '-g'], 0, None, 0, 0), + (['-sWASM=0', '-o', 'something.js', '-O1'], 1, None, 0, 0), + (['-sWASM=0', '-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), # no closure since debug + (['-sWASM=0', '-o', 'something.js', '-O2'], 2, None, 0, 1), + (['-sWASM=0', '-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), + (['-sWASM=0', '-o', 'something.js', '-Os'], 2, None, 0, 1), + (['-sWASM=0', '-o', 'something.js', '-O3'], 3, None, 0, 1), # and, test compiling to bitcode first - (['-flto', '-c', '-o', 'something.o'], 0, [], 0, 0), - (['-flto', '-c', '-o', 'something.o', '-O0'], 0, [], 0, 0), + (['-flto', '-c', '-o', 'something.o'], 0, [], 0, 0), + (['-flto', '-c', '-o', 'something.o', '-O0'], 0, [], 0, 0), (['-flto', '-c', '-o', 'something.o', '-O1'], 1, ['-O1'], 0, 0), (['-flto', '-c', '-o', 'something.o', '-O2'], 2, ['-O2'], 0, 0), (['-flto', '-c', '-o', 'something.o', '-O3'], 3, ['-O3'], 0, 0), - (['-flto', '-O1', '-c', '-o', 'something.o'], 1, [], 0, 0), + (['-flto', '-O1', '-c', '-o', 'something.o'], 1, [], 0, 0), ]: print(params, opt_level, link_params, closure, has_malloc) self.clear() @@ -660,7 +721,9 @@ def test_emcc_4(self, compiler): # XXX these are quite sensitive, and will need updating when code generation changes generated = read_file('something.js') main = self.get_func(generated, '_main') if 'function _main' in generated else generated - assert 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 should be used by default' + assert ( + 'new Uint16Array' in generated and 'new Uint32Array' in generated + ), 'typed arrays 2 should be used by default' assert 'SAFE_HEAP_LOAD' not in generated, 'safe heap should not be used by default' assert 'SAFE_HEAP_STORE' not in generated, 'safe heap should not be used by default' assert ': while(' not in main, 'when relooping we also js-optimize, so there should be no labelled whiles' @@ -766,23 +829,30 @@ def test_combining_object_files_from_archive(self): self.assertContained('side got: hello from main, over', self.run_js('combined.o.js')) def test_js_transform(self): - create_file('t.py', ''' + create_file( + 't.py', + ''' import sys f = open(sys.argv[1], 'a') f.write('transformed!') f.close() -''') +''', + ) - err = self.run_process([EMCC, test_file('hello_world.c'), '-gsource-map', '--js-transform', '%s t.py' % (PYTHON)], stderr=PIPE).stderr + err = self.run_process( + [EMCC, test_file('hello_world.c'), '-gsource-map', '--js-transform', '%s t.py' % (PYTHON)], stderr=PIPE + ).stderr self.assertContained('disabling source maps because a js transform is being done', err) self.assertIn('transformed!', read_file('a.out.js')) - @parameterized({ - '': [[]], - 'O1': [['-O1']], - 'O2': [['-O2']], - 'O3': [['-O3']], - }) + @parameterized( + { + '': [[]], + 'O1': [['-O1']], + 'O2': [['-O2']], + 'O3': [['-O3']], + } + ) def test_emcc_asm_v_wasm(self, opts): for mode in ([], ['-sWASM=0']): self.clear() @@ -814,11 +884,13 @@ def test_emcc_cflags(self): self.assertContained('hello, world!', self.run_js('a.out.js')) @crossplatform - @parameterized({ - '': [[]], - 'lto': [['-flto']], - 'wasm64': [['-sMEMORY64']], - }) + @parameterized( + { + '': [[]], + 'lto': [['-flto']], + 'wasm64': [['-sMEMORY64']], + } + ) def test_print_search_dirs(self, args): output = self.run_process([EMCC, '-print-search-dirs'] + args, stdout=PIPE).stdout output2 = self.run_process([EMCC, '-print-search-dirs'] + args, stdout=PIPE).stdout @@ -834,11 +906,13 @@ def test_print_search_dirs(self, args): self.assertIn(expected, libpath) @crossplatform - @parameterized({ - '': [[]], - 'lto': [['-flto']], - 'wasm64': [['-sMEMORY64']], - }) + @parameterized( + { + '': [[]], + 'lto': [['-flto']], + 'wasm64': [['-sMEMORY64']], + } + ) def test_print_libgcc_file_name(self, args): output = self.run_process([EMCC, '-print-libgcc-file-name'] + args, stdout=PIPE).stdout output2 = self.run_process([EMCC, '--print-libgcc-file-name'] + args, stdout=PIPE).stdout @@ -860,11 +934,13 @@ def test_print_resource_dir(self): self.assertContained(llvm_root, resource_dir) @crossplatform - @parameterized({ - '': [[]], - 'lto': [['-flto']], - 'wasm64': [['-sMEMORY64']], - }) + @parameterized( + { + '': [[]], + 'lto': [['-flto']], + 'wasm64': [['-sMEMORY64']], + } + ) def test_print_file_name(self, args): # make sure the corresponding version of libc exists in the cache self.run_process([EMCC, test_file('hello_world.c'), '-O2'] + args) @@ -907,20 +983,26 @@ def test_emstrip(self): @is_slow_test @crossplatform - @parameterized({ - # ('directory to the test', 'output filename', ['extra args to pass to - # CMake']) Testing all combinations would be too much work and the test - # would take 10 minutes+ to finish (CMake feature detection is slow), so - # combine multiple features into one to try to cover as much as possible - # while still keeping this test in sensible time limit. - 'js': ('target_js', 'test_cmake.js', ['-DCMAKE_BUILD_TYPE=Debug']), - 'html': ('target_html', 'hello_world_gles.html', ['-DCMAKE_BUILD_TYPE=Release']), - 'library': ('target_library', 'libtest_cmake.a', ['-DCMAKE_BUILD_TYPE=MinSizeRel']), - 'static_cpp': ('target_library', 'libtest_cmake.a', ['-DCMAKE_BUILD_TYPE=RelWithDebInfo', '-DCPP_LIBRARY_TYPE=STATIC']), - 'whole_archive': ('whole_archive', 'whole.js', []), - 'stdproperty': ('stdproperty', 'helloworld.js', []), - 'post_build': ('post_build', 'hello.js', []), - }) + @parameterized( + { + # ('directory to the test', 'output filename', ['extra args to pass to + # CMake']) Testing all combinations would be too much work and the test + # would take 10 minutes+ to finish (CMake feature detection is slow), so + # combine multiple features into one to try to cover as much as possible + # while still keeping this test in sensible time limit. + 'js': ('target_js', 'test_cmake.js', ['-DCMAKE_BUILD_TYPE=Debug']), + 'html': ('target_html', 'hello_world_gles.html', ['-DCMAKE_BUILD_TYPE=Release']), + 'library': ('target_library', 'libtest_cmake.a', ['-DCMAKE_BUILD_TYPE=MinSizeRel']), + 'static_cpp': ( + 'target_library', + 'libtest_cmake.a', + ['-DCMAKE_BUILD_TYPE=RelWithDebInfo', '-DCPP_LIBRARY_TYPE=STATIC'], + ), + 'whole_archive': ('whole_archive', 'whole.js', []), + 'stdproperty': ('stdproperty', 'helloworld.js', []), + 'post_build': ('post_build', 'hello.js', []), + } + ) def test_cmake(self, test_dir, output_file, cmake_args): if test_dir == 'whole_archive' and 'EMTEST_SKIP_NEW_CMAKE' in os.environ: self.skipTest('EMTEST_SKIP_NEW_CMAKE set') @@ -932,11 +1014,11 @@ def test_cmake(self, test_dir, output_file, cmake_args): generators = ['Unix Makefiles', 'Ninja', 'Eclipse CDT4 - Ninja'] configurations = { - 'MinGW Makefiles' : {'build' : ['mingw32-make'] }, # noqa - 'NMake Makefiles' : {'build' : ['nmake', '/NOLOGO']}, # noqa - 'Unix Makefiles' : {'build' : ['make']}, # noqa - 'Ninja' : {'build' : ['ninja']}, # noqa - 'Eclipse CDT4 - Ninja': {'build' : ['ninja']}, # noqa + 'MinGW Makefiles': {'build': ['mingw32-make']}, # noqa + 'NMake Makefiles': {'build': ['nmake', '/NOLOGO']}, # noqa + 'Unix Makefiles': {'build': ['make']}, # noqa + 'Ninja': {'build': ['ninja']}, # noqa + 'Eclipse CDT4 - Ninja': {'build': ['ninja']}, # noqa } for generator in generators: conf = configurations[generator] @@ -958,14 +1040,21 @@ def test_cmake(self, test_dir, output_file, cmake_args): if test_dir == 'target_html': env['EMCC_SKIP_SANITY_CHECK'] = '1' print(str(cmd)) - self.run_process(cmd, env=env, stdout=None if EMTEST_BUILD_VERBOSE >= 2 else PIPE, stderr=None if EMTEST_BUILD_VERBOSE >= 1 else PIPE) + self.run_process( + cmd, + env=env, + stdout=None if EMTEST_BUILD_VERBOSE >= 2 else PIPE, + stderr=None if EMTEST_BUILD_VERBOSE >= 1 else PIPE, + ) # Build cmd = conf['build'] if EMTEST_BUILD_VERBOSE >= 3 and 'Ninja' not in generator: cmd += ['VERBOSE=1'] self.run_process(cmd, stdout=None if EMTEST_BUILD_VERBOSE >= 2 else PIPE) - self.assertExists(output_file, 'building a cmake-generated Makefile failed to produce an output file %s!' % output_file) + self.assertExists( + output_file, 'building a cmake-generated Makefile failed to produce an output file %s!' % output_file + ) # Run through node, if CMake produced a .js file. if output_file.endswith('.js'): @@ -982,10 +1071,14 @@ def test_cmake(self, test_dir, output_file, cmake_args): @no_windows('Skipped on Windows because CMake does not configure native Clang builds well on Windows.') def test_cmake_compile_features(self): os.mkdir('build_native') - cmd = ['cmake', - '-DCMAKE_C_COMPILER=' + CLANG_CC, '-DCMAKE_C_FLAGS=--target=' + clang_native.get_native_triple(), - '-DCMAKE_CXX_COMPILER=' + CLANG_CXX, '-DCMAKE_CXX_FLAGS=--target=' + clang_native.get_native_triple(), - test_file('cmake/stdproperty')] + cmd = [ + 'cmake', + '-DCMAKE_C_COMPILER=' + CLANG_CC, + '-DCMAKE_C_FLAGS=--target=' + clang_native.get_native_triple(), + '-DCMAKE_CXX_COMPILER=' + CLANG_CXX, + '-DCMAKE_CXX_FLAGS=--target=' + clang_native.get_native_triple(), + test_file('cmake/stdproperty'), + ] print(str(cmd)) native_features = self.run_process(cmd, stdout=PIPE, cwd='build_native').stdout @@ -1011,10 +1104,12 @@ def test_cmake_explicit_generator(self): # Tests that it's possible to pass C++11 or GNU++11 build modes to CMake by building code that # needs C++11 (embind) @requires_ninja - @parameterized({ - '': [[]], - '_no_gnu': [['-DNO_GNU_EXTENSIONS=1']], - }) + @parameterized( + { + '': [[]], + '_no_gnu': [['-DNO_GNU_EXTENSIONS=1']], + } + ) def test_cmake_with_embind_cpp11_mode(self, args): # Use ninja generator here since we assume its always installed on our build/test machines. configure = [EMCMAKE, 'cmake', '-GNinja', test_file('cmake/cmake_with_emval')] + args @@ -1031,13 +1126,17 @@ def test_cmake_with_embind_cpp11_mode(self, args): # Tests that the Emscripten CMake toolchain option def test_cmake_bitcode_static_libraries(self): # Test that this option produces an error - err = self.expect_fail([EMCMAKE, 'cmake', test_file('cmake/static_lib'), '-DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=ON']) + err = self.expect_fail( + [EMCMAKE, 'cmake', test_file('cmake/static_lib'), '-DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=ON'] + ) self.assertContained('EMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES is not compatible with the', err) - @parameterized({ - '': ['0'], - '_suffix': ['1'], - }) + @parameterized( + { + '': ['0'], + '_suffix': ['1'], + } + ) def test_cmake_static_lib(self, custom): # Test that one is able to use custom suffixes for static libraries. # (sometimes projects want to emulate stuff, and do weird things like files @@ -1066,8 +1165,7 @@ def test_cmake_emscripten_system_processor(self): self.assertContained('CMAKE_SYSTEM_PROCESSOR is x86', out) # It can be overridden by setting EMSCRIPTEN_SYSTEM_PROCESSOR. - out = self.run_process( - [EMCMAKE, 'cmake', cmake_dir, '-DEMSCRIPTEN_SYSTEM_PROCESSOR=arm'], stdout=PIPE).stdout + out = self.run_process([EMCMAKE, 'cmake', cmake_dir, '-DEMSCRIPTEN_SYSTEM_PROCESSOR=arm'], stdout=PIPE).stdout self.assertContained('CMAKE_SYSTEM_PROCESSOR is arm', out) @requires_network @@ -1120,14 +1218,16 @@ def test_pkg_config_packages(self): ('sdl', '1.2.15'), ] for package, version in packages: - out = self.run_process([emmake, 'pkg-config', '--modversion', package], stdout=PIPE).stdout - self.assertContained(version, out) - - @parameterized({ - '': [None], - 'wasm64': ['-sMEMORY64'], - 'pthreads': ['-pthread'], - }) + out = self.run_process([emmake, 'pkg-config', '--modversion', package], stdout=PIPE).stdout + self.assertContained(version, out) + + @parameterized( + { + '': [None], + 'wasm64': ['-sMEMORY64'], + 'pthreads': ['-pthread'], + } + ) def test_cmake_check_type_size(self, cflag): if cflag == '-sMEMORY64': self.require_wasm64() @@ -1216,7 +1316,7 @@ def test_odd_suffixes(self): shutil.copy(test_file('hello_world.c'), 'test.' + suffix) self.do_runf('test.' + suffix, 'hello, world!') - for suffix in ('lo'): + for suffix in 'lo': self.clear() print(suffix) self.run_process([EMCC, test_file('hello_world.c'), '-shared', '-o', 'binary.' + suffix]) @@ -1227,7 +1327,9 @@ def test_preprocessed_input(self): # .i and .ii files are assumed to be the output the pre-processor so clang doesn't add include # paths. This means we can only compile and run things that don't contain includes. for suffix in ('.i', '.ii'): - create_file('simple' + suffix, ''' + create_file( + 'simple' + suffix, + ''' #ifdef __cplusplus extern "C" { #endif @@ -1236,7 +1338,8 @@ def test_preprocessed_input(self): } #endif int main() { puts("hello"); } - ''') + ''', + ) self.do_runf('simple' + suffix, 'hello') create_file('with_include' + suffix, '#include \nint main() { puts("hello"); }') @@ -1245,23 +1348,32 @@ def test_preprocessed_input(self): def test_wl_linkflags(self): # Test path -L and -l via -Wl, arguments and -Wl, response files - create_file('main.c', ''' + create_file( + 'main.c', + ''' void printey(); int main() { printey(); return 0; } - ''') - create_file('libfile.c', ''' + ''', + ) + create_file( + 'libfile.c', + ''' #include void printey() { printf("hello from lib\\n"); } - ''') - create_file('linkflags.txt', ''' + ''', + ) + create_file( + 'linkflags.txt', + ''' -L. -lfoo - ''') + ''', + ) self.run_process([EMCC, '-o', 'libfile.o', '-c', 'libfile.c']) self.run_process([EMAR, 'cr', 'libfoo.a', 'libfile.o']) self.run_process([EMCC, 'main.c', '-L.', '-lfoo']) @@ -1281,20 +1393,22 @@ def test_side_module_global_base(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '-Werror', '-sGLOBAL_BASE=1024', '-sSIDE_MODULE']) self.assertContained('emcc: error: GLOBAL_BASE is not compatible with SIDE_MODULE', err) - @parameterized({ - # In a simple -O0 build we do not set --low-memory-unused (as the stack is - # first, which is nice for debugging but bad for code size (larger globals) - # and bad for the low-memory-unused trick. - '': ([], False), - # When we optimize, we do. - 'O2': (['-O2'], True), - # But a low global base prevents it. - 'O2_GB_512': (['-O2', '-sGLOBAL_BASE=512'], False), - # A large-enough global base allows it. - 'O2_GB_1024': (['-O2', '-sGLOBAL_BASE=1024'], True), - # Forcing the stack to be first in the linker prevents it. - 'linker_flag': (['-O2', '-Wl,--stack-first'], False), - }) + @parameterized( + { + # In a simple -O0 build we do not set --low-memory-unused (as the stack is + # first, which is nice for debugging but bad for code size (larger globals) + # and bad for the low-memory-unused trick. + '': ([], False), + # When we optimize, we do. + 'O2': (['-O2'], True), + # But a low global base prevents it. + 'O2_GB_512': (['-O2', '-sGLOBAL_BASE=512'], False), + # A large-enough global base allows it. + 'O2_GB_1024': (['-O2', '-sGLOBAL_BASE=1024'], True), + # Forcing the stack to be first in the linker prevents it. + 'linker_flag': (['-O2', '-Wl,--stack-first'], False), + } + ) def test_binaryen_low_memory_unused(self, args, low_memory_unused): cmd = [EMCC, test_file('hello_world.c'), '-v'] + args err = self.run_process(cmd, stdout=PIPE, stderr=PIPE).stderr @@ -1302,19 +1416,25 @@ def test_binaryen_low_memory_unused(self, args, low_memory_unused): def test_l_link(self): # Linking with -lLIBNAME and -L/DIRNAME should work, also should work with spaces - create_file('main.c', ''' + create_file( + 'main.c', + ''' extern void printey(); int main() { printey(); return 0; } - ''') - create_file('libfile.c', ''' + ''', + ) + create_file( + 'libfile.c', + ''' #include void printey() { printf("hello from lib\\n"); } - ''') + ''', + ) ensure_dir('libdir') libfile = Path('libdir/libfile.so') @@ -1343,17 +1463,25 @@ def build(path, args): self.assertNotExists('a.exe') def test_commons_link(self): - create_file('a.h', r''' + create_file( + 'a.h', + r''' #if !defined(A_H) #define A_H extern int foo[8]; #endif - ''') - create_file('a.c', r''' + ''', + ) + create_file( + 'a.c', + r''' #include "a.h" int foo[8]; - ''') - create_file('main.c', r''' + ''', + ) + create_file( + 'main.c', + r''' #include #include "a.h" @@ -1361,7 +1489,8 @@ def test_commons_link(self): printf("|%d|\n", foo[0]); return 0; } - ''') + ''', + ) self.run_process([EMCC, '-o', 'a.o', '-c', 'a.c']) self.run_process([EMAR, 'rv', 'library.a', 'a.o']) @@ -1369,10 +1498,12 @@ def test_commons_link(self): self.run_process([EMCC, '-o', 'a.js', 'main.o', 'library.a']) self.assertContained('|0|', self.run_js('a.js')) - @parameterized({ - 'expand_symlinks': [[]], - 'no_canonical_prefixes': [['-no-canonical-prefixes']], - }) + @parameterized( + { + 'expand_symlinks': [[]], + 'no_canonical_prefixes': [['-no-canonical-prefixes']], + } + ) @no_windows('Windows does not support symlinks') def test_symlink_points_to_bad_suffix(self, flags): """Tests compiling a symlink where foobar.c points to foobar.xxx. @@ -1384,25 +1515,29 @@ def test_symlink_points_to_bad_suffix(self, flags): @no_windows('Windows does not support symlinks') def test_symlink_has_bad_suffix(self): - """Tests that compiling foobar.xxx fails even if it points to foobar.c. - """ + """Tests that compiling foobar.xxx fails even if it points to foobar.c.""" create_file('foobar.c', 'int main(){ return 0; }') os.symlink('foobar.c', 'foobar.xxx') err = self.expect_fail([EMCC, 'foobar.xxx', '-o', 'foobar.js']) - self.assertContained(['unknown file type: foobar.xxx', "archive member 'native.o' is neither Wasm object file nor LLVM bitcode"], err) + self.assertContained( + ['unknown file type: foobar.xxx', "archive member 'native.o' is neither Wasm object file nor LLVM bitcode"], err + ) def test_multiply_defined_libsymbols(self): create_file('libA.c', 'int mult() { return 1; }') create_file('a2.c', 'void x() {}') create_file('b2.c', 'void y() {}') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int mult(); int main() { printf("result: %d\n", mult()); return 0; } - ''') + ''', + ) self.emcc_args.remove('-Werror') self.emcc('libA.c', ['-shared'], output_filename='libA.so') @@ -1418,7 +1553,9 @@ def test_multiply_defined_libsymbols_2(self): create_file('a.c', "int x() { return 55; }") create_file('b.c', "int y() { return 2; }") create_file('c.c', "int z() { return 5; }") - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int x(); int y(); @@ -1427,12 +1564,13 @@ def test_multiply_defined_libsymbols_2(self): printf("result: %d\n", x() + y() + z()); return 0; } - ''') + ''', + ) - self.emcc('a.c', ['-c']) # a.o - self.emcc('b.c', ['-c']) # b.o - self.emcc('c.c', ['-c']) # c.o - building.emar('cr', 'libLIB.a', ['a.o', 'b.o']) # libLIB.a with a and b + self.emcc('a.c', ['-c']) # a.o + self.emcc('b.c', ['-c']) # b.o + self.emcc('c.c', ['-c']) # c.o + building.emar('cr', 'libLIB.a', ['a.o', 'b.o']) # libLIB.a with a and b # a is in the lib AND in an .o, so should be ignored in the lib. We do still need b from the lib though self.emcc('main.c', ['a.o', 'c.o', '-L.', '-lLIB']) @@ -1442,18 +1580,21 @@ def test_multiply_defined_libsymbols_2(self): def test_link_group(self): create_file('lib.c', 'int x() { return 42; }') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int x(); int main() { printf("result: %d\n", x()); return 0; } - ''') + ''', + ) - self.emcc('lib.c', ['-c']) # lib.o + self.emcc('lib.c', ['-c']) # lib.o lib_name = 'libLIB.a' - building.emar('cr', lib_name, ['lib.o']) # libLIB.a with lib.o + building.emar('cr', lib_name, ['lib.o']) # libLIB.a with lib.o def test(compiler, main_name, lib_args, err_expected): print(err_expected) @@ -1471,7 +1612,9 @@ def test(compiler, main_name, lib_args, err_expected): print('embind test with groups') - create_file('main.cpp', r''' + create_file( + 'main.cpp', + r''' #include #include using namespace emscripten; @@ -1482,7 +1625,8 @@ def test(compiler, main_name, lib_args, err_expected): printf("result: %d\n", y); return 0; } - ''') + ''', + ) test(EMXX, 'main.cpp', ['-Wl,--start-group', lib_name, '-Wl,--end-group', '-lembind'], None) def test_whole_archive(self): @@ -1505,32 +1649,44 @@ def test_whole_archive(self): def test_whole_archive_48156(self): # Regression test for http://llvm.org/PR48156 # TODO: distill this test further and move to lld - self.run_process([EMXX, '-c', '-o', 'foo.o', '-O1', - test_file('test_whole_archive_foo.cpp')]) - self.run_process([EMXX, '-c', '-o', 'main.o', '-O1', - test_file('test_whole_archive_main.cpp')]) + self.run_process([EMXX, '-c', '-o', 'foo.o', '-O1', test_file('test_whole_archive_foo.cpp')]) + self.run_process([EMXX, '-c', '-o', 'main.o', '-O1', test_file('test_whole_archive_main.cpp')]) self.run_process([EMAR, 'rc', 'libfoo.a', 'foo.o']) self.run_process([EMAR, 'rc', 'libmain.a', 'main.o']) - self.run_process([ - EMXX, test_file('test_whole_archive_init.cpp'), - '-O1', 'libfoo.a', '-Wl,--whole-archive', 'libmain.a', '-Wl,--no-whole-archive']) + self.run_process( + [ + EMXX, + test_file('test_whole_archive_init.cpp'), + '-O1', + 'libfoo.a', + '-Wl,--whole-archive', + 'libmain.a', + '-Wl,--no-whole-archive', + ] + ) self.assertContained('Result: 11', self.run_js('a.out.js')) def test_link_group_bitcode(self): - create_file('1.c', r''' + create_file( + '1.c', + r''' int f(void); int main() { f(); return 0; } -''') - create_file('2.c', r''' +''', + ) + create_file( + '2.c', + r''' #include int f() { printf("Hello\n"); return 0; } -''') +''', + ) self.run_process([EMCC, '-flto', '-o', '1.o', '-c', '1.c']) self.run_process([EMCC, '-flto', '-o', '2.o', '-c', '2.c']) @@ -1544,14 +1700,17 @@ def test_link_group_bitcode(self): # and the .so files are really object files. def test_redundant_link(self): create_file('libA.c', 'int mult() { return 1; }') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int mult(); int main() { printf("result: %d\n", mult()); return 0; } - ''') + ''', + ) self.emcc_args.remove('-Werror') self.emcc('libA.c', ['-shared'], output_filename='libA.so') @@ -1566,11 +1725,12 @@ def test_dot_a_all_contents_invalid(self): # built by mistake create_file('native.c', 'int native() { return 5; }') create_file('main.c', 'extern int native(); int main() { return native(); }') - self.run_process([CLANG_CC, 'native.c', '-c', '-o', 'native.o'] + - clang_native.get_clang_native_args()) + self.run_process([CLANG_CC, 'native.c', '-c', '-o', 'native.o'] + clang_native.get_clang_native_args()) self.run_process([EMAR, 'crs', 'libfoo.a', 'native.o']) stderr = self.expect_fail([EMCC, 'main.c', 'libfoo.a']) - self.assertContained(['unknown file type', "libfoo.a: archive member 'native.o' is neither Wasm object file nor LLVM bitcode"], stderr) + self.assertContained( + ['unknown file type', "libfoo.a: archive member 'native.o' is neither Wasm object file nor LLVM bitcode"], stderr + ) def test_export_all(self): lib = r''' @@ -1580,12 +1740,15 @@ def test_export_all(self): ''' create_file('lib.c', lib) - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.onRuntimeInitialized = () => { _libf1(); _libf2(); }; - ''') + ''', + ) # Explicitly test with -Oz to ensure libc_optz is included alongside # libc when `--whole-archive` is used. @@ -1593,16 +1756,22 @@ def test_export_all(self): self.assertContained('libf1\nlibf2\n', self.run_js('a.out.js')) def test_export_keepalive(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include EMSCRIPTEN_KEEPALIVE int libf1() { return 42; } - ''') + ''', + ) - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.onRuntimeInitialized = () => { out(Module._libf1 ? Module._libf1() : 'unexported'); }; - ''') + ''', + ) # By default, all kept alive functions should be exported. self.do_runf('main.c', '42\n', emcc_args=['--pre-js', 'pre.js']) @@ -1614,10 +1783,13 @@ def test_minimal_modularize_export_keepalive(self): self.set_setting('MODULARIZE') self.set_setting('MINIMAL_RUNTIME') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include EMSCRIPTEN_KEEPALIVE int libf1() { return 42; } - ''') + ''', + ) # With MINIMAL_RUNTIME, the module instantiation function isn't exported neither as a UMD nor as # an ES6 module. @@ -1641,18 +1813,25 @@ def test_minimal_runtime_export_all_modularize(self): In addition, it ensures that EXPORT_ALL is honored while using MINIMAL_RUNTIME. """ - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include EMSCRIPTEN_KEEPALIVE void libf1() { printf("libf1\n"); } EMSCRIPTEN_KEEPALIVE void libf2() { printf("libf2\n"); } - ''') + ''', + ) - self.emcc('main.c', ['-sMODULARIZE=1', '-sMINIMAL_RUNTIME=2', '-sEXPORT_ALL', '-sEXPORT_ES6'], output_filename='test.mjs') + self.emcc( + 'main.c', ['-sMODULARIZE=1', '-sMINIMAL_RUNTIME=2', '-sEXPORT_ALL', '-sEXPORT_ES6'], output_filename='test.mjs' + ) # We must expose __dirname and require globally because emscripten # uses those under the hood. - create_file('main.mjs', ''' + create_file( + 'main.mjs', + ''' import { dirname } from 'path'; import { createRequire } from 'module'; import { fileURLToPath } from 'url'; @@ -1668,7 +1847,8 @@ def test_minimal_runtime_export_all_modularize(self): mod._libf2(); } main(); - ''') + ''', + ) self.assertContained('libf1\nlibf2\n', self.run_js('main.mjs')) def test_export_all_and_exported_functions(self): @@ -1682,27 +1862,34 @@ def test_export_all_and_exported_functions(self): void libfunc2() { puts("libfunc2\n"); } ''' create_file('lib.c', lib) - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.onRuntimeInitialized = () => { _libfunc(); _libfunc2(); }; - ''') + ''', + ) # libfunc2 should not be linked by default, even with EXPORT_ALL self.emcc('lib.c', ['-sEXPORT_ALL', '--pre-js', 'pre.js'], output_filename='a.out.js') err = self.run_js('a.out.js', assert_returncode=NON_ZERO) self.assertContained('_libfunc2 is not defined', err) - self.emcc('lib.c', ['-sEXPORTED_FUNCTIONS=_libfunc2', '-sEXPORT_ALL', '--pre-js', 'pre.js'], output_filename='a.out.js') + self.emcc( + 'lib.c', ['-sEXPORTED_FUNCTIONS=_libfunc2', '-sEXPORT_ALL', '--pre-js', 'pre.js'], output_filename='a.out.js' + ) self.assertContained('libfunc\n', self.run_js('a.out.js')) @also_with_wasmfs @crossplatform - @parameterized({ - '': ([],), - 'closure': (['-O2', '--closure=1'],), - }) + @parameterized( + { + '': ([],), + 'closure': (['-O2', '--closure=1'],), + } + ) def test_stdin(self, args): create_file('in.txt', 'abcdef\nghijkl\n') self.set_setting('ENVIRONMENT', 'node,shell') @@ -1718,24 +1905,29 @@ def test_stdin(self, args): print(cmd, file=sys.stderr) if WINDOWS: os.system(f'type "in.txt" | {cmd} >out.txt') - else: # posix + else: # posix os.system(f'cat in.txt | {cmd} > out.txt') self.assertContained('abcdef\nghijkl\neof', read_file('out.txt')) @crossplatform def test_module_stdin(self): self.set_setting('FORCE_FILESYSTEM') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' const data = 'hello, world!\\n'.split('').map(c => c.charCodeAt(0)); Module['stdin'] = () => data.shift() || null; -''') +''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('module/test_stdin.c', 'hello, world!') @crossplatform def test_module_stdout_stderr(self): self.set_setting('FORCE_FILESYSTEM') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' let stdout = []; let stderr = []; @@ -1747,14 +1939,17 @@ def test_module_stdout_stderr(self): assert(UTF8ArrayToString(stdout).startsWith('hello, world!'), 'stdout should start with the famous greeting. \\n' + 'stdout: \\n' + stdout); } -''') +''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('hello_world.c') @crossplatform def test_module_print_printerr(self): self.set_setting('FORCE_FILESYSTEM') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' let stdout = ''; let stderr = ''; @@ -1766,12 +1961,15 @@ def test_module_print_printerr(self): assert(stdout.startsWith('hello, world!'), 'stdout should start with the famous greeting. \\n' + 'stdout: \\n' + stdout); } -''') +''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('hello_world.c') def test_ungetc_fscanf(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int main(int argc, char const *argv[]) { @@ -1788,7 +1986,8 @@ def test_ungetc_fscanf(self): printf("%s\n", str); return 0; } - ''') + ''', + ) create_file('my_test.input', 'abc') self.emcc('main.c', ['--embed-file', 'my_test.input'], output_filename='a.out.js') self.assertContained('zyx', self.run_process(config.JS_ENGINES[0] + ['a.out.js'], stdout=PIPE, stderr=PIPE).stdout) @@ -1796,15 +1995,17 @@ def test_ungetc_fscanf(self): def test_abspaths(self): # Includes with absolute paths are generally dangerous, things like -I/usr/.. will get to system # local headers, not our portable ones. - for args, expected in [(['-I/usr/something', '-Wwarn-absolute-paths'], True), - (['-L/usr/something', '-Wwarn-absolute-paths'], True), - (['-I/usr/something'], False), - (['-L/usr/something'], False), - (['-I/usr/something', '-Wno-warn-absolute-paths'], False), - (['-L/usr/something', '-Wno-warn-absolute-paths'], False), - (['-Isubdir/something', '-Wwarn-absolute-paths'], False), - (['-Lsubdir/something', '-Wwarn-absolute-paths'], False), - ([], False)]: + for args, expected in [ + (['-I/usr/something', '-Wwarn-absolute-paths'], True), + (['-L/usr/something', '-Wwarn-absolute-paths'], True), + (['-I/usr/something'], False), + (['-L/usr/something'], False), + (['-I/usr/something', '-Wno-warn-absolute-paths'], False), + (['-L/usr/something', '-Wno-warn-absolute-paths'], False), + (['-Isubdir/something', '-Wwarn-absolute-paths'], False), + (['-Lsubdir/something', '-Wwarn-absolute-paths'], False), + ([], False), + ]: print(args, expected) proc = self.run_process([EMCC, test_file('hello_world.c')] + args, stderr=PIPE) WARNING = 'encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' @@ -1815,17 +2016,23 @@ def test_identical_basenames(self): # causing multiply defined symbol errors ensure_dir('foo') ensure_dir('bar') - create_file('foo/main.c', ''' + create_file( + 'foo/main.c', + ''' extern void printey(); int main() { printey(); return 0; } - ''') - create_file('bar/main.c', ''' + ''', + ) + create_file( + 'bar/main.c', + ''' #include void printey() { printf("hello there\\n"); } - ''') + ''', + ) self.run_process([EMCC, Path('foo/main.c'), Path('bar/main.c')]) self.assertContained('hello there', self.run_js('a.out.js')) @@ -1839,19 +2046,25 @@ def test_identical_basenames(self): def test_main_a(self): # if main() is in a .a, we need to pull in that .a - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include extern int f(); int main() { printf("result: %d.\n", f()); return 0; } - ''') + ''', + ) - create_file('other.c', r''' + create_file( + 'other.c', + r''' #include int f() { return 12346; } - ''') + ''', + ) self.run_process([EMCC, '-c', 'main.c']) self.run_process([EMCC, '-c', 'other.c']) @@ -1863,55 +2076,70 @@ def test_main_a(self): self.assertContained('result: 12346.', self.run_js('a.out.js')) def test_multiple_archives_duplicate_basenames(self): - create_file('common.c', r''' + create_file( + 'common.c', + r''' #include void a(void) { printf("a\n"); } - ''') + ''', + ) self.run_process([EMCC, 'common.c', '-c', '-o', 'common.o']) delete_file('liba.a') self.run_process([EMAR, 'rc', 'liba.a', 'common.o']) - create_file('common.c', r''' + create_file( + 'common.c', + r''' #include void b(void) { printf("b\n"); } - ''') + ''', + ) self.run_process([EMCC, 'common.c', '-c', '-o', 'common.o']) delete_file('libb.a') self.run_process([EMAR, 'rc', 'libb.a', 'common.o']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' void a(void); void b(void); int main() { a(); b(); } - ''') + ''', + ) self.run_process([EMCC, 'main.c', '-L.', '-la', '-lb']) self.assertContained('a\nb\n', self.run_js('a.out.js')) def test_archive_duplicate_basenames(self): ensure_dir('a') - create_file('a/common.c', r''' + create_file( + 'a/common.c', + r''' #include void a(void) { printf("a\n"); } - ''') + ''', + ) self.run_process([EMCC, Path('a/common.c'), '-c', '-o', Path('a/common.o')]) ensure_dir('b') - create_file('b/common.c', r''' + create_file( + 'b/common.c', + r''' #include void b(void) { printf("b...\n"); } - ''') + ''', + ) self.run_process([EMCC, Path('b/common.c'), '-c', '-o', Path('b/common.o')]) delete_file('liba.a') @@ -1924,14 +2152,17 @@ def test_archive_duplicate_basenames(self): # should not have huge hash names self.assertLess(len(line), 20, line) - create_file('main.c', r''' + create_file( + 'main.c', + r''' void a(void); void b(void); int main() { a(); b(); } - ''') + ''', + ) err = self.run_process([EMCC, 'main.c', '-L.', '-la'], stderr=PIPE).stderr self.assertNotIn('archive file contains duplicate entries', err) self.assertContained('a\nb...\n', self.run_js('a.out.js')) @@ -1952,20 +2183,26 @@ def test_export_from_archive(self): export_name = 'this_is_an_entry_point' full_export_name = '_this_is_an_entry_point' - create_file('export.c', r''' + create_file( + 'export.c', + r''' #include void this_is_an_entry_point(void) { printf("Hello, world!\n"); } - ''') + ''', + ) self.run_process([EMCC, 'export.c', '-c', '-o', 'export.o']) self.run_process([EMAR, 'rc', 'libexport.a', 'export.o']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' int main() { return 0; } - ''') + ''', + ) # Sanity check: the symbol should not be linked in if not requested. self.run_process([EMCC, 'main.c', '-L.', '-lexport']) @@ -1975,18 +2212,22 @@ def test_export_from_archive(self): self.run_process([EMCC, 'main.c', '-L.', '-lexport', '-sEXPORTED_FUNCTIONS=%s' % full_export_name]) self.assertTrue(self.is_exported_in_wasm(export_name, 'a.out.wasm')) - @parameterized({ - 'embed': (['--embed-file', 'somefile.txt'],), - 'embed_twice': (['--embed-file', 'somefile.txt', '--embed-file', 'somefile.txt'],), - 'preload': (['--preload-file', 'somefile.txt', '-sSTRICT'],), - 'preload_closure': (['--preload-file', 'somefile.txt', '-O2', '--closure=1'],), - 'preload_and_embed': (['--preload-file', 'somefile.txt', '--embed-file', 'hello.txt'],) - }) + @parameterized( + { + 'embed': (['--embed-file', 'somefile.txt'],), + 'embed_twice': (['--embed-file', 'somefile.txt', '--embed-file', 'somefile.txt'],), + 'preload': (['--preload-file', 'somefile.txt', '-sSTRICT'],), + 'preload_closure': (['--preload-file', 'somefile.txt', '-O2', '--closure=1'],), + 'preload_and_embed': (['--preload-file', 'somefile.txt', '--embed-file', 'hello.txt'],), + } + ) @requires_node def test_include_file(self, args): create_file('somefile.txt', 'hello from a file with lots of data and stuff in it thank you very much') create_file('hello.txt', 'hello world') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main() { @@ -2000,17 +2241,20 @@ def test_include_file(self, args): printf("|%s|\n", buf); return 0; } - ''') + ''', + ) self.run_process([EMCC, 'main.c'] + args) # run in node.js to ensure we verify that file preloading works there result = self.run_js('a.out.js') self.assertContained('|hello from a file wi|', result) - @parameterized({ - '': ([],), - 'wasmfs': (['-sWASMFS'],), - }) + @parameterized( + { + '': ([],), + 'wasmfs': (['-sWASMFS'],), + } + ) @crossplatform def test_embed_file_dup(self, args): ensure_dir('tst/test1') @@ -2019,7 +2263,9 @@ def test_embed_file_dup(self, args): create_file('tst/aa.txt', 'frist') create_file('tst/test1/aa.txt', 'sacond') create_file('tst/test2/aa.txt', 'thard') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include void print_file(const char *name) { @@ -2037,10 +2283,10 @@ def test_embed_file_dup(self, args): print_file("tst/test2/aa.txt"); return 0; } - ''') + ''', + ) - self.do_runf('main.c', '|frist|\n|sacond|\n|thard|\n', - emcc_args=['--embed-file', 'tst'] + args) + self.do_runf('main.c', '|frist|\n|sacond|\n|thard|\n', emcc_args=['--embed-file', 'tst'] + args) def test_exclude_file(self): ensure_dir('tst/abc.exe') @@ -2050,7 +2296,9 @@ def test_exclude_file(self): create_file('tst/hello.txt', 'world') create_file('tst/abc.exe/foo', 'emscripten') create_file('tst/abc.txt/bar', '!!!') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int main() { if(fopen("tst/hello.exe", "rb")) printf("Failed\n"); @@ -2060,7 +2308,8 @@ def test_exclude_file(self): return 0; } - ''') + ''', + ) self.run_process([EMCC, 'main.c', '--embed-file', 'tst', '--exclude-file', '*.exe']) self.assertEqual(self.run_js('a.out.js').strip(), '') @@ -2073,23 +2322,24 @@ def test_dylink_exceptions_and_assertions(self): # "function in Table but not functionsInTableMap" when using ASSERTIONS=2 # A side module that uses the STL enables exceptions. - create_file('side.cpp', r''' + create_file( + 'side.cpp', + r''' #include std::vector v; std::vector side(int n) { for (int i=0; i #include std::vector side(int n); @@ -2099,7 +2349,8 @@ def test_dylink_exceptions_and_assertions(self): printf("\n"); return 0; } - ''') + ''', + ) self.do_runf( 'main.cpp', @@ -2109,7 +2360,8 @@ def test_dylink_exceptions_and_assertions(self): '-sDISABLE_EXCEPTION_CATCHING=0', '-sASSERTIONS=2', 'side.wasm', - ]) + ], + ) def test_multidynamic_link(self): # Linking the same dynamic library in statically will error, normally, since we statically link @@ -2121,7 +2373,9 @@ def test(link_flags, lib_suffix): self.clear() ensure_dir('libdir') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include extern void printey(); extern void printother(); @@ -2134,16 +2388,22 @@ def test(link_flags, lib_suffix): printf("*\n"); return 0; } - ''') + ''', + ) - create_file('libdir/libfile.c', ''' + create_file( + 'libdir/libfile.c', + ''' #include void printey() { printf("hello from lib"); } - ''') + ''', + ) - create_file('libdir/libother.c', ''' + create_file( + 'libdir/libother.c', + ''' #include extern void printey(); void printother() { @@ -2151,12 +2411,15 @@ def test(link_flags, lib_suffix): printey(); printf("|"); } - ''') + ''', + ) # Build libfile normally into an .so self.run_process([EMCC, Path('libdir/libfile.c'), '-shared', '-o', Path('libdir/libfile.so' + lib_suffix)]) # Build libother and dynamically link it to libfile - self.run_process([EMCC, '-Llibdir', Path('libdir/libother.c')] + link_flags + ['-shared', '-o', Path('libdir/libother.so')]) + self.run_process( + [EMCC, '-Llibdir', Path('libdir/libother.c')] + link_flags + ['-shared', '-o', Path('libdir/libother.so')] + ) # Build the main file, linking in both the libs self.run_process([EMCC, '-Llibdir', os.path.join('main.c')] + link_flags + ['-lother', '-c']) print('...') @@ -2166,8 +2429,8 @@ def test(link_flags, lib_suffix): self.assertContained('*hello from lib\n|hello from lib|\n*\n', self.run_js('a.out.js')) - test(['-lfile'], '') # -l, auto detection from library path - test([self.in_dir('libdir/libfile.so.3.1.4.1.5.9')], '.3.1.4.1.5.9') # handle libX.so.1.2.3 as well + test(['-lfile'], '') # -l, auto detection from library path + test([self.in_dir('libdir/libfile.so.3.1.4.1.5.9')], '.3.1.4.1.5.9') # handle libX.so.1.2.3 as well @node_pthreads def test_dylink_pthread_static_data(self): @@ -2178,7 +2441,9 @@ def test_dylink_pthread_static_data(self): # the memory is zero-initialized only once (and not once per thread). # * The global object must have a constructor to make sure that it is # constructed only once (and not once per thread). - create_file('side.cpp', r''' + create_file( + 'side.cpp', + r''' struct Data { Data() : value(42) {} int value; @@ -2186,15 +2451,13 @@ def test_dylink_pthread_static_data(self): int * get_address() { return &data.value; } - ''') - self.run_process([ - EMCC, - '-o', 'side.wasm', - 'side.cpp', - '-pthread', '-Wno-experimental', - '-sSIDE_MODULE']) + ''', + ) + self.run_process([EMCC, '-o', 'side.wasm', 'side.cpp', '-pthread', '-Wno-experimental', '-sSIDE_MODULE']) - create_file('main.cpp', r''' + create_file( + 'main.cpp', + r''' #include #include int * get_address(); @@ -2205,18 +2468,21 @@ def test_dylink_pthread_static_data(self): }).join(); return 0; } - ''') + ''', + ) self.do_runf( 'main.cpp', '123', emcc_args=[ - '-pthread', '-Wno-experimental', + '-pthread', + '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-sMAIN_MODULE=2', 'side.wasm', - ]) + ], + ) def test_dylink_pthread_warning(self): err = self.expect_fail([EMCC, '-Werror', '-sMAIN_MODULE', '-pthread', test_file('hello_world.c')]) @@ -2238,14 +2504,18 @@ def test_dylink_pthread_bigint_em_js(self): self.do_runf('core/test_em_js.cpp') @node_pthreads - @parameterized({ - '': (False,), - 'flipped': (True,), - }) + @parameterized( + { + '': (False,), + 'flipped': (True,), + } + ) def test_dylink_pthread_comdat(self, flipped): # Test that the comdat info for `Foo`, which is defined in the side module, # is visible to the main module. - create_file('foo.h', r''' + create_file( + 'foo.h', + r''' struct Foo { Foo() { method(); @@ -2254,8 +2524,11 @@ def test_dylink_pthread_comdat(self, flipped): // class to only be defined in the side module. virtual void method() const; }; - ''') - create_file('main.cpp', r''' + ''', + ) + create_file( + 'main.cpp', + r''' #include "foo.h" #include #include @@ -2272,8 +2545,11 @@ def test_dylink_pthread_comdat(self, flipped): Foo().method(); return 0; } - ''') - create_file('side.cpp', r''' + ''', + ) + create_file( + 'side.cpp', + r''' #include "foo.h" #include #include @@ -2281,7 +2557,8 @@ def test_dylink_pthread_comdat(self, flipped): void Foo::method() const { emscripten_outf("side: Foo typeid: %s", typeid(Foo).name()); } - ''') + ''', + ) if flipped: side = 'main.cpp' main = 'side.cpp' @@ -2289,31 +2566,31 @@ def test_dylink_pthread_comdat(self, flipped): self.skipTest('https://reviews.llvm.org/D128515') side = 'side.cpp' main = 'main.cpp' - self.run_process([ - EMCC, - '-o', 'libside.wasm', - side, - '-pthread', '-Wno-experimental', - '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'libside.wasm', side, '-pthread', '-Wno-experimental', '-sSIDE_MODULE']) self.do_runf( main, 'main: Foo typeid: 3Foo\nside: Foo typeid: 3Foo\n', emcc_args=[ - '-pthread', '-Wno-experimental', + '-pthread', + '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-sMAIN_MODULE=2', 'libside.wasm', - ]) + ], + ) def test_dylink_no_autoload(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int sidey(); int main() { printf("sidey: %d\n", sidey()); return 0; - }''') + }''', + ) create_file('side.c', 'int sidey() { return 42; }') self.run_process([EMCC, '-sSIDE_MODULE', 'side.c', '-o', 'libside.wasm']) @@ -2329,15 +2606,20 @@ def test_dylink_no_autoload(self): self.assertContained("external symbol 'sidey' is missing. perhaps a side module was not linked in?", output) # Now with NO_AUTOLOAD_DYLIBS, but with manual loading of libside.wasm using loadDynamicLibrary - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.preRun = () => loadDynamicLibrary('libside.wasm'); - ''') + ''', + ) self.run_process([EMCC, '-sMAIN_MODULE=2', 'main.c', 'libside.wasm', '-sNO_AUTOLOAD_DYLIBS', '--pre-js=pre.js']) output = self.run_js('a.out.js') self.assertContained('sidey: 42\n', output) def test_dylink_dependencies(self): - create_file('side1.c', r''' + create_file( + 'side1.c', + r''' #include #include @@ -2347,30 +2629,39 @@ def test_dylink_dependencies(self): printf("side1\n"); side2(); } - ''') - create_file('side2.c', r''' + ''', + ) + create_file( + 'side2.c', + r''' #include #include void side2() { printf("side2\n"); } - ''') - create_file('main.c', ''' + ''', + ) + create_file( + 'main.c', + ''' void side1(); int main() { side1(); return 0; } - ''') + ''', + ) self.emcc('side2.c', ['-fPIC', '-sSIDE_MODULE', '-olibside2.so']) self.emcc('side1.c', ['-fPIC', '-sSIDE_MODULE', '-olibside1.so', 'libside2.so']) cmd = [EMCC, 'main.c', '-fPIC', '-sMAIN_MODULE=2', 'libside1.so'] # Unless `.` is added to the library path the libside2.so won't be found. err = self.expect_fail(cmd) - self.assertContained('emcc: error: libside1.so: shared library dependency not found in library path: `libside2.so`.', err) + self.assertContained( + 'emcc: error: libside1.so: shared library dependency not found in library path: `libside2.so`.', err + ) # Adding -L. to the library path makes it work. self.run_process(cmd + ['-L.']) @@ -2379,7 +2670,9 @@ def test_dylink_dependencies(self): def test_dylink_LEGACY_GL_EMULATION(self): # LEGACY_GL_EMULATION wraps JS library functions. This test ensure that when it does # so it preserves the `.sig` attributes needed by dynamic linking. - create_file('test.c', r''' + create_file( + 'test.c', + r''' #include #include @@ -2387,37 +2680,52 @@ def test_dylink_LEGACY_GL_EMULATION(self): printf("glUseProgram: %p\n", &glUseProgram); printf("done\n"); return 0; -}''') +}''', + ) self.do_runf('test.c', 'done\n', emcc_args=['-sLEGACY_GL_EMULATION', '-sMAIN_MODULE=2']) def test_js_link(self): - create_file('before.js', ''' + create_file( + 'before.js', + ''' var MESSAGE = 'hello from js'; // Module is initialized with empty object by default, so if there are no keys - nothing was run yet if (Object.keys(Module).length) throw 'This code should run before anything else!'; - ''') - create_file('after.js', ''' + ''', + ) + create_file( + 'after.js', + ''' out(MESSAGE); - ''') + ''', + ) - self.do_runf(test_file('hello_world.c'), 'hello, world!\nhello from js\n', - emcc_args=['--pre-js', 'before.js', '--post-js', 'after.js', '-sWASM_ASYNC_COMPILATION=0']) + self.do_runf( + test_file('hello_world.c'), + 'hello, world!\nhello from js\n', + emcc_args=['--pre-js', 'before.js', '--post-js', 'after.js', '-sWASM_ASYNC_COMPILATION=0'], + ) def test_sdl_none(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main() { return 0; } - ''') + ''', + ) err = self.expect_fail([EMCC, 'main.c']) self.assertContained('SDL.h:1:2: error: "To use the emscripten port of SDL use -sUSE_SDL or -sUSE_SDL=2"', err) self.run_process([EMCC, 'main.c', '-sUSE_SDL']) def test_sdl_endianness(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include @@ -2425,11 +2733,14 @@ def test_sdl_endianness(self): printf("%d, %d, %d\n", SDL_BYTEORDER, SDL_LIL_ENDIAN, SDL_BIG_ENDIAN); return 0; } - ''') + ''', + ) self.do_runf('main.c', '1234, 1234, 4321\n') def test_sdl_scan_code_from_key(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include @@ -2437,11 +2748,14 @@ def test_sdl_scan_code_from_key(self): printf("%d\n", SDL_GetScancodeFromKey(35)); return 0; } - ''') + ''', + ) self.do_runf('main.c', '204\n') def test_sdl_get_key_name(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include @@ -2453,14 +2767,18 @@ def test_sdl_get_key_name(self): printf("F1 -> '%s'\n", SDL_GetKeyName(SDLK_F1)); return 0; } - ''') - self.do_runf('main.c', '''\ + ''', + ) + self.do_runf( + 'main.c', + '''\ a -> 'a' z -> 'z' 0 -> '0' 0 -> '9' F1 -> '' -''') +''', + ) @requires_network def test_sdl2_mixer_wav(self): @@ -2476,52 +2794,79 @@ def test_sdl2_linkable(self): @requires_network def test_sdl2_gfx_linkable(self): # Same as above but for sdl2_gfx library - self.emcc(test_file('browser/test_sdl2_misc.c'), ['-Wl,-fatal-warnings', '-sLINKABLE', '-sUSE_SDL_GFX=2'], output_filename='a.out.js') - self.emcc(test_file('browser/test_sdl2_misc.c'), ['-Wl,-fatal-warnings', '-sLINKABLE', '--use-port=sdl2_gfx'], output_filename='a.out.js') + self.emcc( + test_file('browser/test_sdl2_misc.c'), + ['-Wl,-fatal-warnings', '-sLINKABLE', '-sUSE_SDL_GFX=2'], + output_filename='a.out.js', + ) + self.emcc( + test_file('browser/test_sdl2_misc.c'), + ['-Wl,-fatal-warnings', '-sLINKABLE', '--use-port=sdl2_gfx'], + output_filename='a.out.js', + ) @requires_network def test_libpng(self): shutil.copy(test_file('third_party/libpng/pngtest.png'), '.') - self.do_runf('third_party/libpng/pngtest.c', 'libpng passes test', - emcc_args=['--embed-file', 'pngtest.png', '-sUSE_LIBPNG']) - self.do_runf('third_party/libpng/pngtest.c', 'libpng passes test', - emcc_args=['--embed-file', 'pngtest.png', '--use-port=libpng']) + self.do_runf( + 'third_party/libpng/pngtest.c', 'libpng passes test', emcc_args=['--embed-file', 'pngtest.png', '-sUSE_LIBPNG'] + ) + self.do_runf( + 'third_party/libpng/pngtest.c', + 'libpng passes test', + emcc_args=['--embed-file', 'pngtest.png', '--use-port=libpng'], + ) @node_pthreads @requires_network def test_libpng_with_pthreads(self): shutil.copy(test_file('third_party/libpng/pngtest.png'), '.') - self.do_runf('third_party/libpng/pngtest.c', 'libpng passes test', - emcc_args=['--embed-file', 'pngtest.png', '-sUSE_LIBPNG', '-pthread']) + self.do_runf( + 'third_party/libpng/pngtest.c', + 'libpng passes test', + emcc_args=['--embed-file', 'pngtest.png', '-sUSE_LIBPNG', '-pthread'], + ) @requires_network def test_giflib(self): # giftext.c contains a sprintf warning self.emcc_args += ['-Wno-fortify-source'] shutil.copy(test_file('third_party/giflib/treescap.gif'), '.') - self.do_runf('third_party/giflib/giftext.c', - 'GIF file terminated normally', - emcc_args=['--embed-file', 'treescap.gif', '-sUSE_GIFLIB'], - args=['treescap.gif']) + self.do_runf( + 'third_party/giflib/giftext.c', + 'GIF file terminated normally', + emcc_args=['--embed-file', 'treescap.gif', '-sUSE_GIFLIB'], + args=['treescap.gif'], + ) # Same again with -sMAIN_MODULE (See #18537) - self.do_runf('third_party/giflib/giftext.c', - 'GIF file terminated normally', - emcc_args=['--embed-file', 'treescap.gif', '-sUSE_GIFLIB', '-sMAIN_MODULE'], - args=['treescap.gif']) - self.do_runf('third_party/giflib/giftext.c', - 'GIF file terminated normally', - emcc_args=['--embed-file', 'treescap.gif', '--use-port=giflib'], - args=['treescap.gif']) + self.do_runf( + 'third_party/giflib/giftext.c', + 'GIF file terminated normally', + emcc_args=['--embed-file', 'treescap.gif', '-sUSE_GIFLIB', '-sMAIN_MODULE'], + args=['treescap.gif'], + ) + self.do_runf( + 'third_party/giflib/giftext.c', + 'GIF file terminated normally', + emcc_args=['--embed-file', 'treescap.gif', '--use-port=giflib'], + args=['treescap.gif'], + ) @requires_network def test_libjpeg(self): shutil.copy(test_file('screenshot.jpg'), '.') - self.do_runf('jpeg_test.c', 'Image is 600 by 450 with 3 components', - emcc_args=['--embed-file', 'screenshot.jpg', '-sUSE_LIBJPEG'], - args=['screenshot.jpg']) - self.do_runf('jpeg_test.c', 'Image is 600 by 450 with 3 components', - emcc_args=['--embed-file', 'screenshot.jpg', '--use-port=libjpeg'], - args=['screenshot.jpg']) + self.do_runf( + 'jpeg_test.c', + 'Image is 600 by 450 with 3 components', + emcc_args=['--embed-file', 'screenshot.jpg', '-sUSE_LIBJPEG'], + args=['screenshot.jpg'], + ) + self.do_runf( + 'jpeg_test.c', + 'Image is 600 by 450 with 3 components', + emcc_args=['--embed-file', 'screenshot.jpg', '--use-port=libjpeg'], + args=['screenshot.jpg'], + ) @requires_network def test_bullet(self): @@ -2536,10 +2881,8 @@ def test_vorbis(self): @requires_network def test_bzip2(self): - self.do_runf('bzip2_test.c', 'usage: unzcrash filename', - emcc_args=['-sUSE_BZIP2', '-Wno-pointer-sign']) - self.do_runf('bzip2_test.c', 'usage: unzcrash filename', - emcc_args=['--use-port=bzip2', '-Wno-pointer-sign']) + self.do_runf('bzip2_test.c', 'usage: unzcrash filename', emcc_args=['-sUSE_BZIP2', '-Wno-pointer-sign']) + self.do_runf('bzip2_test.c', 'usage: unzcrash filename', emcc_args=['--use-port=bzip2', '-Wno-pointer-sign']) @with_all_sjlj @requires_network @@ -2569,7 +2912,9 @@ def test_icu(self): def test_sdl2_ttf(self): # This is a compile-only to test to verify that sdl2-ttf (and freetype and harfbuzz) are buildable. self.emcc(test_file('browser/test_sdl2_ttf.c'), args=['-sUSE_SDL=2', '-sUSE_SDL_TTF=2'], output_filename='a.out.js') - self.emcc(test_file('browser/test_sdl2_ttf.c'), args=['--use-port=sdl2', '--use-port=sdl2_ttf'], output_filename='a.out.js') + self.emcc( + test_file('browser/test_sdl2_ttf.c'), args=['--use-port=sdl2', '--use-port=sdl2_ttf'], output_filename='a.out.js' + ) @requires_network def test_contrib_ports(self): @@ -2591,22 +2936,49 @@ def test_external_ports(self): self.skipTest("test doesn't work with frozen cache") external_port_path = test_file("other/ports/external.py") # testing no option - self.do_runf('other/test_external_ports.c', 'value1=0&value2=0&value3=v3\n', emcc_args=[f'--use-port={external_port_path}']) + self.do_runf( + 'other/test_external_ports.c', 'value1=0&value2=0&value3=v3\n', emcc_args=[f'--use-port={external_port_path}'] + ) # testing 1 option - self.do_runf('other/test_external_ports.c', 'value1=12&value2=0&value3=v3\n', emcc_args=[f'--use-port={external_port_path}:value1=12']) + self.do_runf( + 'other/test_external_ports.c', + 'value1=12&value2=0&value3=v3\n', + emcc_args=[f'--use-port={external_port_path}:value1=12'], + ) # testing 2 options - self.do_runf('other/test_external_ports.c', 'value1=12&value2=36&value3=v3\n', emcc_args=[f'--use-port={external_port_path}:value1=12:value2=36']) + self.do_runf( + 'other/test_external_ports.c', + 'value1=12&value2=36&value3=v3\n', + emcc_args=[f'--use-port={external_port_path}:value1=12:value2=36'], + ) # testing ':' escape - self.do_runf('other/test_external_ports.c', 'value1=12&value2=36&value3=v:3\n', emcc_args=[f'--use-port={external_port_path}:value1=12:value3=v::3:value2=36']) + self.do_runf( + 'other/test_external_ports.c', + 'value1=12&value2=36&value3=v:3\n', + emcc_args=[f'--use-port={external_port_path}:value1=12:value3=v::3:value2=36'], + ) # testing dependency - self.do_runf('other/test_external_ports.c', 'mpg123=45\n', emcc_args=[f'--use-port={external_port_path}:dependency=mpg123']) + self.do_runf( + 'other/test_external_ports.c', 'mpg123=45\n', emcc_args=[f'--use-port={external_port_path}:dependency=mpg123'] + ) # testing invalid dependency - stderr = self.expect_fail([EMCC, test_file('other/test_external_ports.c'), f'--use-port={external_port_path}:dependency=invalid', '-o', 'a4.out.js']) + stderr = self.expect_fail( + [ + EMCC, + test_file('other/test_external_ports.c'), + f'--use-port={external_port_path}:dependency=invalid', + '-o', + 'a4.out.js', + ] + ) self.assertFalse(os.path.exists('a4.out.js')) self.assertContained('unknown dependency `invalid` for port `external`', stderr) # testing help - stdout = self.run_process([EMCC, test_file('other/test_external_ports.c'), f'--use-port={external_port_path}:help'], stdout=PIPE).stdout - self.assertContained('''external (--use-port=external; Test License) + stdout = self.run_process( + [EMCC, test_file('other/test_external_ports.c'), f'--use-port={external_port_path}:help'], stdout=PIPE + ).stdout + self.assertContained( + '''external (--use-port=external; Test License) Test Description Options: * value1: Value for define TEST_VALUE_1 @@ -2614,11 +2986,15 @@ def test_external_ports(self): * value3: String value * dependency: A dependency More info: https://emscripten.org -''', stdout) +''', + stdout, + ) def test_link_memcpy(self): # memcpy can show up *after* optimizations, so after our opportunity to link in libc, so it must be special-cased - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int main(int argc, char **argv) { @@ -2641,10 +3017,12 @@ def test_link_memcpy(self): } return 0; } - ''') + ''', + ) self.run_process([EMCC, '-O2', 'main.c']) output = self.run_js('a.out.js') - self.assertContained('''0:0 + self.assertContained( + '''0:0 1:1 2:6 3:21 @@ -2655,13 +3033,12 @@ def test_link_memcpy(self): 8:55 9:96 10:-16 -''', output) +''', + output, + ) self.assertNotContained('warning: library.js memcpy should not be running, it is only for testing!', output) - @parameterized({ - '': ('out.js',), - 'standalone': ('out.wasm',) - }) + @parameterized({'': ('out.js',), 'standalone': ('out.wasm',)}) def test_undefined_exported_function(self, outfile): cmd = [EMCC, test_file('hello_world.c'), '-o', outfile] self.run_process(cmd) @@ -2681,10 +3058,7 @@ def test_undefined_exported_function(self, outfile): cmd += ['-Wno-undefined'] self.run_process(cmd) - @parameterized({ - '': ('out.js',), - 'standalone': ('out.wasm',) - }) + @parameterized({'': ('out.js',), 'standalone': ('out.wasm',)}) def test_undefined_exported_js_function(self, outfile): cmd = [EMXX, test_file('hello_world.cpp'), '-o', outfile] self.run_process(cmd) @@ -2698,18 +3072,18 @@ def test_undefined_exported_js_function(self, outfile): cmd += ['-Wno-undefined'] self.run_process(cmd) - @parameterized({ - '': [[]], - 'O1': [['-O1']], - 'GL2': [['-sMAX_WEBGL_VERSION=2']], - }) - @parameterized({ - 'warn': ['WARN'], - 'error': ['ERROR'], - 'ignore': [None] - }) + @parameterized( + { + '': [[]], + 'O1': [['-O1']], + 'GL2': [['-sMAX_WEBGL_VERSION=2']], + } + ) + @parameterized({'warn': ['WARN'], 'error': ['ERROR'], 'ignore': [None]}) def test_undefined_symbols(self, args, action): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include "SDL/SDL_opengl.h" @@ -2724,13 +3098,16 @@ def test_undefined_symbols(self, args, action): elsey(); return 0; } - ''') + ''', + ) - for value in ([0, 1]): + for value in [0, 1]: delete_file('a.out.js') print('checking %s' % value) extra = ['-s', action + '_ON_UNDEFINED_SYMBOLS=%d' % value] if action else [] - proc = self.run_process([EMCC, '-sUSE_SDL', '-sGL_ENABLE_GET_PROC_ADDRESS', 'main.c'] + extra + args, stderr=PIPE, check=False) + proc = self.run_process( + [EMCC, '-sUSE_SDL', '-sGL_ENABLE_GET_PROC_ADDRESS', 'main.c'] + extra + args, stderr=PIPE, check=False + ) if common.EMTEST_VERBOSE: print(proc.stderr) if value or action is None: @@ -2757,13 +3134,16 @@ def test_undefined_symbols(self, args, action): self.assertFalse(os.path.exists('a.out.js')) def test_undefined_data_symbols(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' extern int foo; int main() { return foo; } - ''') + ''', + ) output = self.expect_fail([EMCC, 'main.c']) self.assertContained('undefined symbol: foo', output) @@ -2774,29 +3154,47 @@ def test_undefined_data_symbols(self): def test_GetProcAddress_LEGACY_GL_EMULATION(self): # without legacy gl emulation, getting a proc from there should fail - self.do_other_test('test_GetProcAddress_LEGACY_GL_EMULATION.c', args=['0'], emcc_args=['-sLEGACY_GL_EMULATION=0', '-sGL_ENABLE_GET_PROC_ADDRESS']) + self.do_other_test( + 'test_GetProcAddress_LEGACY_GL_EMULATION.c', + args=['0'], + emcc_args=['-sLEGACY_GL_EMULATION=0', '-sGL_ENABLE_GET_PROC_ADDRESS'], + ) # with it, it should work - self.do_other_test('test_GetProcAddress_LEGACY_GL_EMULATION.c', args=['1'], emcc_args=['-sLEGACY_GL_EMULATION', '-sGL_ENABLE_GET_PROC_ADDRESS']) + self.do_other_test( + 'test_GetProcAddress_LEGACY_GL_EMULATION.c', + args=['1'], + emcc_args=['-sLEGACY_GL_EMULATION', '-sGL_ENABLE_GET_PROC_ADDRESS'], + ) # Verifies that is user is building without -sGL_ENABLE_GET_PROC_ADDRESS, then # at link time they should get a helpful error message guiding them to enable # the option. def test_get_proc_address_error_message(self): - err = self.expect_fail([EMCC, '-sGL_ENABLE_GET_PROC_ADDRESS=0', test_file('other/test_GetProcAddress_LEGACY_GL_EMULATION.c')]) - self.assertContained('error: linker: Undefined symbol: SDL_GL_GetProcAddress(). Please pass -sGL_ENABLE_GET_PROC_ADDRESS at link time to link in SDL_GL_GetProcAddress().', err) - - @parameterized({ - '': (False, False), - 'no_initial_run': (True, False), - 'run_dep': (False, True), - }) + err = self.expect_fail( + [EMCC, '-sGL_ENABLE_GET_PROC_ADDRESS=0', test_file('other/test_GetProcAddress_LEGACY_GL_EMULATION.c')] + ) + self.assertContained( + 'error: linker: Undefined symbol: SDL_GL_GetProcAddress(). Please pass -sGL_ENABLE_GET_PROC_ADDRESS at link time to link in SDL_GL_GetProcAddress().', + err, + ) + + @parameterized( + { + '': (False, False), + 'no_initial_run': (True, False), + 'run_dep': (False, True), + } + ) def test_prepost(self, no_initial_run, run_dep): - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' var Module = { preRun: () => out('pre-run'), postRun: () => out('post-run') }; - ''') + ''', + ) self.run_process([EMCC, test_file('hello_world.c'), '--pre-js', 'pre.js', '-sWASM_ASYNC_COMPILATION=0']) self.assertContained('pre-run\nhello, world!\npost-run\n', self.run_js('a.out.js')) @@ -2833,37 +3231,63 @@ def test_prepost(self, no_initial_run, run_dep): self.assertContained('hello, world!\ncallMain -> 0\n', self.run_js('a.out.js')) def test_preinit(self): - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' var Module = { preRun: () => out('pre-run'), postRun: () => out('post-run'), preInit: () => out('pre-init') }; - ''') - self.do_runf(test_file('hello_world.c'), - 'pre-init\npre-run\nhello, world!\npost-run\n', - emcc_args=['--pre-js', 'pre.js']) + ''', + ) + self.do_runf( + test_file('hello_world.c'), 'pre-init\npre-run\nhello, world!\npost-run\n', emcc_args=['--pre-js', 'pre.js'] + ) def test_prepost2(self): create_file('pre.js', 'Module.preRun = () => out("pre-run");') create_file('pre2.js', 'Module.postRun = () => out("post-run");') - self.do_runf(test_file('hello_world.c'), 'pre-run\nhello, world!\npost-run\n', - emcc_args=['--pre-js', 'pre.js', '--pre-js', 'pre2.js']) + self.do_runf( + test_file('hello_world.c'), + 'pre-run\nhello, world!\npost-run\n', + emcc_args=['--pre-js', 'pre.js', '--pre-js', 'pre2.js'], + ) def test_prepre(self): - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.preRun = [() => out('pre-run')]; - ''') - create_file('pre2.js', ''' + ''', + ) + create_file( + 'pre2.js', + ''' Module.preRun.push(() => out('prepre')); - ''') - self.do_runf(test_file('hello_world.c'), 'prepre\npre-run\nhello, world!\n', - emcc_args=['--pre-js', 'pre.js', '--pre-js', 'pre2.js']) + ''', + ) + self.do_runf( + test_file('hello_world.c'), + 'prepre\npre-run\nhello, world!\n', + emcc_args=['--pre-js', 'pre.js', '--pre-js', 'pre2.js'], + ) def test_extern_prepost(self): create_file('extern-pre.js', '// I am an external pre.\n') create_file('extern-post.js', '// I am an external post.\n') - self.run_process([EMCC, '-O2', test_file('hello_world.c'), '--extern-pre-js', 'extern-pre.js', '--extern-post-js', 'extern-post.js', '--closure=1']) + self.run_process( + [ + EMCC, + '-O2', + test_file('hello_world.c'), + '--extern-pre-js', + 'extern-pre.js', + '--extern-post-js', + 'extern-post.js', + '--closure=1', + ] + ) # the files should be included, and externally - not as part of optimized # code, so they are the very first and last things, and they are not # minified. @@ -2881,37 +3305,39 @@ def test_extern_prepost(self): # make sure the slack is tiny compared to the whole program self.assertGreater(js_size, 50 * SLACK) - @parameterized({ - 'minifyGlobals': (['minifyGlobals'],), - 'minifyLocals': (['minifyLocals'],), - 'JSDCE': (['JSDCE'],), - 'JSDCE-hasOwnProperty': (['JSDCE'],), - 'JSDCE-defaultArg': (['JSDCE'],), - 'JSDCE-fors': (['JSDCE'],), - 'JSDCE-objectPattern': (['JSDCE'],), - 'AJSDCE': (['AJSDCE'],), - 'emitDCEGraph': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph-closure': (['emitDCEGraph', '--no-print', '--closure-friendly'], 'emitDCEGraph.js'), - 'emitDCEGraph2': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph3': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph4': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph5': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph-scopes': (['emitDCEGraph', '--no-print'],), - 'minimal-runtime-applyDCEGraphRemovals': (['applyDCEGraphRemovals'],), - 'applyDCEGraphRemovals': (['applyDCEGraphRemovals'],), - 'applyImportAndExportNameChanges': (['applyImportAndExportNameChanges'],), - 'applyImportAndExportNameChanges2': (['applyImportAndExportNameChanges'],), - 'minimal-runtime-emitDCEGraph': (['emitDCEGraph', '--no-print'],), - 'minimal-runtime-2-emitDCEGraph': (['emitDCEGraph', '--no-print'],), - 'standalone-emitDCEGraph': (['emitDCEGraph', '--no-print'],), - 'emittedJSPreservesParens': ([],), - 'growableHeap': (['growableHeap'],), - 'unsignPointers': (['unsignPointers', '--closure-friendly'],), - 'asanify': (['asanify'],), - 'safeHeap': (['safeHeap'],), - 'object-literals': ([],), - 'LittleEndianHeap': (['littleEndianHeap'],), - }) + @parameterized( + { + 'minifyGlobals': (['minifyGlobals'],), + 'minifyLocals': (['minifyLocals'],), + 'JSDCE': (['JSDCE'],), + 'JSDCE-hasOwnProperty': (['JSDCE'],), + 'JSDCE-defaultArg': (['JSDCE'],), + 'JSDCE-fors': (['JSDCE'],), + 'JSDCE-objectPattern': (['JSDCE'],), + 'AJSDCE': (['AJSDCE'],), + 'emitDCEGraph': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph-closure': (['emitDCEGraph', '--no-print', '--closure-friendly'], 'emitDCEGraph.js'), + 'emitDCEGraph2': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph3': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph4': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph5': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph-scopes': (['emitDCEGraph', '--no-print'],), + 'minimal-runtime-applyDCEGraphRemovals': (['applyDCEGraphRemovals'],), + 'applyDCEGraphRemovals': (['applyDCEGraphRemovals'],), + 'applyImportAndExportNameChanges': (['applyImportAndExportNameChanges'],), + 'applyImportAndExportNameChanges2': (['applyImportAndExportNameChanges'],), + 'minimal-runtime-emitDCEGraph': (['emitDCEGraph', '--no-print'],), + 'minimal-runtime-2-emitDCEGraph': (['emitDCEGraph', '--no-print'],), + 'standalone-emitDCEGraph': (['emitDCEGraph', '--no-print'],), + 'emittedJSPreservesParens': ([],), + 'growableHeap': (['growableHeap'],), + 'unsignPointers': (['unsignPointers', '--closure-friendly'],), + 'asanify': (['asanify'],), + 'safeHeap': (['safeHeap'],), + 'object-literals': ([],), + 'LittleEndianHeap': (['littleEndianHeap'],), + } + ) @crossplatform def test_js_optimizer(self, passes, filename=None): if not filename: @@ -2920,7 +3346,9 @@ def test_js_optimizer(self, passes, filename=None): filename = test_file('js_optimizer', filename) expected_file = shared.unsuffixed(filename) + '-output.js' # test calling optimizer - js = self.run_process(config.NODE_JS + [path_from_root('tools/acorn-optimizer.mjs'), filename] + passes, stdin=PIPE, stdout=PIPE).stdout + js = self.run_process( + config.NODE_JS + [path_from_root('tools/acorn-optimizer.mjs'), filename] + passes, stdin=PIPE, stdout=PIPE + ).stdout if common.EMTEST_REBASELINE: write_file(expected_file, js) else: @@ -2936,10 +3364,7 @@ def test_js_optimizer_huge(self): self.assertGreater(os.path.getsize('huge.js'), 50_000_000) self.run_process([PYTHON, path_from_root('tools/js_optimizer.py'), 'huge.js', '--minify-whitespace']) - @parameterized({ - 'wasm2js': ('wasm2js', ['minifyNames']), - 'constructor': ('constructor', ['minifyNames']) - }) + @parameterized({'wasm2js': ('wasm2js', ['minifyNames']), 'constructor': ('constructor', ['minifyNames'])}) @crossplatform def test_js_optimizer_py(self, name, passes): # run the js optimizer python script. this differs from test_js_optimizer @@ -2958,12 +3383,14 @@ def test_m_mm(self): self.assertNotContained('error', proc.stderr) @uses_canonical_tmp - @parameterized({ - 'O0': ('-O0',), - 'O1': ('-O1',), - 'O2': ('-O2',), - 'O3': ('-O3',), - }) + @parameterized( + { + 'O0': ('-O0',), + 'O1': ('-O1',), + 'O2': ('-O2',), + 'O3': ('-O3',), + } + ) def test_emcc_debug_files(self, opt): for debug in (None, '1', '2'): print('debug =', debug) @@ -3032,8 +3459,8 @@ def compile_to_O0_executable(compile_args): def verify_dwarf(self, wasm_file, verify_func): self.assertExists(wasm_file) info = self.run_process([LLVM_DWARFDUMP, '--all', wasm_file], stdout=PIPE).stdout - verify_func('DW_TAG_subprogram', info) # Subprogram entry in .debug_info - verify_func('debug_line[0x', info) # Line table + verify_func('DW_TAG_subprogram', info) # Subprogram entry in .debug_info + verify_func('debug_line[0x', info) # Line table def verify_dwarf_exists(self, wasm_file): self.verify_dwarf(wasm_file, self.assertIn) @@ -3062,6 +3489,7 @@ def test_dwarf(self): def compile_with_dwarf(args, output): # Test that -g enables dwarf info in object files and linked wasm self.run_process([EMCC, test_file('hello_world.c'), '-o', output, '-g'] + args) + compile_with_dwarf(['-c'], 'a.o') self.verify_dwarf_exists('a.o') compile_with_dwarf([], 'a.js') @@ -3073,7 +3501,7 @@ def test_dwarf_sourcemap_names(self): wasm_file = 'a.out.wasm' map_file = 'a.out.wasm.map' - for (flags, expect_dwarf, expect_sourcemap, expect_names) in [ + for flags, expect_dwarf, expect_sourcemap, expect_names in [ ([], False, False, False), (['-g0'], False, False, False), (['-g1'], False, False, False), @@ -3136,26 +3564,30 @@ def test_scons(self): self.assertContained('If you see this - the world is all right!', output) @requires_scons - @with_env_modify({ - 'EMSCRIPTEN_ROOT': path_from_root(), - 'EMSCONS_PKG_CONFIG_LIBDIR': '/pkg/config/libdir', - 'EMSCONS_PKG_CONFIG_PATH': '/pkg/config/path', - }) + @with_env_modify( + { + 'EMSCRIPTEN_ROOT': path_from_root(), + 'EMSCONS_PKG_CONFIG_LIBDIR': '/pkg/config/libdir', + 'EMSCONS_PKG_CONFIG_PATH': '/pkg/config/path', + } + ) def test_scons_env(self): # this test copies the site_scons directory alongside the test shutil.copytree(test_file('scons/env'), 'test') shutil.copytree(path_from_root('tools/scons/site_scons'), Path('test/site_scons')) - expected_to_propagate = json.dumps({ - 'CC': path_from_root('emcc'), - 'CXX': path_from_root('em++'), - 'AR': path_from_root('emar'), - 'RANLIB': path_from_root('emranlib'), - 'ENV': { - 'PKG_CONFIG_LIBDIR': '/pkg/config/libdir', - 'PKG_CONFIG_PATH': '/pkg/config/path', + expected_to_propagate = json.dumps( + { + 'CC': path_from_root('emcc'), + 'CXX': path_from_root('em++'), + 'AR': path_from_root('emar'), + 'RANLIB': path_from_root('emranlib'), + 'ENV': { + 'PKG_CONFIG_LIBDIR': '/pkg/config/libdir', + 'PKG_CONFIG_PATH': '/pkg/config/path', + }, } - }) + ) with utils.chdir('test'): self.run_process(['scons', '--expected-env', expected_to_propagate]) @@ -3165,16 +3597,18 @@ def test_scons_env_no_emscons(self): shutil.copytree(test_file('scons/env'), 'test') shutil.copytree(path_from_root('tools/scons/site_scons'), Path('test/site_scons')) - expected_to_propagate = json.dumps({ - 'CC': 'emcc', - 'CXX': 'em++', - 'AR': 'emar', - 'RANLIB': 'emranlib', - 'ENV': { - 'PKG_CONFIG_LIBDIR': None, - 'PKG_CONFIG_PATH': None, + expected_to_propagate = json.dumps( + { + 'CC': 'emcc', + 'CXX': 'em++', + 'AR': 'emar', + 'RANLIB': 'emranlib', + 'ENV': { + 'PKG_CONFIG_LIBDIR': None, + 'PKG_CONFIG_PATH': None, + }, } - }) + ) with utils.chdir('test'): self.run_process(['scons', '--expected-env', expected_to_propagate]) @@ -3192,16 +3626,18 @@ def test_emscons_env(self): shutil.copytree(test_file('scons/env'), 'test') building_env = get_building_env() - expected_to_propagate = json.dumps({ - 'CC': path_from_root('emcc'), - 'CXX': path_from_root('em++'), - 'AR': path_from_root('emar'), - 'RANLIB': path_from_root('emranlib'), - 'ENV': { - 'PKG_CONFIG_LIBDIR': building_env['PKG_CONFIG_LIBDIR'], - 'PKG_CONFIG_PATH': building_env['PKG_CONFIG_PATH'], + expected_to_propagate = json.dumps( + { + 'CC': path_from_root('emcc'), + 'CXX': path_from_root('em++'), + 'AR': path_from_root('emar'), + 'RANLIB': path_from_root('emranlib'), + 'ENV': { + 'PKG_CONFIG_LIBDIR': building_env['PKG_CONFIG_LIBDIR'], + 'PKG_CONFIG_PATH': building_env['PKG_CONFIG_PATH'], + }, } - }) + ) with utils.chdir('test'): self.run_process([path_from_root('emscons'), 'scons', '--expected-env', expected_to_propagate]) @@ -3212,29 +3648,39 @@ def test_embind_fail(self): def test_embind_invalid_overload(self): expected = 'BindingError: Cannot register multiple overloads of a function with the same number of arguments' - self.do_runf(test_file('embind/test_embind_invalid_overload.cpp'), expected, emcc_args=['-lembind'], assert_returncode=NON_ZERO) + self.do_runf( + test_file('embind/test_embind_invalid_overload.cpp'), expected, emcc_args=['-lembind'], assert_returncode=NON_ZERO + ) def test_embind_asyncify(self): - create_file('post.js', ''' + create_file( + 'post.js', + ''' addOnPostRun(() => { Module.sleep(10); out('done'); }); - ''') - create_file('main.cpp', r''' + ''', + ) + create_file( + 'main.cpp', + r''' #include #include using namespace emscripten; EMSCRIPTEN_BINDINGS(asyncify) { function("sleep", &emscripten_sleep); } - ''') + ''', + ) self.do_runf('main.cpp', 'done', emcc_args=['-lembind', '-sASYNCIFY', '--post-js', 'post.js']) - @parameterized({ - '': ['-sDYNAMIC_EXECUTION=1'], - 'no_dynamic': ['-sDYNAMIC_EXECUTION=0'], - }) + @parameterized( + { + '': ['-sDYNAMIC_EXECUTION=1'], + 'no_dynamic': ['-sDYNAMIC_EXECUTION=0'], + } + ) @requires_jspi def test_embind_jspi(self, extra): self.emcc_args += ['-lembind', '-g'] @@ -3243,12 +3689,17 @@ def test_embind_jspi(self, extra): self.do_runf('embind/embind_jspi_test.cpp', 'done') def test_embind_no_function(self): - create_file('post.js', ''' + create_file( + 'post.js', + ''' Module.onRuntimeInitialized = () => { out((new Module['MyClass'](42)).x); }; - ''') - create_file('main.cpp', r''' + ''', + ) + create_file( + 'main.cpp', + r''' #include #include using namespace emscripten; @@ -3266,17 +3717,23 @@ class MyClass { .constructor() .property("x", &MyClass::getX, &MyClass::setX); } - ''') + ''', + ) self.do_runf('main.cpp', '42', emcc_args=['-lembind', '--post-js', 'post.js']) def test_embind_closure_no_dynamic_execution(self): - create_file('post.js', ''' + create_file( + 'post.js', + ''' Module['onRuntimeInitialized'] = () => { out(Module['foo'](10)); out(Module['bar']()); }; - ''') - create_file('main.cpp', r''' + ''', + ) + create_file( + 'main.cpp', + r''' #include #include #include @@ -3290,33 +3747,47 @@ def test_embind_closure_no_dynamic_execution(self): emscripten::function("foo", &foo); emscripten::function("bar", &bar); } - ''') + ''', + ) self.set_setting('INCOMING_MODULE_JS_API', 'onRuntimeInitialized') self.set_setting('STRICT') self.set_setting('NO_DYNAMIC_EXECUTION') - self.do_runf('main.cpp', '10\nok\n', - emcc_args=['--no-entry', '-lembind', '-O2', '--closure=1', '--minify=0', '--post-js=post.js']) + self.do_runf( + 'main.cpp', + '10\nok\n', + emcc_args=['--no-entry', '-lembind', '-O2', '--closure=1', '--minify=0', '--post-js=post.js'], + ) @is_slow_test - @parameterized({ - '': [], - 'no_utf8': ['-sEMBIND_STD_STRING_IS_UTF8=0'], - 'no_dynamic': ['-sDYNAMIC_EXECUTION=0'], - 'aot_js': ['-sDYNAMIC_EXECUTION=0', '-sEMBIND_AOT', '-DSKIP_UNBOUND_TYPES'], - 'wasm64': ['-sMEMORY64'], - '2gb': ['-sINITIAL_MEMORY=2200mb', '-sGLOBAL_BASE=2gb'], - }) - @parameterized({ - # With no arguments we are effectively testing c++17 since it is the default. - '': [], - # Ensure embind compiles under C++11 which is the miniumum supported version. - 'cxx11': ['-std=c++11'], - 'o1': ['-O1'], - 'o2': ['-O2'], - 'o2_mem_growth': ['-O2', '-sALLOW_MEMORY_GROWTH', test_file('embind/isMemoryGrowthEnabled=true.cpp')], - 'o2_closure': ['-O2', '--closure=1', '--closure-args', '--externs ' + shlex.quote(test_file('embind/underscore-externs.js')), '-sASSERTIONS=1'], - 'strict_js': ['-sSTRICT_JS'] - }) + @parameterized( + { + '': [], + 'no_utf8': ['-sEMBIND_STD_STRING_IS_UTF8=0'], + 'no_dynamic': ['-sDYNAMIC_EXECUTION=0'], + 'aot_js': ['-sDYNAMIC_EXECUTION=0', '-sEMBIND_AOT', '-DSKIP_UNBOUND_TYPES'], + 'wasm64': ['-sMEMORY64'], + '2gb': ['-sINITIAL_MEMORY=2200mb', '-sGLOBAL_BASE=2gb'], + } + ) + @parameterized( + { + # With no arguments we are effectively testing c++17 since it is the default. + '': [], + # Ensure embind compiles under C++11 which is the miniumum supported version. + 'cxx11': ['-std=c++11'], + 'o1': ['-O1'], + 'o2': ['-O2'], + 'o2_mem_growth': ['-O2', '-sALLOW_MEMORY_GROWTH', test_file('embind/isMemoryGrowthEnabled=true.cpp')], + 'o2_closure': [ + '-O2', + '--closure=1', + '--closure-args', + '--externs ' + shlex.quote(test_file('embind/underscore-externs.js')), + '-sASSERTIONS=1', + ], + 'strict_js': ['-sSTRICT_JS'], + } + ) def test_embind(self, *extra_args): if '-sMEMORY64' in extra_args: self.require_wasm64() @@ -3332,8 +3803,10 @@ def test_embind(self, *extra_args): # This test uses a `CustomSmartPtr` class which has 1MB of data embedded in # it which means we need more stack space than normal. '-sSTACK_SIZE=2MB', - '--pre-js', test_file('embind/test.pre.js'), - '--post-js', test_file('embind/test.post.js'), + '--pre-js', + test_file('embind/test.pre.js'), + '--post-js', + test_file('embind/test.post.js'), ] self.emcc_args += extra_args @@ -3360,10 +3833,13 @@ def test_embind(self, *extra_args): @requires_node def test_embind_finalization(self): self.run_process( - [EMXX, - test_file('embind/test_finalization.cpp'), - '--pre-js', test_file('embind/test_finalization.js'), - '-lembind'] + [ + EMXX, + test_file('embind/test_finalization.cpp'), + '--pre-js', + test_file('embind/test_finalization.js'), + '-lembind', + ] ) self.node_args += ['--expose-gc'] output = self.run_js('a.out.js') @@ -3376,19 +3852,16 @@ def test_embind_return_value_policy(self): self.do_runf('embind/test_return_value_policy.cpp') - @parameterized({ - '': [[]], - 'asyncify': [['-sASYNCIFY=1']] - }) + @parameterized({'': [[]], 'asyncify': [['-sASYNCIFY=1']]}) def test_embind_long_long(self, args): - self.do_runf('embind/test_embind_long_long.cpp', '1000000000000n\n-1000000000000n', - emcc_args=['-lembind', '-sWASM_BIGINT'] + args) + self.do_runf( + 'embind/test_embind_long_long.cpp', + '1000000000000n\n-1000000000000n', + emcc_args=['-lembind', '-sWASM_BIGINT'] + args, + ) @requires_jspi - @parameterized({ - '': [['-sJSPI_EXPORTS=async*']], - 'deprecated': [['-Wno-deprecated', '-sASYNCIFY_EXPORTS=async*']] - }) + @parameterized({'': [['-sJSPI_EXPORTS=async*']], 'deprecated': [['-Wno-deprecated', '-sASYNCIFY_EXPORTS=async*']]}) def test_jspi_wildcard(self, opts): self.emcc_args += opts @@ -3401,19 +3874,24 @@ def test_jspi_add_function(self): '-sASYNCIFY=2', '-sEXPORTED_RUNTIME_METHODS=addFunction,dynCall', '-sALLOW_TABLE_GROWTH=1', - '-Wno-experimental'] + '-Wno-experimental', + ] self.do_runf('other/test_jspi_add_function.c', 'done') - @parameterized({ - 'commonjs': [['-sMODULARIZE'], ['--module', 'commonjs', '--moduleResolution', 'node']], - 'esm': [['-sEXPORT_ES6'], ['--module', 'NodeNext', '--moduleResolution', 'nodenext']], - 'esm_with_jsgen': [['-sEXPORT_ES6', '-sEMBIND_AOT'], ['--module', 'NodeNext', '--moduleResolution', 'nodenext']] - }) + @parameterized( + { + 'commonjs': [['-sMODULARIZE'], ['--module', 'commonjs', '--moduleResolution', 'node']], + 'esm': [['-sEXPORT_ES6'], ['--module', 'NodeNext', '--moduleResolution', 'nodenext']], + 'esm_with_jsgen': [['-sEXPORT_ES6', '-sEMBIND_AOT'], ['--module', 'NodeNext', '--moduleResolution', 'nodenext']], + } + ) def test_embind_tsgen_end_to_end(self, opts, tsc_opts): # Check that TypeScript generation works and that the program is runs as # expected. - self.emcc(test_file('other/embind_tsgen.cpp'), - ['-o', 'embind_tsgen.js', '-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] + opts) + self.emcc( + test_file('other/embind_tsgen.cpp'), + ['-o', 'embind_tsgen.js', '-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] + opts, + ) # Test that the output compiles with a TS file that uses the defintions. shutil.copyfile(test_file('other/embind_tsgen_main.ts'), 'main.ts') @@ -3433,33 +3911,42 @@ def test_embind_tsgen_ignore(self): self.emcc_args += ['-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] # These extra arguments are not related to TS binding generation but we want to # verify that they do not interfere with it. - extra_args = ['-sALLOW_MEMORY_GROWTH=1', - '-Wno-pthreads-mem-growth', - '-sMAXIMUM_MEMORY=4GB', - '--pre-js', 'fail.js', - '--post-js', 'fail.js', - '--extern-pre-js', 'fail.js', - '--extern-post-js', 'fail.js', - '-sENVIRONMENT=worker', - '--use-preload-cache', - '--preload-file', 'fail.js', - '-O3', - '-msimd128', - '-pthread', - '-sPROXY_TO_PTHREAD', - '-sPTHREAD_POOL_SIZE=1', - '-sSINGLE_FILE', - '-lembind', # Test duplicated link option. - ] + extra_args = [ + '-sALLOW_MEMORY_GROWTH=1', + '-Wno-pthreads-mem-growth', + '-sMAXIMUM_MEMORY=4GB', + '--pre-js', + 'fail.js', + '--post-js', + 'fail.js', + '--extern-pre-js', + 'fail.js', + '--extern-post-js', + 'fail.js', + '-sENVIRONMENT=worker', + '--use-preload-cache', + '--preload-file', + 'fail.js', + '-O3', + '-msimd128', + '-pthread', + '-sPROXY_TO_PTHREAD', + '-sPTHREAD_POOL_SIZE=1', + '-sSINGLE_FILE', + '-lembind', # Test duplicated link option. + ] self.emcc(test_file('other/embind_tsgen.cpp'), extra_args) self.assertFileContents(test_file('other/embind_tsgen_ignore_1.d.ts'), read_file('embind_tsgen.d.ts')) # Test these args separately since they conflict with arguments in the first test. - extra_args = ['-sMODULARIZE', - '--embed-file', 'fail.js', - '-sMINIMAL_RUNTIME=2', - '-sEXPORT_ES6=1', - '-sASSERTIONS=0', - '-sSTRICT=1'] + extra_args = [ + '-sMODULARIZE', + '--embed-file', + 'fail.js', + '-sMINIMAL_RUNTIME=2', + '-sEXPORT_ES6=1', + '-sASSERTIONS=0', + '-sSTRICT=1', + ] self.emcc(test_file('other/embind_tsgen.cpp'), extra_args) self.assertFileContents(test_file('other/embind_tsgen_ignore_2.d.ts'), read_file('embind_tsgen.d.ts')) # Also test this separately since it conflicts with other settings. @@ -3467,8 +3954,7 @@ def test_embind_tsgen_ignore(self): self.emcc(test_file('other/embind_tsgen.cpp'), extra_args) self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) - extra_args = ['-fsanitize=undefined', - '-gsource-map'] + extra_args = ['-fsanitize=undefined', '-gsource-map'] self.emcc(test_file('other/embind_tsgen.cpp'), extra_args) self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) @@ -3481,14 +3967,22 @@ def test_embind_tsgen_worker_env(self): self.assertFileContents(test_file('other/embind_tsgen.d.ts'), read_file('embind_tsgen.d.ts')) def test_embind_tsgen_dylink(self): - create_file('side.h', r''' + create_file( + 'side.h', + r''' void someLibraryFunc(); - ''') - create_file('side.cpp', r''' + ''', + ) + create_file( + 'side.cpp', + r''' #include "side.h" void someLibraryFunc() {} - ''') - create_file('main.cpp', r''' + ''', + ) + create_file( + 'main.cpp', + r''' #include "side.h" #include void mainLibraryFunc() {} @@ -3497,28 +3991,32 @@ def test_embind_tsgen_dylink(self): emscripten::function("mainLibraryFunc", &mainLibraryFunc ); emscripten::function("someLibraryFunc", &someLibraryFunc ); } - ''') - self.run_process([ - EMCC, - '-o', 'libside.wasm', - 'side.cpp', - '-sSIDE_MODULE']) + ''', + ) + self.run_process([EMCC, '-o', 'libside.wasm', 'side.cpp', '-sSIDE_MODULE']) self.emcc('main.cpp', ['libside.wasm', '-sMAIN_MODULE=2', '-lembind', '--emit-tsd', 'embind_tsgen.d.ts']) def test_embind_tsgen_test_embind(self): - self.run_process([EMXX, test_file('embind/embind_test.cpp'), - '-lembind', '--emit-tsd', 'embind_tsgen_test_embind.d.ts', - # This test explicitly creates std::string from unsigned char pointers - # which is deprecated in upstream LLVM. - '-Wno-deprecated-declarations', - # TypeScript generation requires all type to be bound. - '-DSKIP_UNBOUND_TYPES'] + self.get_emcc_args()) + self.run_process( + [ + EMXX, + test_file('embind/embind_test.cpp'), + '-lembind', + '--emit-tsd', + 'embind_tsgen_test_embind.d.ts', + # This test explicitly creates std::string from unsigned char pointers + # which is deprecated in upstream LLVM. + '-Wno-deprecated-declarations', + # TypeScript generation requires all type to be bound. + '-DSKIP_UNBOUND_TYPES', + ] + + self.get_emcc_args() + ) self.assertExists('embind_tsgen_test_embind.d.ts') def test_embind_tsgen_val(self): # Check that any dependencies from val still works with TS generation enabled. - self.run_process([EMCC, test_file('other/embind_tsgen_val.cpp'), - '-lembind', '--emit-tsd', 'embind_tsgen_val.d.ts']) + self.run_process([EMCC, test_file('other/embind_tsgen_val.cpp'), '-lembind', '--emit-tsd', 'embind_tsgen_val.d.ts']) self.assertExists('embind_tsgen_val.d.ts') def test_embind_tsgen_bigint(self): @@ -3533,24 +4031,38 @@ def test_embind_tsgen_bigint(self): @requires_wasm64 def test_embind_tsgen_memory64(self): # Check that when memory64 is enabled longs & unsigned longs are mapped to bigint in the generated TS bindings - self.run_process([EMXX, test_file('other/embind_tsgen_memory64.cpp'), - '-lembind', '--emit-tsd', 'embind_tsgen_memory64.d.ts', '-sMEMORY64'] + - self.get_emcc_args()) + self.run_process( + [ + EMXX, + test_file('other/embind_tsgen_memory64.cpp'), + '-lembind', + '--emit-tsd', + 'embind_tsgen_memory64.d.ts', + '-sMEMORY64', + ] + + self.get_emcc_args() + ) self.assertFileContents(test_file('other/embind_tsgen_memory64.d.ts'), read_file('embind_tsgen_memory64.d.ts')) - @parameterized({ - '': [0], - 'wasm_exnref': [1] - }) + @parameterized({'': [0], 'wasm_exnref': [1]}) def test_embind_tsgen_exceptions(self, wasm_exnref): self.set_setting('WASM_EXNREF', wasm_exnref) # Check that when Wasm exceptions and assertions are enabled bindings still generate. - self.run_process([EMXX, test_file('other/embind_tsgen.cpp'), - '-lembind', '-fwasm-exceptions', '-sASSERTIONS', - # Use the deprecated `--embind-emit-tsd` to ensure it - # still works until removed. - '--embind-emit-tsd', 'embind_tsgen.d.ts', '-Wno-deprecated'] + - self.get_emcc_args()) + self.run_process( + [ + EMXX, + test_file('other/embind_tsgen.cpp'), + '-lembind', + '-fwasm-exceptions', + '-sASSERTIONS', + # Use the deprecated `--embind-emit-tsd` to ensure it + # still works until removed. + '--embind-emit-tsd', + 'embind_tsgen.d.ts', + '-Wno-deprecated', + ] + + self.get_emcc_args() + ) self.assertFileContents(test_file('other/embind_tsgen.d.ts'), read_file('embind_tsgen.d.ts')) def test_embind_jsgen_method_pointer_stability(self): @@ -3560,30 +4072,49 @@ def test_embind_jsgen_method_pointer_stability(self): self.do_runf('other/embind_jsgen_method_pointer_stability.cpp', 'done') def test_emit_tsd(self): - self.run_process([EMCC, test_file('other/test_emit_tsd.c'), - '--emit-tsd', 'test_emit_tsd.d.ts', '-sEXPORT_ES6', - '-sMODULARIZE', '-sEXPORTED_RUNTIME_METHODS=UTF8ArrayToString,wasmTable', - '-Wno-experimental', '-o', 'test_emit_tsd.js'] + - self.get_emcc_args()) + self.run_process( + [ + EMCC, + test_file('other/test_emit_tsd.c'), + '--emit-tsd', + 'test_emit_tsd.d.ts', + '-sEXPORT_ES6', + '-sMODULARIZE', + '-sEXPORTED_RUNTIME_METHODS=UTF8ArrayToString,wasmTable', + '-Wno-experimental', + '-o', + 'test_emit_tsd.js', + ] + + self.get_emcc_args() + ) self.assertFileContents(test_file('other/test_emit_tsd.d.ts'), read_file('test_emit_tsd.d.ts')) # Test that the output compiles with a TS file that uses the defintions. cmd = shared.get_npm_cmd('tsc') + [test_file('other/test_tsd.ts'), '--noEmit'] shared.check_call(cmd) def test_emit_tsd_sync_compilation(self): - self.run_process([EMCC, test_file('other/test_emit_tsd.c'), - '--emit-tsd', 'test_emit_tsd_sync.d.ts', - '-sMODULARIZE', '-sWASM_ASYNC_COMPILATION=0', - '-o', 'test_emit_tsd_sync.js'] + - self.get_emcc_args()) + self.run_process( + [ + EMCC, + test_file('other/test_emit_tsd.c'), + '--emit-tsd', + 'test_emit_tsd_sync.d.ts', + '-sMODULARIZE', + '-sWASM_ASYNC_COMPILATION=0', + '-o', + 'test_emit_tsd_sync.js', + ] + + self.get_emcc_args() + ) self.assertFileContents(test_file('other/test_emit_tsd_sync.d.ts'), read_file('test_emit_tsd_sync.d.ts')) # Test that the output compiles with a TS file that uses the defintions. cmd = shared.get_npm_cmd('tsc') + [test_file('other/test_tsd_sync.ts'), '--noEmit'] shared.check_call(cmd) def test_emit_tsd_wasm_only(self): - err = self.expect_fail([EMCC, test_file('other/test_emit_tsd.c'), - '--emit-tsd', 'test_emit_tsd_wasm_only.d.ts', '-o', 'out.wasm']) + err = self.expect_fail( + [EMCC, test_file('other/test_emit_tsd.c'), '--emit-tsd', 'test_emit_tsd_wasm_only.d.ts', '-o', 'out.wasm'] + ) self.assertContained('Wasm only output is not compatible --emit-tsd', err) def test_emconfig(self): @@ -3609,21 +4140,27 @@ def test_emconfig(self): def test_link_s(self): # -s OPT=VALUE can conflict with -s as a linker option. We warn and ignore - create_file('main.c', r''' + create_file( + 'main.c', + r''' void something(); int main() { something(); return 0; } - ''') - create_file('supp.c', r''' + ''', + ) + create_file( + 'supp.c', + r''' #include void something() { printf("yello\n"); } - ''') + ''', + ) self.run_process([EMCC, '-c', 'main.c', '-o', 'main.o']) self.run_process([EMCC, '-c', 'supp.c', '-o', 'supp.o']) @@ -3633,11 +4170,14 @@ def test_link_s(self): self.assertContained('SAFE_HEAP', read_file('a.out.js')) def test_conftest_s_flag_passing(self): - create_file('conftest.c', r''' + create_file( + 'conftest.c', + r''' int main() { return 0; } - ''') + ''', + ) # the name "conftest.c" is enough to make us use a configure-like mode, # the same as if EMMAKEN_JUST_CONFIGURE=1 were set in the env. cmd = [EMCC, '-sASSERTIONS', 'conftest.c', '-o', 'conftest'] @@ -3672,12 +4212,16 @@ def check(text): self.assertContained('which is not contained within the current directory', stderr) # relative path that ends up under us is cool - proc = self.run_process([FILE_PACKAGER, 'test.data', '--quiet', '--preload', '../subdir/data2.txt'], stderr=PIPE, stdout=PIPE) + proc = self.run_process( + [FILE_PACKAGER, 'test.data', '--quiet', '--preload', '../subdir/data2.txt'], stderr=PIPE, stdout=PIPE + ) self.assertEqual(proc.stderr, '') check(proc.stdout) # direct path leads to the same code being generated - relative path does not make us do anything different - proc2 = self.run_process([FILE_PACKAGER, 'test.data', '--quiet', '--preload', 'data2.txt'], stderr=PIPE, stdout=PIPE) + proc2 = self.run_process( + [FILE_PACKAGER, 'test.data', '--quiet', '--preload', 'data2.txt'], stderr=PIPE, stdout=PIPE + ) check(proc2.stdout) self.assertEqual(proc2.stderr, '') @@ -3694,7 +4238,20 @@ def test_file_packager_separate_metadata(self): create_file('data1.txt', 'data1') create_file('subdir/data2.txt', 'data2') - self.run_process([FILE_PACKAGER, 'test.data', '--quiet', '--preload', 'data1.txt', '--preload', 'subdir/data2.txt', '--js-output=immutable.js', '--separate-metadata', '--use-preload-cache']) + self.run_process( + [ + FILE_PACKAGER, + 'test.data', + '--quiet', + '--preload', + 'data1.txt', + '--preload', + 'subdir/data2.txt', + '--js-output=immutable.js', + '--separate-metadata', + '--use-preload-cache', + ] + ) self.assertExists('immutable.js.metadata') # verify js output JS file is not touched when the metadata is separated orig_timestamp = os.path.getmtime('immutable.js') @@ -3702,20 +4259,45 @@ def test_file_packager_separate_metadata(self): # ensure some time passes before running the packager again so that if it does touch the # js file it will end up with the different timestamp. time.sleep(1.0) - self.run_process([FILE_PACKAGER, 'test.data', '--quiet', '--preload', 'data1.txt', '--preload', 'subdir/data2.txt', '--js-output=immutable.js', '--separate-metadata', '--use-preload-cache']) + self.run_process( + [ + FILE_PACKAGER, + 'test.data', + '--quiet', + '--preload', + 'data1.txt', + '--preload', + 'subdir/data2.txt', + '--js-output=immutable.js', + '--separate-metadata', + '--use-preload-cache', + ] + ) # assert both file content and timestamp are the same as reference copy self.assertTextDataIdentical(orig_content, read_file('immutable.js')) self.assertEqual(orig_timestamp, os.path.getmtime('immutable.js')) # verify the content of metadata file is correct metadata = json.loads(read_file('immutable.js.metadata')) self.assertEqual(len(metadata['files']), 2) - assert metadata['files'][0]['start'] == 0 and metadata['files'][0]['end'] == len('data1') and metadata['files'][0]['filename'] == '/data1.txt' - assert metadata['files'][1]['start'] == len('data1') and metadata['files'][1]['end'] == len('data1') + len('data2') and metadata['files'][1]['filename'] == '/subdir/data2.txt' + assert ( + metadata['files'][0]['start'] == 0 + and metadata['files'][0]['end'] == len('data1') + and metadata['files'][0]['filename'] == '/data1.txt' + ) + assert ( + metadata['files'][1]['start'] == len('data1') + and metadata['files'][1]['end'] == len('data1') + len('data2') + and metadata['files'][1]['filename'] == '/subdir/data2.txt' + ) assert metadata['remote_package_size'] == len('data1') + len('data2') - self.assertEqual(metadata['package_uuid'], 'sha256-53ddc03623f867c7d4a631ded19c2613f2cb61d47b6aa214f47ff3cc15445bcd') + self.assertEqual( + metadata['package_uuid'], 'sha256-53ddc03623f867c7d4a631ded19c2613f2cb61d47b6aa214f47ff3cc15445bcd' + ) - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -3727,7 +4309,8 @@ def test_file_packager_separate_metadata(self): printf("done\n"); return 0; } - ''') + ''', + ) self.do_runf('src.c', emcc_args=['--pre-js=immutable.js', '-sFORCE_FILESYSTEM']) def test_file_packager_unicode(self): @@ -3762,7 +4345,9 @@ def test_file_packager_mention_FORCE_FILESYSTEM(self): err = self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'data.txt'], stdout=PIPE, stderr=PIPE).stderr self.assertContained(MESSAGE, err) # do not mention from emcc - err = self.run_process([EMCC, test_file('hello_world.c'), '--preload-file', 'data.txt'], stdout=PIPE, stderr=PIPE).stderr + err = self.run_process( + [EMCC, test_file('hello_world.c'), '--preload-file', 'data.txt'], stdout=PIPE, stderr=PIPE + ).stderr self.assertEqual(len(err), 0) def test_file_packager_returns_error_if_target_equal_to_jsoutput(self): @@ -3774,12 +4359,16 @@ def test_file_packager_embed(self): create_file('data.txt', 'hello data') # Without --obj-output we issue a warning - err = self.run_process([FILE_PACKAGER, 'test.data', '--embed', 'data.txt', '--js-output=data.js'], stderr=PIPE).stderr + err = self.run_process( + [FILE_PACKAGER, 'test.data', '--embed', 'data.txt', '--js-output=data.js'], stderr=PIPE + ).stderr self.assertContained('--obj-output is recommended when using --embed', err) self.run_process([FILE_PACKAGER, 'test.data', '--embed', 'data.txt', '--obj-output=data.o']) - create_file('test.c', ''' + create_file( + 'test.c', + ''' #include int main() { @@ -3791,7 +4380,8 @@ def test_file_packager_embed(self): printf("%s\\n", buf); return 0; } - ''') + ''', + ) self.run_process([EMCC, 'test.c', 'data.o', '-sFORCE_FILESYSTEM']) output = self.run_js('a.out.js') self.assertContained('hello data', output) @@ -3802,13 +4392,15 @@ def test_file_packager_depfile(self): ensure_dir('subdir') create_file('subdir/data2.txt', 'data2') - self.run_process([FILE_PACKAGER, 'test.data', '--js-output=test.js', '--depfile=test.data.d', '--from-emcc', '--preload', '.']) + self.run_process( + [FILE_PACKAGER, 'test.data', '--js-output=test.js', '--depfile=test.data.d', '--from-emcc', '--preload', '.'] + ) output = read_file('test.data.d') file_packager = utils.normalize_path(shared.replace_suffix(FILE_PACKAGER, '.py')) file_packager = file_packager.replace(' ', '\\ ') lines = output.splitlines() split = lines.index(': \\') - before, after = set(lines[:split]), set(lines[split + 1:]) + before, after = set(lines[:split]), set(lines[split + 1 :]) # Set comparison used because depfile is not order-sensitive. self.assertTrue('test.data \\' in before) self.assertTrue('test.js \\' in before) @@ -3822,7 +4414,9 @@ def test_file_packager_modularize(self): create_file('somefile.txt', 'hello world') self.run_process([FILE_PACKAGER, 'test.data', '--js-output=embed.js', '--preload', 'somefile.txt']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main() { @@ -3834,11 +4428,22 @@ def test_file_packager_modularize(self): printf("|%s|\n", buf); return 0; } - ''') + ''', + ) create_file('post.js', 'MyModule(Module).then(() => console.log("done"));') - self.run_process([EMCC, 'main.c', '--extern-pre-js=embed.js', '--extern-post-js=post.js', '-sMODULARIZE', '-sEXPORT_NAME=MyModule', '-sFORCE_FILESYSTEM']) + self.run_process( + [ + EMCC, + 'main.c', + '--extern-pre-js=embed.js', + '--extern-post-js=post.js', + '-sMODULARIZE', + '-sEXPORT_NAME=MyModule', + '-sFORCE_FILESYSTEM', + ] + ) result = self.run_js('a.out.js') self.assertContained('|hello world|', result) @@ -3875,7 +4480,9 @@ def test_syntax_only_invalid(self): # `demangle` is a legacy JS function on longer used by emscripten # TODO(sbc): Remove `demangle` and this test. def test_demangle(self): - create_file('src.cpp', ''' + create_file( + 'src.cpp', + ''' #include #include @@ -3906,13 +4513,15 @@ def test_demangle(self): one(17); return 0; } - ''') + ''', + ) # full demangle support self.run_process([EMXX, 'src.cpp', '-sDEMANGLE_SUPPORT']) output = self.run_js('a.out.js') - self.assertContained('''operator new(unsigned long) + self.assertContained( + '''operator new(unsigned long) _main f2() abcdabcdabcd(int) @@ -3929,7 +4538,9 @@ def test_demangle(self): a(int [32], char (*) [5]) FWakaGLXFleeflsMarfoo::FWakaGLXFleeflsMarfoo(unsigned int, unsigned int, unsigned int, void const*, bool, unsigned int, unsigned int) void wakaw::Cm::RasterBase::merbine1::OR>(unsigned int const*, unsigned int) -''', output) +''', + output, + ) # test for multiple functions in one stack trace self.run_process([EMXX, 'src.cpp', '-sDEMANGLE_SUPPORT', '-g']) output = self.run_js('a.out.js') @@ -3937,7 +4548,9 @@ def test_demangle(self): self.assertIn('two(char)', output) def test_demangle_cpp(self): - create_file('src.cpp', ''' + create_file( + 'src.cpp', + ''' #include #include #include @@ -3952,7 +4565,8 @@ def test_demangle_cpp(self): printf("%s\\n", out); return 0; } - ''') + ''', + ) self.do_runf('src.cpp', 'Waka::f::a23412341234::point()') @@ -3963,7 +4577,7 @@ def test_demangle_malloc_infinite_loop_crash(self): output = self.run_js('a.out.js', assert_returncode=NON_ZERO) if output.count('Cannot enlarge memory arrays') > 5: print(output) - self.assertLess(output.count('Cannot enlarge memory arrays'), 6) + self.assertLess(output.count('Cannot enlarge memory arrays'), 6) @requires_node def test_module_exports_with_closure(self): @@ -3973,11 +4587,18 @@ def test_module_exports_with_closure(self): # object will not be visible to node.js # compile without --closure=1 - self.run_process([EMCC, test_file('module_exports/test.c'), - '-o', 'test.js', '-O2', - '-sEXPORTED_FUNCTIONS=_bufferTest,_malloc,_free', - '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap', - '-sWASM_ASYNC_COMPILATION=0']) + self.run_process( + [ + EMCC, + test_file('module_exports/test.c'), + '-o', + 'test.js', + '-O2', + '-sEXPORTED_FUNCTIONS=_bufferTest,_malloc,_free', + '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap', + '-sWASM_ASYNC_COMPILATION=0', + ] + ) # Check that test.js compiled without --closure=1 contains "module['exports'] = Module;" self.assertContained('module["exports"]=Module', read_file('test.js')) @@ -3991,11 +4612,19 @@ def test_module_exports_with_closure(self): delete_file('test.js') # compile with --closure=1 - self.run_process([EMCC, test_file('module_exports/test.c'), - '-o', 'test.js', '-O2', '--closure=1', - '-sEXPORTED_FUNCTIONS=_bufferTest,_malloc,_free', - '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap', - '-sWASM_ASYNC_COMPILATION=0']) + self.run_process( + [ + EMCC, + test_file('module_exports/test.c'), + '-o', + 'test.js', + '-O2', + '--closure=1', + '-sEXPORTED_FUNCTIONS=_bufferTest,_malloc,_free', + '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap', + '-sWASM_ASYNC_COMPILATION=0', + ] + ) # Check that test.js compiled with --closure 1 contains "module.exports", we want to verify that # "module['exports']" got minified to "module.exports" when compiling with --closure 1 @@ -4009,45 +4638,54 @@ def test_module_exports_with_closure(self): def test_node_catch_exit(self): # Test that in top level JS exceptions are caught and rethrown when NODEJS_EXIT_CATCH=1 # is set but not by default. - create_file('count.c', ''' + create_file( + 'count.c', + ''' #include int count(const char *str) { return (int)strlen(str); } - ''') + ''', + ) - create_file('index.js', ''' + create_file( + 'index.js', + ''' const count = require('./count.js'); console.log(xxx); //< here is the ReferenceError - ''') + ''', + ) reference_error_text = 'console.log(xxx); //< here is the ReferenceError' self.run_process([EMCC, 'count.c', '-o', 'count.js', '-sNODEJS_CATCH_EXIT=1']) # Check that the ReferenceError is caught and rethrown and thus the original error line is masked - self.assertNotContained(reference_error_text, - self.run_js('index.js', assert_returncode=NON_ZERO)) + self.assertNotContained(reference_error_text, self.run_js('index.js', assert_returncode=NON_ZERO)) self.run_process([EMCC, 'count.c', '-o', 'count.js']) # Check that the ReferenceError is not caught, so we see the error properly - self.assertContained(reference_error_text, - self.run_js('index.js', assert_returncode=NON_ZERO)) + self.assertContained(reference_error_text, self.run_js('index.js', assert_returncode=NON_ZERO)) @requires_node def test_exported_runtime_methods(self): # Test with node.js that the EXPORTED_RUNTIME_METHODS setting is # considered by libraries - create_file('count.c', ''' + create_file( + 'count.c', + ''' #include int count(const char *str) { return (int)strlen(str); } - ''') + ''', + ) - create_file('index.js', ''' + create_file( + 'index.js', + ''' const count = require('./count.js'); console.log(count.FS_writeFile); count.onRuntimeInitialized = () => { @@ -4057,10 +4695,20 @@ def test_exported_runtime_methods(self): console.log('wasmExports NOT found'); } }; - ''') + ''', + ) - self.run_process([EMCC, 'count.c', '-sFORCE_FILESYSTEM', '-sEXPORTED_FUNCTIONS=_count', - '-sEXPORTED_RUNTIME_METHODS=FS_writeFile,wasmExports', '-o', 'count.js']) + self.run_process( + [ + EMCC, + 'count.c', + '-sFORCE_FILESYSTEM', + '-sEXPORTED_FUNCTIONS=_count', + '-sEXPORTED_RUNTIME_METHODS=FS_writeFile,wasmExports', + '-o', + 'count.js', + ] + ) # Check that the Module.FS_writeFile exists out = self.run_js('index.js') @@ -4071,21 +4719,26 @@ def test_exported_runtime_methods(self): # Check that the Module.FS_writeFile is not exported out = self.run_js('index.js', assert_returncode=NON_ZERO) - self.assertContained('undefined', out), + (self.assertContained('undefined', out),) self.assertContained("Aborted('wasmExports' was not exported. add it to EXPORTED_RUNTIME_METHODS", out) def test_exported_runtime_methods_from_js_library(self): - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.onRuntimeInitialized = () => { out(Module.ptrToString(88)); out('done'); }; - ''') + ''', + ) self.do_runf('hello_world.c', 'done', emcc_args=['--pre-js=pre.js', '-sEXPORTED_RUNTIME_METHODS=ptrToString']) @crossplatform def test_fs_stream_proto(self): - create_file('src.c', br''' + create_file( + 'src.c', + rb''' #include #include #include @@ -4115,7 +4768,9 @@ def test_fs_stream_proto(self): } return 0; } -''', binary=True) +''', + binary=True, + ) self.run_process([EMCC, 'src.c', '--embed-file', 'src.c', '-sENVIRONMENT=node,shell']) for engine in config.JS_ENGINES: out = self.run_js('a.out.js', engine=engine) @@ -4124,7 +4779,9 @@ def test_fs_stream_proto(self): @node_pthreads def test_node_emscripten_num_logical_cores(self): # Test with node.js that the emscripten_num_logical_cores method is working - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -4134,7 +4791,8 @@ def test_node_emscripten_num_logical_cores(self): assert(num != 0); puts("ok"); } -''') +''', + ) self.do_runf('src.c', 'ok') def test_proxyfs(self): @@ -4154,7 +4812,9 @@ def test_proxyfs(self): # var m1 = require('./proxyfs_test1.js'); # var m2 = require('./proxyfs_test2.js'); # - create_file('proxyfs_test_main.js', r''' + create_file( + 'proxyfs_test_main.js', + r''' var m0 = require('./proxyfs_test.js'); var m1 = require('./proxyfs_test1.js'); var m2 = require('./proxyfs_test2.js'); @@ -4251,15 +4911,21 @@ def test_proxyfs(self): section = "test seek."; print("file size"); m0.ccall('myreadSeekEnd', 'number', [], []); -''') +''', + ) - create_file('proxyfs_pre.js', r''' + create_file( + 'proxyfs_pre.js', + r''' Module["noInitialRun"]=true; -''') +''', + ) create_file('proxyfs_embed.txt', 'test\n') - create_file('proxyfs_test.c', r''' + create_file( + 'proxyfs_test.c', + r''' #include #include #include @@ -4385,14 +5051,24 @@ def test_proxyfs(self): fclose(in); return 0; } -''') - - self.run_process([EMCC, - '-o', 'proxyfs_test.js', 'proxyfs_test.c', - '--embed-file', 'proxyfs_embed.txt', '--pre-js', 'proxyfs_pre.js', - '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap,FS,PROXYFS', - '-lproxyfs.js', - '-sWASM_ASYNC_COMPILATION=0']) +''', + ) + + self.run_process( + [ + EMCC, + '-o', + 'proxyfs_test.js', + 'proxyfs_test.c', + '--embed-file', + 'proxyfs_embed.txt', + '--pre-js', + 'proxyfs_pre.js', + '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap,FS,PROXYFS', + '-lproxyfs.js', + '-sWASM_ASYNC_COMPILATION=0', + ] + ) # Following shutil.copy just prevent 'require' of node.js from caching js-object. # See https://nodejs.org/api/modules.html shutil.copy('proxyfs_test.js', 'proxyfs_test1.js') @@ -4444,16 +5120,22 @@ def test_dependency_file(self): # Issue 1732: -MMD (and friends) create dependency files that need to be # copied from the temporary directory. - create_file('test.c', r''' + create_file( + 'test.c', + r''' #include "test.h" void my_function() { } - ''') - create_file('test.h', r''' + ''', + ) + create_file( + 'test.h', + r''' void my_function(); - ''') + ''', + ) self.run_process([EMCC, '-MMD', '-c', 'test.c', '-o', 'test.o']) self.assertExists('test.d') @@ -4484,7 +5166,9 @@ def test_compilation_database(self): self.assertContained('"file": "a.c", "output": "test.o"', read_file('hello.json')) def test_js_lib_no_override(self): - create_file('duplicated_func.c', ''' + create_file( + 'duplicated_func.c', + ''' #include extern int duplicatedFunc(); @@ -4493,29 +5177,41 @@ def test_js_lib_no_override(self): printf("*%d*\\n", res); return 0; } - ''') - create_file('duplicated_func_1.js', ''' + ''', + ) + create_file( + 'duplicated_func_1.js', + ''' addToLibrary( { duplicatedFunc: () => 1 }, { noOverride: true } ); - ''') - create_file('duplicated_func_2.js', ''' + ''', + ) + create_file( + 'duplicated_func_2.js', + ''' addToLibrary( { duplicatedFunc: () => 2 }, { noOverride: true } ); - ''') + ''', + ) self.emcc_args += ['--js-library', 'duplicated_func_1.js', '--js-library', 'duplicated_func_2.js'] err = self.expect_fail([EMCC, 'duplicated_func.c'] + self.get_emcc_args()) - self.assertContained('duplicated_func_2.js: Symbol re-definition in JavaScript library: duplicatedFunc. Do not use noOverride if this is intended', err) + self.assertContained( + 'duplicated_func_2.js: Symbol re-definition in JavaScript library: duplicatedFunc. Do not use noOverride if this is intended', + err, + ) def test_override_stub(self): self.do_other_test('test_override_stub.c') def test_js_lib_missing_sig(self): - create_file('some_func.c', ''' + create_file( + 'some_func.c', + ''' #include extern int someFunc(); @@ -4524,23 +5220,31 @@ def test_js_lib_missing_sig(self): printf("*%d*\\n", res); return 0; } - ''') - create_file('some_func.js', ''' + ''', + ) + create_file( + 'some_func.js', + ''' addToLibrary( { someFunc: () => 1 }, { checkSig: true } ); - ''') + ''', + ) self.emcc_args += ['--js-library', 'some_func.js'] err = self.expect_fail([EMCC, 'some_func.c'] + self.get_emcc_args()) - self.assertContained('some_func.js: __sig is missing for function: someFunc. Do not use checkSig if this is intended', err) + self.assertContained( + 'some_func.js: __sig is missing for function: someFunc. Do not use checkSig if this is intended', err + ) def test_js_lib_extra_args(self): # Verify that extra arguments in addition to those listed in `__sig` are still present # in the generated JS library function. # See https://github.com/emscripten-core/emscripten/issues/21056 - create_file('some_func.js', ''' + create_file( + 'some_func.js', + ''' addToLibrary({ someFunc: (arg1, arg2) => { err('arg1:' + arg1); @@ -4548,18 +5252,24 @@ def test_js_lib_extra_args(self): }, someFunc__sig: 'pp', }); - ''') - create_file('test.c', ''' + ''', + ) + create_file( + 'test.c', + ''' void someFunc(long p); int main() { someFunc(42); } - ''') + ''', + ) self.emcc_args += ['--js-library', 'some_func.js', '-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=4Gb'] self.do_runf('test.c', 'arg1:42\narg2:undefined\n') def test_js_lib_quoted_key(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ __internal_data:{ '<' : 0, @@ -4570,7 +5280,8 @@ def test_js_lib_quoted_key(self): return 0; } }); -''') +''', + ) self.do_run_in_out_file_test('hello_world.c', emcc_args=['--js-library', 'lib.js']) @@ -4579,7 +5290,9 @@ def test_js_lib_proxying(self): # the inner function in a library function consisting of a single # line arrow function. # See https://github.com/emscripten-core/emscripten/issues/20264 - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ $doNotCall: (x) => {}, foo__deps: ['$doNotCall'], @@ -4588,8 +5301,11 @@ def test_js_lib_proxying(self): out('should never see this'); }), }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include void foo(); int main() { @@ -4597,33 +5313,47 @@ def test_js_lib_proxying(self): foo(); printf("done\n"); } - ''') - self.do_runf('src.c', 'main\ndone\n', emcc_args=['-sEXIT_RUNTIME', '-pthread', '-sPROXY_TO_PTHREAD', '--js-library', 'lib.js']) + ''', + ) + self.do_runf( + 'src.c', 'main\ndone\n', emcc_args=['-sEXIT_RUNTIME', '-pthread', '-sPROXY_TO_PTHREAD', '--js-library', 'lib.js'] + ) def test_js_lib_method_syntax(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ foo() { out('foo'); }, }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include void foo(); int main() { foo(); } - ''') + ''', + ) self.do_runf('src.c', 'foo', emcc_args=['--js-library', 'lib.js']) def test_js_lib_exported(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslibfunc: (x) => 2 * x }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include #include int jslibfunc(int x); @@ -4633,12 +5363,18 @@ def test_js_lib_exported(self): out('js calling: ' + Module['_jslibfunc'](5) + '.'); }); } -''') - self.do_runf('src.c', 'c calling: 12\njs calling: 10.', - emcc_args=['--js-library', 'lib.js', '-sEXPORTED_FUNCTIONS=_main,_jslibfunc']) +''', + ) + self.do_runf( + 'src.c', + 'c calling: 12\njs calling: 10.', + emcc_args=['--js-library', 'lib.js', '-sEXPORTED_FUNCTIONS=_main,_jslibfunc'], + ) def test_js_lib_using_asm_lib(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslibfunc__deps: ['asmlibfunc'], jslibfunc: (x) => 2 * _asmlibfunc(x), @@ -4650,53 +5386,73 @@ def test_js_lib_using_asm_lib(self): return x + 1 | 0; } }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include int jslibfunc(int x); int main() { printf("c calling: %d\n", jslibfunc(6)); } -''') +''', + ) self.do_runf('src.c', 'c calling: 14\n', emcc_args=['--js-library', 'lib.js']) def test_js_lib_errors(self): - create_file('lib.js', '''\ + create_file( + 'lib.js', + '''\ // This is a library file #endif // line 2 -''') +''', + ) err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js']) self.assertContained('lib.js:2: #endif without matching #if', err) - create_file('lib.js', '''\ + create_file( + 'lib.js', + '''\ // This is a library file #else // line 3 -''') +''', + ) err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js']) self.assertContained('lib.js:3: #else without matching #if', err) def test_js_internal_deps(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslibfunc__deps: ['$callRuntimeCallbacks'], jslibfunc: (x) => { callRuntimeCallbacks(); }, }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include int jslibfunc(); int main() { printf("c calling: %d\n", jslibfunc()); } -''') +''', + ) err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr - self.assertContained("warning: user library symbol 'jslibfunc' depends on internal symbol '$callRuntimeCallbacks'", err) + self.assertContained( + "warning: user library symbol 'jslibfunc' depends on internal symbol '$callRuntimeCallbacks'", err + ) def test_js_lib_sig_redefinition(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslibfunc__sig: 'ii', jslibfunc: (x) => {}, @@ -4706,91 +5462,129 @@ def test_js_lib_sig_redefinition(self): jslibfunc__sig: 'ii', jslibfunc: (x) => {}, }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include int jslibfunc(); int main() { printf("c calling: %d\n", jslibfunc()); } -''') +''', + ) err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr self.assertContained('lib.js: signature redefinition for: jslibfunc__sig', err) # Add another redefinition, this time not matching - create_file('lib2.js', r''' + create_file( + 'lib2.js', + r''' addToLibrary({ jslibfunc__sig: 'pp', jslibfunc: (x) => {}, }); -''') +''', + ) err = self.expect_fail([EMCC, 'src.c', '--js-library', 'lib.js', '--js-library', 'lib2.js']) self.assertContained('lib2.js: signature redefinition for: jslibfunc__sig. (old=ii vs new=pp)', err) def test_js_lib_invalid_deps(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslibfunc__deps: 'hello', jslibfunc: (x) => {}, }); -''') +''', + ) err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js']) - self.assertContained('lib.js: JS library directive jslibfunc__deps=hello is of type \'string\', but it should be an array', err) + self.assertContained( + 'lib.js: JS library directive jslibfunc__deps=hello is of type \'string\', but it should be an array', err + ) - create_file('lib2.js', r''' + create_file( + 'lib2.js', + r''' addToLibrary({ jslibfunc__deps: [1,2,3], jslibfunc: (x) => {}, }); -''') +''', + ) err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib2.js']) - self.assertContained("lib2.js: __deps entries must be of type 'string' or 'function' not 'number': jslibfunc__deps", err) + self.assertContained( + "lib2.js: __deps entries must be of type 'string' or 'function' not 'number': jslibfunc__deps", err + ) def test_js_lib_invalid_decorator(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslibfunc__async: 'hello', jslibfunc: (x) => {}, }); -''') +''', + ) err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js']) self.assertContained("lib.js: Decorator (jslibfunc__async} has wrong type. Expected 'boolean' not 'string'", err) def test_js_lib_i53abi(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' mergeInto(LibraryManager.library, { jslibfunc__i53abi: true, jslibfunc: (x) => { return 42 }, }); -''') - err = self.expect_fail([EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js']) +''', + ) + err = self.expect_fail( + [EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js'] + ) self.assertContained("error: JS library error: '__i53abi' decorator requires '__sig' decorator: 'jslibfunc'", err) - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' mergeInto(LibraryManager.library, { jslibfunc__i53abi: true, jslibfunc__sig: 'ii', jslibfunc: (x) => { return 42 }, }); -''') - err = self.expect_fail([EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js']) - self.assertContained("error: JS library error: '__i53abi' only makes sense when '__sig' includes 'j' (int64): 'jslibfunc'", err) +''', + ) + err = self.expect_fail( + [EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js'] + ) + self.assertContained( + "error: JS library error: '__i53abi' only makes sense when '__sig' includes 'j' (int64): 'jslibfunc'", err + ) def test_js_lib_legacy(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' mergeInto(LibraryManager.library, { jslibfunc: (x) => { return 42 }, }); -''') - create_file('src.c', r''' +''', + ) + create_file( + 'src.c', + r''' #include int jslibfunc(); int main() { printf("main: %d\n", jslibfunc()); } -''') +''', + ) self.do_runf('src.c', 'main: 42\n', emcc_args=['--js-library', 'lib.js']) # Tests that users can pass custom JS options from command line using @@ -4800,21 +5594,28 @@ def test_js_lib_custom_settings(self): self.emcc_args += ['--js-library', test_file('core/test_custom_js_settings.js'), '-jsDCUSTOM_JS_OPTION=1'] self.do_other_test('test_js_lib_custom_settings.c') - self.assertContained('cannot change built-in settings values with a -jsD directive', self.expect_fail([EMCC, '-jsDWASM=0'])) + self.assertContained( + 'cannot change built-in settings values with a -jsD directive', self.expect_fail([EMCC, '-jsDWASM=0']) + ) def test_EMCC_BUILD_DIR(self): # EMCC_BUILD_DIR env var contains the dir we were building in, when running the js compiler (e.g. when # running a js library). We force the cwd to be src/ for technical reasons, so this lets you find out # where you were. - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' printErr('dir was ' + process.env.EMCC_BUILD_DIR); -''') +''', + ) err = self.run_process([EMXX, test_file('hello_world.c'), '--js-library', 'lib.js'], stderr=PIPE).stderr self.assertContained('dir was ' + os.path.realpath(os.path.normpath(self.get_dir())), err) def test_float_h(self): process = self.run_process([EMCC, test_file('float+.c')], stdout=PIPE, stderr=PIPE) - assert process.returncode == 0, 'float.h should agree with our system: ' + process.stdout + '\n\n\n' + process.stderr + assert process.returncode == 0, ( + 'float.h should agree with our system: ' + process.stdout + '\n\n\n' + process.stderr + ) def test_output_is_dir(self): ensure_dir('out_dir') @@ -4822,7 +5623,9 @@ def test_output_is_dir(self): self.assertContained('error: unable to open output file', err) def test_doublestart_bug(self): - create_file('code.c', r''' + create_file( + 'code.c', + r''' #include #include @@ -4836,14 +5639,18 @@ def test_doublestart_bug(self): emscripten_set_main_loop(main_loop, 10, 0); return 0; } -''') +''', + ) - create_file('pre.js', r''' + create_file( + 'pre.js', + r''' Module["preRun"] = () => { addRunDependency('test_run_dependency'); removeRunDependency('test_run_dependency'); }; -''') +''', + ) self.run_process([EMCC, 'code.c', '--pre-js', 'pre.js']) output = self.run_js('a.out.js') @@ -4851,17 +5658,23 @@ def test_doublestart_bug(self): self.assertEqual(output.count('This should only appear once.'), 1) def test_module_print(self): - create_file('code.c', r''' + create_file( + 'code.c', + r''' #include int main(void) { printf("123456789\n"); return 0; } -''') +''', + ) - create_file('pre.js', r''' + create_file( + 'pre.js', + r''' Module.print = (x) => { throw '<{(' + x + ')}>' }; -''') +''', + ) self.run_process([EMCC, 'code.c', '--pre-js', 'pre.js']) output = self.run_js('a.out.js', assert_returncode=NON_ZERO) @@ -4873,25 +5686,30 @@ def test_precompiled_headers_warnings(self): create_file('header.h', '#define X 5\n') self.run_process([EMCC, '-Werror', '-xc++-header', 'header.h']) - @parameterized({ - 'gch': ['gch'], - 'pch': ['pch'], - }) + @parameterized( + { + 'gch': ['gch'], + 'pch': ['pch'], + } + ) def test_precompiled_headers(self, suffix): create_file('header.h', '#define X 5\n') self.run_process([EMCC, '-xc++-header', 'header.h', '-c']) - self.assertExists('header.h.pch') # default output is pch + self.assertExists('header.h.pch') # default output is pch if suffix != 'pch': self.run_process([EMCC, '-xc++-header', 'header.h', '-o', 'header.h.' + suffix]) self.assertBinaryEqual('header.h.pch', 'header.h.' + suffix) - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include int main() { printf("|%d|\n", X); return 0; } -''') +''', + ) self.run_process([EMCC, 'src.cpp', '-include', 'header.h']) output = self.run_js('a.out.js') @@ -4944,29 +5762,37 @@ def add_on_abort_and_verify(extra=''): # test direct abort() C call - create_file('src.c', ''' + create_file( + 'src.c', + ''' #include int main() { abort(); } - ''') + ''', + ) self.run_process([EMCC, 'src.c', '-sWASM_ASYNC_COMPILATION=0']) add_on_abort_and_verify() # test direct abort() JS call - create_file('src.c', ''' + create_file( + 'src.c', + ''' #include int main() { EM_ASM({ abort() }); } - ''') + ''', + ) self.run_process([EMCC, 'src.c', '-sWASM_ASYNC_COMPILATION=0']) add_on_abort_and_verify() # test throwing in an abort handler, and catching that - create_file('src.c', ''' + create_file( + 'src.c', + ''' #include int main() { EM_ASM({ @@ -4980,7 +5806,8 @@ def add_on_abort_and_verify(extra=''): } }); } - ''') + ''', + ) self.run_process([EMCC, 'src.c', '-sWASM_ASYNC_COMPILATION=0']) js = read_file('a.out.js') with open('a.out.js', 'w') as f: @@ -4996,17 +5823,21 @@ def add_on_abort_and_verify(extra=''): # test an abort during startup self.run_process([EMCC, test_file('hello_world.c')]) - os.remove('a.out.wasm') # trigger onAbort by intentionally causing startup to fail + os.remove('a.out.wasm') # trigger onAbort by intentionally causing startup to fail add_on_abort_and_verify() @also_with_wasm2js - @parameterized({ - '': ([],), - '01': (['-O1', '-g2'],), - 'O2': (['-O2', '-g2', '-flto'],), - }) + @parameterized( + { + '': ([],), + '01': (['-O1', '-g2'],), + 'O2': (['-O2', '-g2', '-flto'],), + } + ) def test_no_exit_runtime(self, opts): - create_file('code.cpp', r''' + create_file( + 'code.cpp', + r''' #include template @@ -5028,13 +5859,14 @@ def test_no_exit_runtime(self, opts): int main(int argc, char **argv) { return 0; } - ''') + ''', + ) for no_exit in (1, 0): print(no_exit) cmd = [EMXX] + opts + ['code.cpp', '-sEXIT_RUNTIME=' + str(1 - no_exit)] + self.get_emcc_args() if self.is_wasm(): - cmd += ['--profiling-funcs'] # for function names + cmd += ['--profiling-funcs'] # for function names self.run_process(cmd) output = self.run_js('a.out.js') src = read_file('a.out.js') @@ -5054,7 +5886,9 @@ def test_no_exit_runtime(self, opts): def test_no_exit_runtime_warnings_flush(self): # check we warn if there is unflushed info - create_file('code.c', r''' + create_file( + 'code.c', + r''' #include #include int main(int argc, char **argv) { @@ -5067,8 +5901,11 @@ def test_no_exit_runtime_warnings_flush(self): emscripten_exit_with_live_runtime(); #endif } -''') - create_file('code.cpp', r''' +''', + ) + create_file( + 'code.cpp', + r''' #include #include int main() { @@ -5082,7 +5919,8 @@ def test_no_exit_runtime_warnings_flush(self): emscripten_exit_with_live_runtime(); #endif } -''') +''', + ) warning = 'warning: stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1' def test(cxx, no_exit, assertions, flush=0, keepalive=0, filesystem=1): @@ -5090,7 +5928,10 @@ def test(cxx, no_exit, assertions, flush=0, keepalive=0, filesystem=1): cmd = [EMXX, 'code.cpp'] else: cmd = [EMCC, 'code.c'] - print('%s: no_exit=%d assertions=%d flush=%d keepalive=%d filesystem=%d' % (cmd[1], no_exit, assertions, flush, keepalive, filesystem)) + print( + '%s: no_exit=%d assertions=%d flush=%d keepalive=%d filesystem=%d' + % (cmd[1], no_exit, assertions, flush, keepalive, filesystem) + ) cmd += ['-sEXIT_RUNTIME=%d' % (1 - no_exit), '-sASSERTIONS=%d' % assertions] if flush: cmd += ['-DFLUSH'] @@ -5127,24 +5968,26 @@ def test_extra_opt_levels(self): self.assertContained(opt, proc.stderr) self.assertContained('hello, world!', self.run_js('a.out.js')) - @parameterized({ - '': [[]], - 'O1': [['-O1']], - }) + @parameterized( + { + '': [[]], + 'O1': [['-O1']], + } + ) def test_fs_after_main(self, args): self.do_runf('test_fs_after_main.c', 'Test passed.') def test_oz_size(self): sizes = {} for name, args in [ - ('0', []), - ('1', ['-O1']), - ('2', ['-O2']), - ('s', ['-Os']), - ('z', ['-Oz']), - ('3', ['-O3']), - ('g', ['-Og']), - ]: + ('0', []), + ('1', ['-O1']), + ('2', ['-O2']), + ('s', ['-Os']), + ('z', ['-Oz']), + ('3', ['-O3']), + ('g', ['-Og']), + ]: print(name, args) self.clear() self.run_process([EMCC, '-c', path_from_root('system/lib/dlmalloc.c')] + args) @@ -5159,7 +6002,9 @@ def test_oz_size(self): @disabled('relies on fastcomp EXIT_RUNTIME=0 optimization not implemented/disabled') def test_global_inits(self): - create_file('inc.h', r''' + create_file( + 'inc.h', + r''' #include template @@ -5175,9 +6020,12 @@ def test_global_inits(self): }; Waste<3> *getMore(); -''') +''', + ) - create_file('main.cpp', r''' + create_file( + 'main.cpp', + r''' #include "inc.h" Waste<1> mw1; @@ -5192,9 +6040,12 @@ def test_global_inits(self): getMore()->test(0); return 0; } -''') +''', + ) - create_file('side.cpp', r''' + create_file( + 'side.cpp', + r''' #include "inc.h" Waste<3> sw3; @@ -5202,7 +6053,8 @@ def test_global_inits(self): Waste<3> *getMore() { return &sw3; } -''') +''', + ) for opts, has_global in [ (['-O2', '-g', '-sEXIT_RUNTIME'], True), @@ -5231,7 +6083,8 @@ def test_implicit_func(self): INCOMPATIBLE = ': incompatible function pointer types' stderr = self.expect_fail( - [EMCC, path_from_root('test/other/test_implicit_func.c'), '-c', '-o', 'implicit_func.o', '-std=gnu89']) + [EMCC, path_from_root('test/other/test_implicit_func.c'), '-c', '-o', 'implicit_func.o', '-std=gnu89'] + ) self.assertContained(IMPLICIT_C89, stderr) self.assertContained(INCOMPATIBLE, stderr) @@ -5241,25 +6094,51 @@ def test_bad_triple(self): # compile a minimal program, with as few dependencies as possible, as # native building on CI may not always work well create_file('minimal.c', 'int main() { return 0; }') - self.run_process([CLANG_CC, 'minimal.c', '-target', 'x86_64-linux', '-c', '-emit-llvm', '-o', 'a.bc'] + clang_native.get_clang_native_args(), env=clang_native.get_clang_native_env()) + self.run_process( + [CLANG_CC, 'minimal.c', '-target', 'x86_64-linux', '-c', '-emit-llvm', '-o', 'a.bc'] + + clang_native.get_clang_native_args(), + env=clang_native.get_clang_native_env(), + ) err = self.expect_fail([EMCC, '-Werror', 'a.bc']) - self.assertContained('error: overriding the module target triple with wasm32-unknown-emscripten [-Werror,-Woverride-module]', err) + self.assertContained( + 'error: overriding the module target triple with wasm32-unknown-emscripten [-Werror,-Woverride-module]', err + ) def test_valid_abspath(self): # Test whether abspath warning appears abs_include_path = os.path.abspath(self.get_dir()) - err = self.run_process([EMCC, '-I%s' % abs_include_path, '-Wwarn-absolute-paths', test_file('hello_world.c')], stderr=PIPE).stderr - warning = '-I or -L of an absolute path "-I%s" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript).' % abs_include_path + err = self.run_process( + [EMCC, '-I%s' % abs_include_path, '-Wwarn-absolute-paths', test_file('hello_world.c')], stderr=PIPE + ).stderr + warning = ( + '-I or -L of an absolute path "-I%s" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript).' + % abs_include_path + ) self.assertContained(warning, err) # Passing an absolute path to a directory inside the emscripten tree is always ok and should not issue a warning. abs_include_path = TEST_ROOT - err = self.run_process([EMCC, '-I%s' % abs_include_path, '-Wwarn-absolute-paths', test_file('hello_world.c')], stderr=PIPE).stderr - warning = '-I or -L of an absolute path "-I%s" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript).' % abs_include_path + err = self.run_process( + [EMCC, '-I%s' % abs_include_path, '-Wwarn-absolute-paths', test_file('hello_world.c')], stderr=PIPE + ).stderr + warning = ( + '-I or -L of an absolute path "-I%s" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript).' + % abs_include_path + ) self.assertNotContained(warning, err) # Hide warning for this include path - err = self.run_process([EMCC, '--valid-abspath', abs_include_path, '-I%s' % abs_include_path, '-Wwarn-absolute-paths', test_file('hello_world.c')], stderr=PIPE).stderr + err = self.run_process( + [ + EMCC, + '--valid-abspath', + abs_include_path, + '-I%s' % abs_include_path, + '-Wwarn-absolute-paths', + test_file('hello_world.c'), + ], + stderr=PIPE, + ).stderr self.assertNotContained(warning, err) def test_valid_abspath_2(self): @@ -5286,15 +6165,19 @@ def test_warn_dylibs(self): self.assertContainedIf(warning, err, suffix in shared_suffixes) @crossplatform - @parameterized({ - 'O2': [['-O2']], - 'O3': [['-O3']], - }) - @parameterized({ - '': [1], - 'wasm2js': [0], - 'wasm2js_2': [2], - }) + @parameterized( + { + 'O2': [['-O2']], + 'O3': [['-O3']], + } + ) + @parameterized( + { + '': [1], + 'wasm2js': [0], + 'wasm2js_2': [2], + } + ) def test_symbol_map(self, opts, wasm): def get_symbols_lines(symbols_file): self.assertTrue(os.path.isfile(symbols_file), "Symbols file %s isn't created" % symbols_file) @@ -5323,7 +6206,9 @@ def guess_symbols_file_type(symbols_file): UNMINIFIED_MIDDLE = 'function middle' self.clear() - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include EM_JS(int, run_js, (), { @@ -5342,7 +6227,8 @@ def guess_symbols_file_type(symbols_file): int main() { EM_ASM({ _middle() }); } -''') +''', + ) cmd = [EMCC, 'src.c', '--emit-symbol-map'] + opts if wasm != 1: cmd.append(f'-sWASM={wasm}') @@ -5363,15 +6249,23 @@ def guess_symbols_file_type(symbols_file): # Ensure symbols file type according to `-sWASM=` mode if wasm == 0: - self.assertEqual(guess_symbols_file_type('a.out.js.symbols'), 'js', 'Primary symbols file should store JS mappings') + self.assertEqual( + guess_symbols_file_type('a.out.js.symbols'), 'js', 'Primary symbols file should store JS mappings' + ) elif wasm == 1: - self.assertEqual(guess_symbols_file_type('a.out.js.symbols'), 'wasm', 'Primary symbols file should store Wasm mappings') + self.assertEqual( + guess_symbols_file_type('a.out.js.symbols'), 'wasm', 'Primary symbols file should store Wasm mappings' + ) elif wasm == 2: # special case when both JS and Wasm targets are created minified_middle_2 = get_minified_middle('a.out.wasm.js.symbols') self.assertNotEqual(minified_middle_2, None, "Missing minified 'middle' function") - self.assertEqual(guess_symbols_file_type('a.out.js.symbols'), 'wasm', 'Primary symbols file should store Wasm mappings') - self.assertEqual(guess_symbols_file_type('a.out.wasm.js.symbols'), 'js', 'Secondary symbols file should store JS mappings') + self.assertEqual( + guess_symbols_file_type('a.out.js.symbols'), 'wasm', 'Primary symbols file should store Wasm mappings' + ) + self.assertEqual( + guess_symbols_file_type('a.out.wasm.js.symbols'), 'js', 'Secondary symbols file should store JS mappings' + ) return # check we don't keep unnecessary debug info with wasm2js when emitting @@ -5386,12 +6280,14 @@ def guess_symbols_file_type(symbols_file): self.assertContained(UNMINIFIED_HEAP8, js) self.assertContained(UNMINIFIED_MIDDLE, js) - @parameterized({ - '': [[]], - # bigint support is interesting to test here because it changes which - # binaryen tools get run, which can affect how debug info is kept around - 'bigint': [['-sWASM_BIGINT']], - }) + @parameterized( + { + '': [[]], + # bigint support is interesting to test here because it changes which + # binaryen tools get run, which can affect how debug info is kept around + 'bigint': [['-sWASM_BIGINT']], + } + ) def test_symbol_map_output_size(self, args): # build with and without a symbol map and verify that the sizes are the # same. using a symbol map should add the map on the side, but not increase @@ -5418,14 +6314,18 @@ def test_bitcode_linking(self): is_bitcode('hello_world.o') building.is_wasm('hello_world2.o') - @parameterized({ - '': (True, False), - 'safe_heap': (True, True), - 'wasm2js': (False, False), - 'wasm2js_safe_heap': (False, True), - }) + @parameterized( + { + '': (True, False), + 'safe_heap': (True, True), + 'wasm2js': (False, False), + 'wasm2js_safe_heap': (False, True), + } + ) def test_bad_function_pointer_cast(self, wasm, safe): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include typedef int (*callback) (int, ...); @@ -5440,7 +6340,8 @@ def test_bad_function_pointer_cast(self, wasm, safe): f(0); /* This fails with or without additional arguments. */ return 0; } -''') +''', + ) for opts in (0, 1, 2): for emulate_casts in (0, 1): @@ -5456,7 +6357,7 @@ def test_bad_function_pointer_cast(self, wasm, safe): if emulate_casts: cmd += ['-sEMULATE_FUNCTION_POINTER_CASTS'] if relocatable: - cmd += ['-sRELOCATABLE'] # disables asm-optimized safe heap + cmd += ['-sRELOCATABLE'] # disables asm-optimized safe heap print(cmd) self.run_process(cmd) returncode = 0 if emulate_casts or not wasm else NON_ZERO @@ -5491,8 +6392,7 @@ def test_no_dynamic_execution(self): # Test that --preload-file doesn't add an use of eval(). create_file('temp.txt', "foo\n") - self.run_process([EMCC, test_file('hello_world.c'), '-O1', - '-sDYNAMIC_EXECUTION=0', '--preload-file', 'temp.txt']) + self.run_process([EMCC, test_file('hello_world.c'), '-O1', '-sDYNAMIC_EXECUTION=0', '--preload-file', 'temp.txt']) src = read_file('a.out.js') self.assertNotContained('eval(', src) self.assertNotContained('eval.', src) @@ -5502,27 +6402,36 @@ def test_no_dynamic_execution(self): # Test that -sDYNAMIC_EXECUTION=0 and -sRELOCATABLE are allowed together. self.do_runf('hello_world.c', emcc_args=['-O1', '-sDYNAMIC_EXECUTION=0', '-sRELOCATABLE']) - create_file('test.c', r''' + create_file( + 'test.c', + r''' #include int main() { emscripten_run_script("console.log('hello from script');"); return 0; } - ''') + ''', + ) # Test that emscripten_run_script() aborts when -sDYNAMIC_EXECUTION=0 self.run_process([EMCC, 'test.c', '-O1', '-sDYNAMIC_EXECUTION=0']) - self.assertContained('DYNAMIC_EXECUTION=0 was set, cannot eval', self.run_js('a.out.js', assert_returncode=NON_ZERO)) + self.assertContained( + 'DYNAMIC_EXECUTION=0 was set, cannot eval', self.run_js('a.out.js', assert_returncode=NON_ZERO) + ) delete_file('a.out.js') # Test that emscripten_run_script() posts a warning when -sDYNAMIC_EXECUTION=2 self.run_process([EMCC, 'test.c', '-O1', '-sDYNAMIC_EXECUTION=2']) - self.assertContained('Warning: DYNAMIC_EXECUTION=2 was set, but calling eval in the following location:', self.run_js('a.out.js')) + self.assertContained( + 'Warning: DYNAMIC_EXECUTION=2 was set, but calling eval in the following location:', self.run_js('a.out.js') + ) self.assertContained('hello from script', self.run_js('a.out.js')) delete_file('a.out.js') def test_init_file_at_offset(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { int data = 0x12345678; @@ -5540,7 +6449,8 @@ def test_init_file_at_offset(self): fclose(f); printf("file size is %ld\n", size); } - ''') + ''', + ) self.do_runf('src.c', 'read: 0\nfile size is 104\n') @no_mac("TODO: investigate different Node FS semantics on Mac") @@ -5551,23 +6461,32 @@ def test_unlink(self): @crossplatform def test_argv0_node(self): - create_file('code.c', r''' + create_file( + 'code.c', + r''' #include int main(int argc, char **argv) { printf("I am %s.\n", argv[0]); return 0; } -''') +''', + ) output = self.do_runf('code.c') - self.assertContained('I am ' + utils.normalize_path(os.path.realpath(self.get_dir())) + '/code.js', utils.normalize_path(output)) + self.assertContained( + 'I am ' + utils.normalize_path(os.path.realpath(self.get_dir())) + '/code.js', utils.normalize_path(output) + ) - @parameterized({ - 'no_exit_runtime': [True], - '': [False], - }) + @parameterized( + { + 'no_exit_runtime': [True], + '': [False], + } + ) def test_returncode(self, no_exit): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { @@ -5577,11 +6496,22 @@ def test_returncode(self, no_exit): return CODE; #endif } - ''') + ''', + ) for code in (0, 123): for call_exit in (0, 1): for async_compile in (0, 1): - self.run_process([EMCC, 'src.c', '-sENVIRONMENT=node,shell', '-DCODE=%d' % code, '-sEXIT_RUNTIME=%d' % (1 - no_exit), '-DCALL_EXIT=%d' % call_exit, '-sWASM_ASYNC_COMPILATION=%d' % async_compile]) + self.run_process( + [ + EMCC, + 'src.c', + '-sENVIRONMENT=node,shell', + '-DCODE=%d' % code, + '-sEXIT_RUNTIME=%d' % (1 - no_exit), + '-DCALL_EXIT=%d' % call_exit, + '-sWASM_ASYNC_COMPILATION=%d' % async_compile, + ] + ) for engine in config.JS_ENGINES: # async compilation can't return a code in d8 if async_compile and engine == config.V8_ENGINE: @@ -5597,23 +6527,31 @@ def test_returncode(self, no_exit): self.assertEqual(proc.returncode, code) def test_emscripten_force_exit_NO_EXIT_RUNTIME(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { #if CALL_EXIT emscripten_force_exit(0); #endif } - ''') + ''', + ) for no_exit in (0, 1): for call_exit in (0, 1): self.run_process([EMCC, 'src.c', '-sEXIT_RUNTIME=%d' % (1 - no_exit), '-DCALL_EXIT=%d' % call_exit]) print(no_exit, call_exit) out = self.run_js('a.out.js') - assert ('emscripten_force_exit cannot actually shut down the runtime, as the build does not have EXIT_RUNTIME set' in out) == (no_exit and call_exit), out + assert ( + 'emscripten_force_exit cannot actually shut down the runtime, as the build does not have EXIT_RUNTIME set' + in out + ) == (no_exit and call_exit), out def test_mkdir_silly(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -5637,11 +6575,13 @@ def test_mkdir_silly(self): } } } - ''') + ''', + ) self.run_process([EMCC, 'src.c']) # cannot create /, can open - self.assertContained(r''' + self.assertContained( + r''' 1: make /: -1 open /: 1 @@ -5651,23 +6591,32 @@ def test_mkdir_silly(self): home, 4 dev, 4 proc, 4 -''', self.run_js('a.out.js', args=['/'])) +''', + self.run_js('a.out.js', args=['/']), + ) # cannot create empty name, cannot open - self.assertContained(r''' + self.assertContained( + r''' 1: make : -1 open : 0 -''', self.run_js('a.out.js', args=[''])) +''', + self.run_js('a.out.js', args=['']), + ) # can create unnormalized path, can open - self.assertContained(r''' + self.assertContained( + r''' 1: make /a//: 0 open /a//: 1 ., 4 .., 4 -''', self.run_js('a.out.js', args=['/a//'])) +''', + self.run_js('a.out.js', args=['/a//']), + ) # can create child unnormalized - self.assertContained(r''' + self.assertContained( + r''' 1: make /a: 0 open /a: 1 @@ -5678,10 +6627,14 @@ def test_mkdir_silly(self): open /a//b//: 1 ., 4 .., 4 -''', self.run_js('a.out.js', args=['/a', '/a//b//'])) +''', + self.run_js('a.out.js', args=['/a', '/a//b//']), + ) def test_stat_silly(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -5697,13 +6650,20 @@ def test_stat_silly(self): } } } - ''') - self.do_runf('src.c', r'''Failed to stat path: '/a'; errno=44 + ''', + ) + self.do_runf( + 'src.c', + r'''Failed to stat path: '/a'; errno=44 Failed to stat path: ''; errno=44 -''', args=['/a', '']) +''', + args=['/a', ''], + ) def test_symlink_silly(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -5718,7 +6678,8 @@ def test_symlink_silly(self): printf("ok\n"); } } - ''') + ''', + ) self.run_process([EMCC, 'src.c']) # cannot symlink nonexistents @@ -5728,7 +6689,9 @@ def test_symlink_silly(self): self.assertContained(r'Failed to symlink paths: abc, ; errno=44', self.run_js('a.out.js', args=['abc', ''])) def test_rename_silly(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include @@ -5739,7 +6702,8 @@ def test_rename_silly(self): printf("ok\n"); } } -''') +''', + ) self.run_process([EMCC, 'src.c']) # cannot symlink nonexistents @@ -5749,7 +6713,9 @@ def test_rename_silly(self): self.assertContained(r'Failed to rename paths: abc, ; errno=44', self.run_js('a.out.js', args=['abc', ''])) def test_readdir_r_silly(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include #include @@ -5854,9 +6820,12 @@ def test_readdir_r_silly(self): ls("dir"); std::cout << "done" << endl; return 0; -}''') +}''', + ) # cannot symlink nonexistents - self.do_runf('src.cpp', r'''Before: + self.do_runf( + 'src.cpp', + r'''Before: dir a b @@ -5872,10 +6841,14 @@ def test_readdir_r_silly(self): After: dir done -''', args=['', 'abc']) +''', + args=['', 'abc'], + ) def test_emversion(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { @@ -5883,7 +6856,8 @@ def test_emversion(self): printf("minor: %d\n", __EMSCRIPTEN_minor__); printf("tiny: %d\n", __EMSCRIPTEN_tiny__); } - ''') + ''', + ) expected = '''\ major: %d minor: %d @@ -5895,22 +6869,28 @@ def test_emversion(self): def test_libc_files_without_syscalls(self): # a program which includes FS due to libc js library support, but has no syscalls, # so full FS support would normally be optimized out - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { return utimes(NULL, NULL); -}''') +}''', + ) self.run_process([EMCC, 'src.c']) def test_syscall_no_filesystem(self): # a program which includes a non-trivial syscall, but disables the filesystem. - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { return openat(0, "foo", 0); -}''') +}''', + ) self.run_process([EMCC, 'src.c', '-sNO_FILESYSTEM']) def test_dylink_no_filesystem(self): @@ -5961,28 +6941,37 @@ def test_compile_ll_file(self): self.assertContained('hello, world!', self.run_js('a.out.js')) def test_dashE(self): - create_file('src.cpp', r'''#include + create_file( + 'src.cpp', + r'''#include __EMSCRIPTEN_major__ __EMSCRIPTEN_minor__ __EMSCRIPTEN_tiny__ EMSCRIPTEN_KEEPALIVE -''') +''', + ) def test(args): print(args) out = self.run_process([EMXX, 'src.cpp', '-E'] + args, stdout=PIPE).stdout - self.assertContained('%d %d %d __attribute__((used))' % (utils.EMSCRIPTEN_VERSION_MAJOR, utils.EMSCRIPTEN_VERSION_MINOR, utils.EMSCRIPTEN_VERSION_TINY), out) + self.assertContained( + '%d %d %d __attribute__((used))' + % (utils.EMSCRIPTEN_VERSION_MAJOR, utils.EMSCRIPTEN_VERSION_MINOR, utils.EMSCRIPTEN_VERSION_TINY), + out, + ) test([]) test(['-lembind']) def test_dashE_respect_dashO(self): # issue #3365 - with_dash_o = self.run_process([EMCC, test_file('hello_world.c'), '-E', '-o', 'ignored.js'], stdout=PIPE, stderr=PIPE).stdout + with_dash_o = self.run_process( + [EMCC, test_file('hello_world.c'), '-E', '-o', 'ignored.js'], stdout=PIPE, stderr=PIPE + ).stdout without_dash_o = self.run_process([EMCC, test_file('hello_world.c'), '-E'], stdout=PIPE, stderr=PIPE).stdout self.assertEqual(len(with_dash_o), 0) self.assertNotEqual(len(without_dash_o), 0) def test_dashM(self): out = self.run_process([EMCC, test_file('hello_world.c'), '-M'], stdout=PIPE).stdout - self.assertContained('hello_world.o:', out) # Verify output is just a dependency rule instead of bitcode or js + self.assertContained('hello_world.o:', out) # Verify output is just a dependency rule instead of bitcode or js def test_dashM_respect_dashO(self): # issue #3365 @@ -5996,7 +6985,9 @@ def test_malloc_implicit(self): def test_switch64phi(self): # issue 2539, fastcomp segfault on phi-i64 interaction - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include #include @@ -6102,7 +7093,8 @@ class time_iterator { iterate_backward(NULL, int_adapter()); iterate_backward(answer1, int_adapter()); } - ''') + ''', + ) self.run_process([EMXX, 'src.cpp', '-O2', '-sSAFE_HEAP']) @also_with_wasmfs @@ -6119,17 +7111,19 @@ def test_fs_dev_random(self): self.skipTest('Crashes on Windows and NodeFS') self.do_runf('fs/test_fs_dev_random.c', 'success') - @parameterized({ - 'none': [{'EMCC_FORCE_STDLIBS': None}, False], - # forced libs is ok, they were there anyhow - 'normal': [{'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++'}, False], - # partial list, but ok since we grab them as needed - 'parial': [{'EMCC_FORCE_STDLIBS': 'libc++'}, False], - # fail! not enough stdlibs - 'partial_only': [{'EMCC_FORCE_STDLIBS': 'libc++,libc,libc++abi', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, True], - # force all the needed stdlibs, so this works even though we ignore the input file - 'full_only': [{'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, False], - }) + @parameterized( + { + 'none': [{'EMCC_FORCE_STDLIBS': None}, False], + # forced libs is ok, they were there anyhow + 'normal': [{'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++'}, False], + # partial list, but ok since we grab them as needed + 'parial': [{'EMCC_FORCE_STDLIBS': 'libc++'}, False], + # fail! not enough stdlibs + 'partial_only': [{'EMCC_FORCE_STDLIBS': 'libc++,libc,libc++abi', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, True], + # force all the needed stdlibs, so this works even though we ignore the input file + 'full_only': [{'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, False], + } + ) def test_only_force_stdlibs(self, env, fail): cmd = [EMXX, test_file('hello_libcxx.cpp')] with env_modify(env): @@ -6144,7 +7138,9 @@ def test_only_force_stdlibs(self, env, fail): self.assertContained('hello, world!', self.run_js('a.out.js')) def test_only_force_stdlibs_2(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include @@ -6158,7 +7154,8 @@ def test_only_force_stdlibs_2(self): std::cout << "Caught exception: " << ex.what() << std::endl; } } -''') +''', + ) with env_modify({'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}): self.run_process([EMXX, 'src.cpp', '-sDISABLE_EXCEPTION_CATCHING=0']) self.assertContained('Caught exception: std::exception', self.run_js('a.out.js')) @@ -6173,11 +7170,13 @@ def test_force_stdlibs(self): def test_time(self): self.do_other_test('test_time.c') - @parameterized({ - '1': ('EST+05EDT',), - '2': ('UTC+0',), - '3': ('CET',), - }) + @parameterized( + { + '1': ('EST+05EDT',), + '2': ('UTC+0',), + '3': ('CET',), + } + ) def test_time_tz(self, tz): print('testing with TZ=%s' % tz) with env_modify({'TZ': tz}): @@ -6229,7 +7228,7 @@ def test_strftime_zZ(self): {'env': {'LC_ALL': 'en_GB', 'TZ': 'Europe/London'}, 'expected_utc': 'UTC+0100'}, {'env': {'LC_ALL': 'th_TH', 'TZ': 'Asia/Bangkok'}, 'expected_utc': 'UTC+0700'}, {'env': {'LC_ALL': 'ar-AE', 'TZ': 'Asia/Dubai'}, 'expected_utc': 'UTC+0400'}, - {'env': {'LC_ALL': 'en-US', 'TZ': 'America/Los_Angeles'}, 'expected_utc': 'UTC-0700'} + {'env': {'LC_ALL': 'en-US', 'TZ': 'America/Los_Angeles'}, 'expected_utc': 'UTC-0700'}, ] for tz_lang_info in tz_lang_infos: @@ -6241,7 +7240,9 @@ def test_strptime_symmetry(self): @also_with_wasmfs def test_truncate_from_0(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include #include @@ -6342,8 +7343,11 @@ def test_truncate_from_0(self): resize(file, 32); return 0; } -''') - self.do_runf('src.cpp', r'''Creating file: /tmp/file with content=This is some content +''', + ) + self.do_runf( + 'src.cpp', + r'''Creating file: /tmp/file with content=This is some content Size of file is: 20 Truncating file=/tmp/file to length=32 Size of file is: 32 @@ -6353,10 +7357,13 @@ def test_truncate_from_0(self): Size of file is: 0 Truncating file=/tmp/file to length=32 Size of file is: 32 -''') +''', + ) def test_create_readonly(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include #include @@ -6423,19 +7430,25 @@ def test_create_readonly(self): readOnlyFile(file, "This should not get written because the file already " "exists and is read-only.\n\n"); } -''') - self.do_runf('src.cpp', r'''Creating file: /tmp/file with content of size=292 +''', + ) + self.do_runf( + 'src.cpp', + r'''Creating file: /tmp/file with content of size=292 Data written to file=/tmp/file; successfully wrote 292 bytes Creating file: /tmp/file with content of size=79 Failed to open file for writing: /tmp/file; errno=2; Permission denied -''') +''', + ) def test_embed_file_large(self): # If such long files are encoded on one line, # they overflow the interpreter's limit large_size = int(1500000) create_file('large.txt', 'x' * large_size) - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { @@ -6449,16 +7462,19 @@ def test_embed_file_large(self): } return 0; } - ''') + ''', + ) self.run_process([EMCC, 'src.c', '--embed-file', 'large.txt']) for engine in config.JS_ENGINES: if engine == config.V8_ENGINE: - continue # ooms + continue # ooms print(engine) self.assertContained('ok\n' + str(large_size) + '\n', self.run_js('a.out.js', engine=engine)) def test_force_exit(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include @@ -6473,14 +7489,17 @@ def test_force_exit(self): emscripten_exit_with_live_runtime(); return 123; } -''') +''', + ) self.run_process([EMCC, 'src.c']) output = self.run_js('a.out.js', assert_returncode=42) self.assertContained('callback pre()', output) self.assertNotContained('callback post()', output) def test_bad_locale(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -6494,45 +7513,57 @@ def test_bad_locale(self): } printf("locale set to %s: %s\n", locale, actual); } -''') +''', + ) self.run_process([EMCC, 'src.c']) - self.assertContained('locale set to C: C', - self.run_js('a.out.js', args=['C'])) - self.assertContained('locale set to waka: waka', - self.run_js('a.out.js', args=['waka'])) + self.assertContained('locale set to C: C', self.run_js('a.out.js', args=['C'])) + self.assertContained('locale set to waka: waka', self.run_js('a.out.js', args=['waka'])) def test_browser_language_detection(self): # Test HTTP Accept-Language parsing by simulating navigator.languages #8751 - self.run_process([EMCC, - test_file('test_browser_language_detection.c')]) + self.run_process([EMCC, test_file('test_browser_language_detection.c')]) self.assertContained('C.UTF-8', self.run_js('a.out.js')) # Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 - create_file('preamble.js', r'''navigator = {}; - navigator.languages = [ "fr", "fr-FR", "en-US", "en" ];''') - self.run_process([EMCC, '--pre-js', 'preamble.js', - test_file('test_browser_language_detection.c')]) + create_file( + 'preamble.js', + r'''navigator = {}; + navigator.languages = [ "fr", "fr-FR", "en-US", "en" ];''', + ) + self.run_process([EMCC, '--pre-js', 'preamble.js', test_file('test_browser_language_detection.c')]) self.assertContained('fr.UTF-8', self.run_js('a.out.js')) # Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.5,en;q=0.3 - create_file('preamble.js', r'''navigator = {}; - navigator.languages = [ "fr-FR", "fr", "en-US", "en" ];''') + create_file( + 'preamble.js', + r'''navigator = {}; + navigator.languages = [ "fr-FR", "fr", "en-US", "en" ];''', + ) self.emcc_args += ['--pre-js', 'preamble.js'] self.do_runf('test_browser_language_detection.c', 'fr_FR.UTF-8') def test_js_main(self): # try to add a main() from JS, at runtime. this is not supported (the # compiler needs to know at compile time about main). - create_file('pre_main.js', r''' + create_file( + 'pre_main.js', + r''' Module['_main'] = () => {}; - ''') + ''', + ) create_file('src.cpp', '') self.emcc_args += ['--pre-js', 'pre_main.js'] - self.do_runf('src.cpp', 'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]', assert_returncode=NON_ZERO) + self.do_runf( + 'src.cpp', + 'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]', + assert_returncode=NON_ZERO, + ) def test_locale_wrong(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include #include @@ -6563,18 +7594,25 @@ def test_locale_wrong(self): return 127; } } -''') +''', + ) self.run_process([EMXX, 'src.cpp', '-sDISABLE_EXCEPTION_CATCHING=0']) - self.assertContained('''\ + self.assertContained( + '''\ Constructed locale "C" This locale is the global locale. This locale is the C locale. -''', self.run_js('a.out.js', args=['C'])) - self.assertContained('''\ +''', + self.run_js('a.out.js', args=['C']), + ) + self.assertContained( + '''\ Constructed locale "waka" This locale is not the global locale. This locale is not the C locale. -''', self.run_js('a.out.js', args=['waka'])) +''', + self.run_js('a.out.js', args=['waka']), + ) def test_cleanup_os(self): # issue 2644 @@ -6588,7 +7626,8 @@ def test(args, be_clean): if be_clean: assert len(clutter) == 0, 'should not leave clutter ' + str(clutter) else: - assert len(clutter) == 2, 'should leave .o files' + assert len(clutter) == 2, 'should leave .o files' + test(['-o', 'c.so', '-r'], True) test(['-o', 'c.js'], True) test(['-o', 'c.html'], True) @@ -6608,6 +7647,7 @@ def test(opts): assert sizes['_'] == sizes[0] == sizes[1] == sizes[2], 'no debug means no llvm debug info ' + str(sizes) assert sizes['g'] == sizes[3] == sizes[4], '-g or -gsource-map means llvm debug info ' + str(sizes) assert sizes['_'] < sizes['g'], 'llvm debug info has positive size ' + str(sizes) + test([]) test(['-O1']) @@ -6651,7 +7691,9 @@ def do(name, source, moar_opts): self.assertContained('hello, world!', self.run_js(padded_name + '.js')) do('normal', 'hello_world_fopen.c', []) - do('no_fs', 'hello_world.c', []) # without fopen, we should auto-detect we do not need full fs support and can do FILESYSTEM=0 + do( + 'no_fs', 'hello_world.c', [] + ) # without fopen, we should auto-detect we do not need full fs support and can do FILESYSTEM=0 do('no_fs_manual', 'hello_world.c', ['-sFILESYSTEM=0']) print(' ', sizes) self.assertLess(sizes['no_fs'], sizes['normal']) @@ -6659,7 +7701,7 @@ def do(name, source, moar_opts): # manual can usually remove a tiny bit more self.assertLess(sizes['no_fs_manual'], sizes['no_fs'] + 30) - test(['-sASSERTIONS=0'], 120000) # we don't care about code size with assertions + test(['-sASSERTIONS=0'], 120000) # we don't care about code size with assertions test(['-O1'], 91000) test(['-O2'], 46000) test(['-O3', '--closure=1'], 17000) @@ -6667,7 +7709,7 @@ def do(name, source, moar_opts): # -Wclosure is needed due to # https://github.com/google/closure-compiler/issues/4108 test(['-O3', '--closure=1', '-Wno-closure', '-sWASM=0'], 36000) - test(['-O3', '--closure=2', '-Wno-closure', '-sWASM=0'], 33000) # might change now and then + test(['-O3', '--closure=2', '-Wno-closure', '-sWASM=0'], 33000) # might change now and then def test_no_main_loop(self): MAINLOOP = 'var MainLoop' @@ -6694,18 +7736,27 @@ def test(opts, has, not_has): test([], "Module['", "Module['waka") test(['-sEXPORTED_RUNTIME_METHODS=[]'], '', "Module['addRunDependency") test(['-sEXPORTED_RUNTIME_METHODS=addRunDependency'], "Module['addRunDependency", "Module['waka") - test(['-sEXPORTED_RUNTIME_METHODS=[]', '-sEXPORTED_RUNTIME_METHODS=addRunDependency'], "Module['addRunDependency", "Module['waka") + test( + ['-sEXPORTED_RUNTIME_METHODS=[]', '-sEXPORTED_RUNTIME_METHODS=addRunDependency'], + "Module['addRunDependency", + "Module['waka", + ) def test_stat_fail_alongtheway(self): self.do_other_test('test_stat_fail_alongtheway.c') def test_link_with_a_static(self): - create_file('x.c', r''' + create_file( + 'x.c', + r''' int init_weakref(int a, int b) { return a + b; } -''') - create_file('y.c', r''' +''', + ) + create_file( + 'y.c', + r''' static int init_weakref(void) { // inlined in -O2, not in -O0 where it shows up in llvm-nm as 't' return 150; } @@ -6713,15 +7764,19 @@ def test_link_with_a_static(self): int testy(void) { return init_weakref(); } -''') - create_file('z.c', r''' +''', + ) + create_file( + 'z.c', + r''' extern int init_weakref(int, int); extern int testy(void); int main(void) { return testy() + init_weakref(5, 6); } -''') +''', + ) self.run_process([EMCC, '-c', 'x.c', '-o', 'x.o']) self.run_process([EMCC, '-c', 'y.c', '-o', 'y.o']) self.run_process([EMCC, '-c', 'z.c', '-o', 'z.o']) @@ -6777,19 +7832,24 @@ def test_modularize_strict(self): output = self.run_js('run.js') self.assertEqual(output, 'hello, world!\n') - @parameterized({ - '': ([],), - 'export_name': (['-sEXPORT_NAME=Foo'],), - 'closure': (['-sEXPORT_NAME=Foo', '--closure=1'],), - }) + @parameterized( + { + '': ([],), + 'export_name': (['-sEXPORT_NAME=Foo'],), + 'closure': (['-sEXPORT_NAME=Foo', '--closure=1'],), + } + ) @crossplatform def test_modularize_incoming(self, args): self.run_process([EMCC, test_file('hello_world.c'), '-o', 'out.mjs'] + self.get_emcc_args() + args) - create_file('run.mjs', ''' + create_file( + 'run.mjs', + ''' import Module from './out.mjs'; await Module({onRuntimeInitialized: () => console.log('done init')}) .then(() => console.log('got module')); - ''') + ''', + ) output = self.run_js('run.mjs') self.assertContained('done init\nhello, world!\ngot module\n', output) @@ -6804,15 +7864,20 @@ def test_pthread_print_override_modularize(self): self.set_setting('PROXY_TO_PTHREAD') self.set_setting('EXIT_RUNTIME') self.set_setting('MODULARIZE') - create_file('main.c', ''' + create_file( + 'main.c', + ''' #include int main() { emscripten_out("hello, world!"); return 0; } - ''') - create_file('main.js', ''' + ''', + ) + create_file( + 'main.js', + ''' const Test = require('./test.js'); async function main() { @@ -6822,7 +7887,8 @@ def test_pthread_print_override_modularize(self): }); } main(); - ''') + ''', + ) self.emcc('main.c', output_filename='test.js') output = self.run_js('main.js') @@ -6835,12 +7901,15 @@ def test_define_modularize(self): create_file('a.out.js', src) self.assertContained("define([], () => Module);", src) - create_file('run_module.js', ''' + 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) @@ -6857,7 +7926,9 @@ def test_EXPORT_NAME_with_html(self): self.assertContained('error: customizing EXPORT_NAME requires that the HTML be customized to use that name', err) def test_modularize_sync_compilation(self): - create_file('post.js', r''' + create_file( + 'post.js', + r''' console.log('before'); var result = Module(); // It should be an object. @@ -6867,22 +7938,27 @@ def test_modularize_sync_compilation(self): // And it should not be a Promise. console.log('typeof result.then: ' + typeof result.then); console.log('after'); -''') - self.run_process([EMCC, test_file('hello_world.c'), - '-sMODULARIZE', - '-sWASM_ASYNC_COMPILATION=0', - '--extern-post-js', 'post.js']) - self.assertContained('''\ +''', + ) + self.run_process( + [EMCC, test_file('hello_world.c'), '-sMODULARIZE', '-sWASM_ASYNC_COMPILATION=0', '--extern-post-js', 'post.js'] + ) + self.assertContained( + '''\ before hello, world! typeof result: object typeof _main: function typeof result.then: undefined after -''', self.run_js('a.out.js')) +''', + self.run_js('a.out.js'), + ) def test_export_all_3142(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' typedef unsigned int Bit32u; struct S_Descriptor { @@ -6901,7 +7977,8 @@ class Descriptor { }; Descriptor desc; - ''') + ''', + ) self.run_process([EMXX, 'src.cpp', '-O2', '-sEXPORT_ALL']) self.assertExists('a.out.js') @@ -6913,6 +7990,7 @@ def check(what, args, fail=True, expect=''): assert ('is a helper for' in output.stderr) == fail assert ('Typical usage' in output.stderr) == fail self.assertContained(expect, output.stdout) + check(emmake, []) check(EMCONFIGURE, []) check(emmake, ['--version']) @@ -6922,17 +8000,23 @@ def check(what, args, fail=True, expect=''): check(EMCONFIGURE, ['./configure'], fail=False) check(EMCMAKE, ['cmake'], fail=False) - create_file('test.py', ''' + create_file( + 'test.py', + ''' import os print(os.environ.get('CROSS_COMPILE')) -''') +''', + ) check(EMCONFIGURE, [PYTHON, 'test.py'], expect=path_from_root('em'), fail=False) check(emmake, [PYTHON, 'test.py'], expect=path_from_root('em'), fail=False) - create_file('test.py', ''' + create_file( + 'test.py', + ''' import os print(os.environ.get('NM')) -''') +''', + ) check(EMCONFIGURE, [PYTHON, 'test.py'], expect=shared.LLVM_NM, fail=False) create_file('test.c', 'int main() { return 0; }') @@ -6955,15 +8039,18 @@ def test_sdl2_config(self): [['--cflags', '--libs'], '-sUSE_SDL=2'], ]: print(args, expected) - out = self.run_process([shared.bat_suffix(cache.get_sysroot_dir('bin/sdl2-config'))] + args, - stdout=PIPE, stderr=PIPE).stdout + out = self.run_process( + [shared.bat_suffix(cache.get_sysroot_dir('bin/sdl2-config'))] + args, stdout=PIPE, stderr=PIPE + ).stdout self.assertContained(expected, out) print('via emmake') out = self.run_process([emmake, 'sdl2-config'] + args, stdout=PIPE, stderr=PIPE).stdout self.assertContained(expected, out) def test_module_onexit(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { EM_ASM({ @@ -6971,7 +8058,8 @@ def test_module_onexit(self): }); return 14; } -''') +''', + ) self.run_process([EMCC, 'src.c', '-sEXIT_RUNTIME']) self.assertContained('exiting now, status 14', self.run_js('a.out.js', assert_returncode=14)) @@ -6988,12 +8076,15 @@ def test_NO_aliasing(self): assert exit_1 != exit_0 def test_underscore_exit(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { _exit(0); // should not end up in an infinite loop with non-underscore exit } -''') +''', + ) self.run_process([EMCC, 'src.c']) self.assertContained('', self.run_js('a.out.js')) @@ -7007,12 +8098,16 @@ def test_file_packager_huge(self): self.assertContained(MESSAGE, err) self.clear() - @parameterized({ - '': (True,), - 'wasm2js': (False,), - }) + @parameterized( + { + '': (True,), + 'wasm2js': (False,), + } + ) def test_massive_alloc(self, wasm): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include @@ -7020,7 +8115,8 @@ def test_massive_alloc(self, wasm): volatile long x = (long)malloc(1024 * 1024 * 1400); return x == 0; // can't alloc it, but don't fail catastrophically, expect null } - ''') + ''', + ) cmd = [EMCC, 'main.c', '-sALLOW_MEMORY_GROWTH', '-sINITIAL_MEMORY=16MB'] if not wasm: cmd += ['-sWASM=0'] @@ -7030,20 +8126,28 @@ def test_massive_alloc(self, wasm): if not wasm: self.assertContained('Warning: Enlarging memory arrays, this is not fast! 16777216,1468137472\n', output) - @parameterized({ - '': (False,), - 'growth': (True,), - }) + @parameterized( + { + '': (False,), + 'growth': (True,), + } + ) @also_with_wasm2js def test_failing_alloc(self, growth): # Force memory growth to fail at runtime self.add_pre_run('growMemory = (size) => false;') for pre_fail, post_fail, opts in [ ('', '', []), - ('EM_ASM( Module.temp = _sbrk() );', 'EM_ASM( assert(Module.temp === _sbrk(), "must not adjust brk when an alloc fails!") );', []), + ( + 'EM_ASM( Module.temp = _sbrk() );', + 'EM_ASM( assert(Module.temp === _sbrk(), "must not adjust brk when an alloc fails!") );', + [], + ), ]: for aborting_args in ([], ['-sABORTING_MALLOC=0']): - create_file('main.cpp', r''' + create_file( + 'main.cpp', + r''' #include #include #include @@ -7082,7 +8186,9 @@ def test_failing_alloc(self, growth): } printf("managed another malloc!\n"); } -''' % (pre_fail, post_fail)) +''' + % (pre_fail, post_fail), + ) args = [EMXX, 'main.cpp', '-sEXPORTED_FUNCTIONS=_main,_sbrk', '-sINITIAL_MEMORY=16MB'] + opts + aborting_args if growth: args += ['-sALLOW_MEMORY_GROWTH'] @@ -7108,15 +8214,21 @@ def test_failing_alloc(self, growth): self.assertContained('Aborted(Cannot enlarge memory arrays', output) if growth: # when growth is enabled, the default is to not abort, so just explain that - self.assertContained('If you want malloc to return NULL (0) instead of this abort, do not link with -sABORTING_MALLOC', output) + self.assertContained( + 'If you want malloc to return NULL (0) instead of this abort, do not link with -sABORTING_MALLOC', output + ) else: # when growth is not enabled, suggest 3 possible solutions (start with more memory, allow growth, or don't abort) - self.assertContained(('higher than the current value 16777216,', 'higher than the current value 33554432,'), output) + self.assertContained( + ('higher than the current value 16777216,', 'higher than the current value 33554432,'), output + ) self.assertContained('compile with -sALLOW_MEMORY_GROWTH', output) self.assertContained('compile with -sABORTING_MALLOC=0', output) def test_failing_growth_2gb(self): - create_file('test.c', r''' + create_file( + 'test.c', + r''' #include #include @@ -7131,7 +8243,8 @@ def test_failing_growth_2gb(self): } } } -''') +''', + ) self.run_process([EMCC, '-O1', 'test.c', '-sALLOW_MEMORY_GROWTH']) self.assertContained('done', self.run_js('a.out.js')) @@ -7140,7 +8253,9 @@ def test_failing_growth_2gb(self): @requires_node_canary def test_failing_growth_wasm64(self): self.require_wasm64() - create_file('test.c', r''' + create_file( + 'test.c', + r''' #include #include #include @@ -7162,11 +8277,24 @@ def test_failing_growth_wasm64(self): } } } -''') - self.do_runf('test.c', 'done\n', emcc_args=['-sGLOBAL_BASE=2Gb', '-sTOTAL_MEMORY=4Gb', '-sMAXIMUM_MEMORY=5Gb', '-sALLOW_MEMORY_GROWTH', '-sMEMORY64']) +''', + ) + self.do_runf( + 'test.c', + 'done\n', + emcc_args=[ + '-sGLOBAL_BASE=2Gb', + '-sTOTAL_MEMORY=4Gb', + '-sMAXIMUM_MEMORY=5Gb', + '-sALLOW_MEMORY_GROWTH', + '-sMEMORY64', + ], + ) def test_libcxx_minimal(self): - create_file('vector.cpp', r''' + create_file( + 'vector.cpp', + r''' #include int main(int argc, char** argv) { std::vector v; @@ -7175,7 +8303,8 @@ def test_libcxx_minimal(self): } return v.size(); } -''') +''', + ) self.run_process([EMXX, '-O2', 'vector.cpp', '-o', 'vector.js']) self.run_process([EMXX, '-O2', test_file('hello_libcxx.cpp'), '-o', 'iostream.js']) @@ -7188,18 +8317,22 @@ def test_libcxx_minimal(self): # we can strip out almost all of libcxx when just using vector self.assertLess(2.25 * vector, iostream) - @parameterized({ - '': ('1',), - # TODO(sbc): make dynamic linking work with wasm2js - # 'wasm2js': ('0',) - }) + @parameterized( + { + '': ('1',), + # TODO(sbc): make dynamic linking work with wasm2js + # 'wasm2js': ('0',) + } + ) def test_minimal_dynamic(self, wasm): library_file = 'library.wasm' if wasm else 'library.js' def test(name, main_args, library_args, expected='hello from main\nhello from library', assert_returncode=0): print(f'testing {name}', main_args, library_args) self.clear() - create_file('library.c', r''' + create_file( + 'library.c', + r''' #include void library_func() { #ifdef USE_PRINTF @@ -7208,10 +8341,26 @@ def test(name, main_args, library_args, expected='hello from main\nhello from li puts("hello from library"); #endif } - ''') + ''', + ) # -fno-builtin to prevent printf -> iprintf optimization - self.run_process([EMCC, 'library.c', '-fno-builtin', '-sSIDE_MODULE', '-O2', '-o', library_file, '-sWASM=' + wasm, '-sEXPORT_ALL'] + library_args) - create_file('main.c', r''' + self.run_process( + [ + EMCC, + 'library.c', + '-fno-builtin', + '-sSIDE_MODULE', + '-O2', + '-o', + library_file, + '-sWASM=' + wasm, + '-sEXPORT_ALL', + ] + + library_args + ) + create_file( + 'main.c', + r''' #include #include int main() { @@ -7227,7 +8376,9 @@ def test(name, main_args, library_args, expected='hello from main\nhello from li if (!x) puts("cannot find side function"); else x(); } - ''' % library_file) + ''' + % library_file, + ) self.run_process([EMCC, 'main.c', '--embed-file', library_file, '-O2', '-sWASM=' + wasm] + main_args) self.assertContained(expected, self.run_js('a.out.js', assert_returncode=assert_returncode)) size = os.path.getsize('a.out.js') @@ -7249,29 +8400,55 @@ def percent_diff(x, y): # main module tests # dce in main, and it fails since puts is not exported - test('dce', main_args=['-sMAIN_MODULE=2'], library_args=[], expected=('is not a function', 'cannot', 'undefined'), assert_returncode=NON_ZERO) + test( + 'dce', + main_args=['-sMAIN_MODULE=2'], + library_args=[], + expected=('is not a function', 'cannot', 'undefined'), + assert_returncode=NON_ZERO, + ) # with exporting, it works dce = test('dce', main_args=['-sMAIN_MODULE=2', '-sEXPORTED_FUNCTIONS=_main,_puts'], library_args=[]) # printf is not used in main, and we dce, so we failz - dce_fail = test('dce_fail', main_args=['-sMAIN_MODULE=2'], library_args=['-DUSE_PRINTF'], expected=('is not a function', 'cannot', 'undefined'), assert_returncode=NON_ZERO) + dce_fail = test( + 'dce_fail', + main_args=['-sMAIN_MODULE=2'], + library_args=['-DUSE_PRINTF'], + expected=('is not a function', 'cannot', 'undefined'), + assert_returncode=NON_ZERO, + ) # exporting printf in main keeps it alive for the library - test('dce_save', main_args=['-sMAIN_MODULE=2', '-sEXPORTED_FUNCTIONS=_main,_printf,_puts'], library_args=['-DUSE_PRINTF']) + test( + 'dce_save', + main_args=['-sMAIN_MODULE=2', '-sEXPORTED_FUNCTIONS=_main,_printf,_puts'], + library_args=['-DUSE_PRINTF'], + ) self.assertLess(percent_diff(full[0], printf[0]), 4) self.assertLess(percent_diff(dce[0], dce_fail[0]), 4) - self.assertLess(dce[0], 0.2 * full[0]) # big effect, 80%+ is gone + self.assertLess(dce[0], 0.2 * full[0]) # big effect, 80%+ is gone # side module tests # mode 2, so dce in side, but library_func is not exported, so it is dce'd - side_dce_fail = test('side_dce_fail', main_args=['-sMAIN_MODULE'], library_args=['-sSIDE_MODULE=2'], expected='cannot find side function') + side_dce_fail = test( + 'side_dce_fail', + main_args=['-sMAIN_MODULE'], + library_args=['-sSIDE_MODULE=2'], + expected='cannot find side function', + ) # mode 2, so dce in side, and library_func is not exported - side_dce_work = test('side_dce_fail', main_args=['-sMAIN_MODULE'], library_args=['-sSIDE_MODULE=2', '-sEXPORTED_FUNCTIONS=_library_func'], expected='hello from library') + side_dce_work = test( + 'side_dce_fail', + main_args=['-sMAIN_MODULE'], + library_args=['-sSIDE_MODULE=2', '-sEXPORTED_FUNCTIONS=_library_func'], + expected='hello from library', + ) - self.assertLess(side_dce_fail[1], 0.95 * side_dce_work[1]) # removing that function saves a chunk + self.assertLess(side_dce_fail[1], 0.95 * side_dce_work[1]) # removing that function saves a chunk def test_RUNTIME_LINKED_LIBS(self): # Verify that the legacy `-sRUNTIME_LINKED_LIBS` option acts the same as passing a @@ -7283,44 +8460,59 @@ def test_RUNTIME_LINKED_LIBS(self): self.run_process([EMCC, '-O2', 'main.c', '-sMAIN_MODULE', '-o', 'main.js', 'side.wasm']) self.run_js('main.js') - err = self.run_process([EMCC, '-O2', 'main.c', '-sMAIN_MODULE', '-o', 'main2.js', '-sRUNTIME_LINKED_LIBS=side.wasm'], stderr=PIPE).stderr + err = self.run_process( + [EMCC, '-O2', 'main.c', '-sMAIN_MODULE', '-o', 'main2.js', '-sRUNTIME_LINKED_LIBS=side.wasm'], stderr=PIPE + ).stderr self.assertContained('emcc: warning: RUNTIME_LINKED_LIBS is deprecated', err) self.run_js('main2.js') self.assertBinaryEqual('main.wasm', 'main2.wasm') - @parameterized({ - '': ([],), - 'pthread': (['-g', '-pthread', '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), - }) + @parameterized( + { + '': ([],), + 'pthread': (['-g', '-pthread', '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), + } + ) def test_ld_library_path(self, args): if args: self.setup_node_pthreads() - create_file('hello1.c', r''' + create_file( + 'hello1.c', + r''' #include void hello1() { printf("Hello1\n"); return; } -''') - create_file('hello2.c', r''' +''', + ) + create_file( + 'hello2.c', + r''' #include void hello2() { printf("Hello2\n"); return; } -''') - create_file('hello3.c', r''' +''', + ) + create_file( + 'hello3.c', + r''' #include void hello3() { printf ("Hello3\n"); return; } -''') - create_file('hello4.c', r''' +''', + ) + create_file( + 'hello4.c', + r''' #include #include @@ -7328,13 +8520,19 @@ def test_ld_library_path(self, args): printf("Hello4\n"); return fmod(x, 2.0); } -''') - create_file('pre.js', r''' +''', + ) + create_file( + 'pre.js', + r''' Module.preRun = () => { ENV['LD_LIBRARY_PATH']='/lib:/usr/lib:/usr/local/lib'; }; -''') - create_file('main.c', r''' +''', + ) + create_file( + 'main.c', + r''' #include #include #include @@ -7379,18 +8577,39 @@ def test_ld_library_path(self, args): } return 0; } -''') +''', + ) self.run_process([EMCC, '-o', 'hello1.wasm', 'hello1.c', '-sSIDE_MODULE'] + args) self.run_process([EMCC, '-o', 'hello2.wasm', 'hello2.c', '-sSIDE_MODULE'] + args) self.run_process([EMCC, '-o', 'hello3.wasm', 'hello3.c', '-sSIDE_MODULE'] + args) self.run_process([EMCC, '-o', 'hello4.wasm', 'hello4.c', '-sSIDE_MODULE'] + args) - self.run_process([EMCC, '--profiling-funcs', '-o', 'main.js', 'main.c', '-sMAIN_MODULE=2', '-sINITIAL_MEMORY=32Mb', - '--embed-file', 'hello1.wasm@/lib/libhello1.wasm', - '--embed-file', 'hello2.wasm@/usr/lib/libhello2.wasm', - '--embed-file', 'hello3.wasm@/libhello3.wasm', - '--embed-file', 'hello4.wasm@/usr/local/lib/libhello4.wasm', - 'hello1.wasm', 'hello2.wasm', 'hello3.wasm', 'hello4.wasm', '-sNO_AUTOLOAD_DYLIBS', - '--pre-js', 'pre.js'] + args) + self.run_process( + [ + EMCC, + '--profiling-funcs', + '-o', + 'main.js', + 'main.c', + '-sMAIN_MODULE=2', + '-sINITIAL_MEMORY=32Mb', + '--embed-file', + 'hello1.wasm@/lib/libhello1.wasm', + '--embed-file', + 'hello2.wasm@/usr/lib/libhello2.wasm', + '--embed-file', + 'hello3.wasm@/libhello3.wasm', + '--embed-file', + 'hello4.wasm@/usr/local/lib/libhello4.wasm', + 'hello1.wasm', + 'hello2.wasm', + 'hello3.wasm', + 'hello4.wasm', + '-sNO_AUTOLOAD_DYLIBS', + '--pre-js', + 'pre.js', + ] + + args + ) out = self.run_js('main.js') self.assertContained('Hello1', out) self.assertContained('Hello2', out) @@ -7399,7 +8618,9 @@ def test_ld_library_path(self, args): self.assertContained('Ok', out) def test_dlopen_bad_flags(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include @@ -7412,13 +8633,16 @@ def test_dlopen_bad_flags(self): printf("%s\n", dlerror()); return 0; } -''') +''', + ) self.run_process([EMCC, 'main.c', '-sMAIN_MODULE=2']) out = self.run_js('a.out.js') self.assertContained('invalid mode for dlopen(): Either RTLD_LAZY or RTLD_NOW is required', out) def test_dlopen_constructors(self): - create_file('side.c', r''' + create_file( + 'side.c', + r''' #include #include @@ -7436,8 +8660,11 @@ def test_dlopen_constructors(self): check_relocations(); printf("done ctor\n"); } - ''') - create_file('main.c', r''' + ''', + ) + create_file( + 'main.c', + r''' #include #include #include @@ -7451,7 +8678,8 @@ def test_dlopen_constructors(self): check(); printf("done\n"); return 0; - }''') + }''', + ) self.run_process([EMCC, '-g', '-o', 'libside.wasm', 'side.c', '-sSIDE_MODULE']) self.run_process([EMCC, '-g', '-sMAIN_MODULE=2', 'main.c', 'libside.wasm', '-sNO_AUTOLOAD_DYLIBS']) self.assertContained('done', self.run_js('a.out.js')) @@ -7465,7 +8693,9 @@ def test_dlopen_rtld_global(self): # to create a redirection function. In wasm we just have wasm, so we # need to introspect the wasm module. Browsers may add that eventually, # or we could ship a little library that does it. - create_file('hello1.c', r''' + create_file( + 'hello1.c', + r''' #include extern int hello1_val; @@ -7475,8 +8705,11 @@ def test_dlopen_rtld_global(self): printf("hello1_val by hello1:%d\n",hello1_val); printf("Hello%d\n",i); } -''') - create_file('hello2.c', r''' +''', + ) + create_file( + 'hello2.c', + r''' #include extern int hello1_val; @@ -7488,8 +8721,11 @@ def test_dlopen_rtld_global(self): f = hello1; f(i); } -''') - create_file('main.c', r''' +''', + ) + create_file( + 'main.c', + r''' #include #include #include @@ -7509,13 +8745,24 @@ def test_dlopen_rtld_global(self): dlclose(h2); return 0; } -''') +''', + ) self.run_process([EMCC, '-o', 'libhello1.wasm', 'hello1.c', '-sSIDE_MODULE', '-sEXPORT_ALL']) self.run_process([EMCC, '-o', 'libhello2.wasm', 'hello2.c', '-sSIDE_MODULE', '-sEXPORT_ALL']) - self.run_process([EMCC, '-o', 'main.js', 'main.c', '-sMAIN_MODULE', - '--embed-file', 'libhello1.wasm', - '--embed-file', 'libhello2.wasm']) + self.run_process( + [ + EMCC, + '-o', + 'main.js', + 'main.c', + '-sMAIN_MODULE', + '--embed-file', + 'libhello1.wasm', + '--embed-file', + 'libhello2.wasm', + ] + ) out = self.run_js('main.js') self.assertContained('Hello1', out) self.assertContained('Hello2', out) @@ -7524,11 +8771,14 @@ def test_dlopen_rtld_global(self): def test_dlopen_async(self): create_file('side.c', 'int foo = 42;\n') - create_file('pre.js', r''' + create_file( + 'pre.js', + r''' Module.preRun = () => { ENV['LD_LIBRARY_PATH']='/usr/lib'; }; -''') +''', + ) self.run_process([EMCC, 'side.c', '-o', 'tmp.so', '-sSIDE_MODULE']) self.set_setting('MAIN_MODULE', 2) self.do_other_test('test_dlopen_async.c', ['--pre-js=pre.js', '--embed-file', 'tmp.so@/usr/lib/libside.so']) @@ -7539,13 +8789,15 @@ def test_dlopen_promise(self): self.set_setting('MAIN_MODULE', 2) self.do_other_test('test_dlopen_promise.c') - @parameterized({ - # Under node this should work even without ASYNCIFY because we can do - # synchronous loading via readBinary - '': (0,), - 'asyncify': (1,), - 'jspi': (2,), - }) + @parameterized( + { + # Under node this should work even without ASYNCIFY because we can do + # synchronous loading via readBinary + '': (0,), + 'asyncify': (1,), + 'jspi': (2,), + } + ) def test_dlopen_blocking(self, asyncify): self.run_process([EMCC, test_file('other/test_dlopen_blocking_side.c'), '-o', 'libside.so', '-sSIDE_MODULE']) self.set_setting('MAIN_MODULE', 2) @@ -7560,13 +8812,18 @@ def test_dlopen_blocking(self, asyncify): self.do_other_test('test_dlopen_blocking.c') def test_dlsym_rtld_default(self): - create_file('side.c', r''' + create_file( + 'side.c', + r''' int baz() { return 99; } - ''') + ''', + ) self.run_process([EMCC, '-o', 'libside.so', 'side.c', '-sSIDE_MODULE']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include @@ -7618,18 +8875,24 @@ def test_dlsym_rtld_default(self): return 0; } -''') +''', + ) self.do_runf('main.c', emcc_args=['-sMAIN_MODULE=2', 'libside.so']) def test_dlsym_rtld_default_js_symbol(self): - create_file('lib.js', ''' + create_file( + 'lib.js', + ''' addToLibrary({ foo__sig: 'ii', foo: function(f) { return f + 10 }, bar: function(f) { returnf + 10 }, }); - ''') - create_file('main.c', r''' + ''', + ) + create_file( + 'main.c', + r''' #include #include #include @@ -7646,11 +8909,9 @@ def test_dlsym_rtld_default_js_symbol(self): printf("%s -> %d\n", argv[1], fp(10)); return 0; } -''') - self.run_process([EMCC, 'main.c', - '--js-library=lib.js', - '-sMAIN_MODULE=2', - '-sEXPORTED_FUNCTIONS=_main,_foo,_bar']) +''', + ) + self.run_process([EMCC, 'main.c', '--js-library=lib.js', '-sMAIN_MODULE=2', '-sEXPORTED_FUNCTIONS=_main,_foo,_bar']) # Fist test the successful use of a JS function with dlsym out = self.run_js('a.out.js', args=['foo']) @@ -7663,7 +8924,9 @@ def test_dlsym_rtld_default_js_symbol(self): def test_main_module_without_exceptions_message(self): # A side module that needs exceptions needs a main module with that # support enabled; show a clear message in that case. - create_file('side.cpp', r''' + create_file( + 'side.cpp', + r''' #include #include @@ -7676,8 +8939,11 @@ def test_main_module_without_exceptions_message(self): } puts("bad location"); } - ''') - create_file('main.cpp', r''' + ''', + ) + create_file( + 'main.cpp', + r''' #include #include #include @@ -7694,26 +8960,31 @@ def test_main_module_without_exceptions_message(self): f(); return 0; } - ''') + ''', + ) self.run_process([EMXX, '-o', 'libside.wasm', 'side.cpp', '-sSIDE_MODULE', '-fexceptions']) def build_main(args): print(args) with env_modify({'EMCC_FORCE_STDLIBS': 'libc++abi'}): - self.run_process([EMXX, 'main.cpp', '-sMAIN_MODULE', - '--embed-file', 'libside.wasm'] + args) + self.run_process([EMXX, 'main.cpp', '-sMAIN_MODULE', '--embed-file', 'libside.wasm'] + args) build_main([]) out = self.run_js('a.out.js', assert_returncode=NON_ZERO) self.assertContained('Exception thrown, but exception catching is not enabled.', out) - self.assertContained('note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support', out) + self.assertContained( + 'note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support', + out, + ) build_main(['-fexceptions']) out = self.run_js('a.out.js') self.assertContained('catch 42', out) def test_emscripten_print_double(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -7743,10 +9014,12 @@ def test_emscripten_print_double(self): test(1.0/0.0); test(-1.0/0.0); } -''') +''', + ) self.run_process([EMCC, 'src.c']) out = self.run_js('a.out.js') - self.assertContained(''' + self.assertContained( + ''' |0 : 1 : 0 : 0 : 1| |1 : 1 : 1 : 1 : 1| |-1 : 2 : -1 : -1 : 2| @@ -7758,10 +9031,14 @@ def test_emscripten_print_double(self): |-1.1234e-20 : 11 : -1.1234e-20 : -1.1234e-20 : 11| |inf : 8 : Infinity : inf : 3| |-inf : 9 : -Infinity : -inf : 4| -''', out) +''', + out, + ) def test_emscripten_scan_stack(self): - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include #include #include @@ -7791,19 +9068,24 @@ def test_emscripten_scan_stack(self): assert(seenInts.count(12345678)); puts("ok"); } -''') +''', + ) self.run_process([EMXX, 'src.cpp']) self.assertContained('ok', self.run_js('a.out.js')) def test_no_warn_exported_jslibfunc(self): - self.run_process([EMCC, test_file('hello_world.c'), - '-sEXPORTED_FUNCTIONS=_main,_alGetError']) + self.run_process([EMCC, test_file('hello_world.c'), '-sEXPORTED_FUNCTIONS=_main,_alGetError']) # Same again but with `_alGet` wich does not exist. This is a regression # test for a bug we had where any prefix of a valid function was accepted. - err = self.expect_fail([EMCC, test_file('hello_world.c'), - '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=alGetError', - '-sEXPORTED_FUNCTIONS=_main,_alGet']) + err = self.expect_fail( + [ + EMCC, + test_file('hello_world.c'), + '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=alGetError', + '-sEXPORTED_FUNCTIONS=_main,_alGet', + ] + ) self.assertContained('wasm-ld: error: symbol exported via --export not found: alGet', err) def test_musl_syscalls(self): @@ -7815,17 +9097,20 @@ def test_musl_syscalls(self): @crossplatform def test_emcc_dev_null(self): out = self.run_process([EMCC, '-dM', '-E', '-x', 'c', os.devnull], stdout=PIPE).stdout - self.assertContained('#define __EMSCRIPTEN__ 1', out) # all our defines should show up + self.assertContained('#define __EMSCRIPTEN__ 1', out) # all our defines should show up def test_umask_0(self): - create_file('src.c', r'''\ + create_file( + 'src.c', + r'''\ #include #include int main() { umask(0); printf("hello, world!\n"); } -''') +''', + ) self.run_process([EMCC, 'src.c']) self.assertContained('hello, world!', self.run_js('a.out.js')) @@ -7839,15 +9124,20 @@ def test_no_missing_symbols(self): self.run_process([EMCC, test_file('hello_world.c')]) # main() is implemented in C, and even if requested from JS, we should not warn - create_file('library_foo.js', ''' + create_file( + 'library_foo.js', + ''' addToLibrary({ my_js__deps: ['main'], my_js: (function() { return () => console.log("hello " + _nonexistingvariable); }()), }); -''') - create_file('test.c', '''\ +''', + ) + create_file( + 'test.c', + '''\ #include #include @@ -7857,18 +9147,22 @@ def test_no_missing_symbols(self): my_js(); return EXIT_SUCCESS; } -''') +''', + ) self.run_process([EMCC, 'test.c', '--js-library', 'library_foo.js']) # but we do error on a missing js var - create_file('library_foo_missing.js', ''' + create_file( + 'library_foo_missing.js', + ''' addToLibrary({ my_js__deps: ['main', 'nonexistingvariable'], my_js: (function() { return () => console.log("hello " + _nonexistingvariable); }()), }); -''') +''', + ) err = self.expect_fail([EMCC, 'test.c', '--js-library', 'library_foo_missing.js']) self.assertContained('undefined symbol: nonexistingvariable. Required by my_js', err) @@ -7879,15 +9173,20 @@ def test_no_missing_symbols(self): def test_js_lib_native_deps(self): # Verify that memset (which lives in compiled code), can be specified as a JS library # dependency. - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ depper__deps: ['memset'], depper: (ptr) => { _memset(ptr, 'd'.charCodeAt(0), 10); }, }); -''') - create_file('test.c', r''' +''', + ) + create_file( + 'test.c', + r''' #include void depper(char*); @@ -7897,14 +9196,17 @@ def test_js_lib_native_deps(self): depper(buffer); puts(buffer); } -''') +''', + ) self.do_runf('test.c', 'dddddddddd\n', emcc_args=['--js-library', 'lib.js']) def test_js_lib_native_deps_extra(self): # Similar to above but the JS symbol is not used by the native code. # Instead is it explicitly injected using `extraLibraryFuncs`. - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jsfunc__deps: ['raise'], jsfunc: (ptr) => { @@ -7912,7 +9214,8 @@ def test_js_lib_native_deps_extra(self): }, }); extraLibraryFuncs.push('jsfunc'); -''') +''', + ) self.do_runf('hello_world.c', emcc_args=['--js-library', 'lib.js']) @crossplatform @@ -7923,11 +9226,13 @@ def test_realpath(self): self.do_other_test('test_realpath.c', emcc_args=['-sSAFE_HEAP', '--embed-file', 'boot']) @crossplatform - @parameterized({ - '': ([],), - # WasmFS requires FORCE_FILESYSTEM for the full JS API (FS.mkdir etc.). - 'wasmfs': (['-sWASMFS', '-sFORCE_FILESYSTEM'],), - }) + @parameterized( + { + '': ([],), + # WasmFS requires FORCE_FILESYSTEM for the full JS API (FS.mkdir etc.). + 'wasmfs': (['-sWASMFS', '-sFORCE_FILESYSTEM'],), + } + ) def test_realpath_nodefs(self, args): create_file('TEST_NODEFS.txt', ' ') self.do_other_test('test_realpath_nodefs.c', emcc_args=args + ['-lnodefs.js']) @@ -7949,7 +9254,9 @@ def test_no_warnings(self): @crossplatform def test_dlmalloc_modes(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { @@ -7958,7 +9265,8 @@ def test_dlmalloc_modes(self): free(c); printf("double-freed\n"); } - ''') + ''', + ) self.run_process([EMCC, 'src.c']) self.assertContained('double-freed', self.run_js('a.out.js')) # in debug mode, the double-free is caught @@ -7990,6 +9298,7 @@ def run(opts): self.assertLess(sizes['emmalloc'], sizes['dlmalloc'] - 5000) # mimalloc is much larger self.assertGreater(sizes['mimalloc'], sizes['dlmalloc'] - 25000) + run([]) run(['-O2']) @@ -8006,8 +9315,7 @@ def test(args, text=None): test(['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=4GB']) def test_emmalloc_high_align(self): - self.do_other_test('test_emmalloc_high_align.c', - emcc_args=['-sMALLOC=emmalloc', '-sINITIAL_MEMORY=128MB']) + self.do_other_test('test_emmalloc_high_align.c', emcc_args=['-sMALLOC=emmalloc', '-sINITIAL_MEMORY=128MB']) def test_2GB_plus(self): # when the heap size can be over 2GB, we rewrite pointers to be unsigned @@ -8032,12 +9340,20 @@ def test(page_diff): # default maximum memory is 2GB. self.assertEqual(less, none) - @parameterized({ - # atm we only test mimalloc here, as we don't need extra coverage for - # dlmalloc/emmalloc, and this is the main test we have for mimalloc - 'mimalloc': ('mimalloc', ['-DWORKERS=1'],), - 'mimalloc_pthreads': ('mimalloc', ['-DWORKERS=4', '-pthread'],), - }) + @parameterized( + { + # atm we only test mimalloc here, as we don't need extra coverage for + # dlmalloc/emmalloc, and this is the main test we have for mimalloc + 'mimalloc': ( + 'mimalloc', + ['-DWORKERS=1'], + ), + 'mimalloc_pthreads': ( + 'mimalloc', + ['-DWORKERS=4', '-pthread'], + ), + } + ) def test_malloc_multithreading(self, allocator, args): args = args + [ '-O2', @@ -8048,10 +9364,12 @@ def test_malloc_multithreading(self, allocator, args): ] self.do_other_test('test_malloc_multithreading.cpp', emcc_args=args) - @parameterized({ - '': ([], 'testbind.js'), - 'bigint': (['-sWASM_BIGINT'], 'testbind_bigint.js'), - }) + @parameterized( + { + '': ([], 'testbind.js'), + 'bigint': (['-sWASM_BIGINT'], 'testbind_bigint.js'), + } + ) @requires_node def test_i64_return_value(self, args, bind_js): # This test checks that the most significant 32 bits of a 64 bit long are correctly made available @@ -8059,33 +9377,53 @@ def test_i64_return_value(self, args, bind_js): # The MS 32 bits should be available in getTempRet0() even when compiled with -O2 --closure 1 # Compile test.c and wrap it in a native JavaScript binding so we can call our compiled function from JS. - self.run_process([EMCC, test_file('return64bit/test.c'), - '--pre-js', test_file('return64bit/testbindstart.js'), - '--pre-js', test_file('return64bit', bind_js), - '--post-js', test_file('return64bit/testbindend.js'), - '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$dynCall', - '-sEXPORTED_RUNTIME_METHODS=getTempRet0', - '-sEXPORTED_FUNCTIONS=_test_return64', '-o', 'test.js', '-O2', - '--closure=1', '-g1', '-sWASM_ASYNC_COMPILATION=0'] + args) + self.run_process( + [ + EMCC, + test_file('return64bit/test.c'), + '--pre-js', + test_file('return64bit/testbindstart.js'), + '--pre-js', + test_file('return64bit', bind_js), + '--post-js', + test_file('return64bit/testbindend.js'), + '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$dynCall', + '-sEXPORTED_RUNTIME_METHODS=getTempRet0', + '-sEXPORTED_FUNCTIONS=_test_return64', + '-o', + 'test.js', + '-O2', + '--closure=1', + '-g1', + '-sWASM_ASYNC_COMPILATION=0', + ] + + args + ) # Simple test program to load the test.js binding library and call the binding to the # C function returning the 64 bit long. - create_file('testrun.js', ''' + create_file( + 'testrun.js', + ''' var test = require("./test.js"); test.runtest(); - ''') + ''', + ) # Run the test and confirm the output is as expected. self.node_args += shared.node_bigint_flags(self.get_nodejs()) out = self.run_js('testrun.js') - self.assertContained('''\ + self.assertContained( + '''\ input = 0xaabbccdd11223344 low = 5678 high = 1234 input = 0xabcdef1912345678 low = 5678 high = 1234 -''', out) +''', + out, + ) def test_lib_include_flags(self): self.run_process([EMCC] + '-l m -l c -I'.split() + [test_file('include_test'), test_file('lib_include_flags.c')]) @@ -8129,21 +9467,21 @@ def test_dash_s_response_file_misssing(self): def test_dash_s_unclosed_quote(self): # Unclosed quote err = self.expect_fail([EMCC, test_file('hello_world.c'), '-s', "TEST_KEY='MISSING_QUOTE"]) - self.assertNotContained('AssertionError', err) # Do not mention that it is an assertion error + self.assertNotContained('AssertionError', err) # Do not mention that it is an assertion error self.assertContained('error: error parsing "-s" setting', err) self.assertContained('unclosed quoted string. expected final character to be "\'"', err) def test_dash_s_single_quote(self): # Only one quote err = self.expect_fail([EMCC, test_file('hello_world.c'), "-sTEST_KEY='"]) - self.assertNotContained('AssertionError', err) # Do not mention that it is an assertion error + self.assertNotContained('AssertionError', err) # Do not mention that it is an assertion error self.assertContained('error: error parsing "-s" setting', err) self.assertContained('unclosed quoted string.', err) def test_dash_s_unclosed_list(self): # Unclosed list err = self.expect_fail([EMCC, test_file('hello_world.cpp'), "-sTEST_KEY=[Value1, Value2"]) - self.assertNotContained('AssertionError', err) # Do not mention that it is an assertion error + self.assertNotContained('AssertionError', err) # Do not mention that it is an assertion error self.assertContained('error: error parsing "-s" setting', err) self.assertContained('unterminated string list. expected final character to be "]"', err) @@ -8164,7 +9502,7 @@ def test_dash_s_typo(self): self.assertContained('did you mean one of DISABLE_EXCEPTION_CATCHING', stderr) # no suggestions stderr = self.expect_fail([EMCC, test_file('hello_world.c'), '-sCHEEZ']) - self.assertContained("perhaps a typo in emcc\'s -sX=Y notation?", stderr) + self.assertContained("perhaps a typo in emcc's -sX=Y notation?", stderr) self.assertContained('(see src/settings.js for valid values)', stderr) # suggestions do not include renamed legacy settings stderr = self.expect_fail([EMCC, test_file('hello_world.c'), '-sZBINARYEN_ASYNC_COMPILATION']) @@ -8191,21 +9529,26 @@ def test_dash_s_bad_json_types(self): self.assertContained("list members in settings must be strings (not $)", err) def test_zeroinit(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int buf[1048576]; int main() { printf("hello, world! %d\n", buf[123456]); return 0; } -''') +''', + ) self.run_process([EMCC, 'src.c', '-O2']) size = os.path.getsize('a.out.wasm') # size should be much smaller than the size of that zero-initialized buffer self.assertLess(size, 123456 / 2) def test_canonicalize_nan_warning(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include union U { @@ -8219,7 +9562,8 @@ def test_canonicalize_nan_warning(self): printf("0x%x\n", a.x); return 0; } -''') +''', + ) self.run_process([EMCC, 'src.c', '-O1']) out = self.run_js('a.out.js') @@ -8233,9 +9577,7 @@ def test_memory_growth_noasm(self): def test_EM_ASM_i64(self): expected = 'Invalid character 106("j") in readEmAsmArgs!' - self.do_runf('other/test_em_asm_i64.cpp', - expected_output=expected, - assert_returncode=NON_ZERO) + self.do_runf('other/test_em_asm_i64.cpp', expected_output=expected, assert_returncode=NON_ZERO) self.set_setting('WASM_BIGINT') self.do_other_test('test_em_asm_i64.cpp') @@ -8277,15 +9619,15 @@ def test(p1, p2, p3, last, expected): return os.path.getsize('a.out.wasm') print('no bad ctor') - first = test(1000, 2000, 3000, 0xe, 0x58e) # noqa - second = test(3000, 1000, 2000, 0xe, 0x8e5) # noqa - third = test(2000, 3000, 1000, 0xe, 0xe58) # noqa + first = test(1000, 2000, 3000, 0xE, 0x58E) # noqa + second = test(3000, 1000, 2000, 0xE, 0x8E5) # noqa + third = test(2000, 3000, 1000, 0xE, 0xE58) # noqa print(first, second, third) assert first == second and second == third print('with bad ctor') - first = test(1000, 2000, 3000, 0xf, 0x58f) # noqa; 2 will succeed - second = test(3000, 1000, 2000, 0xf, 0x8f5) # noqa; 1 will succedd - third = test(2000, 3000, 1000, 0xf, 0xf58) # noqa; 0 will succeed + first = test(1000, 2000, 3000, 0xF, 0x58F) # noqa; 2 will succeed + second = test(3000, 1000, 2000, 0xF, 0x8F5) # noqa; 1 will succedd + third = test(2000, 3000, 1000, 0xF, 0xF58) # noqa; 0 will succeed print(first, second, third) self.assertLess(first, second) self.assertLess(second, third) @@ -8293,19 +9635,25 @@ def test(p1, p2, p3, last, expected): @uses_canonical_tmp @with_env_modify({'EMCC_DEBUG': '1'}) def test_eval_ctors_debug_output(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ external_thing: () => {} }); -''') - create_file('src.cpp', r''' +''', + ) + create_file( + 'src.cpp', + r''' extern "C" void external_thing(); struct C { C() { external_thing(); } // don't remove this! }; C c; int main() {} - ''') + ''', + ) err = self.run_process([EMXX, 'src.cpp', '--js-library', 'lib.js', '-O2', '-sEVAL_CTORS'], stderr=PIPE).stderr # logging should show we failed, and why self.assertNotContained('ctor_evaller: not successful', err) @@ -8313,14 +9661,16 @@ def test_eval_ctors_debug_output(self): @uses_canonical_tmp @with_env_modify({'EMCC_DEBUG': '1'}) - @parameterized({ - # StackIR optimizations should happen once at the end, and not multiple - # times in the middle. In -O2 we simply do them in the main wasm-opt - # invocation, while in -O3 we run wasm-opt later, and so we should disable - # StackIR first and enable it at the end. - 'O2': (['-O2'], False), - 'O3': (['-O3'], True), - }) + @parameterized( + { + # StackIR optimizations should happen once at the end, and not multiple + # times in the middle. In -O2 we simply do them in the main wasm-opt + # invocation, while in -O3 we run wasm-opt later, and so we should disable + # StackIR first and enable it at the end. + 'O2': (['-O2'], False), + 'O3': (['-O3'], True), + } + ) def test_binaryen_stack_ir(self, opts, disable_and_enable): err = self.run_process([EMXX, test_file('hello_world.c')] + opts, stderr=PIPE).stderr DISABLE = '--no-stack-ir' @@ -8332,7 +9682,9 @@ def test_binaryen_stack_ir(self, opts, disable_and_enable): self.assertLess(err.count(ENABLE), 2) def test_override_js_execution_environment(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include int main() { EM_ASM({ @@ -8342,7 +9694,8 @@ def test_override_js_execution_environment(self): out('environment is SHELL? ' + ENVIRONMENT_IS_SHELL); }); } -''') +''', + ) # use SINGLE_FILE since we don't want to depend on loading a side .wasm file on the environment in this test; # with the wrong env we have very odd failures self.run_process([EMCC, 'main.c', '-sSINGLE_FILE']) @@ -8351,7 +9704,7 @@ def test_override_js_execution_environment(self): for env in envs: for engine in config.JS_ENGINES: if engine == config.V8_ENGINE: - continue # ban v8, weird failures + continue # ban v8, weird failures actual = 'NODE' if engine == config.NODE_JS_TEST else 'SHELL' print(env, actual, engine) module = {'ENVIRONMENT': env} @@ -8362,28 +9715,40 @@ def test_override_js_execution_environment(self): print(' ' + curr) create_file('test.js', curr + src) seen = self.run_js('test.js', engine=engine, assert_returncode=NON_ZERO) - self.assertContained('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node', seen) + self.assertContained( + 'Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node', + seen, + ) def test_override_c_environ(self): - create_file('pre.js', r''' + create_file( + 'pre.js', + r''' Module.preRun = () => { ENV.hello = 'world'; ENV.LANG = undefined; } - ''') - create_file('src.c', r''' + ''', + ) + create_file( + 'src.c', + r''' #include #include int main() { printf("|%s|\n", getenv("hello")); printf("LANG is %s\n", getenv("LANG") ? "set" : "not set"); } - ''') + ''', + ) self.run_process([EMCC, 'src.c', '--pre-js', 'pre.js']) output = self.run_js('a.out.js') self.assertContained('|world|', output) self.assertContained('LANG is not set', output) - create_file('pre.js', r''' + create_file( + 'pre.js', + r''' Module.preRun = (module) => { module.ENV.hello = 'world' } - ''') + ''', + ) self.run_process([EMCC, 'src.c', '--pre-js', 'pre.js', '-sEXPORTED_RUNTIME_METHODS=ENV']) self.assertContained('|world|', self.run_js('a.out.js')) @@ -8401,7 +9766,9 @@ def test_warn_no_filesystem(self): self.assertNotContained(error, seen) def test(contents): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include int main() { @@ -8409,7 +9776,9 @@ def test(contents): printf("hello, world!\n"); return 0; } - ''' % contents) + ''' + % contents, + ) self.do_runf('src.c', error, assert_returncode=NON_ZERO) # might appear in handwritten code @@ -8424,22 +9793,26 @@ def test(contents): # text is in the source when needed, but when forcing FS, it isn't there self.emcc('src.c') self.assertContained(error, read_file('a.out.js')) - self.emcc('src.c', args=['-sFORCE_FILESYSTEM']) # forcing FS means no need + self.emcc('src.c', args=['-sFORCE_FILESYSTEM']) # forcing FS means no need self.assertNotContained(error, read_file('a.out.js')) - self.emcc('src.c', args=['-sASSERTIONS=0']) # no assertions, no need + self.emcc('src.c', args=['-sASSERTIONS=0']) # no assertions, no need self.assertNotContained(error, read_file('a.out.js')) - self.emcc('src.c', args=['-O2']) # optimized, so no assertions + self.emcc('src.c', args=['-O2']) # optimized, so no assertions self.assertNotContained(error, read_file('a.out.js')) def test_warn_module_out_err(self): def test(contents, expected, args=[], assert_returncode=0): # noqa - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { EM_ASM({ %s }); return 0; } - ''' % contents) + ''' + % contents, + ) self.do_runf('src.c', expected, emcc_args=args, assert_returncode=assert_returncode) # error shown (when assertions are on) @@ -8453,16 +9826,24 @@ def test(contents, expected, args=[], assert_returncode=0): # noqa test("Module['out']('print'); Module['err']('err'); ", 'print\nerr', ['-sEXPORTED_RUNTIME_METHODS=out,err']) # test backwards compatibility - test("Module['print']('print'); Module['printErr']('err'); ", 'print\nerr', ['-sEXPORTED_RUNTIME_METHODS=print,printErr', '-Wno-js-compiler']) - - @parameterized({ - '': ('hello_world.c',), - 'argv': ('hello_world_argv.c',), - }) - @parameterized({ - '': ([],), - 'O2': (['-O2'],), - }) + test( + "Module['print']('print'); Module['printErr']('err'); ", + 'print\nerr', + ['-sEXPORTED_RUNTIME_METHODS=print,printErr', '-Wno-js-compiler'], + ) + + @parameterized( + { + '': ('hello_world.c',), + 'argv': ('hello_world_argv.c',), + } + ) + @parameterized( + { + '': ([],), + 'O2': (['-O2'],), + } + ) def test_warn_unexported_main(self, filename, args): warning = 'emcc: warning: `main` is defined in the input files, but `_main` is not in `EXPORTED_FUNCTIONS`. Add it to this list if you want `main` to run. [-Wunused-main]' @@ -8479,7 +9860,9 @@ def test_warn_unexported_main(self, filename, args): self.assertEqual('', output) def test_source_file_with_fixed_language_mode(self): - create_file('src_tmp_fixed_lang', ''' + create_file( + 'src_tmp_fixed_lang', + ''' #include #include @@ -8487,7 +9870,8 @@ def test_source_file_with_fixed_language_mode(self): std::cout << "Test_source_fixed_lang_hello" << std::endl; return 0; } - ''') + ''', + ) self.run_process([EMXX, '-Wall', '-x', 'c++', 'src_tmp_fixed_lang']) self.assertContained('Test_source_fixed_lang_hello', self.run_js('a.out.js')) @@ -8495,7 +9879,9 @@ def test_source_file_with_fixed_language_mode(self): self.assertContained('unknown file type: src_tmp_fixed_lang', stderr) def test_disable_inlining(self): - create_file('test.c', r''' + create_file( + 'test.c', + r''' #include static void foo() { @@ -8506,7 +9892,8 @@ def test_disable_inlining(self): foo(); return 0; } -''') +''', + ) # Without the 'INLINING_LIMIT', -O2 inlines foo() and then DCEs it because it has # no callers and is static @@ -8543,24 +9930,62 @@ def test_binaryen_warn_mem(self): # if user changes INITIAL_MEMORY at runtime, the wasm module may not accept the memory import if # it is too big/small create_file('pre.js', 'Module.INITIAL_MEMORY = 50 * 1024 * 1024') - self.run_process([EMCC, test_file('hello_world.c'), '-sINITIAL_MEMORY=' + str(16 * 1024 * 1024), '--pre-js', 'pre.js', '-sWASM_ASYNC_COMPILATION=0', '-sIMPORTED_MEMORY']) + self.run_process( + [ + EMCC, + test_file('hello_world.c'), + '-sINITIAL_MEMORY=' + str(16 * 1024 * 1024), + '--pre-js', + 'pre.js', + '-sWASM_ASYNC_COMPILATION=0', + '-sIMPORTED_MEMORY', + ] + ) out = self.run_js('a.out.js', assert_returncode=NON_ZERO) self.assertContained('LinkError', out) self.assertContained("memory import 2 has a larger maximum size 800 than the module's declared maximum", out) self.assertNotContained('hello, world!', out) # and with memory growth, all should be good - self.run_process([EMCC, test_file('hello_world.c'), '-sINITIAL_MEMORY=' + str(16 * 1024 * 1024), '--pre-js', 'pre.js', '-sALLOW_MEMORY_GROWTH', '-sWASM_ASYNC_COMPILATION=0', '-sIMPORTED_MEMORY']) + self.run_process( + [ + EMCC, + test_file('hello_world.c'), + '-sINITIAL_MEMORY=' + str(16 * 1024 * 1024), + '--pre-js', + 'pre.js', + '-sALLOW_MEMORY_GROWTH', + '-sWASM_ASYNC_COMPILATION=0', + '-sIMPORTED_MEMORY', + ] + ) self.assertContained('hello, world!', self.run_js('a.out.js')) - @parameterized({ - '': ([], 16 * 1024 * 1024), # Default behavior: 16MB initial heap - 'explicit': (['-sINITIAL_HEAP=64KB'], 64 * 1024), # Explicitly set initial heap is passed - 'with_initial_memory': (['-sINITIAL_MEMORY=40MB'], 0), # Backwards compatibility: no initial heap (we can't tell if it'll fit) - 'with_maximum_memory': (['-sMAXIMUM_MEMORY=40MB', '-sALLOW_MEMORY_GROWTH=1'], 0), # Backwards compatibility: no initial heap (we can't tell if it'll fit) - 'with_all': (['-sINITIAL_HEAP=128KB', '-sINITIAL_MEMORY=20MB', '-sMAXIMUM_MEMORY=40MB', '-sALLOW_MEMORY_GROWTH=1'], 128 * 1024), - 'limited_by_initial_memory': (['-sINITIAL_HEAP=10MB', '-sINITIAL_MEMORY=10MB'], None), # Not enough space for stack - 'limited_by_maximum_memory': (['-sINITIAL_HEAP=5MB', '-sMAXIMUM_MEMORY=5MB', '-sALLOW_MEMORY_GROWTH=1'], None), # Not enough space for stack - }) + @parameterized( + { + '': ([], 16 * 1024 * 1024), # Default behavior: 16MB initial heap + 'explicit': (['-sINITIAL_HEAP=64KB'], 64 * 1024), # Explicitly set initial heap is passed + 'with_initial_memory': ( + ['-sINITIAL_MEMORY=40MB'], + 0, + ), # Backwards compatibility: no initial heap (we can't tell if it'll fit) + 'with_maximum_memory': ( + ['-sMAXIMUM_MEMORY=40MB', '-sALLOW_MEMORY_GROWTH=1'], + 0, + ), # Backwards compatibility: no initial heap (we can't tell if it'll fit) + 'with_all': ( + ['-sINITIAL_HEAP=128KB', '-sINITIAL_MEMORY=20MB', '-sMAXIMUM_MEMORY=40MB', '-sALLOW_MEMORY_GROWTH=1'], + 128 * 1024, + ), + 'limited_by_initial_memory': ( + ['-sINITIAL_HEAP=10MB', '-sINITIAL_MEMORY=10MB'], + None, + ), # Not enough space for stack + 'limited_by_maximum_memory': ( + ['-sINITIAL_HEAP=5MB', '-sMAXIMUM_MEMORY=5MB', '-sALLOW_MEMORY_GROWTH=1'], + None, + ), # Not enough space for stack + } + ) def test_initial_heap(self, args, expected_initial_heap): cmd = [EMCC, test_file('hello_world.c'), '-v'] + args @@ -8577,10 +10002,10 @@ def test_initial_heap(self, args, expected_initial_heap): def test_memory_size(self): for args, expect_initial, expect_max in [ - ([], 320, 320), - (['-sALLOW_MEMORY_GROWTH'], 320, 32768), - (['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=40MB'], 320, 640), - ]: + ([], 320, 320), + (['-sALLOW_MEMORY_GROWTH'], 320, 32768), + (['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=40MB'], 320, 640), + ]: cmd = [EMCC, test_file('hello_world.c'), '-O2', '-sINITIAL_MEMORY=20MB'] + args print(' '.join(cmd)) self.run_process(cmd) @@ -8604,15 +10029,19 @@ def test_invalid_mem(self): self.assertContained('hello, world!', self.run_js('a.out.js')) # Must be a multiple of 64KB - ret = self.expect_fail([EMCC, test_file('hello_world.c'), '-sINITIAL_HEAP=32505857', '-sALLOW_MEMORY_GROWTH']) # 31MB + 1 byte + ret = self.expect_fail( + [EMCC, test_file('hello_world.c'), '-sINITIAL_HEAP=32505857', '-sALLOW_MEMORY_GROWTH'] + ) # 31MB + 1 byte self.assertContained('INITIAL_HEAP must be a multiple of WebAssembly page size (64KiB)', ret) - ret = self.expect_fail([EMCC, test_file('hello_world.c'), '-sINITIAL_MEMORY=33554433']) # 32MB + 1 byte + ret = self.expect_fail([EMCC, test_file('hello_world.c'), '-sINITIAL_MEMORY=33554433']) # 32MB + 1 byte self.assertContained('INITIAL_MEMORY must be a multiple of WebAssembly page size (64KiB)', ret) self.run_process([EMCC, test_file('hello_world.c'), '-sMAXIMUM_MEMORY=33MB', '-sALLOW_MEMORY_GROWTH']) - ret = self.expect_fail([EMCC, test_file('hello_world.c'), '-sMAXIMUM_MEMORY=34603009', '-sALLOW_MEMORY_GROWTH']) # 33MB + 1 byte + ret = self.expect_fail( + [EMCC, test_file('hello_world.c'), '-sMAXIMUM_MEMORY=34603009', '-sALLOW_MEMORY_GROWTH'] + ) # 33MB + 1 byte self.assertContained('MAXIMUM_MEMORY must be a multiple of WebAssembly page size (64KiB)', ret) def test_invalid_memory_max(self): @@ -8621,7 +10050,9 @@ def test_invalid_memory_max(self): def test_dasho_invalid_dir(self): ret = self.expect_fail([EMCC, test_file('hello_world.c'), '-o', Path('NONEXISTING_DIRECTORY/out.js')]) - self.assertContained('specified output file (NONEXISTING_DIRECTORY%sout.js) is in a directory that does not exist' % os.path.sep, ret) + self.assertContained( + 'specified output file (NONEXISTING_DIRECTORY%sout.js) is in a directory that does not exist' % os.path.sep, ret + ) def test_dasho_is_dir(self): ret = self.expect_fail([EMCC, test_file('hello_world.c'), '-o', '.']) @@ -8637,7 +10068,9 @@ def test_dasho_is_dir(self): def test_binaryen_ctors(self): # ctor order must be identical to js builds, deterministically - create_file('src.cpp', r''' + create_file( + 'src.cpp', + r''' #include struct A { A() { puts("constructing A!"); } @@ -8648,7 +10081,8 @@ def test_binaryen_ctors(self): }; B b; int main() {} - ''') + ''', + ) self.run_process([EMXX, 'src.cpp']) correct = self.run_js('a.out.js') for args in ([], ['-sRELOCATABLE']): @@ -8661,18 +10095,18 @@ def test_binaryen_ctors(self): @crossplatform def test_binaryen_debug(self): for args, expect_emit_text, expect_clean_js, expect_whitespace_js, expect_closured in [ - (['-O0'], False, False, True, False), - (['-O0', '-g1'], False, False, True, False), - (['-O0', '-g2'], False, False, True, False), # in -g2+, we emit -g to asm2wasm so function names are saved - (['-O0', '-g'], True, False, True, False), - (['-O0', '--profiling-funcs'], False, False, True, False), - (['-O1'], False, False, True, False), - (['-O2'], False, True, False, False), - (['-O2', '-g1'], False, False, True, False), - (['-O2', '-g'], True, False, True, False), - (['-O2', '--closure=1'], False, True, False, True), - (['-O2', '--closure=1', '-g1'], False, True, True, True), - ]: + (['-O0'], False, False, True, False), + (['-O0', '-g1'], False, False, True, False), + (['-O0', '-g2'], False, False, True, False), # in -g2+, we emit -g to asm2wasm so function names are saved + (['-O0', '-g'], True, False, True, False), + (['-O0', '--profiling-funcs'], False, False, True, False), + (['-O1'], False, False, True, False), + (['-O2'], False, True, False, False), + (['-O2', '-g1'], False, False, True, False), + (['-O2', '-g'], True, False, True, False), + (['-O2', '--closure=1'], False, True, False, True), + (['-O2', '--closure=1', '-g1'], False, True, True, True), + ]: print(args, expect_emit_text, expect_clean_js, expect_whitespace_js, expect_closured) delete_file('a.out.wat') cmd = [EMCC, test_file('hello_world.c')] + args @@ -8681,16 +10115,18 @@ def test_binaryen_debug(self): js = read_file('a.out.js') assert expect_clean_js == ('// ' not in js), 'cleaned-up js must not have comments' assert expect_whitespace_js == ('{\n ' in js), 'whitespace-minified js must not have excess spacing' - assert expect_closured == ('var a;' in js or 'var a,' in js or 'var a=' in js or 'var a ' in js), 'closured js must have tiny variable names' + assert expect_closured == ( + 'var a;' in js or 'var a,' in js or 'var a=' in js or 'var a ' in js + ), 'closured js must have tiny variable names' @uses_canonical_tmp def test_binaryen_ignore_implicit_traps(self): sizes = [] with env_modify({'EMCC_DEBUG': '1'}): for args, expect in [ - ([], False), - (['-sBINARYEN_IGNORE_IMPLICIT_TRAPS'], True), - ]: + ([], False), + (['-sBINARYEN_IGNORE_IMPLICIT_TRAPS'], True), + ]: print(args, expect) cmd = [EMXX, test_file('hello_libcxx.cpp'), '-O3'] + args print(' '.join(cmd)) @@ -8720,39 +10156,54 @@ def test_unoptimized_code_size(self): # changes to the size of the unoptimized and unminified code size. # Run with `--rebase` when this test fails. self.build(test_file('hello_world.c'), emcc_args=['-O0', '--output_eol=linux']) - self.check_expected_size_in_file('wasm', - test_file('other/test_unoptimized_code_size.wasm.size'), - os.path.getsize('hello_world.wasm')) - self.check_expected_size_in_file('js', - test_file('other/test_unoptimized_code_size.js.size'), - os.path.getsize('hello_world.js')) - - self.build(test_file('hello_world.c'), emcc_args=['-O0', '--output_eol=linux', '-sASSERTIONS=0'], output_basename='no_asserts') - self.check_expected_size_in_file('wasm', - test_file('other/test_unoptimized_code_size_no_asserts.wasm.size'), - os.path.getsize('no_asserts.wasm')) - self.check_expected_size_in_file('js', - test_file('other/test_unoptimized_code_size_no_asserts.js.size'), - os.path.getsize('no_asserts.js')) - - self.build(test_file('hello_world.c'), emcc_args=['-O0', '--output_eol=linux', '-sSTRICT'], output_basename='strict') - self.check_expected_size_in_file('wasm', - test_file('other/test_unoptimized_code_size_strict.wasm.size'), - os.path.getsize('strict.wasm')) - self.check_expected_size_in_file('js', - test_file('other/test_unoptimized_code_size_strict.js.size'), - os.path.getsize('strict.js')) - - def run_codesize_test(self, filename, args=[], expected_exists=[], expected_not_exists=[], # noqa - check_funcs=True): + self.check_expected_size_in_file( + 'wasm', test_file('other/test_unoptimized_code_size.wasm.size'), os.path.getsize('hello_world.wasm') + ) + self.check_expected_size_in_file( + 'js', test_file('other/test_unoptimized_code_size.js.size'), os.path.getsize('hello_world.js') + ) + + self.build( + test_file('hello_world.c'), + emcc_args=['-O0', '--output_eol=linux', '-sASSERTIONS=0'], + output_basename='no_asserts', + ) + self.check_expected_size_in_file( + 'wasm', test_file('other/test_unoptimized_code_size_no_asserts.wasm.size'), os.path.getsize('no_asserts.wasm') + ) + self.check_expected_size_in_file( + 'js', test_file('other/test_unoptimized_code_size_no_asserts.js.size'), os.path.getsize('no_asserts.js') + ) + + self.build( + test_file('hello_world.c'), emcc_args=['-O0', '--output_eol=linux', '-sSTRICT'], output_basename='strict' + ) + self.check_expected_size_in_file( + 'wasm', test_file('other/test_unoptimized_code_size_strict.wasm.size'), os.path.getsize('strict.wasm') + ) + self.check_expected_size_in_file( + 'js', test_file('other/test_unoptimized_code_size_strict.js.size'), os.path.getsize('strict.js') + ) + def run_codesize_test( + self, + filename, + args=[], + expected_exists=[], + expected_not_exists=[], # noqa + check_funcs=True, + ): # in -Os, -Oz, we remove imports wasm doesn't need print('Running metadce test: %s:' % filename, args, expected_exists, expected_not_exists, check_funcs) filename = test_file('other/codesize', filename) expected_basename = test_file('other/codesize', self.id().split('.')[-1]) # Run once without closure and parse output to find wasmImports - build_cmd = [compiler_for(filename), filename, '--output_eol=linux', '--emit-minification-map=minify.map'] + args + self.get_emcc_args() + build_cmd = ( + [compiler_for(filename), filename, '--output_eol=linux', '--emit-minification-map=minify.map'] + + args + + self.get_emcc_args() + ) self.run_process(build_cmd + ['-g2']) # find the imports we send from JS # TODO(sbc): Find a way to do that that doesn't depend on internal details of @@ -8764,7 +10215,7 @@ def run_codesize_test(self, filename, args=[], expected_exists=[], expected_not_ self.assertNotEqual(end, -1) start = js.find('{', start) self.assertNotEqual(start, -1) - relevant = js[start + 2:end - 1] + relevant = js[start + 2 : end - 1] relevant = relevant.replace(' ', '').replace('"', '').replace("'", '') relevant = relevant.replace('/**@export*/', '') relevant = relevant.split(',') @@ -8835,21 +10286,23 @@ def strip_numeric_suffixes(funcname): data = '\n'.join(funcs) + '\n' self.assertFileContents(filename, data) - @parameterized({ - 'O0': ([], [], ['waka']), # noqa - 'O1': (['-O1'], [], ['waka']), # noqa - 'O2': (['-O2'], [], ['waka']), # noqa - # in -O3, -Os and -Oz we metadce, and they shrink it down to the minimal output we want - 'O3': (['-O3'], [], []), # noqa - 'Os': (['-Os'], [], []), # noqa - 'Oz': (['-Oz'], [], []), # noqa - 'Os_mr': (['-Os', '-sMINIMAL_RUNTIME'], [], [], 74), # noqa - # EVAL_CTORS also removes the __wasm_call_ctors function - 'Oz-ctors': (['-Oz', '-sEVAL_CTORS'], [], []), # noqa - '64': (['-Oz', '-sMEMORY64'], [], []), # noqa - # WasmFS should not be fully linked into a minimal program. - 'wasmfs': (['-Oz', '-sWASMFS'], [], []), # noqa - }) + @parameterized( + { + 'O0': ([], [], ['waka']), # noqa + 'O1': (['-O1'], [], ['waka']), # noqa + 'O2': (['-O2'], [], ['waka']), # noqa + # in -O3, -Os and -Oz we metadce, and they shrink it down to the minimal output we want + 'O3': (['-O3'], [], []), # noqa + 'Os': (['-Os'], [], []), # noqa + 'Oz': (['-Oz'], [], []), # noqa + 'Os_mr': (['-Os', '-sMINIMAL_RUNTIME'], [], [], 74), # noqa + # EVAL_CTORS also removes the __wasm_call_ctors function + 'Oz-ctors': (['-Oz', '-sEVAL_CTORS'], [], []), # noqa + '64': (['-Oz', '-sMEMORY64'], [], []), # noqa + # WasmFS should not be fully linked into a minimal program. + 'wasmfs': (['-Oz', '-sWASMFS'], [], []), # noqa + } + ) def test_codesize_minimal(self, *args): self.set_setting('STRICT') self.emcc_args.append('--no-entry') @@ -8859,116 +10312,118 @@ def test_codesize_minimal(self, *args): def test_codesize_minimal_pthreads(self): self.run_codesize_test('minimal_main.c', ['-Oz', '-pthread', '-sPROXY_TO_PTHREAD', '-sSTRICT']) - @parameterized({ - 'noexcept': (['-O2'], [], ['waka']), # noqa - # exceptions increases code size significantly - 'except': (['-O2', '-fexceptions'], [], ['waka']), # noqa - # exceptions does not pull in demangling by default, which increases code size - 'mangle': (['-O2', '-fexceptions', - '-sDEMANGLE_SUPPORT', '-Wno-deprecated'], [], ['waka']), # noqa - # Wasm EH's code size increase is smaller than that of Emscripten EH - 'except_wasm': (['-O2', '-fwasm-exceptions'], [], ['waka']), - 'except_wasm_exnref': (['-O2', '-fwasm-exceptions', '-sWASM_EXNREF'], [], ['waka']), - # eval_ctors 1 can partially optimize, but runs into getenv() for locale - # code. mode 2 ignores those and fully optimizes out the ctors - 'ctors1': (['-O2', '-sEVAL_CTORS'], [], ['waka']), - 'ctors2': (['-O2', '-sEVAL_CTORS=2'], [], ['waka']), - 'wasmfs': (['-O2', '-sWASMFS'], [], ['waka']), - 'lto': (['-Oz', '-flto'], [], ['waka']), - }) + @parameterized( + { + 'noexcept': (['-O2'], [], ['waka']), # noqa + # exceptions increases code size significantly + 'except': (['-O2', '-fexceptions'], [], ['waka']), # noqa + # exceptions does not pull in demangling by default, which increases code size + 'mangle': (['-O2', '-fexceptions', '-sDEMANGLE_SUPPORT', '-Wno-deprecated'], [], ['waka']), # noqa + # Wasm EH's code size increase is smaller than that of Emscripten EH + 'except_wasm': (['-O2', '-fwasm-exceptions'], [], ['waka']), + 'except_wasm_exnref': (['-O2', '-fwasm-exceptions', '-sWASM_EXNREF'], [], ['waka']), + # eval_ctors 1 can partially optimize, but runs into getenv() for locale + # code. mode 2 ignores those and fully optimizes out the ctors + 'ctors1': (['-O2', '-sEVAL_CTORS'], [], ['waka']), + 'ctors2': (['-O2', '-sEVAL_CTORS=2'], [], ['waka']), + 'wasmfs': (['-O2', '-sWASMFS'], [], ['waka']), + 'lto': (['-Oz', '-flto'], [], ['waka']), + } + ) def test_codesize_cxx(self, *args): # do not check functions in this test as there are a lot of libc++ functions # pulled in here, and small LLVM backend changes can affect their size and # lead to different inlining decisions which add or remove a function self.run_codesize_test('hello_libcxx.cpp', *args, check_funcs=False) - @parameterized({ - 'O0': ([], [], ['waka']), # noqa - 'O1': (['-O1'], [], ['waka']), # noqa - 'O2': (['-O2'], [], ['waka']), # noqa - 'O3': (['-O3'], [], []), # noqa; in -O3, -Os and -Oz we metadce - 'Os': (['-Os'], [], []), # noqa - 'Oz': (['-Oz'], [], []), # noqa - # finally, check what happens when we export nothing. wasm should be almost empty - 'export_nothing': - (['-Os', '-sEXPORTED_FUNCTIONS=[]'], [], []), # noqa - # we don't metadce with linkable code! other modules may want stuff - # TODO(sbc): Investivate why the number of exports is order of magnitude - # larger for wasm backend. - 'dylink': (['-O3', '-sMAIN_MODULE=2'], [], []), # noqa - # WasmFS should not be fully linked into a hello world program. - 'wasmfs': (['-O3', '-sWASMFS'], [], []), # noqa - }) + @parameterized( + { + 'O0': ([], [], ['waka']), # noqa + 'O1': (['-O1'], [], ['waka']), # noqa + 'O2': (['-O2'], [], ['waka']), # noqa + 'O3': (['-O3'], [], []), # noqa; in -O3, -Os and -Oz we metadce + 'Os': (['-Os'], [], []), # noqa + 'Oz': (['-Oz'], [], []), # noqa + # finally, check what happens when we export nothing. wasm should be almost empty + 'export_nothing': (['-Os', '-sEXPORTED_FUNCTIONS=[]'], [], []), # noqa + # we don't metadce with linkable code! other modules may want stuff + # TODO(sbc): Investivate why the number of exports is order of magnitude + # larger for wasm backend. + 'dylink': (['-O3', '-sMAIN_MODULE=2'], [], []), # noqa + # WasmFS should not be fully linked into a hello world program. + 'wasmfs': (['-O3', '-sWASMFS'], [], []), # noqa + } + ) def test_codesize_hello(self, *args): self.run_codesize_test('hello_world.c', *args) - @parameterized({ - 'O3': ('mem.c', ['-O3'], - [], []), # noqa - # argc/argv support code etc. is in the wasm - 'O3_standalone': ('mem.c', ['-O3', '-sSTANDALONE_WASM'], - [], []), # noqa - # without argc/argv, no support code for them is emitted - 'O3_standalone_narg': ('mem_no_argv.c', ['-O3', '-sSTANDALONE_WASM'], - [], []), # noqa - # without main, no support code for argc/argv is emitted either - 'O3_standalone_lib': ('mem_no_main.c', ['-O3', '-sSTANDALONE_WASM', '--no-entry'], - [], []), # noqa - # Growth support code is in JS, no significant change in the wasm - 'O3_grow': ('mem.c', ['-O3', '-sALLOW_MEMORY_GROWTH'], - [], []), # noqa - # Growth support code is in the wasm - 'O3_grow_standalone': ('mem.c', ['-O3', '-sALLOW_MEMORY_GROWTH', '-sSTANDALONE_WASM'], - [], []), # noqa - # without argc/argv, no support code for them is emitted, even with lto - 'O3_standalone_narg_flto': - ('mem_no_argv.c', ['-O3', '-sSTANDALONE_WASM', '-flto'], - [], []), # noqa - }) + @parameterized( + { + 'O3': ('mem.c', ['-O3'], [], []), # noqa + # argc/argv support code etc. is in the wasm + 'O3_standalone': ('mem.c', ['-O3', '-sSTANDALONE_WASM'], [], []), # noqa + # without argc/argv, no support code for them is emitted + 'O3_standalone_narg': ('mem_no_argv.c', ['-O3', '-sSTANDALONE_WASM'], [], []), # noqa + # without main, no support code for argc/argv is emitted either + 'O3_standalone_lib': ('mem_no_main.c', ['-O3', '-sSTANDALONE_WASM', '--no-entry'], [], []), # noqa + # Growth support code is in JS, no significant change in the wasm + 'O3_grow': ('mem.c', ['-O3', '-sALLOW_MEMORY_GROWTH'], [], []), # noqa + # Growth support code is in the wasm + 'O3_grow_standalone': ('mem.c', ['-O3', '-sALLOW_MEMORY_GROWTH', '-sSTANDALONE_WASM'], [], []), # noqa + # without argc/argv, no support code for them is emitted, even with lto + 'O3_standalone_narg_flto': ('mem_no_argv.c', ['-O3', '-sSTANDALONE_WASM', '-flto'], [], []), # noqa + } + ) def test_codesize_mem(self, filename, *args): self.run_codesize_test(filename, *args) - @parameterized({ - 'O3': (['-O3'], [], []), # noqa - # argc/argv support code etc. is in the wasm - 'O3_standalone': (['-O3', '-sSTANDALONE_WASM'], [], []), # noqa - }) + @parameterized( + { + 'O3': (['-O3'], [], []), # noqa + # argc/argv support code etc. is in the wasm + 'O3_standalone': (['-O3', '-sSTANDALONE_WASM'], [], []), # noqa + } + ) def test_codesize_libcxxabi_message(self, *args): self.run_codesize_test('libcxxabi_message.cpp', *args) - @parameterized({ - 'js_fs': (['-O3', '-sNO_WASMFS'], [], []), # noqa - 'wasmfs': (['-O3', '-sWASMFS'], [], []), # noqa - }) + @parameterized( + { + 'js_fs': (['-O3', '-sNO_WASMFS'], [], []), # noqa + 'wasmfs': (['-O3', '-sWASMFS'], [], []), # noqa + } + ) def test_codesize_files(self, *args): self.run_codesize_test('files.cpp', *args) # ensures runtime exports work, even with metadce - @parameterized({ - '': (False,), - 'legacy': (True,) - }) + @parameterized({'': (False,), 'legacy': (True,)}) def test_exported_runtime_methods_metadce(self, use_legacy_name): exports = ['stackSave', 'stackRestore', 'stackAlloc', 'FS'] setting_name = 'EXPORTED_RUNTIME_METHODS' if use_legacy_name: setting_name = 'EXTRA_EXPORTED_RUNTIME_METHODS' - err = self.run_process([EMCC, test_file('hello_world.c'), '-Os', '-s%s=%s' % (setting_name, ','.join(exports))], stderr=PIPE).stderr + err = self.run_process( + [EMCC, test_file('hello_world.c'), '-Os', '-s%s=%s' % (setting_name, ','.join(exports))], stderr=PIPE + ).stderr if use_legacy_name: - self.assertContained('warning: EXTRA_EXPORTED_RUNTIME_METHODS is deprecated (please use EXPORTED_RUNTIME_METHODS instead). Please open a bug if you have a continuing need for this setting [-Wdeprecated]', err) + self.assertContained( + 'warning: EXTRA_EXPORTED_RUNTIME_METHODS is deprecated (please use EXPORTED_RUNTIME_METHODS instead). Please open a bug if you have a continuing need for this setting [-Wdeprecated]', + err, + ) js = read_file('a.out.js') for export in exports: self.assertContained(f'Module["{export}"]', js) def test_legalize_js_ffi(self): # test disabling of JS FFI legalization - for (args, js_ffi) in [ - (['-sLEGALIZE_JS_FFI=1', '-sSIDE_MODULE', '-O1'], True), - (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O1'], False), - (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O0'], False), - (['-sLEGALIZE_JS_FFI=1', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], True), - (['-sLEGALIZE_JS_FFI=0', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], False), - ]: + for args, js_ffi in [ + (['-sLEGALIZE_JS_FFI=1', '-sSIDE_MODULE', '-O1'], True), + (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O1'], False), + (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O0'], False), + (['-sLEGALIZE_JS_FFI=1', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], True), + (['-sLEGALIZE_JS_FFI=0', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], False), + ]: print(args) delete_file('a.out.wasm') cmd = [EMCC, test_file('other/ffi.c'), '-g', '-o', 'a.out.wasm'] + args @@ -8984,14 +10439,16 @@ def test_legalize_js_ffi(self): assert e_add_f32, 'add_f export missing' i_i64_i32 = re.search(r'import "env" "import_ll" .*\(param i32 i32\) \(result i32\)', text) i_i64_i64 = re.search(r'import "env" "import_ll" .*\(param i64\) \(result i64\)', text) - e_i64_i32 = re.search(r'func \$legalstub\$add_ll \(param i32\) \(param i32\) \(param i32\) \(param i32\) \(result i32\)', text) + e_i64_i32 = re.search( + r'func \$legalstub\$add_ll \(param i32\) \(param i32\) \(param i32\) \(param i32\) \(result i32\)', text + ) if js_ffi: - assert i_i64_i32, 'i64 not converted to i32 in imports' + assert i_i64_i32, 'i64 not converted to i32 in imports' assert not i_i64_i64, 'i64 not converted to i32 in imports' - assert e_i64_i32, 'i64 not converted to i32 in exports' + assert e_i64_i32, 'i64 not converted to i32 in exports' else: assert not i_i64_i32, 'i64 converted to i32 in imports' - assert i_i64_i64, 'i64 converted to i32 in imports' + assert i_i64_i64, 'i64 converted to i32 in imports' assert not e_i64_i32, 'i64 converted to i32 in exports' @disabled('https://github.com/WebAssembly/binaryen/pull/6428') @@ -9034,23 +10491,33 @@ def run(args, expected): run([], 258) run(['-sINITIAL_MEMORY=32MB'], 512) run(['-sINITIAL_MEMORY=32MB', '-sALLOW_MEMORY_GROWTH'], (2 * 1024 * 1024 * 1024) // webassembly.WASM_PAGE_SIZE) - run(['-sINITIAL_MEMORY=32MB', '-sALLOW_MEMORY_GROWTH', '-sWASM=0'], (2 * 1024 * 1024 * 1024) // webassembly.WASM_PAGE_SIZE) + run( + ['-sINITIAL_MEMORY=32MB', '-sALLOW_MEMORY_GROWTH', '-sWASM=0'], + (2 * 1024 * 1024 * 1024) // webassembly.WASM_PAGE_SIZE, + ) def test_wasm_target_and_STANDALONE_WASM(self): # STANDALONE_WASM means we never minify imports and exports. for opts, potentially_expect_minified_exports_and_imports in ( - ([], False), - (['-sSTANDALONE_WASM'], False), - (['-O2'], False), - (['-O3'], True), + ([], False), + (['-sSTANDALONE_WASM'], False), + (['-O2'], False), + (['-O3'], True), (['-O3', '-sSTANDALONE_WASM'], False), - (['-Os'], True), + (['-Os'], True), ): # targeting .wasm (without .js) means we enable STANDALONE_WASM automatically, and don't minify imports/exports for target in ('out.js', 'out.wasm'): expect_minified_exports_and_imports = potentially_expect_minified_exports_and_imports and target.endswith('.js') standalone = target.endswith('.wasm') or 'STANDALONE_WASM' in opts - print(opts, potentially_expect_minified_exports_and_imports, target, ' => ', expect_minified_exports_and_imports, standalone) + print( + opts, + potentially_expect_minified_exports_and_imports, + target, + ' => ', + expect_minified_exports_and_imports, + standalone, + ) self.clear() self.run_process([EMCC, test_file('hello_world.c'), '-o', target] + opts) @@ -9082,10 +10549,12 @@ def test_wasm_target_and_STANDALONE_WASM(self): def test_side_module_naming(self): # SIDE_MODULE should work with any arbirary filename - for opts, target in [([], 'a.out.wasm'), - (['-o', 'lib.wasm'], 'lib.wasm'), - (['-o', 'lib.so'], 'lib.so'), - (['-o', 'foo.bar'], 'foo.bar')]: + for opts, target in [ + ([], 'a.out.wasm'), + (['-o', 'lib.wasm'], 'lib.wasm'), + (['-o', 'lib.so'], 'lib.so'), + (['-o', 'foo.bar'], 'foo.bar'), + ]: # specified target print('building: ' + target) self.clear() @@ -9119,24 +10588,30 @@ def test_side_module_transitive_deps(self): self.run_process(final_link) os.remove('libside1.wasm') err = self.expect_fail(final_link) - self.assertContained('error: libside2.wasm: shared library dependency not found in library path: `libside1.wasm`', err) + self.assertContained( + 'error: libside2.wasm: shared library dependency not found in library path: `libside1.wasm`', err + ) def test_side_module_folder_deps(self): # Build side modules in a subfolder os.mkdir('subdir') self.run_process([EMCC, test_file('hello_world.c'), '-sSIDE_MODULE', '-o', 'subdir/libside1.so']) - self.run_process([EMCC, test_file('hello_world.c'), '-sSIDE_MODULE', '-o', 'subdir/libside2.so', '-L', 'subdir', '-lside1']) + self.run_process( + [EMCC, test_file('hello_world.c'), '-sSIDE_MODULE', '-o', 'subdir/libside2.so', '-L', 'subdir', '-lside1'] + ) self.run_process([EMCC, test_file('hello_world.c'), '-sMAIN_MODULE', '-o', 'main.js', '-L', 'subdir', '-lside2']) @is_slow_test - @parameterized({ - '': ([],), - '01': (['-O1'],), - 'O2': (['-O2'],), - 'O3': (['-O3'],), - 'Os': (['-Os'],), - 'Oz': (['-Oz'],), - }) + @parameterized( + { + '': ([],), + '01': (['-O1'],), + 'O2': (['-O2'],), + 'O3': (['-O3'],), + 'Os': (['-Os'],), + 'Oz': (['-Oz'],), + } + ) def test_lto(self, args): # test building of non-wasm-object-files libraries, building with them, and running them @@ -9166,12 +10641,14 @@ def test_lto(self, args): self.run_process([EMXX, 'hello_obj.o'] + args) self.assertContained('hello, world!', self.run_js('a.out.js')) - @parameterized({ - 'noexcept': [], - 'except': ['-sDISABLE_EXCEPTION_CATCHING=0'], - 'except_wasm': ['-fwasm-exceptions'], - 'except_wasm_exnref': ['-fwasm-exceptions', '-sWASM_EXNREF'] - }) + @parameterized( + { + 'noexcept': [], + 'except': ['-sDISABLE_EXCEPTION_CATCHING=0'], + 'except_wasm': ['-fwasm-exceptions'], + 'except_wasm_exnref': ['-fwasm-exceptions', '-sWASM_EXNREF'], + } + ) def test_lto_libcxx(self, *args): self.run_process([EMXX, test_file('hello_libcxx.cpp'), '-flto'] + list(args)) @@ -9185,7 +10662,9 @@ def test_lto_flags(self): ]: self.run_process([EMCC, test_file('hello_world.c')] + flags + ['-c', '-o', 'a.o']) seen_bitcode = is_bitcode('a.o') - self.assertEqual(expect_bitcode, seen_bitcode, 'must emit LTO-capable bitcode when flags indicate so (%s)' % str(flags)) + self.assertEqual( + expect_bitcode, seen_bitcode, 'must emit LTO-capable bitcode when flags indicate so (%s)' % str(flags) + ) # We have LTO tests covered in 'wasmltoN' targets in test_core.py, but they # don't run as a part of Emscripten CI, so we add a separate LTO test here. @@ -9198,10 +10677,12 @@ def test_lto_wasm_exceptions(self): self.set_setting('WASM_EXNREF') self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') - @parameterized({ - '': ([],), - 'O2': (['-O2'],), - }) + @parameterized( + { + '': ([],), + 'O2': (['-O2'],), + } + ) def test_missing_wasm(self, args): # Check that in debug builds we show a good error message if there is no wasm support create_file('pre.js', 'WebAssembly = undefined;\n') @@ -9251,7 +10732,8 @@ def test_exceptions_stack_trace_and_message(self): 'at (src.wasm.)?_?__cxa_throw', # '___cxa_throw' (JS symbol) for Emscripten EH 'at (src.wasm.)?bar', 'at (src.wasm.)?foo', - 'at (src.wasm.)?main'] + 'at (src.wasm.)?main', + ] if '-fwasm-exceptions' in self.emcc_args: # FIXME Node v18.13 (LTS as of Jan 2023) has not yet implemented the new @@ -9268,14 +10750,12 @@ def test_exceptions_stack_trace_and_message(self): # Prints stack traces self.set_setting('ASSERTIONS', 1) self.set_setting('EXCEPTION_STACK_TRACES', 1) - self.do_run(src, assert_all=True, assert_returncode=NON_ZERO, - expected_output=stack_trace_checks, regex=True) + self.do_run(src, assert_all=True, assert_returncode=NON_ZERO, expected_output=stack_trace_checks, regex=True) # Prints stack traces self.set_setting('ASSERTIONS', 0) self.set_setting('EXCEPTION_STACK_TRACES', 1) - self.do_run(src, assert_all=True, assert_returncode=NON_ZERO, - expected_output=stack_trace_checks, regex=True) + self.do_run(src, assert_all=True, assert_returncode=NON_ZERO, expected_output=stack_trace_checks, regex=True) # Not allowed self.set_setting('ASSERTIONS', 1) @@ -9346,14 +10826,17 @@ def test_exceptions_rethrow_stack_trace_and_message(self): 'std::runtime_error[:,][ ]?my message', # 'std::runtime_error: my message' for Emscripten EH 'at ((src.wasm.)?_?__cxa_rethrow|___resumeException)', # '___resumeException' (JS symbol) for Emscripten EH 'at (src.wasm.)?foo', - 'at (src.wasm.)?main'] + 'at (src.wasm.)?main', + ] self.set_setting('ASSERTIONS', 1) - err = self.do_run(rethrow_src1, assert_all=True, assert_returncode=NON_ZERO, - expected_output=rethrow_stack_trace_checks, regex=True) + err = self.do_run( + rethrow_src1, assert_all=True, assert_returncode=NON_ZERO, expected_output=rethrow_stack_trace_checks, regex=True + ) self.assertNotContained('important_function', err) - err = self.do_run(rethrow_src2, assert_all=True, assert_returncode=NON_ZERO, - expected_output=rethrow_stack_trace_checks, regex=True) + err = self.do_run( + rethrow_src2, assert_all=True, assert_returncode=NON_ZERO, expected_output=rethrow_stack_trace_checks, regex=True + ) self.assertNotContained('important_function', err) @with_all_eh_sjlj @@ -9398,25 +10881,32 @@ def test_error_on_missing_libraries(self): # Tests that if user accidentally attempts to link native object code, we show an error def test_native_link_error_message(self): - self.run_process([CLANG_CC, '--target=' + clang_native.get_native_triple(), '-c', test_file('hello_123.c'), '-o', 'hello_123.o']) + self.run_process( + [CLANG_CC, '--target=' + clang_native.get_native_triple(), '-c', test_file('hello_123.c'), '-o', 'hello_123.o'] + ) err = self.expect_fail([EMCC, 'hello_123.o', '-o', 'hello_123.js']) self.assertContained('unknown file type: hello_123.o', err) # Tests that we should give a clear error on INITIAL_MEMORY not being enough for static initialization + stack def test_clear_error_on_massive_static_data(self): - create_file('src.c', ''' + create_file( + 'src.c', + ''' char muchData[128 * 1024]; int main() { return (int)(long)&muchData; } - ''') + ''', + ) err = self.expect_fail([EMCC, 'src.c', '-sSTACK_SIZE=1KB', '-sINITIAL_MEMORY=64KB']) self.assertContained('wasm-ld: error: initial memory too small', err) def test_o_level_clamp(self): for level in (3, 4, 20): err = self.run_process([EMCC, '-O' + str(level), test_file('hello_world.c')], stderr=PIPE).stderr - self.assertContainedIf("optimization level '-O" + str(level) + "' is not supported; using '-O3' instead", err, level > 3) + self.assertContainedIf( + "optimization level '-O" + str(level) + "' is not supported; using '-O3' instead", err, level > 3 + ) def test_o_level_invalid(self): # Test that string values, and negative integers are not accepted @@ -9472,10 +10962,16 @@ def test_standalone_system_headers(self): # But we still want to check they can be included on there own without # any errors or warnings. cxx_only = header in [ - 'wire.h', 'val.h', 'bind.h', - 'webgpu_cpp.h', 'webgpu_cpp_chained_struct.h', 'webgpu_enum_class_bitmasks.h', + 'wire.h', + 'val.h', + 'bind.h', + 'webgpu_cpp.h', + 'webgpu_cpp_chained_struct.h', + 'webgpu_enum_class_bitmasks.h', # Some headers are not yet C compatible - 'arm_neon.h', 'avxintrin.h', 'immintrin.h', + 'arm_neon.h', + 'avxintrin.h', + 'immintrin.h', ] if directory and directory != 'compat': header = f'{directory}/{header}' @@ -9492,14 +10988,15 @@ def test_standalone_system_headers(self): self.run_process([EMCC, 'a.c', 'b.c'] + std + cflags) @is_slow_test - @parameterized({ - '': (True,), - 'disabled': (False,), - }) + @parameterized( + { + '': (True,), + 'disabled': (False,), + } + ) @also_with_wasm2js def test_single_file(self, single_file_enabled): - for (debug_enabled, - closure_enabled) in itertools.product([True, False], repeat=2): + for debug_enabled, closure_enabled in itertools.product([True, False], repeat=2): # skip unhelpful option combinations if closure_enabled and debug_enabled: continue @@ -9567,12 +11064,15 @@ def test_emar_M(self): create_file('file2', ' ') self.run_process([EMAR, 'cr', 'file1.a', 'file1']) self.run_process([EMAR, 'cr', 'file2.a', 'file2']) - self.run_process([EMAR, '-M'], input='''create combined.a + self.run_process( + [EMAR, '-M'], + input='''create combined.a addlib file1.a addlib file2.a save end -''') +''', + ) result = self.run_process([EMAR, 't', 'combined.a'], stdout=PIPE).stdout self.assertContained('file1', result) self.assertContained('file2', result) @@ -9592,7 +11092,9 @@ def test_emar_response_file(self): create_file("file'2", ' ') create_file("hyvää päivää", ' ') create_file("snowman freezes covid ☃ 🦠", ' ') - rsp = response_file.create_response_file(("file'1", "file'2", "hyvää päivää", "snowman freezes covid ☃ 🦠"), shared.TEMP_DIR) + rsp = response_file.create_response_file( + ("file'1", "file'2", "hyvää päivää", "snowman freezes covid ☃ 🦠"), shared.TEMP_DIR + ) building.emar('cr', 'libfoo.a', ['@' + rsp]) def test_response_file_bom(self): @@ -9634,7 +11136,9 @@ def assert_aliases_match(flag1, flag2, flagarg, extra_args): assert_aliases_match('MAXIMUM_MEMORY', 'BINARYEN_MEM_MAX', '16777216', ['-sALLOW_MEMORY_GROWTH']) def test_IGNORE_CLOSURE_COMPILER_ERRORS(self): - create_file('pre.js', r''' + create_file( + 'pre.js', + r''' // make closure compiler very very angry var dupe = 1; var dupe = 2; @@ -9644,7 +11148,8 @@ def test_IGNORE_CLOSURE_COMPILER_ERRORS(self): function Node() { throw '(duplicate) Node is a DOM thing too, and also use the ' + dupe; } - ''') + ''', + ) def test(check, extra): cmd = [EMCC, test_file('hello_world.c'), '-O2', '--closure=1', '--pre-js', 'pre.js'] + extra @@ -9660,15 +11165,17 @@ def test(check, extra): proc = test(check=True, extra=['-sIGNORE_CLOSURE_COMPILER_ERRORS']) self.assertNotContained(WARNING, proc.stderr) - @parameterized({ - '': ([],), - 'asyncify': (['-sASYNCIFY'],), - # set max_memory to 4GB to test handleI64Signatures() with GL emulation - 'gl_emu': (['-sLEGACY_GL_EMULATION', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH'],), - 'no_exception_throwing': (['-sDISABLE_EXCEPTION_THROWING'],), - 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), - 'embind': (['-lembind'],), - }) + @parameterized( + { + '': ([],), + 'asyncify': (['-sASYNCIFY'],), + # set max_memory to 4GB to test handleI64Signatures() with GL emulation + 'gl_emu': (['-sLEGACY_GL_EMULATION', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH'],), + 'no_exception_throwing': (['-sDISABLE_EXCEPTION_THROWING'],), + 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), + 'embind': (['-lembind'],), + } + ) def test_full_js_library(self, args): self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY'] + args) @@ -9683,32 +11190,38 @@ def test_full_js_library_except(self): self.do_other_test('test_full_js_library_except.cpp') @crossplatform - @parameterized({ - '': [[]], - # bigint support is interesting to test here because it changes which - # binaryen tools get run, which can affect how debug info is kept around - 'bigint': [['-sWASM_BIGINT']], - 'pthread': [['-pthread', '-Wno-experimental']], - 'pthread_offscreen': [['-pthread', '-Wno-experimental', '-sOFFSCREEN_FRAMEBUFFER']], - 'wasmfs': [['-sWASMFS']], - 'min_webgl_version': [['-sMIN_WEBGL_VERSION=2', '-sLEGACY_GL_EMULATION=0']], - }) + @parameterized( + { + '': [[]], + # bigint support is interesting to test here because it changes which + # binaryen tools get run, which can affect how debug info is kept around + 'bigint': [['-sWASM_BIGINT']], + 'pthread': [['-pthread', '-Wno-experimental']], + 'pthread_offscreen': [['-pthread', '-Wno-experimental', '-sOFFSCREEN_FRAMEBUFFER']], + 'wasmfs': [['-sWASMFS']], + 'min_webgl_version': [['-sMIN_WEBGL_VERSION=2', '-sLEGACY_GL_EMULATION=0']], + } + ) def test_closure_full_js_library(self, args): # Test for closure errors and warnings in the entire JS library. - self.build(test_file('hello_world.c'), emcc_args=[ - '--closure=1', - '--minify=0', - '-Werror=closure', - '-sINCLUDE_FULL_LIBRARY', - '-sOFFSCREEN_FRAMEBUFFER', - # Enable as many features as possible in order to maximise - # tha amount of library code we inculde here. - '-sMAIN_MODULE', - '-sFETCH', - '-sFETCH_SUPPORT_INDEXEDDB', - '-sLEGACY_GL_EMULATION', - '-sMAX_WEBGL_VERSION=2', - ] + args) + self.build( + test_file('hello_world.c'), + emcc_args=[ + '--closure=1', + '--minify=0', + '-Werror=closure', + '-sINCLUDE_FULL_LIBRARY', + '-sOFFSCREEN_FRAMEBUFFER', + # Enable as many features as possible in order to maximise + # tha amount of library code we inculde here. + '-sMAIN_MODULE', + '-sFETCH', + '-sFETCH_SUPPORT_INDEXEDDB', + '-sLEGACY_GL_EMULATION', + '-sMAX_WEBGL_VERSION=2', + ] + + args, + ) # Check that closure doesn't minify certain attributes. # This list allows us to verify that it's safe to use normal accessors over @@ -9750,12 +11263,9 @@ def test_closure_full_js_library(self, args): @also_with_wasm64 def test_closure_webgpu(self): # This test can be removed if USE_WEBGPU is later included in INCLUDE_FULL_LIBRARY. - self.build(test_file('hello_world.c'), emcc_args=[ - '--closure=1', - '-Werror=closure', - '-sINCLUDE_FULL_LIBRARY', - '-sUSE_WEBGPU' - ]) + self.build( + test_file('hello_world.c'), emcc_args=['--closure=1', '-Werror=closure', '-sINCLUDE_FULL_LIBRARY', '-sUSE_WEBGPU'] + ) # Tests --closure-args command line flag @crossplatform @@ -9769,10 +11279,10 @@ def test_closure_externs(self): ['--closure-args=--externs=local_externs.js'], ) for args in test_cases: - self.run_process([EMCC, test_file('hello_world.c'), - '--closure=1', - '--pre-js', test_file('test_closure_externs_pre_js.js')] + - args) + self.run_process( + [EMCC, test_file('hello_world.c'), '--closure=1', '--pre-js', test_file('test_closure_externs_pre_js.js')] + + args + ) # Tests that it is possible to enable the Closure compiler via --closure=1 even if any of the input files reside in a path with unicode characters. def test_closure_cmdline_utf8_chars(self): @@ -9796,7 +11306,9 @@ def test_closure_type_annotations(self): console.error("my {attribute}"); }}; ''' - create_file('post.js', ''' + create_file( + 'post.js', + ''' /** @constructor */ function Foo() { this.bar = function() { @@ -9818,16 +11330,21 @@ def test_closure_type_annotations(self): /** Also keep alive certain library functions */ Module['keepalive'] = [_emscripten_start_fetch, _emscripten_pause_main_loop, _SDL_AudioQuit]; - ''' % methods) + ''' + % methods, + ) - self.build(test_file('hello_world.c'), emcc_args=[ - '--closure=1', - '-sINCLUDE_FULL_LIBRARY', - '-sFETCH', - '-sFETCH_SUPPORT_INDEXEDDB', - '-Werror=closure', - '--post-js=post.js' - ]) + self.build( + test_file('hello_world.c'), + emcc_args=[ + '--closure=1', + '-sINCLUDE_FULL_LIBRARY', + '-sFETCH', + '-sFETCH_SUPPORT_INDEXEDDB', + '-Werror=closure', + '--post-js=post.js', + ], + ) code = read_file('hello_world.js') # `bar` method is used so should not be DCE'd self.assertContained('my bar', code) @@ -9881,12 +11398,15 @@ def test_noderawfs_disables_embedding(self): def test_noderawfs_access_abspath(self): create_file('foo', 'bar') - create_file('access.c', r''' + create_file( + 'access.c', + r''' #include int main(int argc, char** argv) { return access(argv[1], F_OK); } - ''') + ''', + ) self.run_process([EMCC, 'access.c', '-sNODERAWFS']) self.run_js('a.out.js', args=[os.path.abspath('foo')]) @@ -9897,9 +11417,7 @@ def test_noderawfs_readfile_prerun(self): @disabled('https://github.com/nodejs/node/issues/18265') def test_node_code_caching(self): - self.run_process([EMCC, test_file('hello_world.c'), - '-sNODE_CODE_CACHING', - '-sWASM_ASYNC_COMPILATION=0']) + self.run_process([EMCC, test_file('hello_world.c'), '-sNODE_CODE_CACHING', '-sWASM_ASYNC_COMPILATION=0']) def get_cached(): cached = glob.glob('a.out.wasm.*.cached') @@ -9930,7 +11448,7 @@ def test_autotools_shared_check(self): @also_with_wasmfs def test_ioctl_window_size(self): - self.do_other_test('test_ioctl_window_size.cpp') + self.do_other_test('test_ioctl_window_size.cpp') @also_with_wasmfs def test_ioctl(self): @@ -9971,19 +11489,24 @@ def test_extern_weak_dynamic(self): def test_main_module_without_main(self): create_file('pre.js', 'Module.onRuntimeInitialized = () => Module._foo();') - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include EMSCRIPTEN_KEEPALIVE void foo() { emscripten_out("bar"); } -''') +''', + ) self.do_runf('src.c', 'bar', emcc_args=['--pre-js', 'pre.js', '-sMAIN_MODULE=2']) @crossplatform def test_js_optimizer_parse_error(self): # check we show a proper understandable error for JS parse problems - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include EM_JS(void, js, (void), { var x = !<->5.; // wtf... this will error on the '<' @@ -9991,12 +11514,18 @@ def test_js_optimizer_parse_error(self): int main() { js(); } -''') +''', + ) stderr = self.expect_fail([EMCC, 'src.c', '-O2'] + self.get_emcc_args()) - self.assertContained((''' + self.assertContained( + ( + ''' function js() { var x = !<->5.; } ^ -'''), stderr) +''' + ), + stderr, + ) @crossplatform def test_js_optimizer_chunk_size_determinism(self): @@ -10007,16 +11536,10 @@ def build(): normal = build() - with env_modify({ - 'EMCC_JSOPT_MIN_CHUNK_SIZE': '1', - 'EMCC_JSOPT_MAX_CHUNK_SIZE': '1' - }): + with env_modify({'EMCC_JSOPT_MIN_CHUNK_SIZE': '1', 'EMCC_JSOPT_MAX_CHUNK_SIZE': '1'}): tiny = build() - with env_modify({ - 'EMCC_JSOPT_MIN_CHUNK_SIZE': '4294967296', - 'EMCC_JSOPT_MAX_CHUNK_SIZE': '4294967296' - }): + with env_modify({'EMCC_JSOPT_MIN_CHUNK_SIZE': '4294967296', 'EMCC_JSOPT_MAX_CHUNK_SIZE': '4294967296'}): huge = build() self.assertIdentical(normal, tiny) @@ -10026,35 +11549,39 @@ def build(): def test_js_optimizer_verbose(self): # build at -O3 with wasm2js to use as much as possible of the JS # optimization code, and verify it works ok in verbose mode - self.run_process([EMCC, test_file('hello_world.c'), '-O3', '-sWASM=0', - '-sVERBOSE'], stdout=PIPE, stderr=PIPE) + self.run_process([EMCC, test_file('hello_world.c'), '-O3', '-sWASM=0', '-sVERBOSE'], stdout=PIPE, stderr=PIPE) def test_pthreads_growth_and_unsigned(self): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { EM_ASM({ HEAP8.set([1,2,3], $0); }, 1024); -}''') - self.run_process([EMCC, 'src.c', '-O2', '--profiling', '-pthread', - '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH']) +}''', + ) + self.run_process([EMCC, 'src.c', '-O2', '--profiling', '-pthread', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH']) # growable-heap must not interfere with heap unsigning, and vice versa: # we must have both applied, that is # - GROWABLE_HEAP_I8() replaces HEAP8 # - $0 gets an >>> 0 unsigning - self.assertContained('GROWABLE_HEAP_I8().set([ 1, 2, 3 ], $0 >>> 0)', - read_file('a.out.js')) - - @parameterized({ - '': ([],), # noqa - 'O3': (['-O3'],), # noqa - 'closure': (['--closure=1'],), # noqa - 'closure_O3': (['--closure=1', '-O3'],), # noqa - }) + self.assertContained('GROWABLE_HEAP_I8().set([ 1, 2, 3 ], $0 >>> 0)', read_file('a.out.js')) + + @parameterized( + { + '': ([],), # noqa + 'O3': (['-O3'],), # noqa + 'closure': (['--closure=1'],), # noqa + 'closure_O3': (['--closure=1', '-O3'],), # noqa + } + ) def test_EM_ASM_ES6(self, args): - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include int main() { EM_ASM({ @@ -10064,7 +11591,8 @@ def test_EM_ASM_ES6(self, args): return x; }); } -''') +''', + ) self.do_runf('src.c', 'hello!', emcc_args=args) def test_check_sourcemapurl(self): @@ -10073,7 +11601,12 @@ def test_check_sourcemapurl(self): self.run_process([EMCC, test_file('hello_123.c'), '-gsource-map', '-o', 'a.js', '--source-map-base', 'dir/']) output = read_binary('a.wasm') # has sourceMappingURL section content and points to 'dir/a.wasm.map' file - source_mapping_url_content = webassembly.to_leb(len('sourceMappingURL')) + b'sourceMappingURL' + webassembly.to_leb(len('dir/a.wasm.map')) + b'dir/a.wasm.map' + source_mapping_url_content = ( + webassembly.to_leb(len('sourceMappingURL')) + + b'sourceMappingURL' + + webassembly.to_leb(len('dir/a.wasm.map')) + + b'dir/a.wasm.map' + ) self.assertEqual(output.count(source_mapping_url_content), 1) # make sure no DWARF debug info sections remain - they would just waste space self.assertNotIn(b'.debug_', output) @@ -10089,10 +11622,12 @@ def test_check_source_map_args(self): self.assertIn('please replace -g4 with -gsource-map', err) self.assertExists('a.out.wasm.map') - @parameterized({ - 'normal': [], - 'profiling': ['--profiling'] # -gsource-map --profiling should still emit a source map; see #8584 - }) + @parameterized( + { + 'normal': [], + 'profiling': ['--profiling'], # -gsource-map --profiling should still emit a source map; see #8584 + } + ) def test_check_sourcemapurl_default(self, *args): if self.is_wasm2js(): self.skipTest('only supported with wasm') @@ -10100,20 +11635,32 @@ def test_check_sourcemapurl_default(self, *args): self.run_process([EMCC, test_file('hello_123.c'), '-gsource-map', '-o', 'a.js'] + list(args)) output = read_binary('a.wasm') # has sourceMappingURL section content and points to 'a.wasm.map' file - source_mapping_url_content = webassembly.to_leb(len('sourceMappingURL')) + b'sourceMappingURL' + webassembly.to_leb(len('a.wasm.map')) + b'a.wasm.map' + source_mapping_url_content = ( + webassembly.to_leb(len('sourceMappingURL')) + + b'sourceMappingURL' + + webassembly.to_leb(len('a.wasm.map')) + + b'a.wasm.map' + ) self.assertIn(source_mapping_url_content, output) def test_wasm_sourcemap(self): # The no_main.c will be read (from relative location) due to speficied "-s" shutil.copy(test_file('other/wasm_sourcemap/no_main.c'), '.') - wasm_map_cmd = [PYTHON, path_from_root('tools/wasm-sourcemap.py'), - '--sources', '--prefix', '=wasm-src://', - '--load-prefix', '/emscripten/test/other/wasm_sourcemap=.', - '--dwarfdump-output', - test_file('other/wasm_sourcemap/foo.wasm.dump'), - '-o', 'a.out.wasm.map', - test_file('other/wasm_sourcemap/foo.wasm'), - '--basepath=' + os.getcwd()] + wasm_map_cmd = [ + PYTHON, + path_from_root('tools/wasm-sourcemap.py'), + '--sources', + '--prefix', + '=wasm-src://', + '--load-prefix', + '/emscripten/test/other/wasm_sourcemap=.', + '--dwarfdump-output', + test_file('other/wasm_sourcemap/foo.wasm.dump'), + '-o', + 'a.out.wasm.map', + test_file('other/wasm_sourcemap/foo.wasm'), + '--basepath=' + os.getcwd(), + ] self.run_process(wasm_map_cmd) output = read_file('a.out.wasm.map') # has "sources" entry with file (includes also `--prefix =wasm-src:///` replacement) @@ -10124,12 +11671,16 @@ def test_wasm_sourcemap(self): self.assertRegexpMatches(output, r'"mappings":\s*"[A-Za-z0-9+/]') def test_wasm_sourcemap_dead(self): - wasm_map_cmd = [PYTHON, path_from_root('tools/wasm-sourcemap.py'), - '--dwarfdump-output', - test_file('other/wasm_sourcemap_dead/t.wasm.dump'), - '-o', 'a.out.wasm.map', - test_file('other/wasm_sourcemap_dead/t.wasm'), - '--basepath=' + os.getcwd()] + wasm_map_cmd = [ + PYTHON, + path_from_root('tools/wasm-sourcemap.py'), + '--dwarfdump-output', + test_file('other/wasm_sourcemap_dead/t.wasm.dump'), + '-o', + 'a.out.wasm.map', + test_file('other/wasm_sourcemap_dead/t.wasm'), + '--basepath=' + os.getcwd(), + ] self.run_process(wasm_map_cmd, stdout=PIPE, stderr=PIPE) output = read_file('a.out.wasm.map') # has only two entries @@ -10144,11 +11695,7 @@ def test(infile, source_map_added_dir=''): expected_source_map_path = source_map_added_dir + '/' + expected_source_map_path print(infile, expected_source_map_path) shutil.copy(test_file('hello_123.c'), infile) - infiles = [ - infile, - os.path.abspath(infile), - './' + infile - ] + infiles = [infile, os.path.abspath(infile), './' + infile] for curr in infiles: print(' ', curr) print(' ', 'same CWD for compiler and linker') @@ -10169,14 +11716,9 @@ def test_wasm_sourcemap_extract_comp_dir_map(self): wasm_sourcemap = importlib.import_module('tools.wasm-sourcemap') def test(dump_file): - dwarfdump_output = read_file( - test_file( - os.path.join('other/wasm_sourcemap_extract_comp_dir_map', - dump_file))) - map_stmt_list_to_comp_dir = wasm_sourcemap.extract_comp_dir_map( - dwarfdump_output) - self.assertEqual(map_stmt_list_to_comp_dir, - {'0x00000000': '/emsdk/emscripten'}) + dwarfdump_output = read_file(test_file(os.path.join('other/wasm_sourcemap_extract_comp_dir_map', dump_file))) + map_stmt_list_to_comp_dir = wasm_sourcemap.extract_comp_dir_map(dwarfdump_output) + self.assertEqual(map_stmt_list_to_comp_dir, {'0x00000000': '/emsdk/emscripten'}) # Make sure we can extract the compilation directories no matter what the # order of `DW_AT_*` attributes is. @@ -10196,8 +11738,7 @@ def get_instr_addr(self, text, filename): The addresses here are the offsets to the start of the file. Returns the address string in hexadecimal. ''' - out = self.run_process([common.LLVM_OBJDUMP, '-d', filename], - stdout=PIPE).stdout.strip() + out = self.run_process([common.LLVM_OBJDUMP, '-d', filename], stdout=PIPE).stdout.strip() out_lines = out.splitlines() found = False for line in out_lines: @@ -10210,26 +11751,22 @@ def get_instr_addr(self, text, filename): def test_emsymbolizer_srcloc(self): 'Test emsymbolizer use cases that provide src location granularity info' + def check_dwarf_loc_info(address, funcs, locs): - out = self.run_process( - [emsymbolizer, '-s', 'dwarf', 'test_dwarf.wasm', address], - stdout=PIPE).stdout + out = self.run_process([emsymbolizer, '-s', 'dwarf', 'test_dwarf.wasm', address], stdout=PIPE).stdout for func in funcs: self.assertIn(func, out) for loc in locs: self.assertIn(loc, out) def check_source_map_loc_info(address, loc): - out = self.run_process( - [emsymbolizer, '-s', 'sourcemap', 'test_dwarf.wasm', address], - stdout=PIPE).stdout + out = self.run_process([emsymbolizer, '-s', 'sourcemap', 'test_dwarf.wasm', address], stdout=PIPE).stdout self.assertIn(loc, out) # We test two locations within test_dwarf.c: # out_to_js(0); // line 6 # __builtin_trap(); // line 13 - self.run_process([EMCC, test_file('core/test_dwarf.c'), - '-g', '-gsource-map', '-O1', '-o', 'test_dwarf.js']) + self.run_process([EMCC, test_file('core/test_dwarf.c'), '-g', '-gsource-map', '-O1', '-o', 'test_dwarf.js']) # Address of out_to_js(0) within foo(), uninlined out_to_js_call_addr = self.get_instr_addr('call\t0', 'test_dwarf.wasm') # Address of __builtin_trap() within bar(), inlined into main() @@ -10251,8 +11788,7 @@ def check_source_map_loc_info(address, loc): # For DWARF, we check for the full inlined info for both function names and # source locations. Source maps provide neither function names nor inlined # info. So we only check for the source location of the outermost function. - check_dwarf_loc_info(out_to_js_call_addr, out_to_js_call_func, - out_to_js_call_loc) + check_dwarf_loc_info(out_to_js_call_addr, out_to_js_call_func, out_to_js_call_loc) check_source_map_loc_info(out_to_js_call_addr, out_to_js_call_loc[0]) check_dwarf_loc_info(unreachable_addr, unreachable_func, unreachable_loc) check_source_map_loc_info(unreachable_addr, unreachable_loc[0]) @@ -10261,28 +11797,24 @@ def check_source_map_loc_info(address, loc): # The addresses, function names, and source locations are the same across # the builds because they are relative offsets from the code section, so we # don't need to recompute them - self.run_process([EMCC, test_file('core/test_dwarf.c'), - '-gsource-map', '-O1', '-o', 'test_dwarf.js']) + self.run_process([EMCC, test_file('core/test_dwarf.c'), '-gsource-map', '-O1', '-o', 'test_dwarf.js']) check_source_map_loc_info(out_to_js_call_addr, out_to_js_call_loc[0]) check_source_map_loc_info(unreachable_addr, unreachable_loc[0]) # 3. Test DWARF only - self.run_process([EMCC, test_file('core/test_dwarf.c'), - '-g', '-O1', '-o', 'test_dwarf.js']) - check_dwarf_loc_info(out_to_js_call_addr, out_to_js_call_func, - out_to_js_call_loc) + self.run_process([EMCC, test_file('core/test_dwarf.c'), '-g', '-O1', '-o', 'test_dwarf.js']) + check_dwarf_loc_info(out_to_js_call_addr, out_to_js_call_func, out_to_js_call_loc) check_dwarf_loc_info(unreachable_addr, unreachable_func, unreachable_loc) def test_emsymbolizer_functions(self): 'Test emsymbolizer use cases that only provide function-granularity info' + def check_func_info(filename, address, func): - out = self.run_process( - [emsymbolizer, filename, address], stdout=PIPE).stdout + out = self.run_process([emsymbolizer, filename, address], stdout=PIPE).stdout self.assertIn(func, out) # 1. Test name section only - self.run_process([EMCC, test_file('core/test_dwarf.c'), - '--profiling-funcs', '-O1', '-o', 'test_dwarf.js']) + self.run_process([EMCC, test_file('core/test_dwarf.c'), '--profiling-funcs', '-O1', '-o', 'test_dwarf.js']) with webassembly.Module('test_dwarf.wasm') as wasm: self.assertTrue(wasm.has_name_section()) self.assertIsNone(wasm.get_custom_section('.debug_info')) @@ -10310,9 +11842,7 @@ def test_separate_dwarf(self): # building to a subdirectory should still leave a relative path, which # assumes the debug file is alongside the main one os.mkdir('subdir') - self.run_process([EMCC, test_file('hello_world.c'), - '-gseparate-dwarf', - '-o', Path('subdir/output.js')]) + self.run_process([EMCC, test_file('hello_world.c'), '-gseparate-dwarf', '-o', Path('subdir/output.js')]) wasm = read_binary('subdir/output.wasm') self.assertIn(b'output.wasm.debug.wasm', wasm) # check both unix-style slashes and the system's slashes, so that we don't @@ -10333,9 +11863,7 @@ def test_separate_dwarf(self): pass # Check that dwarfdump can dump the debug info - dwdump = self.run_process( - [LLVM_DWARFDUMP, 'subdir/output.wasm.debug.wasm', '-name', 'main'], - stdout=PIPE).stdout + dwdump = self.run_process([LLVM_DWARFDUMP, 'subdir/output.wasm.debug.wasm', '-name', 'main'], stdout=PIPE).stdout # Basic check that the debug info is more than a skeleton. If so it will # have a subprogram descriptor for main self.assertIn('DW_TAG_subprogram', dwdump) @@ -10353,8 +11881,7 @@ def test_split_dwarf_dwp(self): self.assertNotIn('DW_AT_name\t("main")', dwdump) # The dwo will have a subprogram for main in a section with a .dwo suffix - dwdump = self.run_process([LLVM_DWARFDUMP, 'hello_world.dwo'], - stdout=PIPE).stdout + dwdump = self.run_process([LLVM_DWARFDUMP, 'hello_world.dwo'], stdout=PIPE).stdout self.assertIn('.debug_info.dwo contents:', dwdump) self.assertIn('DW_AT_GNU_dwo_name\t("hello_world.dwo")', dwdump) self.assertIn('DW_AT_name\t("main")', dwdump) @@ -10379,9 +11906,9 @@ def test_separate_dwarf_with_filename(self): # building to a subdirectory, but with the debug file in another place, # should leave a relative path to the debug wasm os.mkdir('subdir') - self.run_process([EMCC, test_file('hello_world.c'), - '-o', Path('subdir/output.js'), - '-gseparate-dwarf=with_dwarf2.wasm']) + self.run_process( + [EMCC, test_file('hello_world.c'), '-o', Path('subdir/output.js'), '-gseparate-dwarf=with_dwarf2.wasm'] + ) self.assertExists('with_dwarf2.wasm') wasm = read_binary('subdir/output.wasm') self.assertIn(b'../with_dwarf2.wasm', wasm) @@ -10389,8 +11916,14 @@ def test_separate_dwarf_with_filename(self): def test_separate_dwarf_with_filename_and_path(self): self.run_process([EMCC, test_file('hello_world.c'), '-gseparate-dwarf=with_dwarf.wasm']) self.assertIn(b'with_dwarf.wasm', read_binary('a.out.wasm')) - self.run_process([EMCC, test_file('hello_world.c'), '-gseparate-dwarf=with_dwarf.wasm', - '-sSEPARATE_DWARF_URL=http://somewhere.com/hosted.wasm']) + self.run_process( + [ + EMCC, + test_file('hello_world.c'), + '-gseparate-dwarf=with_dwarf.wasm', + '-sSEPARATE_DWARF_URL=http://somewhere.com/hosted.wasm', + ] + ) self.assertIn(b'somewhere.com/hosted.wasm', read_binary('a.out.wasm')) @crossplatform @@ -10402,17 +11935,19 @@ def test_dwarf_system_lib(self): self.assertExists(libc) dwdump = self.run_process( - [LLVM_DWARFDUMP, libc, '-debug-info', '-debug-line', '--recurse-depth=0'], - stdout=PIPE).stdout + [LLVM_DWARFDUMP, libc, '-debug-info', '-debug-line', '--recurse-depth=0'], stdout=PIPE + ).stdout # Check that the embedded location of the source file is correct. self.assertIn('DW_AT_name\t("system/lib/emmalloc.c")', dwdump) self.assertIn('DW_AT_comp_dir\t("/emsdk/emscripten")', dwdump) - @parameterized({ - 'O0': (['-O0'],), - 'O1': (['-O1'],), - 'O2': (['-O2'],), - }) + @parameterized( + { + 'O0': (['-O0'],), + 'O1': (['-O1'],), + 'O2': (['-O2'],), + } + ) def test_wasm_producers_section(self, args): self.run_process([EMCC, test_file('hello_world.c')] + args) # if there is no producers section expected by default, verify that, and @@ -10424,13 +11959,15 @@ def test_wasm_producers_section(self, args): size_with_section = os.path.getsize('a.out.wasm') self.assertLess(size, size_with_section) - @parameterized({ - '': ([],), - # in some modes we skip wasm-emscripten-finalize, which normally strips the - # features section for us, so add testing for those - 'bigint': (['-sWASM_BIGINT'],), - 'wasm64': (['-sMEMORY64'],), - }) + @parameterized( + { + '': ([],), + # in some modes we skip wasm-emscripten-finalize, which normally strips the + # features section for us, so add testing for those + 'bigint': (['-sWASM_BIGINT'],), + 'wasm64': (['-sMEMORY64'],), + } + ) def test_wasm_features_section(self, args): # The features section should never be in our output, when we optimize. self.run_process([EMCC, test_file('hello_world.c'), '-O2'] + args) @@ -10442,12 +11979,12 @@ def verify_features_sec(feature, expect_in, linked=False): with webassembly.Module('a.out.wasm' if linked else 'hello_world.o') as module: features = module.get_target_features() if expect_in: - self.assertTrue(feature in features and - features[feature] == webassembly.TargetFeaturePrefix.USED, - f'{feature} missing from wasm file') + self.assertTrue( + feature in features and features[feature] == webassembly.TargetFeaturePrefix.USED, + f'{feature} missing from wasm file', + ) else: - self.assertFalse(feature in features, - f'{feature} unexpectedly found in wasm file') + self.assertFalse(feature in features, f'{feature} unexpectedly found in wasm file') def verify_features_sec_linked(feature, expect_in): return verify_features_sec(feature, expect_in, linked=True) @@ -10497,7 +12034,9 @@ def compile(flags): def test_js_preprocess(self): # Use stderr rather than stdout here because stdout is redirected to the output JS file itself. - create_file('lib.js', ''' + create_file( + 'lib.js', + ''' #if MAIN_MODULE == 1 console.error('JSLIB: MAIN_MODULE=1'); #elif MAIN_MODULE == 2 @@ -10507,22 +12046,29 @@ def test_js_preprocess(self): #else console.error('JSLIB: none of the above'); #endif -''') +''', + ) err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'], stderr=PIPE).stderr self.assertContained('JSLIB: none of the above', err) self.assertNotContained('JSLIB: MAIN_MODULE', err) self.assertNotContained('JSLIB: EXIT_RUNTIME', err) - err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sMAIN_MODULE'], stderr=PIPE).stderr + err = self.run_process( + [EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sMAIN_MODULE'], stderr=PIPE + ).stderr self.assertContained('JSLIB: MAIN_MODULE=1', err) self.assertNotContained('JSLIB: EXIT_RUNTIME', err) - err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sMAIN_MODULE=2'], stderr=PIPE).stderr + err = self.run_process( + [EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sMAIN_MODULE=2'], stderr=PIPE + ).stderr self.assertContained('JSLIB: MAIN_MODULE=2', err) self.assertNotContained('JSLIB: EXIT_RUNTIME', err) - err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sEXIT_RUNTIME'], stderr=PIPE).stderr + err = self.run_process( + [EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sEXIT_RUNTIME'], stderr=PIPE + ).stderr self.assertContained('JSLIB: EXIT_RUNTIME', err) self.assertNotContained('JSLIB: MAIN_MODULE', err) @@ -10532,9 +12078,12 @@ def test_html_preprocess(self): output_file = 'test_stdin.html' shell_file = test_file('module/test_html_preprocess.html') - self.run_process([EMCC, '-o', output_file, src_file, '--shell-file', shell_file, '-sASSERTIONS=0'], stdout=PIPE, stderr=PIPE) + self.run_process( + [EMCC, '-o', output_file, src_file, '--shell-file', shell_file, '-sASSERTIONS=0'], stdout=PIPE, stderr=PIPE + ) output = read_file(output_file) - self.assertContained('''