diff --git a/.circleci/config.yml b/.circleci/config.yml index 78dd8b7383437..482e2cdf4a50d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -427,6 +427,7 @@ jobs: - run: ruff check # TODO (cclauss): When ruff supports rule E303 without --preview, remove following line - run: ruff check --preview --select=E303 + - run: ruff format mypy: executor: focal steps: diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index de72b98c2c862..0000000000000 --- a/.style.yapf +++ /dev/null @@ -1,3 +0,0 @@ -[style] -based_on_style = pep8 -indent_width = 2 diff --git a/bootstrap.py b/bootstrap.py index ff9d55dc129a2..bfd95fb7b5b3a 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -7,6 +7,7 @@ on the timestamps of various input files (kind of like a dumb version of a Makefile). """ + import argparse import os import shutil @@ -21,13 +22,16 @@ actions = [ ('npm packages', ['package.json'], [shutil.which('npm'), 'ci']), - ('create entry points', [ - 'tools/maint/create_entry_points.py', - 'tools/maint/run_python.bat', - 'tools/maint/run_python.sh', - 'tools/maint/run_python.ps1', - ], - [sys.executable, 'tools/maint/create_entry_points.py']), + ( + 'create entry points', + [ + 'tools/maint/create_entry_points.py', + 'tools/maint/run_python.bat', + 'tools/maint/run_python.sh', + 'tools/maint/run_python.ps1', + ], + [sys.executable, 'tools/maint/create_entry_points.py'], + ), ('git submodules', ['test/third_party/posixtestsuite/'], [shutil.which('git'), 'submodule', 'update', '--init']), ] @@ -57,7 +61,9 @@ def main(args): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-v', '--verbose', action='store_true', help='verbose', default=False) parser.add_argument('-n', '--dry-run', action='store_true', help='dry run', default=False) - parser.add_argument('-i', '--install-post-checkout', action='store_true', help='install post checkout script', default=False) + parser.add_argument( + '-i', '--install-post-checkout', action='store_true', help='install post checkout script', default=False + ) args = parser.parse_args() if args.install_post_checkout: diff --git a/docs/process.md b/docs/process.md index f1bf04a714a11..5a5a7f2ff8243 100644 --- a/docs/process.md +++ b/docs/process.md @@ -55,8 +55,9 @@ pre-processor. See [`.clang-format`][clang-format] for more details. ### Python Code We generally follow the pep8 standard with the major exception that we use 2 -spaces for indentation. `ruff` is run on all PRs to ensure that Python code -conforms to this style. See [`pyproject.toml`][pyproject.toml] for more details. +spaces for indentation. `ruff check` and `ruff format` are run on all PRs to +ensure that Python code conforms to this style. See +[`pyproject.toml`][pyproject.toml] for more details. #### Static Type Checking diff --git a/em-config.py b/em-config.py index bcbd9abe1cf8d..73e4e009bfd47 100755 --- a/em-config.py +++ b/em-config.py @@ -20,9 +20,7 @@ def main(): - if len(sys.argv) != 2 or \ - not re.match(r"^[\w\W_][\w\W_\d]*$", sys.argv[1]) or \ - not hasattr(config, sys.argv[1]): + if len(sys.argv) != 2 or not re.match(r"^[\w\W_][\w\W_\d]*$", sys.argv[1]) or not hasattr(config, sys.argv[1]): print('Usage: em-config VAR_NAME', file=sys.stderr) sys.exit(1) diff --git a/emar.py b/emar.py index 061fc5d4ce927..88625b01407c1 100755 --- a/emar.py +++ b/emar.py @@ -4,8 +4,7 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -"""Wrapper script around `llvm-ar`. -""" +"""Wrapper script around `llvm-ar`.""" import sys from tools import shared diff --git a/embuilder.py b/embuilder.py index af634eea12d13..3e60d7857b9c8 100755 --- a/embuilder.py +++ b/embuilder.py @@ -30,96 +30,96 @@ # Minimal subset of targets used by CI systems to build enough to be useful MINIMAL_TASKS = [ - 'libbulkmemory', - 'libcompiler_rt', - 'libcompiler_rt-wasm-sjlj', - 'libcompiler_rt-ww', - 'libc', - 'libc-debug', - 'libc-ww-debug', - 'libc_optz', - 'libc_optz-debug', - 'libc++abi', - 'libc++abi-except', - 'libc++abi-noexcept', - 'libc++abi-debug', - 'libc++abi-debug-except', - 'libc++abi-debug-noexcept', - 'libc++abi-debug-ww-noexcept', - 'libc++', - 'libc++-except', - 'libc++-noexcept', - 'libc++-ww-noexcept', - 'libal', - 'libdlmalloc', - 'libdlmalloc-tracing', - 'libdlmalloc-debug', - 'libdlmalloc-ww', - 'libembind', - 'libembind-rtti', - 'libemmalloc', - 'libemmalloc-debug', - 'libemmalloc-memvalidate', - 'libemmalloc-verbose', - 'libemmalloc-memvalidate-verbose', - 'libmimalloc', - 'libmimalloc-mt', - 'libGL', - 'libGL-getprocaddr', - 'libGL-emu-getprocaddr', - 'libGL-emu-webgl2-ofb-getprocaddr', - 'libGL-webgl2-ofb-getprocaddr', - 'libGL-ww-getprocaddr', - 'libhtml5', - 'libsockets', - 'libsockets-ww', - 'libstubs', - 'libstubs-debug', - 'libstandalonewasm-nocatch', - 'crt1', - 'crt1_proxy_main', - 'crtbegin', - 'libunwind-except', - 'libnoexit', - 'sqlite3', - 'sqlite3-mt', - 'libwebgpu', - 'libwebgpu_cpp', + 'libbulkmemory', + 'libcompiler_rt', + 'libcompiler_rt-wasm-sjlj', + 'libcompiler_rt-ww', + 'libc', + 'libc-debug', + 'libc-ww-debug', + 'libc_optz', + 'libc_optz-debug', + 'libc++abi', + 'libc++abi-except', + 'libc++abi-noexcept', + 'libc++abi-debug', + 'libc++abi-debug-except', + 'libc++abi-debug-noexcept', + 'libc++abi-debug-ww-noexcept', + 'libc++', + 'libc++-except', + 'libc++-noexcept', + 'libc++-ww-noexcept', + 'libal', + 'libdlmalloc', + 'libdlmalloc-tracing', + 'libdlmalloc-debug', + 'libdlmalloc-ww', + 'libembind', + 'libembind-rtti', + 'libemmalloc', + 'libemmalloc-debug', + 'libemmalloc-memvalidate', + 'libemmalloc-verbose', + 'libemmalloc-memvalidate-verbose', + 'libmimalloc', + 'libmimalloc-mt', + 'libGL', + 'libGL-getprocaddr', + 'libGL-emu-getprocaddr', + 'libGL-emu-webgl2-ofb-getprocaddr', + 'libGL-webgl2-ofb-getprocaddr', + 'libGL-ww-getprocaddr', + 'libhtml5', + 'libsockets', + 'libsockets-ww', + 'libstubs', + 'libstubs-debug', + 'libstandalonewasm-nocatch', + 'crt1', + 'crt1_proxy_main', + 'crtbegin', + 'libunwind-except', + 'libnoexit', + 'sqlite3', + 'sqlite3-mt', + 'libwebgpu', + 'libwebgpu_cpp', ] # Additional tasks on top of MINIMAL_TASKS that are necessary for PIC testing on # CI (which has slightly more tests than other modes that want to use MINIMAL) MINIMAL_PIC_TASKS = MINIMAL_TASKS + [ - 'libcompiler_rt-mt', - 'libc-mt', - 'libc-mt-debug', - 'libc_optz-mt', - 'libc_optz-mt-debug', - 'libc++abi-mt', - 'libc++abi-mt-noexcept', - 'libc++abi-debug-mt', - 'libc++abi-debug-mt-noexcept', - 'libc++-mt', - 'libc++-mt-noexcept', - 'libdlmalloc-mt', - 'libGL-emu', - 'libGL-emu-webgl2-getprocaddr', - 'libGL-mt-getprocaddr', - 'libGL-mt-emu', - 'libGL-mt-emu-webgl2-getprocaddr', - 'libGL-mt-emu-webgl2-ofb-getprocaddr', - 'libsockets_proxy', - 'libsockets-mt', - 'crtbegin', - 'libsanitizer_common_rt', - 'libubsan_rt', - 'libwasm_workers-debug-stub', - 'libfetch', - 'libfetch-mt', - 'libwasmfs', - 'libwasmfs-debug', - 'libwasmfs_no_fs', - 'giflib', + 'libcompiler_rt-mt', + 'libc-mt', + 'libc-mt-debug', + 'libc_optz-mt', + 'libc_optz-mt-debug', + 'libc++abi-mt', + 'libc++abi-mt-noexcept', + 'libc++abi-debug-mt', + 'libc++abi-debug-mt-noexcept', + 'libc++-mt', + 'libc++-mt-noexcept', + 'libdlmalloc-mt', + 'libGL-emu', + 'libGL-emu-webgl2-getprocaddr', + 'libGL-mt-getprocaddr', + 'libGL-mt-emu', + 'libGL-mt-emu-webgl2-getprocaddr', + 'libGL-mt-emu-webgl2-ofb-getprocaddr', + 'libsockets_proxy', + 'libsockets-mt', + 'crtbegin', + 'libsanitizer_common_rt', + 'libubsan_rt', + 'libwasm_workers-debug-stub', + 'libfetch', + 'libfetch-mt', + 'libwasmfs', + 'libwasmfs-debug', + 'libwasmfs_no_fs', + 'giflib', ] PORTS = sorted(list(ports.ports_by_name.keys()) + list(ports.port_variants.keys())) @@ -187,19 +187,17 @@ def handle_port_error(target, message): def main(): all_build_start_time = time.time() - parser = argparse.ArgumentParser(description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=get_help()) + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=get_help() + ) parser.add_argument('--lto', action='store_const', const='full', help='build bitcode object for LTO') - parser.add_argument('--lto=thin', dest='lto', action='store_const', const='thin', help='build bitcode object for ThinLTO') - parser.add_argument('--pic', action='store_true', - help='build relocatable objects for suitable for dynamic linking') - parser.add_argument('--force', action='store_true', - help='force rebuild of target (by removing it first)') - parser.add_argument('--verbose', action='store_true', - help='show build commands') - parser.add_argument('--wasm64', action='store_true', - help='use wasm64 architecture') + parser.add_argument( + '--lto=thin', dest='lto', action='store_const', const='thin', help='build bitcode object for ThinLTO' + ) + parser.add_argument('--pic', action='store_true', help='build relocatable objects for suitable for dynamic linking') + parser.add_argument('--force', action='store_true', help='force rebuild of target (by removing it first)') + parser.add_argument('--verbose', action='store_true', help='show build commands') + parser.add_argument('--wasm64', action='store_true', help='use wasm64 architecture') parser.add_argument('operation', choices=['build', 'clear', 'rebuild']) parser.add_argument('targets', nargs='*', help='see below') args = parser.parse_args() @@ -240,7 +238,7 @@ def main(): # process tasks auto_tasks = False - task_targets = dict.fromkeys(args.targets) # use dict to keep targets order + task_targets = dict.fromkeys(args.targets) # use dict to keep targets order # substitute predefined_tasks = { @@ -315,14 +313,28 @@ def main(): return 1 time_taken = time.time() - start_time - logger.info('...success. Took %s(%.2fs)' % (('%02d:%02d mins ' % (time_taken // 60, time_taken % 60) if time_taken >= 60 else ''), time_taken)) + logger.info( + '...success. Took %s(%.2fs)' + % (('%02d:%02d mins ' % (time_taken // 60, time_taken % 60) if time_taken >= 60 else ''), time_taken) + ) if USE_NINJA and args.operation != 'clear': system_libs.build_deferred() if len(tasks) > 1 or USE_NINJA: all_build_time_taken = time.time() - all_build_start_time - logger.info('Built %d targets in %s(%.2fs)' % (len(tasks), ('%02d:%02d mins ' % (all_build_time_taken // 60, all_build_time_taken % 60) if all_build_time_taken >= 60 else ''), all_build_time_taken)) + logger.info( + 'Built %d targets in %s(%.2fs)' + % ( + len(tasks), + ( + '%02d:%02d mins ' % (all_build_time_taken // 60, all_build_time_taken % 60) + if all_build_time_taken >= 60 + else '' + ), + all_build_time_taken, + ) + ) return 0 diff --git a/emcc.py b/emcc.py index 1ae6a24f94477..e114bda1676e6 100644 --- a/emcc.py +++ b/emcc.py @@ -56,6 +56,7 @@ # run already. if os.path.exists(utils.path_from_root('.git')) and os.path.exists(utils.path_from_root('bootstrap.py')): import bootstrap + bootstrap.check() # endings = dot + a suffix, compare against result of shared.suffix() @@ -65,7 +66,7 @@ PREPROCESSED_ENDINGS = ['.i', '.ii'] OBJCXX_ENDINGS = ['.mm', '.mii'] SPECIAL_ENDINGLESS_FILENAMES = [os.devnull] -C_ENDINGS += SPECIAL_ENDINGLESS_FILENAMES # consider the special endingless filenames like /dev/null to be C +C_ENDINGS += SPECIAL_ENDINGLESS_FILENAMES # consider the special endingless filenames like /dev/null to be C SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + OBJC_ENDINGS + OBJCXX_ENDINGS + ['.bc', '.ll', '.S'] ASSEMBLY_ENDINGS = ['.s'] @@ -73,20 +74,34 @@ # These symbol names are allowed in INCOMING_MODULE_JS_API but are not part of the # default set. -EXTRA_INCOMING_JS_API = [ - 'fetchSettings' -] +EXTRA_INCOMING_JS_API = ['fetchSettings'] SIMD_INTEL_FEATURE_TOWER = ['-msse', '-msse2', '-msse3', '-mssse3', '-msse4.1', '-msse4.2', '-msse4', '-mavx'] SIMD_NEON_FLAGS = ['-mfpu=neon'] LINK_ONLY_FLAGS = { - '--bind', '--closure', '--cpuprofiler', '--embed-file', - '--emit-symbol-map', '--emrun', '--exclude-file', '--extern-post-js', - '--extern-pre-js', '--ignore-dynamic-linking', '--js-library', - '--js-transform', '--oformat', '--output_eol', - '--post-js', '--pre-js', '--preload-file', '--profiling-funcs', - '--proxy-to-worker', '--shell-file', '--source-map-base', - '--threadprofiler', '--use-preload-plugins' + '--bind', + '--closure', + '--cpuprofiler', + '--embed-file', + '--emit-symbol-map', + '--emrun', + '--exclude-file', + '--extern-post-js', + '--extern-pre-js', + '--ignore-dynamic-linking', + '--js-library', + '--js-transform', + '--oformat', + '--output_eol', + '--post-js', + '--pre-js', + '--preload-file', + '--profiling-funcs', + '--proxy-to-worker', + '--shell-file', + '--source-map-base', + '--threadprofiler', + '--use-preload-plugins', } @@ -144,10 +159,10 @@ def __init__(self): self.use_closure_compiler = None self.closure_args = [] self.js_transform = None - self.pre_js = [] # before all js - self.post_js = [] # after all js - self.extern_pre_js = [] # before all js, external to optimized code - self.extern_post_js = [] # after all js, external to optimized code + self.pre_js = [] # before all js + self.post_js = [] # after all js + self.extern_pre_js = [] # before all js, external to optimized code + self.extern_post_js = [] # after all js, external to optimized code self.preload_files = [] self.embed_files = [] self.exclude_files = [] @@ -218,13 +233,36 @@ def make_relative(filename): if ignore: continue - if arg in ('-MT', '-MF', '-MJ', '-MQ', '-D', '-U', '-o', '-x', - '-Xpreprocessor', '-include', '-imacros', '-idirafter', - '-iprefix', '-iwithprefix', '-iwithprefixbefore', - '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', - '-install_name', '-compatibility_version', - '-current_version', '-I', '-L', '-include-pch', - '-Xlinker', '-Xclang'): + if arg in ( + '-MT', + '-MF', + '-MJ', + '-MQ', + '-D', + '-U', + '-o', + '-x', + '-Xpreprocessor', + '-include', + '-imacros', + '-idirafter', + '-iprefix', + '-iwithprefix', + '-iwithprefixbefore', + '-isysroot', + '-imultilib', + '-A', + '-isystem', + '-iquote', + '-install_name', + '-compatibility_version', + '-current_version', + '-I', + '-L', + '-include-pch', + '-Xlinker', + '-Xclang', + ): ignore_next = True if arg == '-o': @@ -244,7 +282,7 @@ def expand_byte_size_suffixes(value): value, suffix = match.groups() value = int(value) if suffix: - size_suffixes = {suffix: 1024 ** i for i, suffix in enumerate(['b', 'kb', 'mb', 'gb', 'tb'])} + size_suffixes = {suffix: 1024**i for i, suffix in enumerate(['b', 'kb', 'mb', 'gb', 'tb'])} value *= size_suffixes[suffix.lower()] return value @@ -470,7 +508,11 @@ def array_contains_any_of(hay, needles): if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER) or array_contains_any_of(user_args, SIMD_NEON_FLAGS): if '-msimd128' not in user_args and '-mrelaxed-simd' not in user_args: - exit_with_error('passing any of ' + ', '.join(SIMD_INTEL_FEATURE_TOWER + SIMD_NEON_FLAGS) + ' flags also requires passing -msimd128 (or -mrelaxed-simd)!') + exit_with_error( + 'passing any of ' + + ', '.join(SIMD_INTEL_FEATURE_TOWER + SIMD_NEON_FLAGS) + + ' flags also requires passing -msimd128 (or -mrelaxed-simd)!' + ) cflags += ['-D__SSE__=1'] if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[1:]): @@ -586,7 +628,7 @@ def run(args): ''') return 0 - if '-dumpversion' in args: # gcc's doc states "Print the compiler version [...] and don't do anything else." + if '-dumpversion' in args: # gcc's doc states "Print the compiler version [...] and don't do anything else." print(utils.EMSCRIPTEN_VERSION) return 0 @@ -607,16 +649,22 @@ def run(args): if not lines: exit_with_error(f'unable to parse output of `{cmd}`:\n{proc.stderr}') parts = shlex.split(lines[0].replace('\\', '\\\\')) - parts = [x for x in parts if x not in ['-c', '-o', '-v', '-emit-llvm'] and input_file not in x and temp_target not in x] + parts = [ + x for x in parts if x not in ['-c', '-o', '-v', '-emit-llvm'] and input_file not in x and temp_target not in x + ] print(shared.shlex_join(parts[1:])) return 0 if 'EMMAKEN_NO_SDK' in os.environ: - exit_with_error('EMMAKEN_NO_SDK is no longer supported. The standard -nostdlib and -nostdinc flags should be used instead') + exit_with_error( + 'EMMAKEN_NO_SDK is no longer supported. The standard -nostdlib and -nostdinc flags should be used instead' + ) if 'EMMAKEN_COMPILER' in os.environ: - exit_with_error('`EMMAKEN_COMPILER` is no longer supported.\n' + - 'Please use the `LLVM_ROOT` and/or `COMPILER_WRAPPER` config settings instead') + exit_with_error( + '`EMMAKEN_COMPILER` is no longer supported.\n' + + 'Please use the `LLVM_ROOT` and/or `COMPILER_WRAPPER` config settings instead' + ) if 'EMMAKEN_CFLAGS' in os.environ: exit_with_error('`EMMAKEN_CFLAGS` is no longer supported, please use `EMCC_CFLAGS` instead') @@ -668,6 +716,7 @@ def run(args): exit_with_error('--post-link requires a single input file') # Delay import of link.py to avoid processing this file when only compiling from tools import link + link.run_post_link(input_files[0][1], options, state, newargs) return 0 @@ -677,6 +726,7 @@ def run(args): if state.mode == Mode.COMPILE_AND_LINK: # Delay import of link.py to avoid processing this file when only compiling from tools import link + return link.run(linker_inputs, options, state, newargs) else: logger.debug('stopping after compile phase') @@ -747,8 +797,7 @@ def phase_parse_arguments(state): @ToolchainProfiler.profile_block('setup') def phase_setup(options, state, newargs): - """Second phase: configure and setup the compiler based on the specified settings and arguments. - """ + """Second phase: configure and setup the compiler based on the specified settings and arguments.""" if settings.RUNTIME_LINKED_LIBS: newargs += settings.RUNTIME_LINKED_LIBS @@ -773,14 +822,39 @@ def phase_setup(options, state, newargs): continue arg = newargs[i] - if arg in {'-MT', '-MF', '-MJ', '-MQ', '-D', '-U', '-o', '-x', - '-Xpreprocessor', '-include', '-imacros', '-idirafter', - '-iprefix', '-iwithprefix', '-iwithprefixbefore', - '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', - '-install_name', '-compatibility_version', - '-current_version', '-I', '-L', '-include-pch', - '-undefined', '-target', - '-Xlinker', '-Xclang', '-z'}: + if arg in { + '-MT', + '-MF', + '-MJ', + '-MQ', + '-D', + '-U', + '-o', + '-x', + '-Xpreprocessor', + '-include', + '-imacros', + '-idirafter', + '-iprefix', + '-iwithprefix', + '-iwithprefixbefore', + '-isysroot', + '-imultilib', + '-A', + '-isystem', + '-iquote', + '-install_name', + '-compatibility_version', + '-current_version', + '-I', + '-L', + '-include-pch', + '-undefined', + '-target', + '-Xlinker', + '-Xclang', + '-z', + }: skip = True if not arg.startswith('-'): @@ -790,7 +864,11 @@ def phase_setup(options, state, newargs): # python before 3.8: # https://bugs.python.org/issue1311 if not os.path.exists(arg) and arg != os.devnull: - exit_with_error('%s: No such file or directory ("%s" was expected to be an input file, based on the commandline arguments provided)', arg, arg) + exit_with_error( + '%s: No such file or directory ("%s" was expected to be an input file, based on the commandline arguments provided)', + arg, + arg, + ) file_suffix = get_file_suffix(arg) if file_suffix in HEADER_ENDINGS: has_header_inputs = True @@ -841,14 +919,10 @@ def phase_setup(options, state, newargs): if state.mode in (Mode.COMPILE_ONLY, Mode.PREPROCESS_ONLY): for key in user_settings: if key not in COMPILE_TIME_SETTINGS: - diagnostics.warning( - 'unused-command-line-argument', - "linker setting ignored during compilation: '%s'" % key) + diagnostics.warning('unused-command-line-argument', "linker setting ignored during compilation: '%s'" % key) for arg in state.orig_args: if arg in LINK_ONLY_FLAGS: - diagnostics.warning( - 'unused-command-line-argument', - "linker flag ignored during compilation: '%s'" % arg) + diagnostics.warning('unused-command-line-argument', "linker flag ignored during compilation: '%s'" % arg) if settings.MAIN_MODULE or settings.SIDE_MODULE: settings.RELOCATABLE = 1 @@ -868,7 +942,9 @@ def phase_setup(options, state, newargs): # on the command line. This is no longer valid so report either an error or a warning (for # backwards compat with the old `DISABLE_EXCEPTION_CATCHING=2` if user_settings['DISABLE_EXCEPTION_CATCHING'] in ('0', '2'): - diagnostics.warning('deprecated', 'DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED') + diagnostics.warning( + 'deprecated', 'DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED' + ) else: exit_with_error('DISABLE_EXCEPTION_CATCHING and EXCEPTION_CATCHING_ALLOWED are mutually exclusive') @@ -883,18 +959,26 @@ def phase_setup(options, state, newargs): # -fwasm-exceptions takes care of enabling them, so users aren't supposed to # pass them explicitly, regardless of their values if 'DISABLE_EXCEPTION_CATCHING' in user_settings or 'DISABLE_EXCEPTION_THROWING' in user_settings: - diagnostics.warning('emcc', 'you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions') + diagnostics.warning( + 'emcc', + 'you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', + ) settings.DISABLE_EXCEPTION_CATCHING = 1 settings.DISABLE_EXCEPTION_THROWING = 1 if user_settings.get('ASYNCIFY') == '1': - diagnostics.warning('emcc', 'ASYNCIFY=1 is not compatible with -fwasm-exceptions. Parts of the program that mix ASYNCIFY and exceptions will not compile.') + diagnostics.warning( + 'emcc', + 'ASYNCIFY=1 is not compatible with -fwasm-exceptions. Parts of the program that mix ASYNCIFY and exceptions will not compile.', + ) if user_settings.get('SUPPORT_LONGJMP') == 'emscripten': exit_with_error('SUPPORT_LONGJMP=emscripten is not compatible with -fwasm-exceptions') if settings.DISABLE_EXCEPTION_THROWING and not settings.DISABLE_EXCEPTION_CATCHING: - exit_with_error("DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions") + exit_with_error( + "DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions" + ) if options.target.startswith('wasm64'): default_setting('MEMORY64', 1) @@ -1040,7 +1124,10 @@ def get_clang_command_asm(): if options.output_file: cmd += ['-o', options.output_file] if get_file_suffix(options.output_file) == '.bc' and not settings.LTO and '-emit-llvm' not in state.orig_args: - diagnostics.warning('emcc', '.bc output file suffix used without -flto or -emit-llvm. Consider using .o extension since emcc will output an object file, not a bitcode file') + diagnostics.warning( + 'emcc', + '.bc output file suffix used without -flto or -emit-llvm. Consider using .o extension since emcc will output an object file, not a bitcode file', + ) shared.exec_process(cmd) assert False, 'exec_process does not return' @@ -1117,8 +1204,8 @@ def version_string(): revision_suffix = '' if os.path.exists(utils.path_from_root('.git')): git_rev = run_process( - ['git', 'rev-parse', 'HEAD'], - stdout=PIPE, stderr=PIPE, cwd=utils.path_from_root()).stdout.strip() + ['git', 'rev-parse', 'HEAD'], stdout=PIPE, stderr=PIPE, cwd=utils.path_from_root() + ).stdout.strip() revision_suffix = ' (%s)' % git_rev elif os.path.exists(utils.path_from_root('emscripten-revision.txt')): rev = read_file(utils.path_from_root('emscripten-revision.txt')).strip() @@ -1339,7 +1426,9 @@ def consume_arg_file(): elif check_flag('--use-preload-cache'): options.use_preload_cache = True elif check_flag('--no-heap-copy'): - diagnostics.warning('legacy-settings', 'ignoring legacy flag --no-heap-copy (that is the only mode supported now)') + diagnostics.warning( + 'legacy-settings', 'ignoring legacy flag --no-heap-copy (that is the only mode supported now)' + ) elif check_flag('--use-preload-plugins'): options.use_preload_plugins = True elif check_flag('--ignore-dynamic-linking'): @@ -1362,7 +1451,10 @@ def consume_arg_file(): elif check_arg('--js-library'): settings.JS_LIBRARIES.append((i + 1, os.path.abspath(consume_arg_file()))) elif check_flag('--remove-duplicates'): - diagnostics.warning('legacy-settings', '--remove-duplicates is deprecated as it is no longer needed. If you cannot link without it, file a bug with a testcase') + diagnostics.warning( + 'legacy-settings', + '--remove-duplicates is deprecated as it is no longer needed. If you cannot link without it, file a bug with a testcase', + ) elif check_flag('--jcache'): logger.error('jcache is no longer supported') elif check_arg('--cache'): @@ -1374,13 +1466,13 @@ def consume_arg_file(): elif check_flag('--clear-cache'): logger.info('clearing cache as requested by --clear-cache: `%s`', cache.cachedir) cache.erase() - shared.perform_sanity_checks() # this is a good time for a sanity check + shared.perform_sanity_checks() # this is a good time for a sanity check should_exit = True elif check_flag('--clear-ports'): logger.info('clearing ports and cache as requested by --clear-ports') ports.clear() cache.erase() - shared.perform_sanity_checks() # this is a good time for a sanity check + shared.perform_sanity_checks() # this is a good time for a sanity check should_exit = True elif check_flag('--check'): print(version_string(), file=sys.stderr) @@ -1405,10 +1497,12 @@ def consume_arg_file(): # that are e.g. x86 specific and non-portable. The emscripten bundled # headers are modified to be portable, local system ones are generally not. diagnostics.warning( - 'absolute-paths', f'-I or -L of an absolute path "{arg}" ' - '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).') + 'absolute-paths', + f'-I or -L of an absolute path "{arg}" ' + '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).', + ) elif check_flag('--emrun'): options.emrun = True elif check_flag('--cpuprofiler'): @@ -1421,22 +1515,16 @@ def consume_arg_file(): settings.WASM_EXCEPTIONS = 0 elif arg == '-mbulk-memory': settings.BULK_MEMORY = 1 - feature_matrix.enable_feature(feature_matrix.Feature.BULK_MEMORY, - '-mbulk-memory', - override=True) + feature_matrix.enable_feature(feature_matrix.Feature.BULK_MEMORY, '-mbulk-memory', override=True) elif arg == '-mno-bulk-memory': settings.BULK_MEMORY = 0 feature_matrix.disable_feature(feature_matrix.Feature.BULK_MEMORY) elif arg == '-msign-ext': - feature_matrix.enable_feature(feature_matrix.Feature.SIGN_EXT, - '-msign-ext', - override=True) + feature_matrix.enable_feature(feature_matrix.Feature.SIGN_EXT, '-msign-ext', override=True) elif arg == '-mno-sign-ext': feature_matrix.disable_feature(feature_matrix.Feature.SIGN_EXT) elif arg == '-mnontrappting-fptoint': - feature_matrix.enable_feature(feature_matrix.Feature.NON_TRAPPING_FPTOINT, - '-mnontrapping-fptoint', - override=True) + feature_matrix.enable_feature(feature_matrix.Feature.NON_TRAPPING_FPTOINT, '-mnontrapping-fptoint', override=True) elif arg == '-mno-nontrapping-fptoint': feature_matrix.disable_feature(feature_matrix.Feature.NON_TRAPPING_FPTOINT) elif arg == '-fexceptions': @@ -1486,7 +1574,9 @@ def consume_arg_file(): else: value = '1' if key in settings.keys(): - exit_with_error(f'{arg}: cannot change built-in settings values with a -jsD directive. Pass -s{key}={value} instead!') + exit_with_error( + f'{arg}: cannot change built-in settings values with a -jsD directive. Pass -s{key}={value} instead!' + ) user_js_defines += [(key, value)] newargs[i] = '' elif check_flag('-shared'): @@ -1501,7 +1591,9 @@ def consume_arg_file(): elif check_arg('-target') or check_arg('--target'): options.target = consume_arg() if options.target not in ('wasm32', 'wasm64', 'wasm64-unknown-emscripten', 'wasm32-unknown-emscripten'): - exit_with_error(f'unsupported target: {options.target} (emcc only supports wasm64-unknown-emscripten and wasm32-unknown-emscripten)') + exit_with_error( + f'unsupported target: {options.target} (emcc only supports wasm64-unknown-emscripten and wasm32-unknown-emscripten)' + ) elif check_arg('--use-port'): ports.handle_use_port_arg(settings, consume_arg()) elif arg == '-mllvm': @@ -1555,7 +1647,9 @@ def parse_string_value(text): if first == "'" or first == '"': text = text.rstrip() if text[-1] != text[0] or len(text) < 2: - raise ValueError(f'unclosed quoted string. expected final character to be "{text[0]}" and length to be greater than 1 in "{text[0]}"') + raise ValueError( + f'unclosed quoted string. expected final character to be "{text[0]}" and length to be greater than 1 in "{text[0]}"' + ) return text[1:-1] return text @@ -1565,7 +1659,7 @@ def parse_string_list_members(text): result = [] index = 0 while True: - current = values[index].lstrip() # Cannot safely rstrip for cases like: "HERE-> ," + current = values[index].lstrip() # Cannot safely rstrip for cases like: "HERE-> ," if not len(current): raise ValueError('empty value in string list') first = current[0] @@ -1573,7 +1667,7 @@ def parse_string_list_members(text): result.append(current.rstrip()) else: start = index - while True: # Continue until closing quote found + while True: # Continue until closing quote found if index >= len(values): raise ValueError(f"unclosed quoted string. expected final character to be '{first}' in '{values[start]}'") new = values[index].rstrip() @@ -1643,7 +1737,9 @@ def validate_arg_level(level_string, max_level, err_msg, clamp=False): exit_with_error(err_msg) if clamp: if level > max_level: - logger.warning("optimization level '-O" + level_string + "' is not supported; using '-O" + str(max_level) + "' instead") + logger.warning( + "optimization level '-O" + level_string + "' is not supported; using '-O" + str(max_level) + "' instead" + ) level = max_level if not 0 <= level <= max_level: exit_with_error(err_msg) diff --git a/emcmake.py b/emcmake.py index a9dc2294b91c2..84b6c57c424db 100755 --- a/emcmake.py +++ b/emcmake.py @@ -18,12 +18,15 @@ # def run(): if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'): - print('''\ + print( + '''\ emcmake is a helper for cmake, setting various environment variables so that emcc etc. are used. Typical usage: emcmake cmake [FLAGS] -''', file=sys.stderr) +''', + file=sys.stderr, + ) return 1 args = sys.argv[1:] @@ -53,7 +56,10 @@ def has_substr(args, substr): elif shutil.which('ninja'): args += ['-G', 'Ninja'] else: - print('emcmake: no compatible cmake generator found; Please install ninja or mingw32-make, or specify a generator explicitly using -G', file=sys.stderr) + print( + 'emcmake: no compatible cmake generator found; Please install ninja or mingw32-make, or specify a generator explicitly using -G', + file=sys.stderr, + ) return 1 print('configure: ' + shared.shlex_join(args), file=sys.stderr) diff --git a/emconfigure.py b/emconfigure.py index deba798069bb3..82d096983c9cf 100755 --- a/emconfigure.py +++ b/emconfigure.py @@ -27,13 +27,16 @@ # def run(): if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'): - print('''\ + print( + '''\ emconfigure is a helper for configure, setting various environment variables so that emcc etc. are used. Typical usage: emconfigure ./configure [FLAGS] -(but you can run any command instead of configure)''', file=sys.stderr) +(but you can run any command instead of configure)''', + file=sys.stderr, + ) return 1 args = sys.argv[1:] diff --git a/emmake.py b/emmake.py index 426e5cc4cd63e..62cb5a2f4321d 100755 --- a/emmake.py +++ b/emmake.py @@ -34,13 +34,16 @@ # def run(): if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'): - print('''\ + print( + '''\ emmake is a helper for make, setting various environment variables so that emcc etc. are used. Typical usage: emmake make [FLAGS] -(but you can run any command instead of make)''', file=sys.stderr) +(but you can run any command instead of make)''', + file=sys.stderr, + ) return 1 args = sys.argv[1:] diff --git a/emrun.py b/emrun.py index 0d33218c2d747..1c1c8e6606ce1 100644 --- a/emrun.py +++ b/emrun.py @@ -136,8 +136,7 @@ def tick(): def logi(msg): - """Prints a log message to 'info' stdout channel. Always printed. - """ + """Prints a log message to 'info' stdout channel. Always printed.""" global last_message_time with http_mutex: sys.stdout.write(msg + '\n') @@ -158,8 +157,7 @@ def logv(msg): def loge(msg): - """Prints an error message to stderr channel. - """ + """Prints an error message to stderr channel.""" global last_message_time with http_mutex: sys.stderr.write(msg + '\n') @@ -174,8 +172,7 @@ def format_eol(msg): def browser_logi(msg): - """Prints a message to the browser stdout output stream. - """ + """Prints a message to the browser stdout output stream.""" global last_message_time msg = format_eol(msg) browser_stdout_handle.write(msg + '\n') @@ -184,8 +181,7 @@ def browser_logi(msg): def browser_loge(msg): - """Prints a message to the browser stderr output stream. - """ + """Prints a message to the browser stderr output stream.""" global last_message_time msg = format_eol(msg) browser_stderr_handle.write(msg + '\n') @@ -330,13 +326,16 @@ def is_browser_process_alive(): if current_browser_processes: try: import psutil + for p in current_browser_processes: if psutil.pid_exists(p['pid']): return True return False except Exception: # Fail gracefully if psutil not available - logv('psutil is not available, emrun may not be able to accurately track whether the browser process is alive or not') + logv( + 'psutil is not available, emrun may not be able to accurately track whether the browser process is alive or not' + ) # We do not have a track of the browser process ID that we spawned. # Make an assumption that the browser process is open as long until @@ -381,8 +380,12 @@ def kill_browser_process(): else: logv("Terminating all processes that have string '" + processname_killed_atexit + "' in their name.") if WINDOWS: - process_image = processname_killed_atexit if '.exe' in processname_killed_atexit else (processname_killed_atexit + '.exe') - process = subprocess.Popen(['taskkill', '/F', '/IM', process_image, '/T'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process_image = ( + processname_killed_atexit if '.exe' in processname_killed_atexit else (processname_killed_atexit + '.exe') + ) + process = subprocess.Popen( + ['taskkill', '/F', '/IM', process_image, '/T'], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) process.communicate() else: try: @@ -391,7 +394,9 @@ def kill_browser_process(): try: subprocess.call(['killall', processname_killed_atexit]) except OSError: - loge('Both commands pkill and killall failed to clean up the spawned browser process. Perhaps neither of these utilities is available on your system?') + loge( + 'Both commands pkill and killall failed to clean up the spawned browser process. Perhaps neither of these utilities is available on your system?' + ) delete_emrun_safe_firefox_profile() # Clear the process name to represent that the browser is now dead. processname_killed_atexit = '' @@ -408,7 +413,7 @@ def kill_browser_process(): # process that immediately exits. def detect_browser_processes(): if not browser_exe: - return # Running with --no-browser, we are not binding to a spawned browser. + return # Running with --no-browser, we are not binding to a spawned browser. global current_browser_processes logv('First navigation occurred. Identifying currently running browser processes') @@ -421,12 +426,19 @@ def pid_existed(pid): return False for p in running_browser_processes: - logv('Detected running browser process id: ' + str(p['pid']) + ', existed already at emrun startup? ' + str(pid_existed(p['pid']))) + logv( + 'Detected running browser process id: ' + + str(p['pid']) + + ', existed already at emrun startup? ' + + str(pid_existed(p['pid'])) + ) current_browser_processes = [p for p in running_browser_processes if not pid_existed(p['pid'])] if len(current_browser_processes) == 0: - logv('Was unable to detect the browser process that was spawned by emrun. This may occur if the target page was opened in a tab on a browser process that already existed before emrun started up.') + logv( + 'Was unable to detect the browser process that was spawned by emrun. This may occur if the target page was opened in a tab on a browser process that already existed before emrun started up.' + ) # Our custom HTTP web server that will server the target page to run via .html. @@ -437,6 +449,7 @@ def pid_existed(pid): class HTTPWebServer(socketserver.ThreadingMixIn, HTTPServer): """Log messaging arriving via HTTP can come in out of sequence. Implement a sequencing mechanism to enforce ordered transmission.""" + expected_http_seq_num = 1 # Stores messages that have arrived out of order, pending for a send as soon # as the missing message arrives. Kept in sorted order, first element is the @@ -526,7 +539,13 @@ def serve_forever(self, timeout=0.5): time_since_message = now - last_message_time if emrun_options.silence_timeout != 0 and time_since_message > emrun_options.silence_timeout: self.shutdown() - logi('No activity in ' + str(emrun_options.silence_timeout) + ' seconds. Quitting web server with return code ' + str(emrun_options.timeout_returncode) + '. (--silence-timeout option)') + logi( + 'No activity in ' + + str(emrun_options.silence_timeout) + + ' seconds. Quitting web server with return code ' + + str(emrun_options.timeout_returncode) + + '. (--silence-timeout option)' + ) page_exit_code = emrun_options.timeout_returncode emrun_options.kill_exit = True @@ -534,7 +553,13 @@ def serve_forever(self, timeout=0.5): time_since_start = now - page_start_time if emrun_options.timeout != 0 and time_since_start > emrun_options.timeout: self.shutdown() - logi('Page has not finished in ' + str(emrun_options.timeout) + ' seconds. Quitting web server with return code ' + str(emrun_options.timeout_returncode) + '. (--timeout option)') + logi( + 'Page has not finished in ' + + str(emrun_options.timeout) + + ' seconds. Quitting web server with return code ' + + str(emrun_options.timeout_returncode) + + '. (--timeout option)' + ) emrun_options.kill_exit = True page_exit_code = emrun_options.timeout_returncode @@ -542,7 +567,9 @@ def serve_forever(self, timeout=0.5): if not emrun_not_enabled_nag_printed and page_last_served_time is not None: time_since_page_serve = now - page_last_served_time if not have_received_messages and time_since_page_serve > 10: - logv('The html page you are running is not emrun-capable. Stdout, stderr and exit(returncode) capture will not work. Recompile the application with the --emrun linker flag to enable this, or pass --no-emrun-detect to emrun to hide this check.') + logv( + 'The html page you are running is not emrun-capable. Stdout, stderr and exit(returncode) capture will not work. Recompile the application with the --emrun linker flag to enable this, or pass --no-emrun-detect to emrun to hide this check.' + ) emrun_not_enabled_nag_printed = True # Clean up at quit, print any leftover messages in queue. @@ -666,7 +693,7 @@ def do_POST(self): # Binary file dump/upload handling. Requests to # "stdio.html?file=filename" will write binary data to the given file. data = self.rfile.read(int(self.headers['Content-Length'])) - filename = unquote_u(query[len('file='):]) + filename = unquote_u(query[len('file=') :]) filename = os.path.join(emrun_options.dump_out_directory, os.path.normpath(filename)) try: os.makedirs(os.path.dirname(filename)) @@ -698,12 +725,16 @@ def do_POST(self): data = data.replace("+", " ") data = unquote_u(data) - if data == '^pageload^': # Browser is just notifying that it has successfully launched the page. + if data == '^pageload^': # Browser is just notifying that it has successfully launched the page. have_received_messages = True elif data.startswith('^exit^'): if not emrun_options.serve_after_exit: page_exit_code = int(data[6:]) - logv('Web page has quit with a call to exit() with return code ' + str(page_exit_code) + '. Shutting down web server. Pass --serve-after-exit to keep serving even after the page terminates with exit().') + logv( + 'Web page has quit with a call to exit() with return code ' + + str(page_exit_code) + + '. Shutting down web server. Pass --serve-after-exit to keep serving even after the page terminates with exit().' + ) # Set server socket to nonblocking on shutdown to avoid sporadic deadlocks self.server.socket.setblocking(False) self.server.shutdown() @@ -722,7 +753,7 @@ def do_POST(self): try: i = data.index('^', 5) seq_num = int(data[5:i]) - data = data[i + 1:] + data = data[i + 1 :] except ValueError: pass @@ -741,7 +772,9 @@ def do_POST(self): # Returns stdout by running command with universal_newlines=True def check_output(cmd, universal_newlines=True, *args, **kwargs): if hasattr(subprocess, "run"): - return subprocess.run(cmd, universal_newlines=universal_newlines, stdout=subprocess.PIPE, check=True, *args, **kwargs).stdout + return subprocess.run( + cmd, universal_newlines=universal_newlines, stdout=subprocess.PIPE, check=True, *args, **kwargs + ).stdout else: # check_output is considered as an old API so prefer subprocess.run if possible return subprocess.check_output(cmd, universal_newlines=universal_newlines, *args, **kwargs) @@ -757,6 +790,7 @@ def get_cpu_info(): try: if WINDOWS: from win32com.client import GetObject + root_winmgmts = GetObject('winmgmts:root\\cimv2') cpus = root_winmgmts.ExecQuery('Select * from Win32_Processor') cpu_name = cpus[0].Name + ', ' + platform.processor() @@ -780,18 +814,16 @@ def get_cpu_info(): logical_cores = physical_cores * int(re.search(r'Thread\(s\) per core: (.*)', lscpu).group(1).strip()) except Exception as e: import traceback + loge(traceback.format_exc()) - return {'model': 'Unknown ("' + str(e) + '")', - 'physicalCores': 1, - 'logicalCores': 1, - 'frequency': 0 - } + return {'model': 'Unknown ("' + str(e) + '")', 'physicalCores': 1, 'logicalCores': 1, 'frequency': 0} - return {'model': platform.machine() + ', ' + cpu_name, - 'physicalCores': physical_cores, - 'logicalCores': logical_cores, - 'frequency': frequency - } + return { + 'model': platform.machine() + ', ' + cpu_name, + 'physicalCores': physical_cores, + 'logicalCores': logical_cores, + 'frequency': frequency, + } def get_android_cpu_infoline(): @@ -800,11 +832,13 @@ def get_android_cpu_infoline(): hardware = '' for line in lines: if line.startswith('Processor'): - processor = line[line.find(':') + 1:].strip() + processor = line[line.find(':') + 1 :].strip() elif line.startswith('Hardware'): - hardware = line[line.find(':') + 1:].strip() + hardware = line[line.find(':') + 1 :].strip() - freq = int(check_output([ADB, 'shell', 'cat', '/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq']).strip()) // 1000 + freq = ( + int(check_output([ADB, 'shell', 'cat', '/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq']).strip()) // 1000 + ) return 'CPU: ' + processor + ', ' + hardware + ' @ ' + str(freq) + ' MHz' @@ -866,11 +900,11 @@ def linux_get_gpu_info(): glxinfo = check_output('glxinfo') for line in glxinfo.split("\n"): if "OpenGL vendor string:" in line: - gl_vendor = line[len("OpenGL vendor string:"):].strip() + gl_vendor = line[len("OpenGL vendor string:") :].strip() if "OpenGL version string:" in line: - gl_version = line[len("OpenGL version string:"):].strip() + gl_version = line[len("OpenGL version string:") :].strip() if "OpenGL renderer string:" in line: - gl_renderer = line[len("OpenGL renderer string:"):].strip() + gl_renderer = line[len("OpenGL renderer string:") :].strip() glinfo = gl_vendor + ' ' + gl_renderer + ', GL version ' + gl_version except Exception as e: logv(e) @@ -929,13 +963,14 @@ def get_executable_version(filename): try: if WINDOWS: import win32api + info = win32api.GetFileVersionInfo(filename, "\\") ms = info['FileVersionMS'] ls = info['FileVersionLS'] version = win32api.HIWORD(ms), win32api.LOWORD(ms), win32api.HIWORD(ls), win32api.LOWORD(ls) return '.'.join(map(str, version)) elif MACOS: - plistfile = filename[0:filename.find('MacOS')] + 'Info.plist' + plistfile = filename[0 : filename.find('MacOS')] + 'Info.plist' info = plistlib.readPlist(plistfile) # Data in Info.plists is a bit odd, this check combo gives best information on each browser. if 'firefox' in filename.lower(): @@ -959,7 +994,7 @@ def get_executable_version(filename): def get_browser_build_date(filename): try: if MACOS: - plistfile = filename[0:filename.find('MacOS')] + 'Info.plist' + plistfile = filename[0 : filename.find('MacOS')] + 'Info.plist' info = plistlib.readPlist(plistfile) # Data in Info.plists is a bit odd, this check combo gives best information on each browser. if 'firefox' in filename.lower(): @@ -979,32 +1014,55 @@ def get_browser_build_date(filename): def get_browser_info(filename, format_json): if format_json: - return json.dumps({ - 'name': browser_display_name(filename), - 'version': get_executable_version(filename), - 'buildDate': get_browser_build_date(filename) - }, indent=2) + return json.dumps( + { + 'name': browser_display_name(filename), + 'version': get_executable_version(filename), + 'buildDate': get_browser_build_date(filename), + }, + indent=2, + ) else: - return 'Browser: ' + browser_display_name(filename) + ' ' + get_executable_version(filename) + ', build ' + get_browser_build_date(filename) + return ( + 'Browser: ' + + browser_display_name(filename) + + ' ' + + get_executable_version(filename) + + ', build ' + + get_browser_build_date(filename) + ) # http://stackoverflow.com/questions/580924/python-windows-file-version-attribute def win_get_file_properties(fname): - propNames = ('Comments', 'InternalName', 'ProductName', - 'CompanyName', 'LegalCopyright', 'ProductVersion', - 'FileDescription', 'LegalTrademarks', 'PrivateBuild', - 'FileVersion', 'OriginalFilename', 'SpecialBuild') + propNames = ( + 'Comments', + 'InternalName', + 'ProductName', + 'CompanyName', + 'LegalCopyright', + 'ProductVersion', + 'FileDescription', + 'LegalTrademarks', + 'PrivateBuild', + 'FileVersion', + 'OriginalFilename', + 'SpecialBuild', + ) props = {'FixedFileInfo': None, 'StringFileInfo': None, 'FileVersion': None} import win32api + # backslash as parm returns dictionary of numeric info corresponding to VS_FIXEDFILEINFO struct fixedInfo = win32api.GetFileVersionInfo(fname, '\\') props['FixedFileInfo'] = fixedInfo - props['FileVersion'] = "%d.%d.%d.%d" % (fixedInfo['FileVersionMS'] / 65536, - fixedInfo['FileVersionMS'] % 65536, - fixedInfo['FileVersionLS'] / 65536, - fixedInfo['FileVersionLS'] % 65536) + props['FileVersion'] = "%d.%d.%d.%d" % ( + fixedInfo['FileVersionMS'] / 65536, + fixedInfo['FileVersionMS'] % 65536, + fixedInfo['FileVersionLS'] / 65536, + fixedInfo['FileVersionLS'] % 65536, + ) # \VarFileInfo\Translation returns list of available (language, codepage) # pairs that can be used to retrieve string info. We are using only the first pair. @@ -1015,7 +1073,7 @@ def win_get_file_properties(fname): strInfo = {} for propName in propNames: - strInfoPath = u'\\StringFileInfo\\%04X%04X\\%s' % (lang, codepage, propName) + strInfoPath = '\\StringFileInfo\\%04X%04X\\%s' % (lang, codepage, propName) ## print str_info strInfo[propName] = win32api.GetFileVersionInfo(fname, strInfoPath) @@ -1045,7 +1103,7 @@ def get_computer_model(): model = re.search('(.*)', model) model = model.group(1).strip() with open(os.path.join(os.getenv("HOME"), '.emrun.hwmodel.cached'), 'w') as fh: - fh.write(model) # Cache the hardware model to disk + fh.write(model) # Cache the hardware model to disk return model except Exception: hwmodel = check_output(['sysctl', 'hw.model']) @@ -1067,7 +1125,20 @@ def get_computer_model(): bios_vendor = check_output(['cat', '/sys/devices/virtual/dmi/id/bios_vendor']).strip() bios_version = check_output(['cat', '/sys/devices/virtual/dmi/id/bios_version']).strip() bios_date = check_output(['cat', '/sys/devices/virtual/dmi/id/bios_date']).strip() - return board_vendor + ' ' + board_name + ' ' + board_version + ', ' + bios_vendor + ' ' + bios_version + ' (' + bios_date + ')' + return ( + board_vendor + + ' ' + + board_name + + ' ' + + board_version + + ', ' + + bios_vendor + + ' ' + + bios_version + + ' (' + + bios_date + + ')' + ) except Exception as e: logv(str(e)) return 'Generic' @@ -1090,7 +1161,14 @@ def get_os_version(): return 'macOS ' + platform.mac_ver()[0] + bitness elif LINUX: kernel_version = check_output(['uname', '-r']).strip() - return ' '.join(platform.linux_distribution()) + ', linux kernel ' + kernel_version + ' ' + platform.architecture()[0] + bitness + return ( + ' '.join(platform.linux_distribution()) + + ', linux kernel ' + + kernel_version + + ' ' + + platform.architecture()[0] + + bitness + ) except Exception: return 'Unknown OS' @@ -1110,6 +1188,7 @@ def get_system_memory(): return int(sline[1]) * 1024 elif WINDOWS: import win32api + return win32api.GlobalMemoryStatusEx()['TotalPhys'] elif MACOS: return int(check_output(['sysctl', '-n', 'hw.memsize']).strip()) @@ -1192,14 +1271,16 @@ def find_browser(name): if MACOS: # Note: by default Firefox beta installs as 'Firefox.app', you must manually rename it to # FirefoxBeta.app after installation. - browser_locations = [('firefox', '/Applications/Firefox.app/Contents/MacOS/firefox'), - ('firefox_beta', '/Applications/FirefoxBeta.app/Contents/MacOS/firefox'), - ('firefox_aurora', '/Applications/FirefoxAurora.app/Contents/MacOS/firefox'), - ('firefox_nightly', '/Applications/FirefoxNightly.app/Contents/MacOS/firefox'), - ('safari', '/Applications/Safari.app/Contents/MacOS/Safari'), - ('opera', '/Applications/Opera.app/Contents/MacOS/Opera'), - ('chrome', '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'), - ('chrome_canary', '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary')] + browser_locations = [ + ('firefox', '/Applications/Firefox.app/Contents/MacOS/firefox'), + ('firefox_beta', '/Applications/FirefoxBeta.app/Contents/MacOS/firefox'), + ('firefox_aurora', '/Applications/FirefoxAurora.app/Contents/MacOS/firefox'), + ('firefox_nightly', '/Applications/FirefoxNightly.app/Contents/MacOS/firefox'), + ('safari', '/Applications/Safari.app/Contents/MacOS/Safari'), + ('opera', '/Applications/Opera.app/Contents/MacOS/Opera'), + ('chrome', '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'), + ('chrome_canary', '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'), + ] elif WINDOWS: pf_locations = ['ProgramFiles(x86)', 'ProgramFiles', 'ProgramW6432', 'LOCALAPPDATA'] @@ -1208,31 +1289,35 @@ def find_browser(name): continue program_files = os.environ[pf_env] if WINDOWS else '' - browser_locations += [('chrome', os.path.join(program_files, 'Google/Chrome/Application/chrome.exe')), - ('chrome_canary', os.path.expanduser("~/AppData/Local/Google/Chrome SxS/Application/chrome.exe")), - ('firefox_nightly', os.path.join(program_files, 'Nightly/firefox.exe')), - ('firefox_aurora', os.path.join(program_files, 'Aurora/firefox.exe')), - ('firefox_beta', os.path.join(program_files, 'Beta/firefox.exe')), - ('firefox_beta', os.path.join(program_files, 'FirefoxBeta/firefox.exe')), - ('firefox_beta', os.path.join(program_files, 'Firefox Beta/firefox.exe')), - ('firefox', os.path.join(program_files, 'Mozilla Firefox/firefox.exe')), - ('iexplore', os.path.join(program_files, 'Internet Explorer/iexplore.exe')), - ('opera', os.path.join(program_files, 'Opera/launcher.exe'))] + browser_locations += [ + ('chrome', os.path.join(program_files, 'Google/Chrome/Application/chrome.exe')), + ('chrome_canary', os.path.expanduser("~/AppData/Local/Google/Chrome SxS/Application/chrome.exe")), + ('firefox_nightly', os.path.join(program_files, 'Nightly/firefox.exe')), + ('firefox_aurora', os.path.join(program_files, 'Aurora/firefox.exe')), + ('firefox_beta', os.path.join(program_files, 'Beta/firefox.exe')), + ('firefox_beta', os.path.join(program_files, 'FirefoxBeta/firefox.exe')), + ('firefox_beta', os.path.join(program_files, 'Firefox Beta/firefox.exe')), + ('firefox', os.path.join(program_files, 'Mozilla Firefox/firefox.exe')), + ('iexplore', os.path.join(program_files, 'Internet Explorer/iexplore.exe')), + ('opera', os.path.join(program_files, 'Opera/launcher.exe')), + ] elif LINUX: - browser_locations = [('firefox', os.path.expanduser('~/firefox/firefox')), - ('firefox_beta', os.path.expanduser('~/firefox_beta/firefox')), - ('firefox_aurora', os.path.expanduser('~/firefox_aurora/firefox')), - ('firefox_nightly', os.path.expanduser('~/firefox_nightly/firefox')), - ('chrome', which('google-chrome-stable')), - ('chrome', which('google-chrome'))] + browser_locations = [ + ('firefox', os.path.expanduser('~/firefox/firefox')), + ('firefox_beta', os.path.expanduser('~/firefox_beta/firefox')), + ('firefox_aurora', os.path.expanduser('~/firefox_aurora/firefox')), + ('firefox_nightly', os.path.expanduser('~/firefox_nightly/firefox')), + ('chrome', which('google-chrome-stable')), + ('chrome', which('google-chrome')), + ] for alias, browser_exe in browser_locations: if name == alias: if browser_exe is not None and os.path.isfile(browser_exe): return [browser_exe] - return None # Could not find the browser + return None # Could not find the browser def get_android_model(): @@ -1295,7 +1380,17 @@ def list_android_browsers(): def list_pc_browsers(): - browsers = ['firefox', 'firefox_beta', 'firefox_aurora', 'firefox_nightly', 'chrome', 'chrome_canary', 'iexplore', 'safari', 'opera'] + browsers = [ + 'firefox', + 'firefox_beta', + 'firefox_aurora', + 'firefox_nightly', + 'chrome', + 'chrome_canary', + 'iexplore', + 'safari', + 'opera', + ] logi('emrun has automatically found the following browsers in the default install locations on the system:') logi('') for browser in browsers: @@ -1306,7 +1401,9 @@ def list_pc_browsers(): logi(' - ' + browser + ': ' + browser_display_name(browser_exe) + ' ' + get_executable_version(browser_exe)) logi('') logi('You can pass the --browser option to launch with the given browser above.') - logi('Even if your browser was not detected, you can use --browser /path/to/browser/executable to launch with that browser.') + logi( + 'Even if your browser was not detected, you can use --browser /path/to/browser/executable to launch with that browser.' + ) def browser_display_name(browser): @@ -1335,8 +1432,8 @@ def subprocess_env(): e = os.environ.copy() # https://bugzilla.mozilla.org/show_bug.cgi?id=745154 e['MOZ_DISABLE_AUTO_SAFE_MODE'] = '1' - e['MOZ_DISABLE_SAFE_MODE_KEY'] = '1' # https://bugzilla.mozilla.org/show_bug.cgi?id=653410#c9 - e['JIT_OPTION_asmJSAtomicsEnable'] = 'true' # https://bugzilla.mozilla.org/show_bug.cgi?id=1299359#c0 + e['MOZ_DISABLE_SAFE_MODE_KEY'] = '1' # https://bugzilla.mozilla.org/show_bug.cgi?id=653410#c9 + e['JIT_OPTION_asmJSAtomicsEnable'] = 'true' # https://bugzilla.mozilla.org/show_bug.cgi?id=1299359#c0 return e @@ -1344,12 +1441,14 @@ def subprocess_env(): def remove_tree(d): os.chmod(d, stat.S_IWRITE) try: + def remove_readonly_and_try_again(func, path, _exc_info): if not (os.stat(path).st_mode & stat.S_IWRITE): os.chmod(path, stat.S_IWRITE) func(path) else: raise + shutil.rmtree(d, onerror=remove_readonly_and_try_again) except Exception: pass @@ -1358,14 +1457,20 @@ def remove_readonly_and_try_again(func, path, _exc_info): def get_system_info(format_json): if emrun_options.android: if format_json: - return json.dumps({'model': get_android_model(), - 'os': get_android_os_version(), - 'ram': get_system_memory(), - 'cpu': get_android_cpu_infoline() - }, indent=2) + return json.dumps( + { + 'model': get_android_model(), + 'os': get_android_os_version(), + 'ram': get_system_memory(), + 'cpu': get_android_cpu_infoline(), + }, + indent=2, + ) else: info = 'Model: ' + get_android_model() + '\n' - info += 'OS: ' + get_android_os_version() + ' with ' + str(get_system_memory() // 1024 // 1024) + ' MB of System RAM\n' + info += ( + 'OS: ' + get_android_os_version() + ' with ' + str(get_system_memory() // 1024 // 1024) + ' MB of System RAM\n' + ) info += 'CPU: ' + get_android_cpu_infoline() + '\n' return info.strip() else: @@ -1374,6 +1479,7 @@ def get_system_info(format_json): unique_system_id = fh.read().strip() except Exception: import uuid + unique_system_id = str(uuid.uuid4()) try: open(os.path.expanduser('~/.emrun.generated.guid'), 'w').write(unique_system_id) @@ -1381,25 +1487,44 @@ def get_system_info(format_json): logv(e) if format_json: - return json.dumps({'name': socket.gethostname(), - 'model': get_computer_model(), - 'os': get_os_version(), - 'ram': get_system_memory(), - 'cpu': get_cpu_info(), - 'gpu': get_gpu_info(), - 'uuid': unique_system_id}, indent=2) + return json.dumps( + { + 'name': socket.gethostname(), + 'model': get_computer_model(), + 'os': get_os_version(), + 'ram': get_system_memory(), + 'cpu': get_cpu_info(), + 'gpu': get_gpu_info(), + 'uuid': unique_system_id, + }, + indent=2, + ) else: cpu = get_cpu_info() gpus = get_gpu_info() - info = 'Computer name: ' + socket.gethostname() + '\n' # http://stackoverflow.com/questions/799767/getting-name-of-windows-computer-running-python-script + info = ( + 'Computer name: ' + socket.gethostname() + '\n' + ) # http://stackoverflow.com/questions/799767/getting-name-of-windows-computer-running-python-script info += 'Model: ' + get_computer_model() + '\n' info += 'OS: ' + get_os_version() + ' with ' + str(get_system_memory() // 1024 // 1024) + ' MB of System RAM\n' - info += 'CPU: ' + cpu['model'] + ', ' + str(cpu['frequency']) + ' MHz, ' + str(cpu['physicalCores']) + ' physical cores, ' + str(cpu['logicalCores']) + ' logical cores\n' + info += ( + 'CPU: ' + + cpu['model'] + + ', ' + + str(cpu['frequency']) + + ' MHz, ' + + str(cpu['physicalCores']) + + ' physical cores, ' + + str(cpu['logicalCores']) + + ' logical cores\n' + ) if len(gpus) == 1: info += 'GPU: ' + gpus[0]['model'] + ' with ' + str(gpus[0]['ram'] // 1024 // 1024) + " MB of VRAM\n" elif len(gpus) > 1: for i in range(0, len(gpus)): - info += 'GPU' + str(i) + ": " + gpus[i]['model'] + ' with ' + str(gpus[i]['ram'] // 1024 // 1024) + ' MBs of VRAM\n' + info += ( + 'GPU' + str(i) + ": " + gpus[i]['model'] + ' with ' + str(gpus[i]['ram'] // 1024 // 1024) + ' MBs of VRAM\n' + ) info += 'UUID: ' + unique_system_id return info.strip() @@ -1416,6 +1541,7 @@ def list_processes_by_name(exe_full_path): pids = [] try: import psutil + for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'name', 'exe']) @@ -1449,121 +1575,170 @@ def list_processes_by_name(exe_full_path): def parse_args(args): parser = argparse.ArgumentParser(usage=usage_str) - parser.add_argument('--kill-start', action='store_true', - help='If true, any previously running instances of ' - 'the target browser are killed before starting.') - - parser.add_argument('--kill-exit', action='store_true', - help='If true, the spawned browser process is forcibly ' - 'killed when it calls exit(). Note: Using this ' - 'option may require explicitly passing the option ' - '--browser=/path/to/browser, to avoid emrun being ' - 'detached from the browser process it spawns.') - - parser.add_argument('--no-server', dest='run_server', action='store_false', - default=True, - help='If specified, a HTTP web server is not launched ' - 'to host the page to run.') - - parser.add_argument('--no-browser', dest='run_browser', action='store_false', - default=True, - help='If specified, emrun will not launch a web browser ' - 'to run the page.') - - parser.add_argument('--no-emrun-detect', action='store_true', - help='If specified, skips printing the warning message ' - 'if html page is detected to not have been built ' - 'with --emrun linker flag.') - - parser.add_argument('--serve-after-close', action='store_true', - help='If true, serves the web page even after the ' - 'application quits by user closing the web page.') - - parser.add_argument('--serve-after-exit', action='store_true', - help='If true, serves the web page even after the ' - 'application quits by a call to exit().') - - parser.add_argument('--serve-root', - help='If set, specifies the root path that the emrun ' - 'web server serves. If not specified, the directory ' - 'where the target .html page lives in is served.') - - parser.add_argument('--verbose', action='store_true', - help='Enable verbose logging from emrun internal operation.') - - parser.add_argument('--hostname', default=default_webserver_hostname, - help='Specifies the hostname the server runs in.') - - parser.add_argument('--port', default=default_webserver_port, type=int, - help='Specifies the port the server runs in.') - - parser.add_argument('--log-stdout', - help='Specifies a log filename where the browser process ' - 'stdout data will be appended to.') - - parser.add_argument('--log-stderr', - help='Specifies a log filename where the browser process stderr data will be appended to.') - - parser.add_argument('--silence-timeout', type=int, default=0, - help='If no activity is received in this many seconds, ' - 'the browser process is assumed to be hung, and the web ' - 'server is shut down and the target browser killed. ' - 'Disabled by default.') - - parser.add_argument('--timeout', type=int, default=0, - help='If the browser process does not quit or the page ' - 'exit() in this many seconds, the browser is assumed ' - 'to be hung, and the web server is shut down and the ' - 'target browser killed. Disabled by default.') - - parser.add_argument('--timeout-returncode', type=int, default=99999, - help='Sets the exit code that emrun reports back to ' - 'caller in the case that a page timeout occurs. ' - 'Default: 99999.') - - parser.add_argument('--list-browsers', action='store_true', - help='Prints out all detected browser that emrun is able ' - 'to use with the --browser command and exits.') - - parser.add_argument('--browser', - help='Specifies the browser executable to run the web page in.') - - parser.add_argument('--browser-args', default='', - help='Specifies the arguments to the browser executable.') - - parser.add_argument('--android', action='store_true', - help='Launches the page in a browser of an Android ' - 'device connected to an USB on the local system. (via adb)') - - parser.add_argument('--android-tunnel', action='store_true', - help='Expose the port directly to the Android device ' - 'and connect to it as localhost, establishing ' - 'cross origin isolation. Implies --android. A ' - 'reverse socket connection is created by adb ' - 'reverse, and remains after emrun terminates (it ' - 'can be removed by adb reverse --remove).') - - parser.add_argument('--system-info', action='store_true', - help='Prints information about the current system at startup.') - - parser.add_argument('--browser-info', action='store_true', - help='Prints information about the target browser to launch at startup.') - - parser.add_argument('--json', action='store_true', - help='If specified, --system-info and --browser-info are ' - 'outputted in JSON format.') - - parser.add_argument('--safe-firefox-profile', action='store_true', - help='If true, the browser is launched into a new clean ' - 'Firefox profile that is suitable for unattended ' - 'automated runs. (If target browser != Firefox, ' - 'this parameter is ignored)') - - parser.add_argument('--private-browsing', action='store_true', - help='If specified, opens browser in private/incognito mode.') - - parser.add_argument('--dump-out-directory', default='dump_out', type=str, - help='If specified, overrides the directory for dump files using emrun_file_dump method.') + parser.add_argument( + '--kill-start', + action='store_true', + help='If true, any previously running instances of ' 'the target browser are killed before starting.', + ) + + parser.add_argument( + '--kill-exit', + action='store_true', + help='If true, the spawned browser process is forcibly ' + 'killed when it calls exit(). Note: Using this ' + 'option may require explicitly passing the option ' + '--browser=/path/to/browser, to avoid emrun being ' + 'detached from the browser process it spawns.', + ) + + parser.add_argument( + '--no-server', + dest='run_server', + action='store_false', + default=True, + help='If specified, a HTTP web server is not launched ' 'to host the page to run.', + ) + + parser.add_argument( + '--no-browser', + dest='run_browser', + action='store_false', + default=True, + help='If specified, emrun will not launch a web browser ' 'to run the page.', + ) + + parser.add_argument( + '--no-emrun-detect', + action='store_true', + help='If specified, skips printing the warning message ' + 'if html page is detected to not have been built ' + 'with --emrun linker flag.', + ) + + parser.add_argument( + '--serve-after-close', + action='store_true', + help='If true, serves the web page even after the ' 'application quits by user closing the web page.', + ) + + parser.add_argument( + '--serve-after-exit', + action='store_true', + help='If true, serves the web page even after the ' 'application quits by a call to exit().', + ) + + parser.add_argument( + '--serve-root', + help='If set, specifies the root path that the emrun ' + 'web server serves. If not specified, the directory ' + 'where the target .html page lives in is served.', + ) + + parser.add_argument('--verbose', action='store_true', help='Enable verbose logging from emrun internal operation.') + + parser.add_argument( + '--hostname', default=default_webserver_hostname, help='Specifies the hostname the server runs in.' + ) + + parser.add_argument('--port', default=default_webserver_port, type=int, help='Specifies the port the server runs in.') + + parser.add_argument( + '--log-stdout', help='Specifies a log filename where the browser process ' 'stdout data will be appended to.' + ) + + parser.add_argument( + '--log-stderr', help='Specifies a log filename where the browser process stderr data will be appended to.' + ) + + parser.add_argument( + '--silence-timeout', + type=int, + default=0, + help='If no activity is received in this many seconds, ' + 'the browser process is assumed to be hung, and the web ' + 'server is shut down and the target browser killed. ' + 'Disabled by default.', + ) + + parser.add_argument( + '--timeout', + type=int, + default=0, + help='If the browser process does not quit or the page ' + 'exit() in this many seconds, the browser is assumed ' + 'to be hung, and the web server is shut down and the ' + 'target browser killed. Disabled by default.', + ) + + parser.add_argument( + '--timeout-returncode', + type=int, + default=99999, + help='Sets the exit code that emrun reports back to ' + 'caller in the case that a page timeout occurs. ' + 'Default: 99999.', + ) + + parser.add_argument( + '--list-browsers', + action='store_true', + help='Prints out all detected browser that emrun is able ' 'to use with the --browser command and exits.', + ) + + parser.add_argument('--browser', help='Specifies the browser executable to run the web page in.') + + parser.add_argument('--browser-args', default='', help='Specifies the arguments to the browser executable.') + + parser.add_argument( + '--android', + action='store_true', + help='Launches the page in a browser of an Android ' 'device connected to an USB on the local system. (via adb)', + ) + + parser.add_argument( + '--android-tunnel', + action='store_true', + help='Expose the port directly to the Android device ' + 'and connect to it as localhost, establishing ' + 'cross origin isolation. Implies --android. A ' + 'reverse socket connection is created by adb ' + 'reverse, and remains after emrun terminates (it ' + 'can be removed by adb reverse --remove).', + ) + + parser.add_argument( + '--system-info', action='store_true', help='Prints information about the current system at startup.' + ) + + parser.add_argument( + '--browser-info', action='store_true', help='Prints information about the target browser to launch at startup.' + ) + + parser.add_argument( + '--json', + action='store_true', + help='If specified, --system-info and --browser-info are ' 'outputted in JSON format.', + ) + + parser.add_argument( + '--safe-firefox-profile', + action='store_true', + help='If true, the browser is launched into a new clean ' + 'Firefox profile that is suitable for unattended ' + 'automated runs. (If target browser != Firefox, ' + 'this parameter is ignored)', + ) + + parser.add_argument( + '--private-browsing', action='store_true', help='If specified, opens browser in private/incognito mode.' + ) + + parser.add_argument( + '--dump-out-directory', + default='dump_out', + type=str, + help='If specified, overrides the directory for dump files using emrun_file_dump method.', + ) parser.add_argument('serve', nargs='?', default='') @@ -1637,7 +1812,9 @@ def run(args): # noqa: C901, PLR0912, PLR0915 file_to_serve = options.serve else: file_to_serve = '.' - file_to_serve_is_url = file_to_serve.startswith('file://') or file_to_serve.startswith('http://') or file_to_serve.startswith('https://') + file_to_serve_is_url = ( + file_to_serve.startswith('file://') or file_to_serve.startswith('http://') or file_to_serve.startswith('https://') + ) if options.serve_root: serve_dir = os.path.abspath(options.serve_root) @@ -1680,7 +1857,9 @@ def run(args): # noqa: C901, PLR0912, PLR0915 if options.android: if options.run_browser or options.browser_info: if not options.browser: - loge("Running on Android requires that you explicitly specify the browser to run with --browser . Run emrun --android --list-browsers to obtain a list of installed browsers you can use.") + loge( + "Running on Android requires that you explicitly specify the browser to run with --browser . Run emrun --android --list-browsers to obtain a list of installed browsers you can use." + ) return 1 elif options.browser == 'firefox': browser_app = 'org.mozilla.firefox/org.mozilla.gecko.BrowserApp' @@ -1713,15 +1892,19 @@ def run(args): # noqa: C901, PLR0912, PLR0915 url = url.replace('&', '\\&') browser = [ADB, 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-n', browser_app, '-d', url] - processname_killed_atexit = browser_app[:browser_app.find('/')] - else: # Launching a web page on local system. + processname_killed_atexit = browser_app[: browser_app.find('/')] + else: # Launching a web page on local system. if options.browser: options.browser = unwrap(options.browser) if options.run_browser or options.browser_info: browser = find_browser(str(options.browser)) if not browser: - loge('Unable to find browser "' + str(options.browser) + '"! Check the correctness of the passed --browser=xxx parameter!') + loge( + 'Unable to find browser "' + + str(options.browser) + + '"! Check the correctness of the passed --browser=xxx parameter!' + ) return 1 browser_exe = browser[0] browser_args = shlex.split(unwrap(options.browser_args)) @@ -1737,12 +1920,20 @@ def run(args): # noqa: C901, PLR0912, PLR0915 processname_killed_atexit = 'Safari' elif 'chrome' in browser_exe.lower(): processname_killed_atexit = 'chrome' - browser_args += ['--enable-nacl', '--enable-pnacl', '--disable-restore-session-state', '--enable-webgl', - '--no-default-browser-check', '--no-first-run', '--allow-file-access-from-files', '--password-store=basic'] + browser_args += [ + '--enable-nacl', + '--enable-pnacl', + '--disable-restore-session-state', + '--enable-webgl', + '--no-default-browser-check', + '--no-first-run', + '--allow-file-access-from-files', + '--password-store=basic', + ] if options.private_browsing: browser_args += ['--incognito'] - # if not options.run_server: - # browser_args += ['--disable-web-security'] + # if not options.run_server: + # browser_args += ['--disable-web-security'] elif 'firefox' in browser_exe.lower(): processname_killed_atexit = 'firefox' elif 'iexplore' in browser_exe.lower(): @@ -1777,7 +1968,9 @@ def run(cmd): run(['adb', 'shell', 'mkdir', '/mnt/sdcard/safe_firefox_profile']) run(['adb', 'push', os.path.join(profile_dir, 'prefs.js'), '/mnt/sdcard/safe_firefox_profile/prefs.js']) except Exception as e: - loge('Creating Firefox profile prefs.js file to internal storage in /mnt/sdcard failed with error ' + str(e) + '!') + loge( + 'Creating Firefox profile prefs.js file to internal storage in /mnt/sdcard failed with error ' + str(e) + '!' + ) loge('Try running without --safe-firefox-profile flag if unattended execution mode is not important, or') loge('enable rooted debugging on the Android device to allow adb to write files to /mnt/sdcard.') browser += ['--es', 'args', '"--profile /mnt/sdcard/safe_firefox_profile"'] @@ -1785,7 +1978,12 @@ def run(cmd): # Create temporary Firefox profile to run the page with. This is important to # run after kill_browser_process()/kill_start op above, since that cleans up # the temporary profile if one exists. - if processname_killed_atexit == 'firefox' and options.safe_firefox_profile and options.run_browser and not options.android: + if ( + processname_killed_atexit == 'firefox' + and options.safe_firefox_profile + and options.run_browser + and not options.android + ): profile_dir = create_emrun_safe_firefox_profile() browser += ['-no-remote', '--profile', profile_dir.replace('\\', '/')] @@ -1827,7 +2025,12 @@ def run(cmd): logv(browser_exe) previous_browser_processes = list_processes_by_name(browser_exe) for p in previous_browser_processes: - logv('Before spawning web browser, found a running ' + os.path.basename(browser_exe) + ' browser process id: ' + str(p['pid'])) + logv( + 'Before spawning web browser, found a running ' + + os.path.basename(browser_exe) + + ' browser process id: ' + + str(p['pid']) + ) browser_process = subprocess.Popen(browser, env=subprocess_env()) logv('Launched browser process with pid=' + str(browser_process.pid)) if options.kill_exit: @@ -1841,9 +2044,15 @@ def run(cmd): premature_quit_code = browser_process.poll() if premature_quit_code is not None: options.serve_after_close = True - logv('Warning: emrun got immediately detached from the target browser process (the process quit with exit code ' + str(premature_quit_code) + '). Cannot detect when user closes the browser. Behaving as if --serve-after-close was passed in.') + logv( + 'Warning: emrun got immediately detached from the target browser process (the process quit with exit code ' + + str(premature_quit_code) + + '). Cannot detect when user closes the browser. Behaving as if --serve-after-close was passed in.' + ) if not options.browser: - logv('Try passing the --browser=/path/to/browser option to avoid this from occurring. See https://github.com/emscripten-core/emscripten/issues/3234 for more discussion.') + logv( + 'Try passing the --browser=/path/to/browser option to avoid this from occurring. See https://github.com/emscripten-core/emscripten/issues/3234 for more discussion.' + ) if options.run_server: try: @@ -1880,7 +2089,11 @@ def main(args): returncode = run(args) logv('emrun quitting with process exit code ' + str(returncode)) if temp_firefox_profile_dir is not None: - logi('Warning: Had to leave behind a temporary Firefox profile directory ' + temp_firefox_profile_dir + ' because --safe-firefox-profile was set and the browser did not quit before emrun did.') + logi( + 'Warning: Had to leave behind a temporary Firefox profile directory ' + + temp_firefox_profile_dir + + ' because --safe-firefox-profile was set and the browser did not quit before emrun did.' + ) return returncode diff --git a/emsize.py b/emsize.py index 8bf92a3843c01..6ea849351f20a 100755 --- a/emsize.py +++ b/emsize.py @@ -61,8 +61,7 @@ def print_sizes(js_file): if not os.path.isfile(wasm_file): return error('Wasm file %s not found' % wasm_file) - sizes = shared.check_call([LLVM_SIZE, '--format=sysv', wasm_file], - stdout=subprocess.PIPE).stdout + sizes = shared.check_call([LLVM_SIZE, '--format=sysv', wasm_file], stdout=subprocess.PIPE).stdout # llvm-size may emit some number of blank lines (after the total), ignore them lines = [line for line in sizes.splitlines() if line] diff --git a/emstrip.py b/emstrip.py index f054fe7e9f1df..b330234f960cb 100755 --- a/emstrip.py +++ b/emstrip.py @@ -4,8 +4,7 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -"""Wrapper script around `llvm-strip`. -""" +"""Wrapper script around `llvm-strip`.""" import sys from tools import shared diff --git a/emsymbolizer.py b/emsymbolizer.py index 7ba3b951c852b..37728882b53fb 100755 --- a/emsymbolizer.py +++ b/emsymbolizer.py @@ -22,8 +22,7 @@ from tools import shared from tools import webassembly -LLVM_SYMBOLIZER = os.path.expanduser( - shared.build_llvm_tool_path(shared.exe_suffix('llvm-symbolizer'))) +LLVM_SYMBOLIZER = os.path.expanduser(shared.build_llvm_tool_path(shared.exe_suffix('llvm-symbolizer'))) class Error(BaseException): @@ -68,8 +67,7 @@ def symbolize_address_symbolizer(module, address, is_dwarf): vma_adjust = get_codesec_offset(module) else: vma_adjust = 0 - cmd = [LLVM_SYMBOLIZER, '-e', module.filename, f'--adjust-vma={vma_adjust}', - str(address)] + cmd = [LLVM_SYMBOLIZER, '-e', module.filename, f'--adjust-vma={vma_adjust}', str(address)] out = shared.run_process(cmd, stdout=subprocess.PIPE).stdout.strip() out_lines = out.splitlines() @@ -184,11 +182,7 @@ def lookup(self, offset): nearest = self.find_offset(offset) assert nearest in self.mappings, 'Sourcemap has an offset with no mapping' info = self.mappings[nearest] - return LocationInfo( - self.sources[info.source] if info.source is not None else None, - info.line, - info.column - ) + return LocationInfo(self.sources[info.source] if info.source is not None else None, info.line, info.column) def symbolize_address_sourcemap(module, address, force_file): @@ -223,36 +217,32 @@ def main(args): if args.addrtype == 'code': address += get_codesec_offset(module) - if ((has_debug_line_section(module) and not args.source) or - 'dwarf' in args.source): + if (has_debug_line_section(module) and not args.source) or 'dwarf' in args.source: symbolize_address_symbolizer(module, address, is_dwarf=True) - elif ((get_sourceMappingURL_section(module) and not args.source) or - 'sourcemap' in args.source): + elif (get_sourceMappingURL_section(module) and not args.source) or 'sourcemap' in args.source: symbolize_address_sourcemap(module, address, args.file) - elif ((has_name_section(module) and not args.source) or - 'names' in args.source): + elif (has_name_section(module) and not args.source) or 'names' in args.source: symbolize_address_symbolizer(module, address, is_dwarf=False) - elif ((has_linking_section(module) and not args.source) or - 'symtab' in args.source): + elif (has_linking_section(module) and not args.source) or 'symtab' in args.source: symbolize_address_symbolizer(module, address, is_dwarf=False) else: - raise Error('No .debug_line or sourceMappingURL section found in ' - f'{module.filename}.' - " I don't know how to symbolize this file yet") + raise Error( + 'No .debug_line or sourceMappingURL section found in ' + f'{module.filename}.' + " I don't know how to symbolize this file yet" + ) def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('-s', '--source', choices=['dwarf', 'sourcemap', - 'names', 'symtab'], - help='Force debug info source type', default=()) - parser.add_argument('-f', '--file', action='store', - help='Force debug info source file') - parser.add_argument('-t', '--addrtype', choices=['code', 'file'], - default='file', - help='Address type (code section or file offset)') - parser.add_argument('-v', '--verbose', action='store_true', - help='Print verbose info for debugging this script') + parser.add_argument( + '-s', '--source', choices=['dwarf', 'sourcemap', 'names', 'symtab'], help='Force debug info source type', default=() + ) + parser.add_argument('-f', '--file', action='store', help='Force debug info source file') + parser.add_argument( + '-t', '--addrtype', choices=['code', 'file'], default='file', help='Address type (code section or file offset)' + ) + parser.add_argument('-v', '--verbose', action='store_true', help='Print verbose info for debugging this script') parser.add_argument('wasm_file', help='Wasm file') parser.add_argument('address', help='Address to lookup') args = parser.parse_args() diff --git a/pyproject.toml b/pyproject.toml index 874462532f8e3..825e5e34451ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,12 @@ exclude = [ "./tools/scons/", ".git", ] +format.exclude = [ + "./test/test_browser.py", +] +format.quote-style = "preserve" +indent-width = 2 +line-length = 120 lint.select = [ "ARG", diff --git a/requirements-dev.txt b/requirements-dev.txt index 84c824c5ee1b6..97d17eaf370d5 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,7 +6,7 @@ coverage[toml]==5.5 mypy==0.971 -ruff==0.8.2 +ruff==0.8.3 types-requests==2.27.14 unittest-xml-reporting==3.1.0 diff --git a/site/source/get_api_items.py b/site/source/get_api_items.py index ee94f6909e6d3..404bb42eee026 100755 --- a/site/source/get_api_items.py +++ b/site/source/get_api_items.py @@ -26,77 +26,83 @@ def parseFiles(): - """Parse api-reference files to extract the code items. - """ - - def addapiitems(matchobj): - # print 'matcobj0: %s' % matchobj.group(0) - # print 'matcobj1: %s' % matchobj.group(1) - # print 'matcobj2: %s' % matchobj.group(2) - # print 'matcobj3: %s' % matchobj.group(3) - # print 'matcobj4: %s' % matchobj.group(4) - - lang = matchobj.group(2) - data_type = matchobj.group(3) - if data_type == 'function': - data_type = 'func' - api_item = matchobj.group(4) - api_item = api_item.strip() - api_item = api_item.split('(')[0] - try: - api_item = api_item.split(' ')[1] - except IndexError: - pass - - # print lang - # print data_type - # print api_item - - api_reference_items[api_item] = ':%s:%s:`%s`' % (lang, data_type, api_item) - # Add additional index for functions declared as func() rather than just func - if data_type == 'func': - api_item_index = api_item + '()' - api_reference_items[api_item_index] = ':%s:%s:`%s`' % (lang, data_type, api_item) - - # print api_reference_items[api_item] - - for file in os.listdir(api_reference_directory): - if file.endswith(".rst"): - filepath = api_reference_directory + file - print(file) - # open file - with open(filepath, 'r') as infile: - for line in infile: - # parse line for API items - re.sub(r'^\.\.\s+((\w+)\:(\w+)\:\:(.*))', addapiitems, line) + """Parse api-reference files to extract the code items.""" + + def addapiitems(matchobj): + # print 'matcobj0: %s' % matchobj.group(0) + # print 'matcobj1: %s' % matchobj.group(1) + # print 'matcobj2: %s' % matchobj.group(2) + # print 'matcobj3: %s' % matchobj.group(3) + # print 'matcobj4: %s' % matchobj.group(4) + + lang = matchobj.group(2) + data_type = matchobj.group(3) + if data_type == 'function': + data_type = 'func' + api_item = matchobj.group(4) + api_item = api_item.strip() + api_item = api_item.split('(')[0] + try: + api_item = api_item.split(' ')[1] + except IndexError: + pass + + # print lang + # print data_type + # print api_item + + api_reference_items[api_item] = ':%s:%s:`%s`' % (lang, data_type, api_item) + # Add additional index for functions declared as func() rather than just func + if data_type == 'func': + api_item_index = api_item + '()' + api_reference_items[api_item_index] = ':%s:%s:`%s`' % (lang, data_type, api_item) + + # print api_reference_items[api_item] + + for file in os.listdir(api_reference_directory): + if file.endswith(".rst"): + filepath = api_reference_directory + file + print(file) + # open file + with open(filepath, 'r') as infile: + for line in infile: + # parse line for API items + re.sub(r'^\.\.\s+((\w+)\:(\w+)\:\:(.*))', addapiitems, line) def exportItems(): - """Export the API items into form for use in another script. - """ - with open(api_item_filename, 'w') as infile: - # write function lead in - infile.write("# Auto-generated file (see get_api_items.py)\n\ndef get_mapped_items():\n mapped_wiki_inline_code = dict()\n") + """Export the API items into form for use in another script.""" + with open(api_item_filename, 'w') as infile: + # write function lead in + infile.write( + "# Auto-generated file (see get_api_items.py)\n\ndef get_mapped_items():\n mapped_wiki_inline_code = dict()\n" + ) - items = list((key, value) for key, value in api_reference_items.items()) - items.sort() - for key, value in items: - # Write out each API item to add - infile.write(" mapped_wiki_inline_code['%s'] = '%s'\n" % (key, value)) + items = list((key, value) for key, value in api_reference_items.items()) + items.sort() + for key, value in items: + # Write out each API item to add + infile.write(" mapped_wiki_inline_code['%s'] = '%s'\n" % (key, value)) - # write the return function - infile.write(" return mapped_wiki_inline_code\n") + # write the return function + infile.write(" return mapped_wiki_inline_code\n") def main(): - parser = optparse.OptionParser(usage="Usage: %prog [options] version") - parser.add_option("-s", "--siteapi", dest="siteapi", default="http://www.developer.nokia.com/Community/Wiki/api.php", help="Location of API") - (options, args) = parser.parse_args() - # print 'Site: %s' % options.siteapi - parseFiles() - exportItems() - return 0 + parser = optparse.OptionParser(usage="Usage: %prog [options] version") + parser.add_option( + "-s", + "--siteapi", + dest="siteapi", + default="http://www.developer.nokia.com/Community/Wiki/api.php", + help="Location of API", + ) + (options, args) = parser.parse_args() + # print 'Site: %s' % options.siteapi + parseFiles() + exportItems() + return 0 if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) diff --git a/site/source/get_wiki.py b/site/source/get_wiki.py index 899531541f222..dbe2a3c5e5b78 100755 --- a/site/source/get_wiki.py +++ b/site/source/get_wiki.py @@ -39,185 +39,197 @@ temp_set_of_codemarkup = set() logfile = open(logfilename, 'w') # snapshot_version_information = '.. note:: This is a **snapshot** of the wiki: %s\n\n' % strftime("%a, %d %b %Y %H:%M", gmtime()) -snapshot_version_information = '.. note:: This article was migrated from the wiki (%s) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon!\n\n' % time.strftime("%a, %d %b %Y %H:%M", time.gmtime()) +snapshot_version_information = ( + '.. note:: This article was migrated from the wiki (%s) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon!\n\n' + % time.strftime("%a, %d %b %Y %H:%M", time.gmtime()) +) def CleanWiki(): - """Delete the wiki clone directory and all contained files. - """ + """Delete the wiki clone directory and all contained files.""" - def errorhandler(func, path, exc_info): - # where func is os.listdir, os.remove, or os.rmdir; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info() - print(func) - print(path) - print(exc_info) - os.chmod(path, stat.S_IWRITE) - os.remove(path) + def errorhandler(func, path, exc_info): + # where func is os.listdir, os.remove, or os.rmdir; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info() + print(func) + print(path) + print(exc_info) + os.chmod(path, stat.S_IWRITE) + os.remove(path) - try: - shutil.rmtree(output_dir, ignore_errors=False, onerror=errorhandler) - print('Old wiki clone removed') - except IOError: - print('No directory to clean found') + try: + shutil.rmtree(output_dir, ignore_errors=False, onerror=errorhandler) + print('Old wiki clone removed') + except IOError: + print('No directory to clean found') def CloneWiki(): - """ - Clone the wiki into a temporary location (first cleaning) - """ - # Clean up existing repo - CleanWiki() + """ + Clone the wiki into a temporary location (first cleaning) + """ + # Clean up existing repo + CleanWiki() - # Create directory for output and temporary files - try: - os.makedirs(output_dir) - print('Created directory') - except OSError: - pass + # Create directory for output and temporary files + try: + os.makedirs(output_dir) + print('Created directory') + except OSError: + pass - # Clone - git_clone_command = 'git clone %s %s' % (wiki_repo, wiki_checkout) - print(git_clone_command) - os.system(git_clone_command) + # Clone + git_clone_command = 'git clone %s %s' % (wiki_repo, wiki_checkout) + print(git_clone_command) + os.system(git_clone_command) def ConvertFilesToRst(): - """ - Add template to specified page object (wikitools) - """ - indexfiletext = '============================\nWiki snapshot (ready-for-review)\n============================\n\n%s\n.. toctree::\n :maxdepth: 2\n' % snapshot_version_information - for file in os.listdir(wiki_checkout): - if not file.endswith(".md"): - continue - - inputfilename = wiki_checkout + file - markdown = Path(inputfilename).read_text() - if 'This article has moved from the wiki to the new site' in markdown: - continue - if 'This page has been migrated to the main site' in markdown: - continue - - print(file) - # get name of file - filenamestripped = os.path.splitext(file)[0] - indexfiletext += '\n %s' % filenamestripped - outputfilename = output_dir + filenamestripped + '.rst' - - command = 'pandoc -f markdown -t rst -o "%s" "%s"' % (outputfilename, inputfilename) - print(command) - if os.system(command): - sys.exit(1) - title = filenamestripped.replace('-', ' ') - # print title - logfile.write('title from filename: %s \n' % title) - # add import message to title - title += ' (wiki-import)' - length = len(title) - # print length - headerbar = '' - for _ in range(length): - headerbar += '=' - page_reference = filenamestripped - page_reference_link_text = '.. _%s:\n\n' % page_reference - titlebar = page_reference_link_text + headerbar + '\n' + title + '\n' + headerbar + '\n' - textinfile = '' - # Add titlebar to start of the file (from the filename) - textinfile += titlebar - # Add wiki snapshot information - - textinfile += snapshot_version_information - - with open(outputfilename) as infile: - for line in infile: - textinfile += line - - # print textinfile - with open(outputfilename, 'w') as outfile: - outfile.write(textinfile) - - # write the index - with open(output_dir + 'index.rst', 'w') as outfile: - outfile.write(indexfiletext) + """ + Add template to specified page object (wikitools) + """ + indexfiletext = ( + '============================\nWiki snapshot (ready-for-review)\n============================\n\n%s\n.. toctree::\n :maxdepth: 2\n' + % snapshot_version_information + ) + for file in os.listdir(wiki_checkout): + if not file.endswith(".md"): + continue + + inputfilename = wiki_checkout + file + markdown = Path(inputfilename).read_text() + if 'This article has moved from the wiki to the new site' in markdown: + continue + if 'This page has been migrated to the main site' in markdown: + continue + + print(file) + # get name of file + filenamestripped = os.path.splitext(file)[0] + indexfiletext += '\n %s' % filenamestripped + outputfilename = output_dir + filenamestripped + '.rst' + + command = 'pandoc -f markdown -t rst -o "%s" "%s"' % (outputfilename, inputfilename) + print(command) + if os.system(command): + sys.exit(1) + title = filenamestripped.replace('-', ' ') + # print title + logfile.write('title from filename: %s \n' % title) + # add import message to title + title += ' (wiki-import)' + length = len(title) + # print length + headerbar = '' + for _ in range(length): + headerbar += '=' + page_reference = filenamestripped + page_reference_link_text = '.. _%s:\n\n' % page_reference + titlebar = page_reference_link_text + headerbar + '\n' + title + '\n' + headerbar + '\n' + textinfile = '' + # Add titlebar to start of the file (from the filename) + textinfile += titlebar + # Add wiki snapshot information + + textinfile += snapshot_version_information + + with open(outputfilename) as infile: + for line in infile: + textinfile += line + + # print textinfile + with open(outputfilename, 'w') as outfile: + outfile.write(textinfile) + + # write the index + with open(output_dir + 'index.rst', 'w') as outfile: + outfile.write(indexfiletext) def FixupConvertedRstFiles(): - """Add template to specified page object (wikitools) + """Add template to specified page object (wikitools)""" + + def fixInternalWikiLinks(aOldText): + """ + Fixes wiki links in [[linkname]] format by changing this to a document link in current directory. + """ + + def fixwikilinks(matchobj): + # print 'matcobj0: %s' % matchobj.group(0) + # print 'matcobj1: %s' % matchobj.group(1) + linktext = matchobj.group(1) + linktext = linktext.replace(' ', '-') + # linktext = ':doc:`%s`' % linktext + # use reference for linking as allows pages to be moved around + linktext = ':ref:`%s`' % linktext + # print 'linkdoc: %s' % linktext + logfile.write('linkdoc: %s \n' % linktext) + return linktext + + # print 'fixing wiki links' + return re.sub(r'\[\[(.+?)\]\]', fixwikilinks, aOldText) + + def fixWikiCodeMarkupToCodeLinks(aOldText): """ + Links "known" code objects if they are found in wiki markup. + """ + + def fixcodemarkuplinks(matchobj): + # print 'Inline code: %s' % matchobj.group(0) + # print 'matcobj1: %s' % matchobj.group(1) + temp_set_of_codemarkup.add(matchobj.group(0)) + linktext = matchobj.group(1) + if linktext in mapped_wiki_inline_code: + logfile.write('Replace: %s \n' % mapped_wiki_inline_code[linktext]) + return mapped_wiki_inline_code[linktext] + + return matchobj.group(0) # linktext + + # print 'fixing up code markup to code reference' + return re.sub(r'``(.+?)``', fixcodemarkuplinks, aOldText) + + for file in os.listdir(output_dir): + if file.endswith(".rst"): + input_file = output_dir + file + # print input_file + textinfile = '' + with open(input_file) as infile: + for line in infile: + textinfile += line + + # print textinfile + # fix up broken wiki-page links in files + textinfile = fixInternalWikiLinks(textinfile) + + # convert codemarkup to links if possible + textinfile = fixWikiCodeMarkupToCodeLinks(textinfile) + + with open(input_file, 'w') as outfile: + outfile.write(textinfile) - def fixInternalWikiLinks(aOldText): - """ - Fixes wiki links in [[linkname]] format by changing this to a document link in current directory. - """ - def fixwikilinks(matchobj): - # print 'matcobj0: %s' % matchobj.group(0) - # print 'matcobj1: %s' % matchobj.group(1) - linktext = matchobj.group(1) - linktext = linktext.replace(' ', '-') - # linktext = ':doc:`%s`' % linktext - # use reference for linking as allows pages to be moved around - linktext = ':ref:`%s`' % linktext - # print 'linkdoc: %s' % linktext - logfile.write('linkdoc: %s \n' % linktext) - return linktext - # print 'fixing wiki links' - return re.sub(r'\[\[(.+?)\]\]', fixwikilinks, aOldText) - - def fixWikiCodeMarkupToCodeLinks(aOldText): - """ - Links "known" code objects if they are found in wiki markup. - """ - def fixcodemarkuplinks(matchobj): - # print 'Inline code: %s' % matchobj.group(0) - # print 'matcobj1: %s' % matchobj.group(1) - temp_set_of_codemarkup.add(matchobj.group(0)) - linktext = matchobj.group(1) - if linktext in mapped_wiki_inline_code: - logfile.write('Replace: %s \n' % mapped_wiki_inline_code[linktext]) - return mapped_wiki_inline_code[linktext] - - return matchobj.group(0) # linktext - # print 'fixing up code markup to code reference' - return re.sub(r'``(.+?)``', fixcodemarkuplinks, aOldText) - - for file in os.listdir(output_dir): - if file.endswith(".rst"): - input_file = output_dir + file - # print input_file - textinfile = '' - with open(input_file) as infile: - for line in infile: - textinfile += line - - # print textinfile - # fix up broken wiki-page links in files - textinfile = fixInternalWikiLinks(textinfile) - - # convert codemarkup to links if possible - textinfile = fixWikiCodeMarkupToCodeLinks(textinfile) - - with open(input_file, 'w') as outfile: - outfile.write(textinfile) - - logfile.write('\n\nCODE MARKUP THAT WONT BE LINKED (add entry to mapped_wiki_inline_code if one of these need to be linked. The tool get-api-items.py can be used to generate the list of the documented API items. \n') - for item in temp_set_of_codemarkup: - logfile.write('%s\n' % item) + logfile.write( + '\n\nCODE MARKUP THAT WONT BE LINKED (add entry to mapped_wiki_inline_code if one of these need to be linked. The tool get-api-items.py can be used to generate the list of the documented API items. \n' + ) + for item in temp_set_of_codemarkup: + logfile.write('%s\n' % item) # parser options def main(): - parser = optparse.OptionParser(version="%prog 0.1.1", usage="Usage: %prog [options] version") - parser.add_option("-c", "--clonewiki", action="store_true", default=False, dest="clonewiki", help="Clean and clone the latest wiki") - options, args = parser.parse_args() + parser = optparse.OptionParser(version="%prog 0.1.1", usage="Usage: %prog [options] version") + parser.add_option( + "-c", "--clonewiki", action="store_true", default=False, dest="clonewiki", help="Clean and clone the latest wiki" + ) + options, args = parser.parse_args() - print('Clone wiki: %s' % options.clonewiki) - if options.clonewiki: - CloneWiki() - # input = raw_input('CHECK ALL files were cloned! (look for "error: unable to create file" )\n') + print('Clone wiki: %s' % options.clonewiki) + if options.clonewiki: + CloneWiki() + # input = raw_input('CHECK ALL files were cloned! (look for "error: unable to create file" )\n') - ConvertFilesToRst() - FixupConvertedRstFiles() - print('See LOG for details: %s ' % logfilename) + ConvertFilesToRst() + FixupConvertedRstFiles() + print('See LOG for details: %s ' % logfilename) if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) diff --git a/system/bin/sdl-config.py b/system/bin/sdl-config.py index e028a4f7397be..9d1bb92a72622 100755 --- a/system/bin/sdl-config.py +++ b/system/bin/sdl-config.py @@ -11,4 +11,3 @@ print('') elif '--version' in args: print('1.3.0') - diff --git a/system/bin/sdl2-config.py b/system/bin/sdl2-config.py index 957ef5900a3ec..bb8266c7dabec 100755 --- a/system/bin/sdl2-config.py +++ b/system/bin/sdl2-config.py @@ -10,4 +10,3 @@ print('-sUSE_SDL=2') elif '--version' in args: print('2.0.10') - diff --git a/test/benchmark/benchmark_sse.py b/test/benchmark/benchmark_sse.py index 65f296c1dafce..e24f60e2e208a 100644 --- a/test/benchmark/benchmark_sse.py +++ b/test/benchmark/benchmark_sse.py @@ -34,161 +34,195 @@ def run_benchmark(benchmark_file, results_file, build_args): - # Run native build - out_file = os.path.join(temp_dir, 'benchmark_sse_native') - if WINDOWS: - out_file += '.exe' - cmd = [CLANG_CXX] + clang_native.get_clang_native_args() + [benchmark_file, '-O3', '-o', out_file] - print('Building native version of the benchmark:') - print(' '.join(cmd)) - run_process(cmd, env=clang_native.get_clang_native_env()) + # Run native build + out_file = os.path.join(temp_dir, 'benchmark_sse_native') + if WINDOWS: + out_file += '.exe' + cmd = [CLANG_CXX] + clang_native.get_clang_native_args() + [benchmark_file, '-O3', '-o', out_file] + print('Building native version of the benchmark:') + print(' '.join(cmd)) + run_process(cmd, env=clang_native.get_clang_native_env()) - native_results = Popen([out_file], stdout=PIPE, stderr=PIPE).communicate() - print(native_results[0]) + native_results = Popen([out_file], stdout=PIPE, stderr=PIPE).communicate() + print(native_results[0]) - # Run emscripten build - out_file = os.path.join(temp_dir, 'benchmark_sse_html.js') - cmd = [EMCC, benchmark_file, '-O3', '-sTOTAL_MEMORY=536870912', '-o', out_file] + build_args - print('Building Emscripten version of the benchmark:') - print(' '.join(cmd)) - run_process(cmd) + # Run emscripten build + out_file = os.path.join(temp_dir, 'benchmark_sse_html.js') + cmd = [EMCC, benchmark_file, '-O3', '-sTOTAL_MEMORY=536870912', '-o', out_file] + build_args + print('Building Emscripten version of the benchmark:') + print(' '.join(cmd)) + run_process(cmd) - cmd = V8_ENGINE + ['--experimental-wasm-simd', os.path.basename(out_file)] - print(' '.join(cmd)) - old_dir = os.getcwd() - os.chdir(os.path.dirname(out_file)) - wasm_results = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() - os.chdir(old_dir) + cmd = V8_ENGINE + ['--experimental-wasm-simd', os.path.basename(out_file)] + print(' '.join(cmd)) + old_dir = os.getcwd() + os.chdir(os.path.dirname(out_file)) + wasm_results = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() + os.chdir(old_dir) - if not wasm_results: - raise Exception('Unable to run benchmark in V8!') + if not wasm_results: + raise Exception('Unable to run benchmark in V8!') - if not wasm_results[0].strip(): - print(wasm_results[1]) - sys.exit(1) + if not wasm_results[0].strip(): + print(wasm_results[1]) + sys.exit(1) - print(wasm_results[0]) + print(wasm_results[0]) - def strip_comments(text): - return re.sub('//.*?\n|/\*.*?\*/', '', text, re.S) # noqa + def strip_comments(text): + return re.sub('//.*?\n|/\*.*?\*/', '', text, re.S) # noqa - benchmark_results = strip_comments(wasm_results[0]) + benchmark_results = strip_comments(wasm_results[0]) - # Strip out unwanted print output. - benchmark_results = benchmark_results[benchmark_results.find('{'):].strip() - if '*************************' in benchmark_results: - benchmark_results = benchmark_results[:benchmark_results.find('*************************')].strip() + # Strip out unwanted print output. + benchmark_results = benchmark_results[benchmark_results.find('{') :].strip() + if '*************************' in benchmark_results: + benchmark_results = benchmark_results[: benchmark_results.find('*************************')].strip() - print(benchmark_results) + print(benchmark_results) - shutil.rmtree(temp_dir) + shutil.rmtree(temp_dir) - native_results = json.loads(native_results[0]) - benchmark_results = benchmark_results[benchmark_results.index('{'):benchmark_results.rindex('}') + 1] - wasm_results = json.loads(benchmark_results) + native_results = json.loads(native_results[0]) + benchmark_results = benchmark_results[benchmark_results.index('{') : benchmark_results.rindex('}') + 1] + wasm_results = json.loads(benchmark_results) - # native_workload = native_results['workload'] - # html_workload = wasm_results['workload'] + # native_workload = native_results['workload'] + # html_workload = wasm_results['workload'] - html = '''

SSE JavaScript Benchmark

+ html = ( + '''

SSE JavaScript Benchmark

System Info:
- ''' + system_info[0].replace('\n', '
') + ''' + ''' + + system_info[0].replace('\n', '
') + + ''' Native Clang Compiler:
- ''' + native_info[1].replace('\n', '
') + ''' + ''' + + native_info[1].replace('\n', '
') + + ''' Emscripten Compiler:
- ''' + emscripten_info[0].replace('\n', '
') - - charts_native = {} - charts_html = {} - for result in native_results['results']: - ch = result['chart'] - if ch not in charts_native: - charts_native[ch] = [] - charts_native[ch] += [result] - for result in wasm_results['results']: - ch = result['chart'] - if ch not in charts_html: - charts_html[ch] = [] - charts_html[ch] += [result] - - def find_result_in_category(results, category): - for result in results: - if result['category'] == category: - return result - return None - - def format_comparison(a, b): - if a < b and a != 0: - return " {:10.2f}".format(b / a) + 'x FASTER' - elif b != 0: - return " {:10.2f}".format(a / b) + 'x SLOWER' - else: - return " NaN " - - chartNumber = 0 - - total_time_native_scalar = 0 - total_time_native_simd = 0 - total_time_html_scalar = 0 - total_time_html_simd = 0 - - for chart_name, chart_native_results in charts_native.items(): - # Extract data for each chart. - categories = [] - nativeScalarResults = [] - nativeSimdResults = [] - htmlScalarResults = [] - htmlSimdResults = [] - native_results = chart_native_results - wasm_results = charts_html[chart_name] - textual_results_native = '

' - textual_results_html = '

' - textual_results_html2 = '

' - textual_results_html3 = '

' - for result in native_results: - categories += ["'" + result['category'] + "'"] - nsc = result['scalar'] - nsi = result['simd'] - nativeScalarResults += [str(nsc)] - nativeSimdResults += [str(nsi)] - html_result = find_result_in_category(wasm_results, result['category']) - textual_results_native += 'Native ' + result['category'] + ': ' + "{:10.4f}".format(nsc) + 'ns -> ' + "{:10.4f}".format(nsi) + 'ns. ' - textual_results_native += 'Native SSE is ' + format_comparison(nsi, nsc) + ' than native scalar.        
' - - if html_result is not None: - hsc = html_result['scalar'] - htmlScalarResults += [str(hsc)] - hsi = html_result['simd'] - htmlSimdResults += [str(hsi)] - textual_results_html += 'JS ' + result['category'] + ': ' + "{:10.4f}".format(hsc) + 'ns -> ' + "{:10.4f}".format(hsi) + 'ns. ' - textual_results_html += 'JS SSE is ' + format_comparison(hsi, hsc) + ' than JS scalar.        
' - textual_results_html2 += 'JS ' + result['category'] + ': JS scalar is ' + format_comparison(hsc, nsc) + ' than native scalar.        
' - textual_results_html3 += 'JS ' + result['category'] + ': JS SSE is ' + format_comparison(hsi, nsi) + ' than native SSE.        
' - total_time_native_scalar += nsc - total_time_native_simd += nsi - total_time_html_scalar += hsc - total_time_html_simd += hsi - else: - htmlScalarResults += [str(-1)] - htmlSimdResults += [str(-1)] - - chartNumber += 1 - html += '

' - html += '''''' + '
' + textual_results_native + '' + textual_results_html + '
' + textual_results_html2 + '' + textual_results_html3 + '
' - - # Final overall score - - html += '
' - html += '''''' + + '
' + + textual_results_native + + '' + + textual_results_html + + '
' + + textual_results_html2 + + '' + + textual_results_html3 + + '
' + ) + + # Final overall score + + html += '
' + html += ( + '''''' + ) - html += '' + html += '' - open(results_file, 'w').write(html) - print('Wrote ' + str(len(html)) + ' bytes to file ' + results_file + '.') + open(results_file, 'w').write(html) + print('Wrote ' + str(len(html)) + ' bytes to file ' + results_file + '.') if __name__ == '__main__': - suite = sys.argv[1].lower() if len(sys.argv) == 2 else None - if suite in ['sse', 'sse1']: - run_benchmark(test_file('sse/benchmark_sse1.cpp'), 'results_sse1.html', ['-msse']) - elif suite == 'sse2': - run_benchmark(test_file('sse/benchmark_sse2.cpp'), 'results_sse2.html', ['-msse2']) - elif suite == 'sse3': - run_benchmark(test_file('sse/benchmark_sse3.cpp'), 'results_sse3.html', ['-msse3']) - elif suite == 'ssse3': - run_benchmark(test_file('sse/benchmark_ssse3.cpp'), 'results_ssse3.html', ['-mssse3']) - else: - raise Exception('Usage: python test/benchmark_sse.py sse1|sse2|sse3') + suite = sys.argv[1].lower() if len(sys.argv) == 2 else None + if suite in ['sse', 'sse1']: + run_benchmark(test_file('sse/benchmark_sse1.cpp'), 'results_sse1.html', ['-msse']) + elif suite == 'sse2': + run_benchmark(test_file('sse/benchmark_sse2.cpp'), 'results_sse2.html', ['-msse2']) + elif suite == 'sse3': + run_benchmark(test_file('sse/benchmark_sse3.cpp'), 'results_sse3.html', ['-msse3']) + elif suite == 'ssse3': + run_benchmark(test_file('sse/benchmark_ssse3.cpp'), 'results_ssse3.html', ['-mssse3']) + else: + raise Exception('Usage: python test/benchmark_sse.py sse1|sse2|sse3') diff --git a/test/clang_native.py b/test/clang_native.py index 1193eb969bf52..027bd5205f2f5 100644 --- a/test/clang_native.py +++ b/test/clang_native.py @@ -15,15 +15,15 @@ def get_native_triple(): arch = { - 'aarch64': 'arm64', - 'arm64': 'arm64', - 'x86_64': 'x86_64', - 'AMD64': 'x86_64', + 'aarch64': 'arm64', + 'arm64': 'arm64', + 'x86_64': 'x86_64', + 'AMD64': 'x86_64', }[platform.machine()] OS = { - 'linux': 'linux', - 'darwin': 'darwin', - 'win32': 'windows-msvc', + 'linux': 'linux', + 'darwin': 'darwin', + 'win32': 'windows-msvc', }[sys.platform] return f'{arch}-{OS}' @@ -78,7 +78,11 @@ def get_clang_native_env(): else: visual_studio_path = 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0' if not os.path.isdir(visual_studio_path): - raise Exception('Visual Studio 2015 was not found in "' + visual_studio_path + '"! Run in Visual Studio X64 command prompt to avoid the need to autoguess this location (or set VSINSTALLDIR env var).') + raise Exception( + 'Visual Studio 2015 was not found in "' + + visual_studio_path + + '"! Run in Visual Studio X64 command prompt to avoid the need to autoguess this location (or set VSINSTALLDIR env var).' + ) # Guess where Program Files (x86) is located if 'ProgramFiles(x86)' in env: @@ -98,19 +102,31 @@ def get_clang_native_env(): else: windows8_sdk_dir = os.path.join(prog_files_x86, 'Windows Kits', '8.1') if not os.path.isdir(windows8_sdk_dir): - raise Exception('Windows 8.1 SDK was not found in "' + windows8_sdk_dir + '"! Run in Visual Studio command prompt to avoid the need to autoguess this location (or set WindowsSdkDir env var).') + raise Exception( + 'Windows 8.1 SDK was not found in "' + + windows8_sdk_dir + + '"! Run in Visual Studio command prompt to avoid the need to autoguess this location (or set WindowsSdkDir env var).' + ) # Guess where Windows 10 SDK is located if os.path.isdir(os.path.join(prog_files_x86, 'Windows Kits', '10')): windows10_sdk_dir = os.path.join(prog_files_x86, 'Windows Kits', '10') if not os.path.isdir(windows10_sdk_dir): - raise Exception('Windows 10 SDK was not found in "' + windows10_sdk_dir + '"! Run in Visual Studio command prompt to avoid the need to autoguess this location.') + raise Exception( + 'Windows 10 SDK was not found in "' + + windows10_sdk_dir + + '"! Run in Visual Studio command prompt to avoid the need to autoguess this location.' + ) env.setdefault('VSINSTALLDIR', visual_studio_path) env.setdefault('VCINSTALLDIR', os.path.join(visual_studio_path, 'VC')) windows10sdk_kits_include_dir = os.path.join(windows10_sdk_dir, 'Include') - windows10sdk_kit_version_name = [x for x in os.listdir(windows10sdk_kits_include_dir) if os.path.isdir(os.path.join(windows10sdk_kits_include_dir, x))][0] # e.g. "10.0.10150.0" or "10.0.10240.0" + windows10sdk_kit_version_name = [ + x + for x in os.listdir(windows10sdk_kits_include_dir) + if os.path.isdir(os.path.join(windows10sdk_kits_include_dir, x)) + ][0] # e.g. "10.0.10150.0" or "10.0.10240.0" def append_item(key, item): if key not in env or len(env[key].strip()) == 0: diff --git a/test/common.py b/test/common.py index 541d89aaca73f..02367a76e48f2 100644 --- a/test/common.py +++ b/test/common.py @@ -191,6 +191,7 @@ def no_wasm64(note=''): def decorated(f): return skip_if(f, 'is_wasm64', note) + return decorated @@ -206,7 +207,9 @@ def decorated(self, *args, **kwargs): if self.get_setting('INITIAL_MEMORY') == '2200mb': self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -221,7 +224,9 @@ def decorated(self, *args, **kwargs): if self.is_4gb(): self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -328,6 +333,7 @@ def node_pthreads(f): def decorated(self, *args, **kwargs): self.setup_node_pthreads() f(self, *args, **kwargs) + return decorated @@ -366,6 +372,7 @@ def decorated(f): def modified(self, *args, **kwargs): with env_modify(updates): return f(self, *args, **kwargs) + return modified return decorated @@ -384,8 +391,7 @@ def metafunc(self, wasmfs, *args, **kwargs): self.emcc_args += ['-DMEMFS'] f(self, *args, **kwargs) - parameterize(metafunc, {'': (False,), - 'wasmfs': (True,)}) + parameterize(metafunc, {'': (False,), 'wasmfs': (True,)}) return metafunc @@ -401,8 +407,13 @@ def metafunc(self, fs, *args, **kwargs): assert fs is None func(self, *args, **kwargs) - parameterize(metafunc, {'': (None,), - 'nodefs': ('nodefs',)}) + parameterize( + metafunc, + { + '': (None,), + 'nodefs': ('nodefs',), + }, + ) return metafunc @@ -420,9 +431,14 @@ def metafunc(self, fs, *args, **kwargs): assert fs is None func(self, *args, **kwargs) - parameterize(metafunc, {'': (None,), - 'nodefs': ('nodefs',), - 'rawfs': ('rawfs',)}) + parameterize( + metafunc, + { + '': (None,), + 'nodefs': ('nodefs',), + 'rawfs': ('rawfs',), + }, + ) return metafunc @@ -444,10 +460,15 @@ def metafunc(self, fs, *args, **kwargs): # TODO(sbc): rather than treat WASMFS as orthogonal we should # probably make it combinatorial with nodefs and noderawfs. - parameterize(metafunc, {'': (None,), - 'nodefs': ('nodefs',), - 'rawfs': ('rawfs',), - 'wasmfs': ('wasmfs',)}) + parameterize( + metafunc, + { + '': (None,), + 'nodefs': ('nodefs',), + 'rawfs': ('rawfs',), + 'wasmfs': ('wasmfs',), + }, + ) return metafunc @@ -464,14 +485,12 @@ def metafunc(self, rawfs, *args, **kwargs): self.emcc_args += ['-DMEMFS'] func(self, *args, **kwargs) - parameterize(metafunc, {'': (False,), - 'rawfs': (True,)}) + parameterize(metafunc, {'': (False,), 'rawfs': (True,)}) return metafunc # Decorator version of env_modify def also_with_env_modify(name_updates_mapping): - def decorated(f): @wraps(f) def metafunc(self, updates, *args, **kwargs): @@ -506,8 +525,7 @@ def metafunc(self, with_minimal_runtime, *args, **kwargs): self.set_setting('MINIMAL_RUNTIME', 1) f(self, *args, **kwargs) - parameterize(metafunc, {'': (False,), - 'minimal_runtime': (True,)}) + parameterize(metafunc, {'': (False,), 'minimal_runtime': (True,)}) return metafunc @@ -530,8 +548,7 @@ def metafunc(self, with_bigint, *args, **kwargs): else: f(self, *args, **kwargs) - parameterize(metafunc, {'': (False,), - 'bigint': (True,)}) + parameterize(metafunc, {'': (False,), 'bigint': (True,)}) return metafunc @@ -549,8 +566,7 @@ def metafunc(self, with_wasm64, *args, **kwargs): else: f(self, *args, **kwargs) - parameterize(metafunc, {'': (False,), - 'wasm64': (True,)}) + parameterize(metafunc, {'': (False,), 'wasm64': (True,)}) return metafunc @@ -569,8 +585,7 @@ def metafunc(self, with_wasm2js, *args, **kwargs): else: f(self, *args, **kwargs) - parameterize(metafunc, {'': (False,), - 'wasm2js': (True,)}) + parameterize(metafunc, {'': (False,), 'wasm2js': (True,)}) return metafunc @@ -583,11 +598,13 @@ def can_do_standalone(self, impure=False): # This is way to detect the core_2gb test mode in test_core.py if self.get_setting('INITIAL_MEMORY') == '2200mb': return False - return self.is_wasm() and \ - self.get_setting('STACK_OVERFLOW_CHECK', 0) < 2 and \ - not self.get_setting('MINIMAL_RUNTIME') and \ - not self.get_setting('SAFE_HEAP') and \ - not any(a.startswith('-fsanitize=') for a in self.emcc_args) + return ( + self.is_wasm() + and self.get_setting('STACK_OVERFLOW_CHECK', 0) < 2 + and not self.get_setting('MINIMAL_RUNTIME') + and not self.get_setting('SAFE_HEAP') + and not any(a.startswith('-fsanitize=') for a in self.emcc_args) + ) # Impure means a test that cannot run in a wasm VM yet, as it is not 100% @@ -618,8 +635,7 @@ def metafunc(self, standalone): self.node_args += shared.node_bigint_flags(nodejs) func(self) - parameterize(metafunc, {'': (False,), - 'standalone': (True,)}) + parameterize(metafunc, {'': (False,), 'standalone': (True,)}) return metafunc return decorated @@ -662,9 +678,7 @@ def metafunc(self, mode, *args, **kwargs): self.set_setting('DEFAULT_TO_CXX') f(self, *args, **kwargs) - parameterize(metafunc, {'emscripten': ('emscripten',), - 'wasm': ('wasm',), - 'wasm_exnref': ('wasm_exnref',)}) + parameterize(metafunc, {'emscripten': ('emscripten',), 'wasm': ('wasm',), 'wasm_exnref': ('wasm_exnref',)}) return metafunc @@ -692,9 +706,7 @@ def metafunc(self, mode, *args, **kwargs): self.set_setting('SUPPORT_LONGJMP', 'emscripten') f(self, *args, **kwargs) - parameterize(metafunc, {'emscripten': ('emscripten',), - 'wasm': ('wasm',), - 'wasm_exnref': ('wasm_exnref',)}) + parameterize(metafunc, {'emscripten': ('emscripten',), 'wasm': ('wasm',), 'wasm_exnref': ('wasm_exnref',)}) return metafunc @@ -716,11 +728,11 @@ def limit_size(string): if len(line) > max_line: lines[i] = line[:max_line] + '[..]' if len(lines) > maxlines: - lines = lines[0:maxlines // 2] + ['[..]'] + lines[-maxlines // 2:] + lines = lines[0 : maxlines // 2] + ['[..]'] + lines[-maxlines // 2 :] lines.append('(not all output shown. See `limit_size`)') string = '\n'.join(lines) + '\n' if len(string) > maxbytes: - string = string[0:maxbytes // 2] + '\n[..]\n' + string[-maxbytes // 2:] + string = string[0 : maxbytes // 2] + '\n[..]\n' + string[-maxbytes // 2 :] return string @@ -765,8 +777,7 @@ def force_delete_contents(dirname): def find_browser_test_file(filename): - """Looks for files in test/browser and then in test/ - """ + """Looks for files in test/browser and then in test/""" if not os.path.exists(filename): fullname = test_file('browser', filename) if not os.path.exists(fullname): @@ -786,7 +797,8 @@ def parameterize(func, parameters): if prev: # If we're parameterizing 2nd time, construct a cartesian product for various combinations. func._parameterize = { - '_'.join(filter(None, [k1, k2])): v2 + v1 for (k1, v1), (k2, v2) in itertools.product(prev.items(), parameters.items()) + '_'.join(filter(None, [k1, k2])): v2 + v1 + for (k1, v1), (k2, v2) in itertools.product(prev.items(), parameters.items()) } else: func._parameterize = parameters @@ -812,9 +824,11 @@ def test_something_subtest1(self): def test_something_subtest2(self): # runs test_something(4, 5, 6) """ + def decorator(func): parameterize(func, parameters) return func + return decorator @@ -1109,7 +1123,7 @@ def set_temp_dir(self, temp_dir): @classmethod def setUpClass(cls): super().setUpClass() - print('(checking sanity from test runner)') # do this after we set env stuff + print('(checking sanity from test runner)') # do this after we set env stuff shared.check_sanity(force=True) def setUp(self): @@ -1148,12 +1162,15 @@ def setUp(self): emcc_min_node_version = ( int(emcc_min_node_version_str[0:2]), int(emcc_min_node_version_str[2:4]), - int(emcc_min_node_version_str[4:6]) + int(emcc_min_node_version_str[4:6]), ) if node_version < emcc_min_node_version: self.emcc_args += building.get_emcc_node_flags(node_version) self.emcc_args.append('-Wno-transpile') - if node_version[0] < feature_matrix.min_browser_versions[feature_matrix.Feature.JS_BIGINT_INTEGRATION]['node'] / 10000: + if ( + node_version[0] + < feature_matrix.min_browser_versions[feature_matrix.Feature.JS_BIGINT_INTEGRATION]['node'] / 10000 + ): self.emcc_args.append('-sWASM_BIGINT=0') self.v8_args = ['--wasm-staging'] @@ -1216,16 +1233,19 @@ def tearDown(self): # They may not be due to us, but e.g. the browser when running browser # tests. Until we figure out a proper solution, ignore some temp file # names that we see on our CI infrastructure. - ignorable_file_prefixes = [ - '/tmp/tmpaddon', - '/tmp/circleci-no-output-timeout', - '/tmp/wasmer' - ] + ignorable_file_prefixes = ['/tmp/tmpaddon', '/tmp/circleci-no-output-timeout', '/tmp/wasmer'] left_over_files = set(temp_files_after_run) - set(self.temp_files_before_run) - left_over_files = [f for f in left_over_files if not any([f.startswith(prefix) for prefix in ignorable_file_prefixes])] + left_over_files = [ + f for f in left_over_files if not any([f.startswith(prefix) for prefix in ignorable_file_prefixes]) + ] if len(left_over_files): - print('ERROR: After running test, there are ' + str(len(left_over_files)) + ' new temporary files/directories left behind:', file=sys.stderr) + print( + 'ERROR: After running test, there are ' + + str(len(left_over_files)) + + ' new temporary files/directories left behind:', + file=sys.stderr, + ) for f in left_over_files: print('leaked file: ' + f, file=sys.stderr) self.fail('Test leaked ' + str(len(left_over_files)) + ' temporary files!') @@ -1286,7 +1306,17 @@ def add_on_exit(self, code): # libraries, for example def get_emcc_args(self, main_file=False, compile_only=False, asm_only=False): def is_ldflag(f): - return any(f.startswith(s) for s in ['-sEXPORT_ES6', '-sPROXY_TO_PTHREAD', '-sENVIRONMENT=', '--pre-js=', '--post-js=', '-sPTHREAD_POOL_SIZE=']) + return any( + f.startswith(s) + for s in [ + '-sEXPORT_ES6', + '-sPROXY_TO_PTHREAD', + '-sENVIRONMENT=', + '--pre-js=', + '--post-js=', + '-sPTHREAD_POOL_SIZE=', + ] + ) args = self.serialize_settings(compile_only or asm_only) + self.emcc_args if asm_only: @@ -1325,7 +1355,9 @@ def verify_es5(self, filename): self.fail('es-check failed to verify ES5 output compliance') # Build JavaScript code from source code - def build(self, filename, libraries=None, includes=None, force_c=False, js_outfile=True, emcc_args=None, output_basename=None): + def build( + self, filename, libraries=None, includes=None, force_c=False, js_outfile=True, emcc_args=None, output_basename=None + ): if not os.path.exists(filename): filename = test_file(filename) suffix = '.js' if js_outfile else '.wasm' @@ -1363,7 +1395,7 @@ def get_func(self, src, name): elif src[t] == '}': n -= 1 if n == 0: - return src[start:t + 1] + return src[start : t + 1] t += 1 assert t < len(src) @@ -1384,7 +1416,9 @@ def count_funcs(self, javascript_file): return num_funcs def count_wasm_contents(self, wasm_binary, what): - out = self.run_process([os.path.join(building.get_binaryen_bin(), 'wasm-opt'), wasm_binary, '--metrics'], stdout=PIPE).stdout + out = self.run_process( + [os.path.join(building.get_binaryen_bin(), 'wasm-opt'), wasm_binary, '--metrics'], stdout=PIPE + ).stdout # output is something like # [?] : 125 for line in out.splitlines(): @@ -1433,9 +1467,7 @@ def cleanup(line): assert len(long_lines) == 1 return '\n'.join(lines) - def run_js(self, filename, engine=None, args=None, - assert_returncode=0, - interleaved_output=True): + def run_js(self, filename, engine=None, args=None, assert_returncode=0, interleaved_output=True): # use files, as PIPE can get too full and hang us stdout_file = self.in_dir('stdout') stderr_file = None @@ -1454,10 +1486,7 @@ def run_js(self, filename, engine=None, args=None, if engine == config.V8_ENGINE: engine = engine + self.v8_args try: - jsrun.run_js(filename, engine, args, - stdout=stdout, - stderr=stderr, - assert_returncode=assert_returncode) + jsrun.run_js(filename, engine, args, stdout=stdout, stderr=stderr, assert_returncode=assert_returncode) except subprocess.TimeoutExpired as e: timeout_error = e except subprocess.CalledProcessError as e: @@ -1491,7 +1520,10 @@ def run_js(self, filename, engine=None, args=None, if assert_returncode == NON_ZERO: self.fail('JS subprocess unexpectedly succeeded (%s): Output:\n%s' % (error.cmd, ret)) else: - self.fail('JS subprocess failed (%s): %s (expected=%s). Output:\n%s' % (error.cmd, error.returncode, assert_returncode, ret)) + self.fail( + 'JS subprocess failed (%s): %s (expected=%s). Output:\n%s' + % (error.cmd, error.returncode, assert_returncode, ret) + ) # We should pass all strict mode checks self.assertNotContained('strict warning:', ret) @@ -1515,21 +1547,18 @@ def assertPathsIdentical(self, path1, path2): # Tests that the given two multiline text content are identical, modulo line # ending differences (\r\n on Windows, \n on Unix). - def assertTextDataIdentical(self, text1, text2, msg=None, - fromfile='expected', tofile='actual'): + def assertTextDataIdentical(self, text1, text2, msg=None, fromfile='expected', tofile='actual'): text1 = text1.replace('\r\n', '\n') text2 = text2.replace('\r\n', '\n') return self.assertIdentical(text1, text2, msg, fromfile, tofile) - def assertIdentical(self, values, y, msg=None, - fromfile='expected', tofile='actual'): + def assertIdentical(self, values, y, msg=None, fromfile='expected', tofile='actual'): if type(values) not in (list, tuple): values = [values] for x in values: if x == y: - return # success - diff_lines = difflib.unified_diff(x.splitlines(), y.splitlines(), - fromfile=fromfile, tofile=tofile) + return # success + diff_lines = difflib.unified_diff(x.splitlines(), y.splitlines(), fromfile=fromfile, tofile=tofile) diff = ''.join([a.rstrip() + '\n' for a in diff_lines]) if EMTEST_VERBOSE: print("Expected to have '%s' == '%s'" % (limit_size(values[0]), limit_size(y))) @@ -1557,12 +1586,10 @@ def assertFileContents(self, filename, contents): return if not os.path.exists(filename): - self.fail('Test expectation file not found: ' + filename + '.\n' + - 'Run with --rebaseline to generate.') + self.fail('Test expectation file not found: ' + filename + '.\n' + 'Run with --rebaseline to generate.') expected_content = read_file(filename) message = "Run with --rebaseline to automatically update expectations" - self.assertTextDataIdentical(expected_content, contents, message, - filename, filename + '.new') + self.assertTextDataIdentical(expected_content, contents, message, filename, filename + '.new') def assertContained(self, values, string, additional_info='', regex=False): if callable(string): @@ -1582,14 +1609,14 @@ def assertContained(self, values, string, additional_info='', regex=False): if not any(v in string for v in values): diff = difflib.unified_diff(values[0].split('\n'), string.split('\n'), fromfile='expected', tofile='actual') diff = ''.join(a.rstrip() + '\n' for a in diff) - self.fail("Expected to find '%s' in '%s', diff:\n\n%s\n%s" % ( - limit_size(values[0]), limit_size(string), limit_size(diff), - additional_info - )) + self.fail( + "Expected to find '%s' in '%s', diff:\n\n%s\n%s" + % (limit_size(values[0]), limit_size(string), limit_size(diff), additional_info) + ) def assertNotContained(self, value, string): if callable(value): - value = value() # lazy loading + value = value() # lazy loading if callable(string): string = string() if value in string: @@ -1602,10 +1629,8 @@ def assertContainedIf(self, value, string, condition): self.assertNotContained(value, string) def assertBinaryEqual(self, file1, file2): - self.assertEqual(os.path.getsize(file1), - os.path.getsize(file2)) - self.assertEqual(read_binary(file1), - read_binary(file2)) + self.assertEqual(os.path.getsize(file1), os.path.getsize(file2)) + self.assertEqual(read_binary(file1), read_binary(file2)) def check_expected_size_in_file(self, desc, filename, size): if EMTEST_REBASELINE: @@ -1614,7 +1639,9 @@ def check_expected_size_in_file(self, desc, filename, size): expected_size = int(read_file(filename).strip()) delta = size - expected_size ratio = abs(delta) / float(expected_size) - print(' seen %s size: %d (expected: %d) (delta: %d), ratio to expected: %f' % (desc, size, expected_size, delta, ratio)) + print( + ' seen %s size: %d (expected: %d) (delta: %d), ratio to expected: %f' % (desc, size, expected_size, delta, ratio) + ) self.assertLess(ratio, size_slack) library_cache: Dict[str, Tuple[str, object]] = {} @@ -1624,10 +1651,19 @@ def get_build_dir(self): ensure_dir(ret) return ret - def get_library(self, name, generated_libs, configure=['sh', './configure'], # noqa - configure_args=None, make=None, make_args=None, - env_init=None, cache_name_extra='', native=False, - force_rebuild=False): + def get_library( + self, + name, + generated_libs, + configure=['sh', './configure'], # noqa + configure_args=None, + make=None, + make_args=None, + env_init=None, + cache_name_extra='', + native=False, + force_rebuild=False, + ): if make is None: make = ['make'] if env_init is None: @@ -1646,7 +1682,13 @@ def get_library(self, name, generated_libs, configure=['sh', './configure'], # emcc_args = self.get_emcc_args(compile_only=True) hash_input = (str(emcc_args) + ' $ ' + str(env_init)).encode('utf-8') - cache_name = name + ','.join([opt for opt in emcc_args if len(opt) < 7]) + '_' + hashlib.md5(hash_input).hexdigest() + cache_name_extra + cache_name = ( + name + + ','.join([opt for opt in emcc_args if len(opt) < 7]) + + '_' + + hashlib.md5(hash_input).hexdigest() + + cache_name_extra + ) valid_chars = "_%s%s" % (string.ascii_letters, string.digits) cache_name = ''.join([(c if c in valid_chars else '_') for c in cache_name]) @@ -1669,9 +1711,19 @@ def get_library(self, name, generated_libs, configure=['sh', './configure'], # cflags = ' '.join(emcc_args) env_init.setdefault('CFLAGS', cflags) env_init.setdefault('CXXFLAGS', cflags) - return build_library(name, build_dir, output_dir, generated_libs, configure, - make, make_args, self.library_cache, - cache_name, env_init=env_init, native=native) + return build_library( + name, + build_dir, + output_dir, + generated_libs, + configure, + make, + make_args, + self.library_cache, + cache_name, + env_init=env_init, + native=native, + ) def clear(self): force_delete_contents(self.get_dir()) @@ -1730,7 +1782,9 @@ def expect_fail(self, cmd, expect_traceback=False, **args): # when run under browser it excercises how dynamic linker handles concurrency # - because B and C are loaded in parallel. def _test_dylink_dso_needed(self, do_run): - create_file('liba.cpp', r''' + create_file( + 'liba.cpp', + r''' #include #include @@ -1752,9 +1806,12 @@ def _test_dylink_dso_needed(self, do_run): }; static ainit _; - ''') + ''', + ) - create_file('libb.c', r''' + create_file( + 'libb.c', + r''' #include void afunc(const char *s); @@ -1762,9 +1819,12 @@ def _test_dylink_dso_needed(self, do_run): EMSCRIPTEN_KEEPALIVE void bfunc() { afunc("b"); } - ''') + ''', + ) - create_file('libc.c', r''' + create_file( + 'libc.c', + r''' #include void afunc(const char *s); @@ -1772,7 +1832,8 @@ def _test_dylink_dso_needed(self, do_run): EMSCRIPTEN_KEEPALIVE void cfunc() { afunc("c"); } - ''') + ''', + ) # _test_dylink_dso_needed can be potentially called several times by a test. # reset dylink-related options first. @@ -1797,7 +1858,8 @@ def ccshared(src, linkto=None): self.set_setting('MAIN_MODULE') extra_args = ['-L.', 'libb' + so, 'libc' + so] - do_run(r''' + do_run( + r''' #ifdef __cplusplus extern "C" { #endif @@ -1813,12 +1875,15 @@ def ccshared(src, linkto=None): return 0; } ''', - 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n', emcc_args=extra_args) + 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n', + emcc_args=extra_args, + ) extra_args = [] for libname in ('liba', 'libb', 'libc'): extra_args += ['--embed-file', libname + so] - do_run(r''' + do_run( + r''' #include #include #include @@ -1842,8 +1907,11 @@ def ccshared(src, linkto=None): cfunc_ptr(); return 0; } - ''' % locals(), - 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n', emcc_args=extra_args) + ''' + % locals(), + 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n', + emcc_args=extra_args, + ) def do_run(self, src, expected_output=None, force_c=False, **kwargs): if 'no_build' in kwargs: @@ -1874,23 +1942,37 @@ def do_run_in_out_file_test(self, srcfile, **kwargs): return output ## Does a complete test - builds, runs, checks output, etc. - def _build_and_run(self, filename, expected_output, args=None, - no_build=False, - libraries=None, - includes=None, - assert_returncode=0, assert_identical=False, assert_all=False, - check_for_error=True, force_c=False, emcc_args=None, - interleaved_output=True, - regex=False, - output_basename=None): + def _build_and_run( + self, + filename, + expected_output, + args=None, + no_build=False, + libraries=None, + includes=None, + assert_returncode=0, + assert_identical=False, + assert_all=False, + check_for_error=True, + force_c=False, + emcc_args=None, + interleaved_output=True, + regex=False, + output_basename=None, + ): logger.debug(f'_build_and_run: {filename}') if no_build: js_file = filename else: - js_file = self.build(filename, libraries=libraries, includes=includes, - force_c=force_c, emcc_args=emcc_args, - output_basename=output_basename) + js_file = self.build( + filename, + libraries=libraries, + includes=includes, + force_c=force_c, + emcc_args=emcc_args, + output_basename=output_basename, + ) self.assertExists(js_file) engines = self.js_engines.copy() @@ -1906,9 +1988,9 @@ def _build_and_run(self, filename, expected_output, args=None, if len(engines) == 0: self.fail('No JS engine present to run this test with. Check %s and the paths therein.' % config.EM_CONFIG) for engine in engines: - js_output = self.run_js(js_file, engine, args, - assert_returncode=assert_returncode, - interleaved_output=interleaved_output) + js_output = self.run_js( + js_file, engine, args, assert_returncode=assert_returncode, interleaved_output=interleaved_output + ) js_output = js_output.replace('\r\n', '\n') if expected_output: if type(expected_output) not in [list, tuple]: @@ -1938,16 +2020,18 @@ def get_freetype_library(self): # And because gnu-offsetof-extensions is a new warning: '-Wno-unknown-warning-option', ] - return self.get_library(os.path.join('third_party', 'freetype'), - os.path.join('objs', '.libs', 'libfreetype.a'), - configure_args=['--disable-shared', '--without-zlib']) + return self.get_library( + os.path.join('third_party', 'freetype'), + os.path.join('objs', '.libs', 'libfreetype.a'), + configure_args=['--disable-shared', '--without-zlib'], + ) def get_poppler_library(self, env_init=None): freetype = self.get_freetype_library() self.emcc_args += [ '-I' + test_file('third_party/freetype/include'), - '-I' + test_file('third_party/poppler/include') + '-I' + test_file('third_party/poppler/include'), ] # Poppler has some pretty glaring warning. Suppress them to keep the @@ -1973,10 +2057,24 @@ def get_poppler_library(self, env_init=None): env_init['FONTCONFIG_LIBS'] = ' ' poppler = self.get_library( - os.path.join('third_party', 'poppler'), - [os.path.join('utils', 'pdftoppm.o'), os.path.join('utils', 'parseargs.o'), os.path.join('poppler', '.libs', 'libpoppler.a')], - env_init=env_init, - configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--disable-shared']) + os.path.join('third_party', 'poppler'), + [ + os.path.join('utils', 'pdftoppm.o'), + os.path.join('utils', 'parseargs.o'), + os.path.join('poppler', '.libs', 'libpoppler.a'), + ], + env_init=env_init, + configure_args=[ + '--disable-libjpeg', + '--disable-libpng', + '--disable-poppler-qt', + '--disable-poppler-qt4', + '--disable-cms', + '--disable-cairo-output', + '--disable-abiword-output', + '--disable-shared', + ], + ) return poppler + freetype @@ -1992,10 +2090,13 @@ def get_zlib_library(self, cmake): # https://github.com/emscripten-core/emscripten/issues/16908 is fixed self.emcc_args.append('-Wno-pointer-sign') if cmake: - rtn = self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'), - configure=['cmake', '.'], - make=['cmake', '--build', '.', '--'], - make_args=[]) + rtn = self.get_library( + os.path.join('third_party', 'zlib'), + os.path.join('libz.a'), + configure=['cmake', '.'], + make=['cmake', '--build', '.', '--'], + make_args=[], + ) else: rtn = self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'), make_args=['libz.a']) self.emcc_args = old_args @@ -2131,7 +2232,7 @@ def log_request(code=0, size=0): SimpleHTTPRequestHandler.extensions_map['.wasm'] = 'application/wasm' httpd = HTTPServer(('localhost', port), TestServerHandler) - httpd.serve_forever() # test runner will kill us + httpd.serve_forever() # test runner will kill us class Reporting(Enum): @@ -2139,6 +2240,7 @@ class Reporting(Enum): code for reporting results back to the browser. This enum allows tests to decide what type of support code they need/want. """ + NONE = 0 # Include the JS helpers for reporting results JS_ONLY = 1 @@ -2193,7 +2295,9 @@ def setUpClass(cls): return cls.harness_in_queue = multiprocessing.Queue() cls.harness_out_queue = multiprocessing.Queue() - cls.harness_server = multiprocessing.Process(target=harness_server_func, args=(cls.harness_in_queue, cls.harness_out_queue, cls.PORT)) + cls.harness_server = multiprocessing.Process( + target=harness_server_func, args=(cls.harness_in_queue, cls.harness_out_queue, cls.PORT) + ) cls.harness_server.start() print('[Browser harness server on process %d]' % cls.harness_server.pid) cls.browser_open(cls.HARNESS_URL) @@ -2237,10 +2341,7 @@ def run_browser(self, html_file, expected=None, message=None, timeout=None, extr assert not (message and expected), 'run_browser expects `expected` or `message`, but not both' if expected is not None: try: - self.harness_in_queue.put(( - 'http://localhost:%s/%s' % (self.PORT, html_file), - self.get_dir() - )) + self.harness_in_queue.put(('http://localhost:%s/%s' % (self.PORT, html_file), self.get_dir())) if timeout is None: timeout = self.BROWSER_TIMEOUT try: @@ -2257,7 +2358,7 @@ def run_browser(self, html_file, expected=None, message=None, timeout=None, extr # us to also fail the test self.fail('browser harness error') if output.startswith('/report_result?skipped:'): - self.skipTest(unquote(output[len('/report_result?skipped:'):]).strip()) + self.skipTest(unquote(output[len('/report_result?skipped:') :]).strip()) else: # verify the result, and try again if we should do so output = unquote(output) @@ -2271,7 +2372,7 @@ def run_browser(self, html_file, expected=None, message=None, timeout=None, extr else: raise e finally: - time.sleep(0.1) # see comment about Windows above + time.sleep(0.1) # see comment about Windows above self.assert_out_queue_empty('this test') else: webbrowser.open_new(os.path.abspath(html_file)) @@ -2292,8 +2393,11 @@ def compile_btest(self, filename, args, reporting=Reporting.FULL): if reporting == Reporting.FULL: # If C reporting (i.e. the REPORT_RESULT macro) is required we # also include report_result.c and force-include report_result.h - self.run_process([EMCC, '-c', '-I' + TEST_ROOT, - test_file('report_result.c')] + self.get_emcc_args(compile_only=True) + (['-fPIC'] if '-fPIC' in args else [])) + self.run_process( + [EMCC, '-c', '-I' + TEST_ROOT, test_file('report_result.c')] + + self.get_emcc_args(compile_only=True) + + (['-fPIC'] if '-fPIC' in args else []) + ) args += ['report_result.o', '-include', test_file('report_result.h')] if EMTEST_BROWSER == 'node': args.append('-DEMTEST_NODE') @@ -2315,12 +2419,18 @@ def btest_exit(self, filename, assert_returncode=0, *args, **kwargs): kwargs['expected'] = 'exit:%d' % assert_returncode return self.btest(filename, *args, **kwargs) - def btest(self, filename, expected=None, - post_build=None, - args=None, url_suffix='', timeout=None, - extra_tries=1, - reporting=Reporting.FULL, - output_basename='test'): + def btest( + self, + filename, + expected=None, + post_build=None, + args=None, + url_suffix='', + timeout=None, + extra_tries=1, + reporting=Reporting.FULL, + output_basename='test', + ): assert expected, 'a btest must have an expected output' if args is None: args = [] @@ -2347,23 +2457,20 @@ def btest(self, filename, expected=None, output = self.run_js('test.js') self.assertContained('RESULT: ' + expected[0], output) else: - self.run_browser(outfile + url_suffix, expected=['/report_result?' + e for e in expected], timeout=timeout, extra_tries=extra_tries) + self.run_browser( + outfile + url_suffix, + expected=['/report_result?' + e for e in expected], + timeout=timeout, + extra_tries=extra_tries, + ) ################################################################################################### -def build_library(name, - build_dir, - output_dir, - generated_libs, - configure, - make, - make_args, - cache, - cache_name, - env_init, - native): +def build_library( + name, build_dir, output_dir, generated_libs, configure, make, make_args, cache, cache_name, env_init, native +): """Build a library and cache the result. We build the library file once and cache it for all our tests. (We cache in memory since the test directory is destroyed and recreated for each test. Note that we cache @@ -2406,8 +2513,7 @@ def build_library(name, with open(os.path.join(project_dir, 'configure_err'), 'w') as err: stdout = out if EMTEST_BUILD_VERBOSE < 2 else None stderr = err if EMTEST_BUILD_VERBOSE < 1 else None - shared.run_process(configure, env=env, stdout=stdout, stderr=stderr, - cwd=project_dir) + shared.run_process(configure, env=env, stdout=stdout, stderr=stderr, cwd=project_dir) except subprocess.CalledProcessError: print('-- configure stdout --') print(read_file(Path(project_dir, 'configure_out'))) @@ -2435,8 +2541,7 @@ def open_make_err(mode='r'): with open_make_err('w') as make_err: stdout = make_out if EMTEST_BUILD_VERBOSE < 2 else None stderr = make_err if EMTEST_BUILD_VERBOSE < 1 else None - shared.run_process(make + make_args, stdout=stdout, stderr=stderr, env=env, - cwd=project_dir) + shared.run_process(make + make_args, stdout=stdout, stderr=stderr, env=env, cwd=project_dir) except subprocess.CalledProcessError: with open_make_out() as f: print('-- make stdout --') diff --git a/test/gen_large_switchcase.py b/test/gen_large_switchcase.py index e9f5cef0825f2..e8883a903108f 100755 --- a/test/gen_large_switchcase.py +++ b/test/gen_large_switchcase.py @@ -15,7 +15,8 @@ i += incr incr = (incr % 5) + 1 -print('''#include +print( + '''#include #include #include @@ -23,14 +24,19 @@ { switch(x) { -''' + cases + ''' +''' + + cases + + ''' default: return "default"; } } int main() { - for(int i = 0; i < ''' + str((num_cases + 99) // 100) + '''; ++i) + for(int i = 0; i < ''' + + str((num_cases + 99) // 100) + + '''; ++i) printf("%d: %s\\n", i*301, foo(i*301)); printf("Success!\\n"); -}''') +}''' +) diff --git a/test/gen_many_js_functions.py b/test/gen_many_js_functions.py index dccc74aca2b29..80138cf448796 100644 --- a/test/gen_many_js_functions.py +++ b/test/gen_many_js_functions.py @@ -11,7 +11,10 @@ def func_name(i): - return 'thisIsAFunctionWithVeryLongFunctionNameThatWouldBeGreatToBeMinifiedWhenImportingToAsmJsOrWasmSideCodeToCallOtherwiseCodeSizesWillBeLargeAndNetworkTransfersBecomeVerySlowThatUsersWillGoAwayAndVisitSomeOtherSiteInsteadAndThenWebAssemblyDeveloperIsSadOrEvenWorseNobodyNoticesButInternetPipesWillGetMoreCongestedWhichContributesToGlobalWarmingAndThenEveryoneElseWillBeSadAsWellEspeciallyThePolarBearsAndPenguinsJustThinkAboutThePenguins' + str(i + 1) + return ( + 'thisIsAFunctionWithVeryLongFunctionNameThatWouldBeGreatToBeMinifiedWhenImportingToAsmJsOrWasmSideCodeToCallOtherwiseCodeSizesWillBeLargeAndNetworkTransfersBecomeVerySlowThatUsersWillGoAwayAndVisitSomeOtherSiteInsteadAndThenWebAssemblyDeveloperIsSadOrEvenWorseNobodyNoticesButInternetPipesWillGetMoreCongestedWhichContributesToGlobalWarmingAndThenEveryoneElseWillBeSadAsWellEspeciallyThePolarBearsAndPenguinsJustThinkAboutThePenguins' + + str(i + 1) + ) def generate_js_library_with_lots_of_functions(out_file): @@ -38,7 +41,13 @@ def generate_c_program_that_calls_js_library_with_lots_of_functions(out_file): for i in range(NUM_FUNCS_TO_GENERATE): f.write(' sum += ' + func_name(i) + '();\n') - f.write('\n printf("Sum of numbers from 1 to ' + str(NUM_FUNCS_TO_GENERATE) + ': %d (expected ' + str(int((NUM_FUNCS_TO_GENERATE * (NUM_FUNCS_TO_GENERATE + 1)) / 2)) + ')\\n", sum);\n') + f.write( + '\n printf("Sum of numbers from 1 to ' + + str(NUM_FUNCS_TO_GENERATE) + + ': %d (expected ' + + str(int((NUM_FUNCS_TO_GENERATE * (NUM_FUNCS_TO_GENERATE + 1)) / 2)) + + ')\\n", sum);\n' + ) f.write('}\n') diff --git a/test/jsrun.py b/test/jsrun.py index b918becaed8e0..8f8a58d8e783a 100644 --- a/test/jsrun.py +++ b/test/jsrun.py @@ -12,7 +12,7 @@ from tools import shared, utils -WORKING_ENGINES = {} # Holds all configured engines and whether they work: maps path -> True/False +WORKING_ENGINES = {} # Holds all configured engines and whether they work: maps path -> True/False DEFAULT_TIMEOUT = 5 * 60 @@ -83,10 +83,19 @@ def require_engine(engine): sys.exit(1) -def run_js(filename, engine, args=None, - stdin=None, stdout=PIPE, stderr=None, cwd=None, - full_output=False, assert_returncode=0, skip_check=False, - timeout=DEFAULT_TIMEOUT): +def run_js( + filename, + engine, + args=None, + stdin=None, + stdout=PIPE, + stderr=None, + cwd=None, + full_output=False, + assert_returncode=0, + skip_check=False, + timeout=DEFAULT_TIMEOUT, +): """Execute javascript code generated by tests, with possible timeout.""" # We used to support True here but we no longer do. Assert here just in case. @@ -100,13 +109,8 @@ def run_js(filename, engine, args=None, print(f"Running: '{shared.shlex_join(command)}'") try: proc = subprocess.run( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - timeout=timeout, - universal_newlines=True) + command, stdin=stdin, stdout=stdout, stderr=stderr, cwd=cwd, timeout=timeout, universal_newlines=True + ) except Exception: # the failure may be because the engine is not present. show the proper # error in that case diff --git a/test/other/ports/external.py b/test/other/ports/external.py index 5fb8c8d764f4f..2c5f57915bbad 100644 --- a/test/other/ports/external.py +++ b/test/other/ports/external.py @@ -18,12 +18,7 @@ } # user options (from --use-port) -opts: Dict[str, Optional[str]] = { - 'value1': None, - 'value2': None, - 'value3': "v3", - 'dependency': None -} +opts: Dict[str, Optional[str]] = {'value1': None, 'value2': None, 'value3': "v3", 'dependency': None} deps = ['sdl2_image:formats=jpg'] diff --git a/test/parallel_testsuite.py b/test/parallel_testsuite.py index 05f3717f47f83..013d0490835cc 100644 --- a/test/parallel_testsuite.py +++ b/test/parallel_testsuite.py @@ -91,11 +91,12 @@ def combine_results(self, result, buffered_results): return result -class BufferedParallelTestResult(): +class BufferedParallelTestResult: """A picklable struct used to communicate test results across processes Fulfills the interface for unittest.TestResult """ + def __init__(self): self.buffered_result = None @@ -145,8 +146,9 @@ def addError(self, test, err): self.buffered_result = BufferedTestError(test, err) -class BufferedTestBase(): +class BufferedTestBase: """Abstract class that holds test result data, split by type of result.""" + def __init__(self, test, err=None): self.test = test if err: @@ -181,6 +183,7 @@ def fixup_fake_exception(fake_exc): # the data def make_wrapper(rtn): return lambda: rtn + ex.tb_frame.f_code.co_positions = make_wrapper(ex.tb_frame.f_code.positions) ex = ex.tb_next @@ -209,7 +212,7 @@ def updateResult(self, result): result.addUnexpectedSuccess(self.test) -class FakeTraceback(): +class FakeTraceback: """A fake version of a traceback object that is picklable across processes. Python's traceback objects contain hidden stack information that isn't able @@ -228,14 +231,14 @@ def __init__(self, tb): self.tb_lasti = tb.tb_lasti -class FakeFrame(): +class FakeFrame: def __init__(self, f): self.f_code = FakeCode(f.f_code) # f.f_globals is not picklable, not used in stack traces, and needs to be iterable self.f_globals = [] -class FakeCode(): +class FakeCode: def __init__(self, co): self.co_filename = co.co_filename self.co_name = co.co_name diff --git a/test/runner.py b/test/runner.py index 5896fe4f15b9e..5ae1bacbafca6 100755 --- a/test/runner.py +++ b/test/runner.py @@ -135,7 +135,7 @@ def get_all_tests(modules): def get_crossplatform_tests(modules): - suites = ['core0', 'other', 'sanity'] # We don't need all versions of every test + suites = ['core0', 'other', 'sanity'] # We don't need all versions of every test crossplatform_tests = [] # Walk over the test suites and find the test functions with the # is_crossplatform_test attribute applied by @crossplatform decorator @@ -248,15 +248,18 @@ def print_random_test_statistics(num_tests): std = 0.5 / math.sqrt(num_tests) expected = 100.0 * (1.0 - std) print() - print('running those %d randomly-selected tests. if they all pass, then there is a ' - 'greater than 95%% chance that at least %.2f%% of the test suite will pass' - % (num_tests, expected)) + print( + 'running those %d randomly-selected tests. if they all pass, then there is a ' + 'greater than 95%% chance that at least %.2f%% of the test suite will pass' % (num_tests, expected) + ) print() def show(): - print('if all tests passed then there is a greater than 95%% chance that at least ' - '%.2f%% of the test suite will pass' - % (expected)) + print( + 'if all tests passed then there is a greater than 95%% chance that at least ' + '%.2f%% of the test suite will pass' % (expected) + ) + atexit.register(show) @@ -314,6 +317,7 @@ def flattened_tests(loaded_tests): tests.extend(subsuite) return tests + def suite_for_module(module, tests): suite_supported = module.__name__ in ('test_core', 'test_other', 'test_posixtest') if not common.EMTEST_SAVE_DIR and not shared.DEBUG: @@ -338,9 +342,9 @@ def run_tests(options, suites): os.makedirs('out', exist_ok=True) # output fd must remain open until after testRunner.run() below output = open('out/test-results.xml', 'wb') - import xmlrunner # type: ignore - testRunner = xmlrunner.XMLTestRunner(output=output, verbosity=2, - failfast=options.failfast) + import xmlrunner # type: ignore + + testRunner = xmlrunner.XMLTestRunner(output=output, verbosity=2, failfast=options.failfast) print('Writing XML test output to ' + os.path.abspath(output.name)) else: testRunner = unittest.TextTestRunner(verbosity=2, failfast=options.failfast) @@ -348,8 +352,13 @@ def run_tests(options, suites): for mod_name, suite in suites: print('Running %s: (%s tests)' % (mod_name, suite.countTestCases())) res = testRunner.run(suite) - msg = ('%s: %s run, %s errors, %s failures, %s skipped' % - (mod_name, res.testsRun, len(res.errors), len(res.failures), len(res.skipped))) + msg = '%s: %s run, %s errors, %s failures, %s skipped' % ( + mod_name, + res.testsRun, + len(res.errors), + len(res.failures), + len(res.skipped), + ) num_failures += len(res.errors) + len(res.failures) + len(res.unexpectedSuccesses) resultMessages.append(msg) @@ -365,32 +374,41 @@ def run_tests(options, suites): def parse_args(args): parser = argparse.ArgumentParser(prog='runner.py', description=__doc__) - parser.add_argument('--save-dir', action='store_true', - help='Save the temporary directory used during for each ' - 'test. Implies --cores=1. Defaults to true when running a single test') - parser.add_argument('--no-clean', action='store_true', - help='Do not clean the temporary directory before each test run') + parser.add_argument( + '--save-dir', + action='store_true', + help='Save the temporary directory used during for each ' + 'test. Implies --cores=1. Defaults to true when running a single test', + ) + parser.add_argument( + '--no-clean', action='store_true', help='Do not clean the temporary directory before each test run' + ) parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--all-engines', action='store_true') parser.add_argument('--detect-leaks', action='store_true') parser.add_argument('--skip-slow', action='store_true', help='Skip tests marked as slow') - parser.add_argument('--cores', '-j', - help='Set the number tests to run in parallel. Defaults ' - 'to the number of CPU cores.', default=None) - parser.add_argument('--rebaseline', action='store_true', - help='Automatically update test expectations for tests that support it.') - parser.add_argument('--browser', - help='Command to launch web browser in which to run browser tests.') + parser.add_argument( + '--cores', + '-j', + help='Set the number tests to run in parallel. Defaults ' 'to the number of CPU cores.', + default=None, + ) + parser.add_argument( + '--rebaseline', action='store_true', help='Automatically update test expectations for tests that support it.' + ) + parser.add_argument('--browser', help='Command to launch web browser in which to run browser tests.') parser.add_argument('tests', nargs='*') parser.add_argument('--failfast', action='store_true') parser.add_argument('--start-at', metavar='NAME', help='Skip all tests up until ') - parser.add_argument('--continue', dest='_continue', action='store_true', - help='Resume from the last run test.' - 'Useful when combined with --failfast') + parser.add_argument( + '--continue', + dest='_continue', + action='store_true', + help='Resume from the last run test.' 'Useful when combined with --failfast', + ) parser.add_argument('--force64', action='store_true') parser.add_argument('--crossplatform-only', action='store_true') - parser.add_argument('--repeat', type=int, default=1, - help='Repeat each test N times (default: 1).') + parser.add_argument('--repeat', type=int, default=1, help='Repeat each test N times (default: 1).') return parser.parse_args() diff --git a/test/test_benchmark.py b/test/test_benchmark.py index c0c615fc138e5..bdca3c8138a20 100644 --- a/test/test_benchmark.py +++ b/test/test_benchmark.py @@ -56,7 +56,7 @@ EMTEST_BENCHMARKERS = os.getenv('EMTEST_BENCHMARKERS', 'clang,v8,v8-lto,v8-ctors') -class Benchmarker(): +class Benchmarker: # Whether to record statistics. Set by SizeBenchmarker. record_stats = False @@ -78,7 +78,7 @@ def bench(self, args, output_parser=None, reps=TEST_REPS, expected_output=None): if expected_output is not None and expected_output not in output: raise ValueError('Incorrect benchmark output:\n' + output) - if not output_parser or args == ['0']: # if arg is 0, we are not running code, and have no output to parse + if not output_parser or args == ['0']: # if arg is 0, we are not running code, and have no output to parse curr = time.time() - start else: try: @@ -101,11 +101,15 @@ def display(self, baseline=None): sorted_times = sorted(self.times) count = len(sorted_times) if count % 2 == 0: - median = sum(sorted_times[count // 2 - 1:count // 2 + 1]) / 2 + median = sum(sorted_times[count // 2 - 1 : count // 2 + 1]) / 2 else: median = sorted_times[count // 2] - print(' %10s: mean: %4.3f (+-%4.3f) secs median: %4.3f range: %4.3f-%4.3f (noise: %4.3f%%) (%d runs)' % (self.name, mean, std, median, min(self.times), max(self.times), 100 * std / mean, self.reps), end=' ') + print( + ' %10s: mean: %4.3f (+-%4.3f) secs median: %4.3f range: %4.3f-%4.3f (noise: %4.3f%%) (%d runs)' + % (self.name, mean, std, median, min(self.times), max(self.times), 100 * std / mean, self.reps), + end=' ', + ) if baseline: mean_baseline = sum(baseline.times) / len(baseline.times) @@ -119,14 +123,18 @@ def display(self, baseline=None): recorded_stats = [] def add_stat(name, size, gzip_size): - recorded_stats.append({ - 'value': name, - 'measurement': size, - }) - recorded_stats.append({ - 'value': name + ' (gzipped)', - 'measurement': gzip_size, - }) + recorded_stats.append( + { + 'value': name, + 'measurement': size, + } + ) + recorded_stats.append( + { + 'value': name + ' (gzipped)', + 'measurement': gzip_size, + } + ) total_size = 0 total_gzip_size = 0 @@ -160,7 +168,9 @@ def __init__(self, name, cc, cxx, args=None): self.cxx = cxx self.args = args or [OPTIMIZATIONS] - def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser): + def build( + self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser + ): native_args = native_args or [] shared_args = shared_args or [] self.parent = parent @@ -170,11 +180,14 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat native_args = native_args + lib_builder(self.name, native=True, env_init=env) if not native_exec: compiler = self.cxx if filename.endswith('cpp') else self.cc - cmd = compiler + [ - '-fno-math-errno', - filename, - '-o', filename + '.native' - ] + self.args + shared_args + native_args + clang_native.get_clang_native_args() + cmd = ( + compiler + + ['-fno-math-errno', filename, '-o', filename + '.native'] + + self.args + + shared_args + + native_args + + clang_native.get_clang_native_args() + ) # print(cmd) run_process(cmd, env=clang_native.get_clang_native_env()) else: @@ -196,11 +209,9 @@ def get_size_text(self): def run_binaryen_opts(filename, opts): - run_process([ - os.path.join(building.get_binaryen_bin(), 'wasm-opt', '--all-features'), - filename, - '-o', filename - ] + opts) + run_process( + [os.path.join(building.get_binaryen_bin(), 'wasm-opt', '--all-features'), filename, '-o', filename] + opts + ) class EmscriptenBenchmarker(Benchmarker): @@ -213,7 +224,9 @@ def __init__(self, name, engine, extra_args=None, env=None, binaryen_opts=None): self.env.update(env) self.binaryen_opts = binaryen_opts or [] - def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser): + def build( + self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser + ): emcc_args = emcc_args or [] self.filename = filename llvm_root = self.env.get('LLVM') or config.LLVM_ROOT @@ -226,15 +239,24 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat # This shouldn't be 'emcc_args += ...', because emcc_args is passed in as # a parameter and changes will be visible to the caller. emcc_args = emcc_args + lib_builder('js_' + llvm_root, native=False, env_init=env_init) - final = os.path.dirname(filename) + os.path.sep + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js' + final = ( + os.path.dirname(filename) + + os.path.sep + + self.name + + ('_' if self.name else '') + + os.path.basename(filename) + + '.js' + ) final = final.replace('.cpp', '') utils.delete_file(final) cmd = [ - EMCC, filename, + EMCC, + filename, OPTIMIZATIONS, '-sINITIAL_MEMORY=256MB', '-sENVIRONMENT=node,shell', - '-o', final + '-o', + final, ] + LLVM_FEATURE_FLAGS if shared_args: cmd += shared_args @@ -294,7 +316,9 @@ def __init__(self, name, engine, args=None, binaryen_opts=None): self.args = args or [OPTIMIZATIONS] self.binaryen_opts = binaryen_opts or [] - def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser): + def build( + self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser + ): cheerp_args = [ '-fno-math-errno', ] @@ -303,20 +327,31 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat if lib_builder: # build as "native" (so no emcc env stuff), but with all the cheerp stuff # set in the env - cheerp_args = cheerp_args + lib_builder(self.name, native=True, env_init={ - 'CC': CHEERP_BIN + 'clang', - 'CXX': CHEERP_BIN + 'clang++', - 'AR': CHEERP_BIN + '../libexec/cheerp-unknown-none-ar', - 'LD': CHEERP_BIN + 'clang', - 'NM': CHEERP_BIN + 'llvm-nm', - 'LDSHARED': CHEERP_BIN + 'clang', - 'RANLIB': CHEERP_BIN + '../libexec/cheerp-unknown-none-ranlib', - 'CXXFLAGS': "-Wno-c++11-narrowing", - 'CHEERP_PREFIX': CHEERP_BIN + '../', - }) + cheerp_args = cheerp_args + lib_builder( + self.name, + native=True, + env_init={ + 'CC': CHEERP_BIN + 'clang', + 'CXX': CHEERP_BIN + 'clang++', + 'AR': CHEERP_BIN + '../libexec/cheerp-unknown-none-ar', + 'LD': CHEERP_BIN + 'clang', + 'NM': CHEERP_BIN + 'llvm-nm', + 'LDSHARED': CHEERP_BIN + 'clang', + 'RANLIB': CHEERP_BIN + '../libexec/cheerp-unknown-none-ranlib', + 'CXXFLAGS': "-Wno-c++11-narrowing", + 'CHEERP_PREFIX': CHEERP_BIN + '../', + }, + ) if PROFILING: - cheerp_args += ['-cheerp-pretty-code'] # get function names, like emcc --profiling - final = os.path.dirname(filename) + os.path.sep + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js' + cheerp_args += ['-cheerp-pretty-code'] # get function names, like emcc --profiling + final = ( + os.path.dirname(filename) + + os.path.sep + + self.name + + ('_' if self.name else '') + + os.path.basename(filename) + + '.js' + ) final = final.replace('.cpp', '') utils.delete_file(final) dirs_to_delete = [] @@ -327,12 +362,18 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat compiler = CHEERP_BIN + '/clang' else: compiler = CHEERP_BIN + '/clang++' - cmd = [compiler] + cheerp_args + [ - '-cheerp-linear-heap-size=256', - '-cheerp-secondary-output-file=' + final.replace('.js', '.wasm'), - filename, - '-o', final - ] + shared_args + cmd = ( + [compiler] + + cheerp_args + + [ + '-cheerp-linear-heap-size=256', + '-cheerp-secondary-output-file=' + final.replace('.js', '.wasm'), + filename, + '-o', + final, + ] + + shared_args + ) # print(' '.join(cmd)) run_process(cmd, stdout=PIPE, stderr=PIPE) self.filename = final @@ -360,7 +401,7 @@ def get_output_files(self): named_benchmarkers = { 'clang': NativeBenchmarker('clang', [CLANG_CC], [CLANG_CXX]), - 'gcc': NativeBenchmarker('gcc', ['gcc', '-no-pie'], ['g++', '-no-pie']), + 'gcc': NativeBenchmarker('gcc', ['gcc', '-no-pie'], ['g++', '-no-pie']), 'size': SizeBenchmarker('size'), 'v8': EmscriptenBenchmarker('v8', aot_v8), 'v8-lto': EmscriptenBenchmarker('v8-lto', aot_v8, ['-flto']), @@ -371,7 +412,7 @@ def get_output_files(self): 'cherp-v8': CheerpBenchmarker('cheerp-v8-wasm', aot_v8), # TODO: ensure no baseline compiler is used, see v8 'sm': EmscriptenBenchmarker('sm', config.SPIDERMONKEY_ENGINE), - 'cherp-sm': CheerpBenchmarker('cheerp-sm-wasm', config.SPIDERMONKEY_ENGINE) + 'cherp-sm': CheerpBenchmarker('cheerp-sm-wasm', config.SPIDERMONKEY_ENGINE), } for name in EMTEST_BENCHMARKERS.split(','): @@ -382,7 +423,7 @@ def get_output_files(self): class benchmark(common.RunnerCore): save_dir = True - stats = [] # type: ignore + stats = [] # type: ignore @classmethod def setUpClass(cls): @@ -398,7 +439,10 @@ def setUpClass(cls): pass try: with common.chdir(os.path.expanduser('~/Dev/mozilla-central')): - fingerprint.append('sm: ' + [line for line in run_process(['hg', 'tip'], stdout=PIPE).stdout.splitlines() if 'changeset' in line][0]) + fingerprint.append( + 'sm: ' + + [line for line in run_process(['hg', 'tip'], stdout=PIPE).stdout.splitlines() if 'changeset' in line][0] + ) except Exception: pass fingerprint.append('llvm: ' + config.LLVM_ROOT) @@ -408,11 +452,7 @@ def setUpClass(cls): def tearDownClass(cls): super().tearDownClass() if cls.stats: - output = { - 'version': 1, - 'git_hash': '', - 'results': cls.stats - } + output = {'version': 1, 'git_hash': '', 'results': cls.stats} utils.write_file('stats.json', json.dumps(output, indent=2) + '\n') # avoid depending on argument reception from the commandline @@ -422,21 +462,36 @@ def hardcode_arguments(self, code): main_pattern = 'int main(int argc, char **argv)' assert main_pattern in code code = code.replace(main_pattern, 'int benchmark_main(int argc, char **argv)') - code += ''' + code += ( + ''' int main() { int newArgc = 2; char* newArgv[] = { (char*)"./program.exe", (char*)"%s" }; int ret = benchmark_main(newArgc, newArgv); return ret; } - ''' % DEFAULT_ARG + ''' + % DEFAULT_ARG + ) return code - def do_benchmark(self, name, src, expected_output='FAIL', args=None, - emcc_args=None, native_args=None, shared_args=None, - force_c=False, reps=TEST_REPS, native_exec=None, - output_parser=None, args_processor=None, lib_builder=None, - skip_native=False): + def do_benchmark( + self, + name, + src, + expected_output='FAIL', + args=None, + emcc_args=None, + native_args=None, + shared_args=None, + force_c=False, + reps=TEST_REPS, + native_exec=None, + output_parser=None, + args_processor=None, + lib_builder=None, + skip_native=False, + ): if not benchmarkers: raise Exception('error, no benchmarkers') @@ -459,22 +514,24 @@ def do_benchmark(self, name, src, expected_output='FAIL', args=None, reps = 0 baseline = b print('Running benchmarker: %s: %s' % (b.__class__.__name__, b.name)) - b.build(self, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser=output_parser is not None) + b.build( + self, + filename, + args, + shared_args, + emcc_args, + native_args, + native_exec, + lib_builder, + has_output_parser=output_parser is not None, + ) b.bench(args, output_parser, reps, expected_output) recorded_stats = b.display(baseline) if recorded_stats: self.add_stats(name, recorded_stats) def add_stats(self, name, stats): - self.stats.append({ - 'key': { - 'test': name, - 'units': 'bytes' - }, - 'measurements': { - 'stats': stats - } - }) + self.stats.append({'key': {'test': name, 'units': 'bytes'}, 'measurements': {'stats': stats}}) def test_primes(self, check=True): src = r''' @@ -516,7 +573,12 @@ def test_primes(self, check=True): return 0; } ''' - self.do_benchmark('primes' if check else 'primes-nocheck', src, 'lastprime:' if check else '', shared_args=['-DCHECK'] if check else []) + self.do_benchmark( + 'primes' if check else 'primes-nocheck', + src, + 'lastprime:' if check else '', + shared_args=['-DCHECK'] if check else [], + ) # Also interesting to test it without the printfs which allow checking the output. Without # printf, code size is dominated by the runtime itself (the compiled code is just a few lines). @@ -750,7 +812,7 @@ def test_fannkuch(self): case 5: n = 12; break; default: printf("error: %d\\n", arg); return -1; } - ''' + ''', ) assert 'switch(arg)' in src self.do_benchmark('fannkuch', src, 'Pfannkuchen(') @@ -824,7 +886,9 @@ def test_corrections64(self): def fasta(self, name, double_rep): src = read_file(test_file('fasta.cpp')).replace('double', double_rep) - src = src.replace(' const size_t n = ( argc > 1 ) ? atoi( argv[1] ) : 512;', ''' + src = src.replace( + ' const size_t n = ( argc > 1 ) ? atoi( argv[1] ) : 512;', + ''' int n; int arg = argc > 1 ? argv[1][0] - '0' : 3; switch(arg) { @@ -836,7 +900,8 @@ def fasta(self, name, double_rep): case 5: n = 19000000*10; break; default: printf("error: %d\\n", arg); return -1; } - ''') + ''', + ) assert 'switch(arg)' in src self.do_benchmark('fasta', src, '') @@ -854,8 +919,7 @@ def test_skinning(self): def test_havlak(self): src = read_file(test_file('havlak.cpp')) # This runs many recursive calls (DFS) and thus needs a larger stack - self.do_benchmark('havlak', src, 'Found', shared_args=['-std=c++11'], - emcc_args=['-sSTACK_SIZE=1MB']) + self.do_benchmark('havlak', src, 'Found', shared_args=['-std=c++11'], emcc_args=['-sSTACK_SIZE=1MB']) def test_base64(self): src = read_file(test_file('base64.c')) @@ -870,111 +934,216 @@ def test_zzz_linpack(self): def output_parser(output): mflops = re.search(r'Unrolled Double Precision ([\d\.]+) Mflops', output).group(1) return 10000.0 / float(mflops) - self.do_benchmark('linpack_double', read_file(test_file('benchmark/linpack2.c')), '''Unrolled Double Precision''', force_c=True, output_parser=output_parser) + + self.do_benchmark( + 'linpack_double', + read_file(test_file('benchmark/linpack2.c')), + '''Unrolled Double Precision''', + force_c=True, + output_parser=output_parser, + ) # Benchmarks the synthetic performance of calling native functions. @non_core def test_native_functions(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('native_functions', read_file(test_file('benchmark/benchmark_ffis.cpp')), 'Total time:', - output_parser=output_parser, - # Not minimal because this uses functions in library_browsers.js - emcc_args=['-sMINIMAL_RUNTIME=0'], - shared_args=['-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'native_functions', + read_file(test_file('benchmark/benchmark_ffis.cpp')), + 'Total time:', + output_parser=output_parser, + # Not minimal because this uses functions in library_browsers.js + emcc_args=['-sMINIMAL_RUNTIME=0'], + shared_args=['-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) # Benchmarks the synthetic performance of calling function pointers. @non_core def test_native_function_pointers(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('native_functions', read_file(test_file('benchmark/benchmark_ffis.cpp')), 'Total time:', - output_parser=output_parser, - # Not minimal because this uses functions in library_browsers.js - emcc_args=['-sMINIMAL_RUNTIME=0'], - shared_args=['-DBENCHMARK_FUNCTION_POINTER=1', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'native_functions', + read_file(test_file('benchmark/benchmark_ffis.cpp')), + 'Total time:', + output_parser=output_parser, + # Not minimal because this uses functions in library_browsers.js + emcc_args=['-sMINIMAL_RUNTIME=0'], + shared_args=['-DBENCHMARK_FUNCTION_POINTER=1', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) # Benchmarks the synthetic performance of calling "foreign" JavaScript functions. @non_core def test_foreign_functions(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('foreign_functions', read_file(test_file('benchmark/benchmark_ffis.cpp')), 'Total time:', - output_parser=output_parser, - # Not minimal because this uses functions in library_browsers.js - emcc_args=['--js-library', test_file('benchmark/benchmark_ffis.js'), '-sMINIMAL_RUNTIME=0'], - shared_args=['-DBENCHMARK_FOREIGN_FUNCTION=1', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'foreign_functions', + read_file(test_file('benchmark/benchmark_ffis.cpp')), + 'Total time:', + output_parser=output_parser, + # Not minimal because this uses functions in library_browsers.js + emcc_args=['--js-library', test_file('benchmark/benchmark_ffis.js'), '-sMINIMAL_RUNTIME=0'], + shared_args=['-DBENCHMARK_FOREIGN_FUNCTION=1', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memcpy_128b(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memcpy_128b', read_file(test_file('benchmark/benchmark_memcpy.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMAX_COPY=128', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memcpy_128b', + read_file(test_file('benchmark/benchmark_memcpy.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMAX_COPY=128', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memcpy_4k(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memcpy_4k', read_file(test_file('benchmark/benchmark_memcpy.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=128', '-DMAX_COPY=4096', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memcpy_4k', + read_file(test_file('benchmark/benchmark_memcpy.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=128', '-DMAX_COPY=4096', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memcpy_16k(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memcpy_16k', read_file(test_file('benchmark/benchmark_memcpy.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=4096', '-DMAX_COPY=16384', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memcpy_16k', + read_file(test_file('benchmark/benchmark_memcpy.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=4096', '-DMAX_COPY=16384', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memcpy_1mb(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memcpy_1mb', read_file(test_file('benchmark/benchmark_memcpy.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=16384', '-DMAX_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memcpy_1mb', + read_file(test_file('benchmark/benchmark_memcpy.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=16384', '-DMAX_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memcpy_16mb(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memcpy_16mb', read_file(test_file('benchmark/benchmark_memcpy.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memcpy_16mb', + read_file(test_file('benchmark/benchmark_memcpy.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memset_128b(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memset_128b', read_file(test_file('benchmark/benchmark_memset.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMAX_COPY=128', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memset_128b', + read_file(test_file('benchmark/benchmark_memset.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMAX_COPY=128', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memset_4k(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memset_4k', read_file(test_file('benchmark/benchmark_memset.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=128', '-DMAX_COPY=4096', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memset_4k', + read_file(test_file('benchmark/benchmark_memset.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=128', '-DMAX_COPY=4096', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memset_16k(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memset_16k', read_file(test_file('benchmark/benchmark_memset.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=4096', '-DMAX_COPY=16384', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memset_16k', + read_file(test_file('benchmark/benchmark_memset.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=4096', '-DMAX_COPY=16384', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memset_1mb(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memset_1mb', read_file(test_file('benchmark/benchmark_memset.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=16384', '-DMAX_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memset_1mb', + read_file(test_file('benchmark/benchmark_memset.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=16384', '-DMAX_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) @non_core def test_memset_16mb(self): def output_parser(output): return float(re.search(r'Total time: ([\d\.]+)', output).group(1)) - self.do_benchmark('memset_16mb', read_file(test_file('benchmark/benchmark_memset.cpp')), 'Total time:', output_parser=output_parser, shared_args=['-DMIN_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')]) + + self.do_benchmark( + 'memset_16mb', + read_file(test_file('benchmark/benchmark_memset.cpp')), + 'Total time:', + output_parser=output_parser, + shared_args=['-DMIN_COPY=1048576', '-DBUILD_FOR_SHELL', '-I' + test_file('benchmark')], + ) def test_malloc_multithreading(self): # Multithreaded malloc test. For emcc we use mimalloc here. src = read_file(test_file('other/test_malloc_multithreading.cpp')) # TODO measure with different numbers of cores and not fixed 4 - self.do_benchmark('malloc_multithreading', src, 'Done.', shared_args=['-DWORKERS=4', '-pthread'], emcc_args=['-sEXIT_RUNTIME', '-sMALLOC=mimalloc']) + self.do_benchmark( + 'malloc_multithreading', + src, + 'Done.', + shared_args=['-DWORKERS=4', '-pthread'], + emcc_args=['-sEXIT_RUNTIME', '-sMALLOC=mimalloc'], + ) def test_matrix_multiply(self): def output_parser(output): return float(re.search(r'Total elapsed: ([\d\.]+)', output).group(1)) - self.do_benchmark('matrix_multiply', read_file(test_file('matrix_multiply.cpp')), 'Total elapsed:', output_parser=output_parser, shared_args=['-I' + test_file('benchmark')]) + + self.do_benchmark( + 'matrix_multiply', + read_file(test_file('matrix_multiply.cpp')), + 'Total elapsed:', + output_parser=output_parser, + shared_args=['-I' + test_file('benchmark')], + ) def lua(self, benchmark, expected, output_parser=None, args_processor=None): self.emcc_args.remove('-Werror') @@ -983,13 +1152,34 @@ def lua(self, benchmark, expected, output_parser=None, args_processor=None): def lib_builder(name, native, env_init): # We force recomputation for the native benchmarker because this benchmark # uses native_exec=True, so we need to copy the native executable - return self.get_library(os.path.join('third_party', 'lua_native' if native else 'lua'), [os.path.join('src', 'lua.o'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=native, cache_name_extra=name, env_init=env_init, force_rebuild=native) - - self.do_benchmark('lua_' + benchmark, '', expected, - force_c=True, args=[benchmark + '.lua', DEFAULT_ARG], - emcc_args=['--embed-file', benchmark + '.lua', '-sFORCE_FILESYSTEM', '-sMINIMAL_RUNTIME=0'], # not minimal because of files - lib_builder=lib_builder, native_exec=os.path.join('building', 'third_party', 'lua_native', 'src', 'lua'), - output_parser=output_parser, args_processor=args_processor) + return self.get_library( + os.path.join('third_party', 'lua_native' if native else 'lua'), + [os.path.join('src', 'lua.o'), os.path.join('src', 'liblua.a')], + make=['make', 'generic'], + configure=None, + native=native, + cache_name_extra=name, + env_init=env_init, + force_rebuild=native, + ) + + self.do_benchmark( + 'lua_' + benchmark, + '', + expected, + force_c=True, + args=[benchmark + '.lua', DEFAULT_ARG], + emcc_args=[ + '--embed-file', + benchmark + '.lua', + '-sFORCE_FILESYSTEM', + '-sMINIMAL_RUNTIME=0', + ], # not minimal because of files + lib_builder=lib_builder, + native_exec=os.path.join('building', 'third_party', 'lua_native', 'src', 'lua'), + output_parser=output_parser, + args_processor=args_processor, + ) def test_zzz_lua_scimark(self): def output_parser(output): @@ -1006,30 +1196,62 @@ def test_zzz_zlib(self): src = read_file(test_file('benchmark/test_zlib_benchmark.c')) def lib_builder(name, native, env_init): - return self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'), make_args=['libz.a'], native=native, cache_name_extra=name, env_init=env_init) - - self.do_benchmark('zlib', src, 'ok.', - force_c=True, shared_args=['-I' + test_file('third_party/zlib')], lib_builder=lib_builder) + return self.get_library( + os.path.join('third_party', 'zlib'), + os.path.join('libz.a'), + make_args=['libz.a'], + native=native, + cache_name_extra=name, + env_init=env_init, + ) + + self.do_benchmark( + 'zlib', src, 'ok.', force_c=True, shared_args=['-I' + test_file('third_party/zlib')], lib_builder=lib_builder + ) def test_zzz_coremark(self): src = read_file(test_file('third_party/coremark/core_main.c')) def lib_builder(name, native, env_init): - return self.get_library('third_party/coremark', [os.path.join('coremark.a')], configure=None, native=native, cache_name_extra=name, env_init=env_init) + return self.get_library( + 'third_party/coremark', + [os.path.join('coremark.a')], + configure=None, + native=native, + cache_name_extra=name, + env_init=env_init, + ) def output_parser(output): iters_sec = re.search(r'Iterations/Sec : ([\d\.]+)', output).group(1) return 100000.0 / float(iters_sec) - self.do_benchmark('coremark', src, 'Correct operation validated.', shared_args=['-I' + test_file('third_party/coremark')], lib_builder=lib_builder, output_parser=output_parser, force_c=True) + self.do_benchmark( + 'coremark', + src, + 'Correct operation validated.', + shared_args=['-I' + test_file('third_party/coremark')], + lib_builder=lib_builder, + output_parser=output_parser, + force_c=True, + ) def test_zzz_box2d(self): src = read_file(test_file('benchmark/test_box2d_benchmark.cpp')) def lib_builder(name, native, env_init): - return self.get_library(os.path.join('third_party', 'box2d'), ['box2d.a'], configure=None, native=native, cache_name_extra=name, env_init=env_init) - - self.do_benchmark('box2d', src, 'frame averages', shared_args=['-I' + test_file('third_party/box2d')], lib_builder=lib_builder) + return self.get_library( + os.path.join('third_party', 'box2d'), + ['box2d.a'], + configure=None, + native=native, + cache_name_extra=name, + env_init=env_init, + ) + + self.do_benchmark( + 'box2d', src, 'frame averages', shared_args=['-I' + test_file('third_party/box2d')], lib_builder=lib_builder + ) def test_zzz_bullet(self): self.emcc_args.remove('-Werror') @@ -1038,40 +1260,64 @@ def test_zzz_bullet(self): src += read_file(test_file('third_party/bullet/Demos/Benchmarks/main.cpp')) def lib_builder(name, native, env_init): - return self.get_library(str(Path('third_party/bullet')), - [Path('src/.libs/libBulletDynamics.a'), - Path('src/.libs/libBulletCollision.a'), - Path('src/.libs/libLinearMath.a')], - # The --host parameter is needed for 2 reasons: - # 1) bullet in it's configure.ac tries to do platform detection and will fail on unknown platforms - # 2) configure will try to compile and run a test file to check if the C compiler is sane. As Cheerp - # will generate a wasm file (which cannot be run), configure will fail. Passing `--host` enables - # cross compile mode, which lets configure complete happily. - configure_args=['--disable-demos', '--disable-dependency-tracking', '--host=i686-unknown-linux'], native=native, cache_name_extra=name, env_init=env_init) - - self.do_benchmark('bullet', src, '\nok.\n', - shared_args=['-I' + test_file('third_party/bullet/src'), '-I' + test_file('third_party/bullet/Demos/Benchmarks')], - lib_builder=lib_builder) + return self.get_library( + str(Path('third_party/bullet')), + [ + Path('src/.libs/libBulletDynamics.a'), + Path('src/.libs/libBulletCollision.a'), + Path('src/.libs/libLinearMath.a'), + ], + # The --host parameter is needed for 2 reasons: + # 1) bullet in it's configure.ac tries to do platform detection and will fail on unknown platforms + # 2) configure will try to compile and run a test file to check if the C compiler is sane. As Cheerp + # will generate a wasm file (which cannot be run), configure will fail. Passing `--host` enables + # cross compile mode, which lets configure complete happily. + configure_args=['--disable-demos', '--disable-dependency-tracking', '--host=i686-unknown-linux'], + native=native, + cache_name_extra=name, + env_init=env_init, + ) + + self.do_benchmark( + 'bullet', + src, + '\nok.\n', + shared_args=['-I' + test_file('third_party/bullet/src'), '-I' + test_file('third_party/bullet/Demos/Benchmarks')], + lib_builder=lib_builder, + ) def test_zzz_lzma(self): src = read_file(test_file('benchmark/test_lzma_benchmark.c')) def lib_builder(name, native, env_init): - return self.get_library(os.path.join('third_party', 'lzma'), [os.path.join('lzma.a')], configure=None, native=native, cache_name_extra=name, env_init=env_init) + return self.get_library( + os.path.join('third_party', 'lzma'), + [os.path.join('lzma.a')], + configure=None, + native=native, + cache_name_extra=name, + env_init=env_init, + ) self.do_benchmark('lzma', src, 'ok.', shared_args=['-I' + test_file('third_party/lzma')], lib_builder=lib_builder) def test_zzz_sqlite(self): src = read_file(test_file('third_party/sqlite/sqlite3.c')) + read_file(test_file('sqlite/speedtest1.c')) - self.do_benchmark('sqlite', src, 'TOTAL...', - native_args=['-ldl', '-pthread'], - shared_args=['-I' + test_file('third_party/sqlite')], - # not minimal because of files - emcc_args=['-sFILESYSTEM', '-sMINIMAL_RUNTIME=0'], - force_c=True) + self.do_benchmark( + 'sqlite', + src, + 'TOTAL...', + native_args=['-ldl', '-pthread'], + shared_args=['-I' + test_file('third_party/sqlite')], + # not minimal because of files + emcc_args=['-sFILESYSTEM', '-sMINIMAL_RUNTIME=0'], + force_c=True, + ) def test_zzz_poppler(self): - utils.write_file('pre.js', ''' + utils.write_file( + 'pre.js', + ''' var benchmarkArgument = %s; var benchmarkArgumentToPageCount = { '0': 0, @@ -1107,17 +1353,27 @@ def test_zzz_poppler(self): out(files.length + ' files emitted, total output size: ' + totalSize + ', hashed printout: ' + hash); }; } - ''' % DEFAULT_ARG) + ''' + % DEFAULT_ARG, + ) def lib_builder(name, native, env_init): return self.get_poppler_library(env_init=env_init) # TODO: Fix poppler native build and remove skip_native=True - self.do_benchmark('poppler', '', 'hashed printout', - shared_args=['-I' + test_file('poppler/include'), - '-I' + test_file('freetype/include')], - emcc_args=['-sFILESYSTEM', '--pre-js=pre.js', '--embed-file', - test_file('poppler/emscripten_html5.pdf') + '@input.pdf', - '-sERROR_ON_UNDEFINED_SYMBOLS=0', - '-sMINIMAL_RUNTIME=0'], # not minimal because of files - lib_builder=lib_builder, skip_native=True) + self.do_benchmark( + 'poppler', + '', + 'hashed printout', + shared_args=['-I' + test_file('poppler/include'), '-I' + test_file('freetype/include')], + emcc_args=[ + '-sFILESYSTEM', + '--pre-js=pre.js', + '--embed-file', + test_file('poppler/emscripten_html5.pdf') + '@input.pdf', + '-sERROR_ON_UNDEFINED_SYMBOLS=0', + '-sMINIMAL_RUNTIME=0', + ], # not minimal because of files + lib_builder=lib_builder, + skip_native=True, + ) diff --git a/test/test_core.py b/test/test_core.py index 8075a42ade9bd..6e4fa734e5255 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -28,7 +28,14 @@ from common import read_file, read_binary, requires_v8, requires_node, requires_wasm2js, requires_node_canary from common import compiler_for, crossplatform, no_4gb, no_2gb, also_with_minimal_runtime from common import with_all_fs, also_with_nodefs, also_with_nodefs_both, also_with_noderawfs, also_with_wasmfs -from common import with_all_eh_sjlj, with_all_sjlj, also_with_standalone_wasm, can_do_standalone, no_wasm64, requires_wasm_exnref +from common import ( + with_all_eh_sjlj, + with_all_sjlj, + also_with_standalone_wasm, + can_do_standalone, + no_wasm64, + requires_wasm_exnref, +) from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, PYTHON import clang_native @@ -51,11 +58,14 @@ def decorated(self, *args, **kwargs): if self.is_wasm2js(): self.skipTest('wasm2js only supports MVP for now') if '-O3' in self.emcc_args: - self.skipTest('SIMD tests are too slow with -O3 in the new LLVM pass manager, https://github.com/emscripten-core/emscripten/issues/13427') + self.skipTest( + 'SIMD tests are too slow with -O3 in the new LLVM pass manager, https://github.com/emscripten-core/emscripten/issues/13427' + ) self.emcc_args.append('-msimd128') self.emcc_args.append('-fno-lax-vector-conversions') self.v8_args.append('--experimental-wasm-simd') f(self, *args, **kwargs) + return decorated @@ -71,6 +81,7 @@ def decorated(self): self.skipTest('wasm2js only supports MVP for now') self.emcc_args.append('-mrelaxed-simd') f(self) + return decorated @@ -82,6 +93,7 @@ def decorated(self): if self.is_wasm2js(): self.skipTest('wasm2js only supports MVP for now') f(self) + return decorated @@ -106,8 +118,7 @@ def decorated(self, dylink_reversed, *args, **kwargs): return func(self, *args, **kwargs) - parameterize(decorated, {'': (False,), - 'reversed': (True,)}) + parameterize(decorated, {'': (False,), 'reversed': (True,)}) return decorated @@ -136,6 +147,7 @@ def no_wasm2js(note=''): def decorated(f): return skip_if(f, 'is_wasm2js', note) + return decorated @@ -154,6 +166,7 @@ def only_wasm2js(note=''): def decorated(f): return skip_if(f, 'is_wasm2js', note, negate=True) + return decorated @@ -170,8 +183,7 @@ def metafunc(self, jspi): self.set_setting('ASYNCIFY') f(self) - parameterize(metafunc, {'': (False,), - 'jspi': (True,)}) + parameterize(metafunc, {'': (False,), 'jspi': (True,)}) return metafunc @@ -186,7 +198,9 @@ def decorated(self): if self.is_optimizing(): self.skipTest(note) func(self) + return decorated + return decorator @@ -208,7 +222,9 @@ def decorated(self, *args, **kwargs): if '-fsanitize=address' in self.emcc_args: self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -223,7 +239,9 @@ def decorated(self, *args, **kwargs): if '-fsanitize=leak' in self.emcc_args: self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -238,7 +256,9 @@ def decorated(self, *args, **kwargs): if '-fsanitize=undefined' in self.emcc_args: self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -253,7 +273,9 @@ def decorated(self, *args, **kwargs): if any(a.startswith('-fsanitize=') for a in self.emcc_args): self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -268,7 +290,9 @@ def decorated(self, *args, **kwargs): if self.get_setting('WASMFS'): self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator @@ -284,8 +308,11 @@ def decorated(self, *args, **kwargs): if (name + '=1') in self.emcc_args or self.get_setting(name): self.skipTest(note) f(self, *args, **kwargs) + return decorated + return decorator + return outer_decorator @@ -318,7 +345,7 @@ def maybe_closure(self): return False def assertStartswith(self, output, prefix): - self.assertEqual(prefix, output[:len(prefix)]) + self.assertEqual(prefix, output[: len(prefix)]) def verify_in_strict_mode(self, filename): js = read_file(filename) @@ -332,29 +359,39 @@ def do_core_test(self, testname, **kwargs): def get_bullet_library(self, use_cmake): if use_cmake: configure_commands = ['cmake', '.'] - configure_args = ['-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF', '-DUSE_GLUT=OFF', - '-DCMAKE_CXX_STANDARD=14'] + configure_args = ['-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF', '-DUSE_GLUT=OFF', '-DCMAKE_CXX_STANDARD=14'] # Depending on whether 'configure' or 'cmake' is used to build, Bullet # places output files in different directory structures. - generated_libs = [Path('src/BulletDynamics/libBulletDynamics.a'), - Path('src/BulletCollision/libBulletCollision.a'), - Path('src/LinearMath/libLinearMath.a')] + generated_libs = [ + Path('src/BulletDynamics/libBulletDynamics.a'), + Path('src/BulletCollision/libBulletCollision.a'), + Path('src/LinearMath/libLinearMath.a'), + ] else: configure_commands = ['sh', './configure'] # Force a nondefault --host= so that the configure script will interpret # that we are doing cross-compilation # and skip attempting to run the generated executable with './a.out', # which would fail since we are building a .js file. - configure_args = ['--disable-shared', '--host=i686-pc-linux-gnu', - '--disable-demos', '--disable-dependency-tracking'] - generated_libs = [Path('src/.libs/libBulletDynamics.a'), - Path('src/.libs/libBulletCollision.a'), - Path('src/.libs/libLinearMath.a')] + configure_args = [ + '--disable-shared', + '--host=i686-pc-linux-gnu', + '--disable-demos', + '--disable-dependency-tracking', + ] + generated_libs = [ + Path('src/.libs/libBulletDynamics.a'), + Path('src/.libs/libBulletCollision.a'), + Path('src/.libs/libLinearMath.a'), + ] - return self.get_library('third_party/bullet', generated_libs, - configure=configure_commands, - configure_args=configure_args, - cache_name_extra=configure_commands[0]) + return self.get_library( + 'third_party/bullet', + generated_libs, + configure=configure_commands, + configure_args=configure_args, + cache_name_extra=configure_commands[0], + ) def test_hello_world(self): self.do_core_test('test_hello_world.c') @@ -388,7 +425,10 @@ def test_int53(self): def test_int53_convertI32PairToI53Checked(self): if common.EMTEST_REBASELINE: - self.run_process([EMCC, test_file('core/test_convertI32PairToI53Checked.cpp'), '-o', 'a.js', '-DGENERATE_ANSWERS'] + self.emcc_args) + self.run_process( + [EMCC, test_file('core/test_convertI32PairToI53Checked.cpp'), '-o', 'a.js', '-DGENERATE_ANSWERS'] + + self.emcc_args + ) ret = self.run_process(config.NODE_JS + ['a.js'], stdout=PIPE).stdout write_file(test_file('core/test_convertI32PairToI53Checked.out'), ret) else: @@ -545,13 +585,19 @@ def test_cube2md5(self): @needs_make('make') def test_cube2hash(self): # A good test of i64 math - self.do_run('// empty file', 'Usage: hashstring ', - libraries=self.get_library('third_party/cube2hash', ['libcube2hash.a'], configure=None), - includes=[test_file('third_party/cube2hash')], assert_returncode=NON_ZERO) + self.do_run( + '// empty file', + 'Usage: hashstring ', + libraries=self.get_library('third_party/cube2hash', ['libcube2hash.a'], configure=None), + includes=[test_file('third_party/cube2hash')], + assert_returncode=NON_ZERO, + ) - for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'), - ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'), - ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]: + for text, output in [ + ('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'), + ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'), + ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670'), + ]: self.do_run('src.js', 'hash value: ' + output, args=[text], no_build=True) @only_wasm2js('tests 64-bit alignment of structs') @@ -597,11 +643,14 @@ def test_align64(self): } ''' - self.do_run(src, '''16,32 + self.do_run( + src, + '''16,32 0,8,8,8 16,24,24,24 0.00,10,123.46,0.00 : 0.00,10,123.46,0.00 -''') +''', + ) @only_wasm2js('tests signed vs unsigned values') def test_unsigned(self): @@ -744,11 +793,16 @@ def test_stack_align(self): src = test_file('core/test_stack_align.c') def test(): - self.do_runf(src, ['''align 4: 0 + self.do_runf( + src, + [ + '''align 4: 0 align 8: 0 align 16: 0 align 32: 0 -base align: 0, 0, 0, 0''']) +base align: 0, 0, 0, 0''' + ], + ) test() @@ -774,11 +828,13 @@ def test_mainenv(self): @no_asan('ASan does not support custom memory allocators') @no_lsan('LSan does not support custom memory allocators') - @parameterized({ - 'normal': [], - 'memvalidate': ['-DEMMALLOC_MEMVALIDATE'], - 'memvalidate_verbose': ['-DEMMALLOC_MEMVALIDATE', '-DEMMALLOC_VERBOSE', '-DRANDOM_ITERS=130'], - }) + @parameterized( + { + 'normal': [], + 'memvalidate': ['-DEMMALLOC_MEMVALIDATE'], + 'memvalidate_verbose': ['-DEMMALLOC_MEMVALIDATE', '-DEMMALLOC_VERBOSE', '-DRANDOM_ITERS=130'], + } + ) def test_emmalloc(self, *args): self.maybe_closure() # in newer clang+llvm, the internal calls to malloc in emmalloc may be optimized under @@ -788,7 +844,7 @@ def test_emmalloc(self, *args): self.emcc_args += [ '-fno-builtin', path_from_root('system/lib/libc/sbrk.c'), - path_from_root('system/lib/emmalloc.c') + path_from_root('system/lib/emmalloc.c'), ] self.emcc_args += args self.do_run_in_out_file_test('core/test_emmalloc.c') @@ -859,7 +915,7 @@ def test_longjmp_zero(self): def test_longjmp_with_and_without_exceptions(self): # Emscripten SjLj with and without Emscripten EH support self.set_setting('SUPPORT_LONGJMP', 'emscripten') - self.set_setting('DEFAULT_TO_CXX') # See comments on @with_all_eh_sjlj + self.set_setting('DEFAULT_TO_CXX') # See comments on @with_all_eh_sjlj for disable_catching in (0, 1): self.set_setting('DISABLE_EXCEPTION_CATCHING', disable_catching) self.do_core_test('test_longjmp.c') @@ -1082,7 +1138,9 @@ class MyException { } ''' - self.do_run(src, 'Throw...Construct...Caught...Destruct...Throw...Construct...Copy...Caught...Destruct...Destruct...\n') + self.do_run( + src, 'Throw...Construct...Caught...Destruct...Throw...Construct...Copy...Caught...Destruct...Destruct...\n' + ) @with_all_eh_sjlj def test_exceptions_2(self): @@ -1204,12 +1262,18 @@ def test_exceptions_allowed_misuse(self): # Test old =2 setting for DISABLE_EXCEPTION_CATCHING self.set_setting('DISABLE_EXCEPTION_CATCHING', 2) err = self.expect_fail([EMCC, test_file('hello_world.c')] + self.get_emcc_args()) - self.assertContained('error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]', err) + self.assertContained( + 'error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]', + err, + ) # =0 should also be a warning self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) err = self.expect_fail([EMCC, test_file('hello_world.c')] + self.get_emcc_args()) - self.assertContained('error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]', err) + self.assertContained( + 'error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]', + err, + ) # =1 should be a hard error self.set_setting('DISABLE_EXCEPTION_CATCHING', 1) @@ -1284,7 +1348,7 @@ def test_exceptions_uncaught_2(self): def test_exceptions_typed(self): # Depends on static destructors running self.set_setting('EXIT_RUNTIME') - self.clear_setting('SAFE_HEAP') # Throwing null will cause an ignorable null pointer access. + self.clear_setting('SAFE_HEAP') # Throwing null will cause an ignorable null pointer access. self.do_core_test('test_exceptions_typed.cpp') @with_all_eh_sjlj @@ -1369,7 +1433,9 @@ def test_EXPORT_EXCEPTION_HANDLING_HELPERS(self): self.emcc_args.append('-D__USING_EMSCRIPTEN_EXCEPTION__') self.maybe_closure() - create_file('main.cpp', ''' + create_file( + 'main.cpp', + ''' #include #include #include @@ -1423,7 +1489,8 @@ class myexception : public exception { } }); } - ''') + ''', + ) expected = '''\ int, char, @@ -1436,7 +1503,8 @@ class myexception : public exception { @with_all_eh_sjlj def test_bad_typeid(self): - self.do_run(r''' + self.do_run( + r''' // exception example #include // std::cerr #include // operator typeid @@ -1456,12 +1524,15 @@ class Polymorphic {virtual void member(){}}; } return 0; } -''', 'exception caught: std::bad_typeid') +''', + 'exception caught: std::bad_typeid', + ) @with_all_eh_sjlj def test_abort_no_dtors(self): # abort() should not run destructors - out = self.do_run(r''' + out = self.do_run( + r''' #include #include @@ -1473,13 +1544,16 @@ def test_abort_no_dtors(self): Foo f; abort(); } -''', assert_returncode=NON_ZERO) +''', + assert_returncode=NON_ZERO, + ) self.assertNotContained('Destructing Foo', out) def test_iostream_ctors(self): # iostream stuff must be globally constructed before user global # constructors, so iostream works in global constructors - self.do_run(r''' + self.do_run( + r''' #include struct A { @@ -1491,7 +1565,9 @@ def test_iostream_ctors(self): std::cout << "free code" << std::endl; return 0; } -''', 'bugfree code') +''', + 'bugfree code', + ) @with_all_eh_sjlj def test_exceptions_longjmp1(self): @@ -1535,7 +1611,10 @@ def clear_all_relevant_settings(self): self.set_setting('DISABLE_EXCEPTION_THROWING', 1) self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_emcc_args()) - self.assertContained("error: DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions", err) + self.assertContained( + "error: DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions", + err, + ) clear_all_relevant_settings(self) # When using Wasm EH, users are not supposed to explicitly pass @@ -1545,12 +1624,18 @@ def clear_all_relevant_settings(self): # test setting includes -Werror. self.set_setting('DISABLE_EXCEPTION_THROWING', 1) err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_emcc_args()) - self.assertContained('error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', err) + self.assertContained( + 'error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', + err, + ) clear_all_relevant_settings(self) self.set_setting('DISABLE_EXCEPTION_CATCHING', 1) err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_emcc_args()) - self.assertContained('error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', err) + self.assertContained( + 'error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', + err, + ) clear_all_relevant_settings(self) # Emscripten SjLj and Wasm EH cannot mix @@ -1575,14 +1660,19 @@ def clear_all_relevant_settings(self): # Wasm EH does not support ASYNCIFY=1 self.set_setting('ASYNCIFY', 1) err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_emcc_args()) - self.assertContained('error: ASYNCIFY=1 is not compatible with -fwasm-exceptions. Parts of the program that mix ASYNCIFY and exceptions will not compile.', err) + self.assertContained( + 'error: ASYNCIFY=1 is not compatible with -fwasm-exceptions. Parts of the program that mix ASYNCIFY and exceptions will not compile.', + err, + ) clear_all_relevant_settings(self) # EXPORT_EXCEPTION_HANDLING_HELPERS and EXCEPTION_STACK_TRACES requires # either Emscripten EH or Wasm EH self.set_setting('EXPORT_EXCEPTION_HANDLING_HELPERS') err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_emcc_args()) - self.assertContained('error: EXPORT_EXCEPTION_HANDLING_HELPERS requires either of -fexceptions or -fwasm-exceptions', err) + self.assertContained( + 'error: EXPORT_EXCEPTION_HANDLING_HELPERS requires either of -fexceptions or -fwasm-exceptions', err + ) clear_all_relevant_settings(self) self.set_setting('EXCEPTION_STACK_TRACES') @@ -1618,7 +1708,8 @@ def test_segfault(self): for addr in ('get_null()', 'new D2()'): print(addr) - src = r''' + src = ( + r''' #include #include @@ -1651,7 +1742,9 @@ def test_segfault(self): return 0; } - ''' % addr + ''' + % addr + ) if 'get_null' in addr: self.do_run(src, 'segmentation fault', assert_returncode=NON_ZERO) else: @@ -1679,7 +1772,7 @@ def test_rename(self): self.do_run_in_out_file_test('stdio/test_rename.c') def test_remove(self): - self.do_run_in_out_file_test('stdio/test_remove.c') + self.do_run_in_out_file_test('stdio/test_remove.c') def test_alloca_stack(self): self.do_core_test('test_alloca_stack.c') @@ -1813,7 +1906,8 @@ def test_inlinejs3(self): self.do_run(src, read_file(output)) def test_inlinejs4(self): - self.do_run(r''' + self.do_run( + r''' #include #define TO_STRING_INNER(x) #x @@ -1830,7 +1924,10 @@ def test_inlinejs4(self): assert(false); return 0; } -''', 'false', assert_returncode=NON_ZERO) +''', + 'false', + assert_returncode=NON_ZERO, + ) def test_em_asm(self): self.maybe_closure() @@ -1853,10 +1950,12 @@ def test_em_asm_2(self): # test_em_asm_2, just search-replaces EM_ASM to MAIN_THREAD_EM_ASM on the test # file. That way if new test cases are added to test_em_asm_2.cpp for EM_ASM, # they will also get tested in MAIN_THREAD_EM_ASM form. - @parameterized({ - '': ([],), - 'pthread': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), - }) + @parameterized( + { + '': ([],), + 'pthread': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), + } + ) def test_main_thread_em_asm(self, args): if args: self.setup_node_pthreads() @@ -1870,11 +1969,13 @@ def test_main_thread_em_asm(self, args): self.do_run_in_out_file_test('test.cpp', emcc_args=args, force_c=True) @needs_dylink - @parameterized({ - '': ([], False), - 'relocatable': (['-sMAIN_MODULE=2'], False), - 'force_c': ([], True), - }) + @parameterized( + { + '': ([], False), + 'relocatable': (['-sMAIN_MODULE=2'], False), + 'force_c': ([], True), + } + ) def test_main_thread_async_em_asm(self, args, force_c=False): self.do_core_test('test_main_thread_async_em_asm.cpp', emcc_args=args, force_c=force_c) @@ -1912,17 +2013,24 @@ def test_em_asm_direct(self): @needs_dylink def test_em_asm_side_module(self): - self.build(test_file('core/test_em_asm_side.c'), js_outfile=False, emcc_args=['-sSIDE_MODULE'], output_basename='side') + self.build( + test_file('core/test_em_asm_side.c'), js_outfile=False, emcc_args=['-sSIDE_MODULE'], output_basename='side' + ) self.do_core_test('test_em_asm_main.c', emcc_args=['-sMAIN_MODULE=2', 'side.wasm']) - @parameterized({ - '': ([], False), - 'pthreads': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'], False), - 'pthreads_dylink': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-sMAIN_MODULE=2', '-Wno-experimental'], False), - 'c': ([], True), - 'dylink': (['-sMAIN_MODULE=2'], False), - 'dylink_c': (['-sMAIN_MODULE=2'], True), - }) + @parameterized( + { + '': ([], False), + 'pthreads': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'], False), + 'pthreads_dylink': ( + ['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-sMAIN_MODULE=2', '-Wno-experimental'], + False, + ), + 'c': ([], True), + 'dylink': (['-sMAIN_MODULE=2'], False), + 'dylink_c': (['-sMAIN_MODULE=2'], True), + } + ) @crossplatform def test_em_js(self, args, force_c): if '-sMAIN_MODULE=2' in args: @@ -1937,7 +2045,9 @@ def test_em_js(self, args, force_c): @no_wasm2js('test depends on WASM_BIGINT which is not compatible with wasm2js') def test_em_js_i64(self): err = self.expect_fail([EMCC, '-Werror', '-sWASM_BIGINT=0', test_file('core/test_em_js_i64.c')]) - self.assertContained('emcc: error: using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `foo`', err) + self.assertContained( + 'emcc: error: using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `foo`', err + ) self.node_args += shared.node_bigint_flags(self.get_nodejs()) self.do_core_test('test_em_js_i64.c') @@ -1990,9 +2100,11 @@ def test_memorygrowth(self): # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized) code_start = '// EMSCRIPTEN_START_FUNCS' self.assertContained(code_start, fail) - fail = fail[fail.find(code_start):] - win = win[win.find(code_start):] - assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str([len(fail), len(win)]) + fail = fail[fail.find(code_start) :] + win = win[win.find(code_start) :] + assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str( + [len(fail), len(win)] + ) # Tracing of memory growths should work # (SAFE_HEAP would instrument the tracing code itself, leading to recursion) @@ -2021,7 +2133,9 @@ def test_memorygrowth_2(self): if '-O2' in self.emcc_args and self.is_wasm2js(): # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized) - assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str([len(fail), len(win)]) + assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str( + [len(fail), len(win)] + ) def test_memorygrowth_3(self): if self.has_changed_setting('ALLOW_MEMORY_GROWTH'): @@ -2054,7 +2168,13 @@ def test_memorygrowth_linear_step(self): self.skipTest('wasm memory specific test') # check that memory growth does not exceed the wasm mem max limit and is exactly or one step below the wasm mem max - self.emcc_args += ['-sALLOW_MEMORY_GROWTH', '-sSTACK_SIZE=1Mb', '-sINITIAL_MEMORY=64Mb', '-sMAXIMUM_MEMORY=130Mb', '-sMEMORY_GROWTH_LINEAR_STEP=1Mb'] + self.emcc_args += [ + '-sALLOW_MEMORY_GROWTH', + '-sSTACK_SIZE=1Mb', + '-sINITIAL_MEMORY=64Mb', + '-sMAXIMUM_MEMORY=130Mb', + '-sMEMORY_GROWTH_LINEAR_STEP=1Mb', + ] self.do_core_test('test_memorygrowth_linear_step.c') @no_ubsan('UBSan seems to effect the precise memory usage') @@ -2066,7 +2186,12 @@ def test_memorygrowth_geometric_step(self): if self.is_wasm2js(): self.skipTest('wasm memory specific test') - self.emcc_args += ['-sINITIAL_MEMORY=16MB', '-sALLOW_MEMORY_GROWTH', '-sMEMORY_GROWTH_GEOMETRIC_STEP=8.5', '-sMEMORY_GROWTH_GEOMETRIC_CAP=32MB'] + self.emcc_args += [ + '-sINITIAL_MEMORY=16MB', + '-sALLOW_MEMORY_GROWTH', + '-sMEMORY_GROWTH_GEOMETRIC_STEP=8.5', + '-sMEMORY_GROWTH_GEOMETRIC_CAP=32MB', + ] self.do_core_test('test_memorygrowth_geometric_step.c') def test_memorygrowth_3_force_fail_reallocBuffer(self): @@ -2078,10 +2203,7 @@ def test_memorygrowth_3_force_fail_reallocBuffer(self): self.add_pre_run('growMemory = (size) => false;') self.do_core_test('test_memorygrowth_3.c') - @parameterized({ - 'nogrow': ([],), - 'grow': (['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=18MB'],) - }) + @parameterized({'nogrow': ([],), 'grow': (['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=18MB'],)}) @no_asan('requires more memory when growing') @no_lsan('requires more memory when growing') @no_4gb('depends on MAXIMUM_MEMORY') @@ -2092,10 +2214,12 @@ def test_aborting_new(self, args): self.emcc_args += args self.do_core_test('test_aborting_new.cpp') - @parameterized({ - 'nogrow': (['-sABORTING_MALLOC=0'],), - 'grow': (['-sABORTING_MALLOC=0', '-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=18MB'],) - }) + @parameterized( + { + 'nogrow': (['-sABORTING_MALLOC=0'],), + 'grow': (['-sABORTING_MALLOC=0', '-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=18MB'],), + } + ) @no_asan('requires more memory when growing') @no_lsan('requires more memory when growing') @no_4gb('depends on MAXIMUM_MEMORY') @@ -2116,7 +2240,7 @@ def test_module_wasm_memory(self): self.set_setting('INCOMING_MODULE_JS_API', ['wasmMemory']) self.do_runf('core/test_module_wasm_memory.c', 'success') - def test_ssr(self): # struct self-ref + def test_ssr(self): # struct self-ref src = ''' #include @@ -2158,11 +2282,15 @@ def test_bigswitch(self): if not self.is_optimizing(): self.skipTest('nodejs takes ~4GB to compile this if the wasm is not optimized, which OOMs') self.set_setting('USE_SDL') - self.do_runf('bigswitch.cpp', '''34962: GL_ARRAY_BUFFER (0x8892) + self.do_runf( + 'bigswitch.cpp', + '''34962: GL_ARRAY_BUFFER (0x8892) 26214: what? 35040: GL_STREAM_DRAW (0x88E0) 3060: what? -''', args=['34962', '26214', '35040', str(0xbf4)]) +''', + args=['34962', '26214', '35040', str(0xBF4)], + ) @no_wasm2js('massive switches can break js engines') @is_slow_test @@ -2170,14 +2298,21 @@ def test_biggerswitch(self): if self.is_optimizing(): self.skipTest('https://github.com/emscripten-core/emscripten/issues/22179') if not self.is_optimizing(): - self.skipTest('nodejs takes >6GB to compile this if the wasm is not optimized, which OOMs, see https://github.com/emscripten-core/emscripten/issues/7928#issuecomment-458308453') + self.skipTest( + 'nodejs takes >6GB to compile this if the wasm is not optimized, which OOMs, see https://github.com/emscripten-core/emscripten/issues/7928#issuecomment-458308453' + ) num_cases = 20000 - switch_case = self.run_process([PYTHON, test_file('gen_large_switchcase.py'), str(num_cases)], stdout=PIPE, stderr=PIPE).stdout - self.do_run(switch_case, '''58996: 589965899658996 + switch_case = self.run_process( + [PYTHON, test_file('gen_large_switchcase.py'), str(num_cases)], stdout=PIPE, stderr=PIPE + ).stdout + self.do_run( + switch_case, + '''58996: 589965899658996 59297: 592975929759297 59598: default 59899: 598995989959899 -Success!''') +Success!''', + ) @no_ubsan('local count too large for VMs') def test_indirectbr(self): @@ -2190,7 +2325,9 @@ def test_indirectbr(self): @no_wasm2js('extremely deep nesting, hits stack limit on some VMs') def test_indirectbr_many(self): if not self.is_optimizing(): - self.skipTest('nodejs takes ~1.8GB to compile this if the wasm is not optimized, which can cause OOM on the test runners') + self.skipTest( + 'nodejs takes ~1.8GB to compile this if the wasm is not optimized, which can cause OOM on the test runners' + ) self.do_core_test('test_indirectbr_many.c') def test_pack(self): @@ -2293,11 +2430,14 @@ def test_varargs_byval(self): printf("The current type of b is: %d\n", b.tt); } ''' - self.do_run(src, '''The original address of a is: 0x12345678 + self.do_run( + src, + '''The original address of a is: 0x12345678 The original type of b is: 9 The current address of a is: 0x12345678 The current type of b is: 9 -''') +''', + ) def test_functionpointer_libfunc_varargs(self): self.do_core_test('test_functionpointer_libfunc_varargs.c') @@ -2354,7 +2494,9 @@ def test_stdlibs(self): self.do_core_test('test_stdlibs.c', out_suffix=out_suffix) def test_stdbool(self): - create_file('test_stdbool.c', r''' + create_file( + 'test_stdbool.c', + r''' #include #include @@ -2364,7 +2506,8 @@ def test_stdbool(self): printf("*%d*\n", x != y); return 0; } - ''') + ''', + ) self.do_runf('test_stdbool.c', '*1*') @@ -2435,10 +2578,12 @@ def test_pthread_equal(self): self.do_run_in_out_file_test('pthread/test_pthread_equal.cpp') @node_pthreads - @parameterized({ + @parameterized( + { '': (False,), 'modularize': (True,), - }) + } + ) def test_pthread_proxying(self, modularize): if modularize and self.get_setting('WASM') == 0: self.skipTest('MODULARIZE + WASM=0 + pthreads does not work (#16794)') @@ -2451,16 +2596,14 @@ def test_pthread_proxying(self, modularize): self.set_setting('MODULARIZE') self.set_setting('EXPORT_NAME=ModuleFactory') args = ['--extern-post-js', test_file('modularize_post_js.js')] - self.do_run_in_out_file_test('pthread/test_pthread_proxying.c', - interleaved_output=False, emcc_args=args) + self.do_run_in_out_file_test('pthread/test_pthread_proxying.c', interleaved_output=False, emcc_args=args) @node_pthreads def test_pthread_proxying_cpp(self): self.set_setting('PROXY_TO_PTHREAD') if not self.has_changed_setting('INITIAL_MEMORY'): self.set_setting('INITIAL_MEMORY=32mb') - self.do_run_in_out_file_test('pthread/test_pthread_proxying_cpp.cpp', - interleaved_output=False) + self.do_run_in_out_file_test('pthread/test_pthread_proxying_cpp.cpp', interleaved_output=False) @node_pthreads def test_pthread_proxying_dropped_work(self): @@ -2470,9 +2613,7 @@ def test_pthread_proxying_dropped_work(self): @node_pthreads def test_pthread_proxying_canceled_work(self): self.set_setting('PROXY_TO_PTHREAD') - self.do_run_in_out_file_test( - 'pthread/test_pthread_proxying_canceled_work.c', - interleaved_output=False) + self.do_run_in_out_file_test('pthread/test_pthread_proxying_canceled_work.c', interleaved_output=False) @node_pthreads @flaky('https://github.com/emscripten-core/emscripten/issues/19795') @@ -2622,10 +2763,12 @@ def test_copyop(self): # (llvm-gcc copies items one by one). self.do_core_test('test_copyop.cpp') - @parameterized({ - '': ([],), - 'bulkmem': (['-mbulk-memory'],), - }) + @parameterized( + { + '': ([],), + 'bulkmem': (['-mbulk-memory'],), + } + ) def test_memcpy_zero_bytes(self, args): self.do_core_test('test_memcpy_zero_bytes.c', emcc_args=['-fno-builtin'] + args) @@ -2678,7 +2821,9 @@ def test_legacy_stack_deps(self): # functions that must be $-prefixed in `__deps` lists. However, # to support legacy code we continue to support the non-prefixed # versions in `__deps` lists. - create_file('lib.js', ''' + create_file( + 'lib.js', + ''' addToLibrary({ foo__deps: ['stackSave', 'stackRestore'], foo: () => { @@ -2686,13 +2831,17 @@ def test_legacy_stack_deps(self): stackRestore(a); return 0; } - })''') - create_file('main.c', ''' + })''', + ) + create_file( + 'main.c', + ''' int foo(); int main() { return foo(); - }''') + }''', + ) self.do_runf('main.c', emcc_args=['--js-library=lib.js']) def test_nestedstructs(self): @@ -2838,15 +2987,19 @@ def test_dlfcn_missing(self): self.do_run(src, expected) @needs_dylink - @parameterized({ - '': ([],), - 'pthreads': (['-pthread', '-sEXIT_RUNTIME', '-sPROXY_TO_PTHREAD', '-Wno-experimental'],), - }) + @parameterized( + { + '': ([],), + 'pthreads': (['-pthread', '-sEXIT_RUNTIME', '-sPROXY_TO_PTHREAD', '-Wno-experimental'],), + } + ) def test_dlfcn_basic(self, args): if args: self.setup_node_pthreads() self.emcc_args += args - create_file('liblib.cpp', ''' + create_file( + 'liblib.cpp', + ''' #include class Foo { @@ -2857,7 +3010,8 @@ class Foo { }; Foo side_global; - ''') + ''', + ) self.build_dlfcn_lib('liblib.cpp') self.prep_dlfcn_main() @@ -2883,13 +3037,16 @@ class Bar { @needs_dylink def test_dlfcn_i64(self): - create_file('liblib.c', ''' + create_file( + 'liblib.c', + ''' #include int64_t foo(int x) { return (long long)x / (long long)1234; } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() @@ -2922,7 +3079,9 @@ def test_dlfcn_i64(self): @needs_dylink def test_dlfcn_em_asm(self): - create_file('liblib.cpp', ''' + create_file( + 'liblib.cpp', + ''' #include class Foo { public: @@ -2931,7 +3090,8 @@ class Foo { } }; Foo side_global; - ''') + ''', + ) self.build_dlfcn_lib('liblib.cpp') self.prep_dlfcn_main() @@ -2955,7 +3115,9 @@ class Bar { @needs_dylink def test_dlfcn_qsort(self): - create_file('liblib.c', ''' + create_file( + 'liblib.c', + ''' int lib_cmp(const void* left, const void* right) { const int* a = (const int*) left; const int* b = (const int*) right; @@ -2969,7 +3131,8 @@ def test_dlfcn_qsort(self): CMP_TYPE get_cmp() { return lib_cmp; } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() @@ -3026,7 +3189,9 @@ def test_dlfcn_qsort(self): @needs_dylink def test_dlfcn_data_and_fptr(self): - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include int theglobal = 42; @@ -3051,7 +3216,8 @@ def test_dlfcn_data_and_fptr(self): fptr(); return lib_fptr; } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() @@ -3108,26 +3274,33 @@ def test_dlfcn_data_and_fptr(self): return 0; } ''' - self.do_run(src, '''\ + self.do_run( + src, + '''\ In func: 13 First calling main_fptr from lib. Second calling lib_fptr from main. parent_func called from child parent_func called from child Var: 42 -''', force_c=True) +''', + force_c=True, + ) @needs_dylink def test_dlfcn_varargs(self): # this test is not actually valid - it fails natively. the child should fail # to be loaded, not load and successfully see the parent print_ints func - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' void print_ints(int n, ...); void func() { print_ints(2, 13, 42); } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() @@ -3168,11 +3341,14 @@ def test_dlfcn_varargs(self): @no_4gb('output is sensitive to absolute data layout') def test_dlfcn_alignment_and_zeroing(self): self.set_setting('INITIAL_MEMORY', '16mb') - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' int prezero = 0; __attribute__((aligned(1024))) int superAligned = 12345; int postzero = 0; - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') for i in range(10): curr = '%d.so' % i @@ -3180,7 +3356,9 @@ def test_dlfcn_alignment_and_zeroing(self): self.prep_dlfcn_main() self.set_setting('INITIAL_MEMORY', '128mb') - create_file('src.c', r''' + create_file( + 'src.c', + r''' #include #include #include @@ -3235,7 +3413,8 @@ def test_dlfcn_alignment_and_zeroing(self): printf("success.\n"); return 0; } - ''') + ''', + ) self.do_runf('src.c', 'success.\n') @needs_dylink @@ -3273,17 +3452,22 @@ def get_data_exports(wasm): @needs_dylink def test_dlfcn_unique_sig(self): - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include int myfunc(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m) { return 13; } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include @@ -3305,22 +3489,28 @@ def test_dlfcn_unique_sig(self): return 0; } - ''') + ''', + ) self.do_runf('main.c', 'success') @needs_dylink def test_dlfcn_info(self): - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include int myfunc(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m) { return 13; } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() - create_file('main.c', ''' + create_file( + 'main.c', + ''' #include #include #include @@ -3352,12 +3542,15 @@ def test_dlfcn_info(self): return 0; } - ''') + ''', + ) self.do_runf('main.c', 'success') @needs_dylink def test_dlfcn_stacks(self): - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include #include #include @@ -3371,11 +3564,14 @@ def test_dlfcn_stacks(self): snprintf(bigstack, sizeof(bigstack), "%s", input); return strlen(bigstack); } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() - create_file('main.c', ''' + create_file( + 'main.c', + ''' #include #include #include @@ -3405,12 +3601,15 @@ def test_dlfcn_stacks(self): return 0; } - ''') + ''', + ) self.do_runf('main.c', 'success') @needs_dylink def test_dlfcn_funcs(self): - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include #include #include @@ -3440,11 +3639,14 @@ def test_dlfcn_funcs(self): default: return NULL; } } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include @@ -3490,8 +3692,11 @@ def test_dlfcn_funcs(self): puts("ok"); return 0; } - ''') - self.do_runf('main.c', '''go + ''', + ) + self.do_runf( + 'main.c', + '''go void_main. int_main 201 void 0 @@ -3499,11 +3704,14 @@ def test_dlfcn_funcs(self): int 0 54 int 1 9000 ok -''') +''', + ) @needs_dylink def test_dlfcn_longjmp(self): - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include #include @@ -3513,11 +3721,14 @@ def test_dlfcn_longjmp(self): if (i == 10) longjmp(buf, i); printf("pre %d\n", i); } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include @@ -3545,8 +3756,11 @@ def test_dlfcn_longjmp(self): return 0; } - ''') - self.do_runf('main.c', '''go! + ''', + ) + self.do_runf( + 'main.c', + '''go! pre 1 pre 2 pre 3 @@ -3557,7 +3771,8 @@ def test_dlfcn_longjmp(self): pre 8 pre 9 out! -''') +''', + ) # TODO: make this work. need to forward tempRet0 across modules # TODO Enable @with_all_eh_sjlj (the test is not working now) @@ -3565,7 +3780,9 @@ def test_dlfcn_longjmp(self): def zzztest_dlfcn_exceptions(self): self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) - create_file('liblib.cpp', r''' + create_file( + 'liblib.cpp', + r''' extern "C" { int ok() { return 65; @@ -3574,7 +3791,8 @@ def zzztest_dlfcn_exceptions(self): throw 123; } } - ''') + ''', + ) self.build_dlfcn_lib('liblib.cpp') self.prep_dlfcn_main() @@ -3617,11 +3835,14 @@ def zzztest_dlfcn_exceptions(self): return 0; } ''' - self.do_run(src, '''go! + self.do_run( + src, + '''go! ok: 65 int 123 ok -''') +''', + ) @needs_dylink def test_dlfcn_handle_alloc(self): @@ -3631,7 +3852,9 @@ def test_dlfcn_handle_alloc(self): def indir(name): return os.path.join(dirname, name) - create_file('a.cpp', r''' + create_file( + 'a.cpp', + r''' #include static class A { @@ -3640,9 +3863,12 @@ def indir(name): puts("a: loaded"); } } _; - ''') + ''', + ) - create_file('b.cpp', r''' + create_file( + 'b.cpp', + r''' #include static class B { @@ -3651,7 +3877,8 @@ def indir(name): puts("b: loaded"); } } _; - ''') + ''', + ) self.build_dlfcn_lib('a.cpp', outfile='liba.so') self.build_dlfcn_lib('b.cpp', outfile='libb.so') @@ -3659,7 +3886,9 @@ def indir(name): self.set_setting('MAIN_MODULE') self.clear_setting('SIDE_MODULE') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include @@ -3685,7 +3914,8 @@ def indir(name): return 0; } - ''') + ''', + ) self.do_runf('main.c', 'a: loaded\nb: loaded\n') @needs_dylink @@ -3693,11 +3923,14 @@ def indir(name): def test_dlfcn_feature_in_lib(self): self.emcc_args.append('-mnontrapping-fptoint') - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' int magic(float x) { return __builtin_wasm_trunc_saturate_s_i32_f32(x); } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() @@ -3729,7 +3962,9 @@ def test_dlfcn_feature_in_lib(self): def test_dlfcn_asyncify(self): self.set_setting('ASYNCIFY') - create_file('liblib.c', r''' + create_file( + 'liblib.c', + r''' #include #include @@ -3739,7 +3974,8 @@ def test_dlfcn_asyncify(self): printf("after sleep\n"); return 42; } - ''') + ''', + ) self.build_dlfcn_lib('liblib.c') self.prep_dlfcn_main() @@ -3763,7 +3999,9 @@ def test_dlfcn_rtld_local(self): # Create two shared libraries that both depend on a third. # liba.so -> libsub.so # libb.so -> libsub.so - create_file('liba.c', r''' + create_file( + 'liba.c', + r''' #include void func_sub(); @@ -3774,9 +4012,12 @@ def test_dlfcn_rtld_local(self): // be available here even though liba itself is loaded with RTLD_LOCAL. func_sub(); } - ''') + ''', + ) - create_file('libb.c', r''' + create_file( + 'libb.c', + r''' #include void func_sub(); @@ -3787,22 +4028,28 @@ def test_dlfcn_rtld_local(self): // be available here even though liba itself is loaded with RTLD_LOCAL. func_sub(); } - ''') + ''', + ) - create_file('libsub.c', r''' + create_file( + 'libsub.c', + r''' #include void func_sub() { printf("func_sub\n"); } - ''') + ''', + ) self.build_dlfcn_lib('libsub.c', outfile='libsub.so') self.build_dlfcn_lib('libb.c', outfile='libb.so', emcc_args=['libsub.so']) self.build_dlfcn_lib('liba.c', outfile='liba.so', emcc_args=['libsub.so']) self.prep_dlfcn_main(['liba.so', 'libb.so', '-L.']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include #include @@ -3840,7 +4087,8 @@ def test_dlfcn_rtld_local(self): printf("done\n"); return 0; } - ''') + ''', + ) self.do_runf('main.c', 'main\nfunc_a\nfunc_sub\nfunc_b\nfunc_sub\ndone\n') @@ -3848,26 +4096,36 @@ def test_dlfcn_rtld_local(self): def test_dlfcn_preload(self): # Create chain of dependencies and load the first libary with preload plugin. # main -> libb.so -> liba.so - create_file('liba.c', r''' + create_file( + 'liba.c', + r''' #include int liba_fun() { return 23; } - ''') + ''', + ) self.build_dlfcn_lib('liba.c', outfile='liba.so') - create_file('libb.c', r''' + create_file( + 'libb.c', + r''' #include int liba_fun(); int libb_fun() { return liba_fun()*2; } - ''') + ''', + ) self.build_dlfcn_lib('libb.c', outfile='libb.so', emcc_args=['liba.so']) - self.prep_dlfcn_main(['--preload-file', 'libb.so', '--use-preload-plugins', '-L.', '-sAUTOLOAD_DYLIBS=0', 'libb.so']) - create_file('main.c', r''' + self.prep_dlfcn_main( + ['--preload-file', 'libb.so', '--use-preload-plugins', '-L.', '-sAUTOLOAD_DYLIBS=0', 'libb.so'] + ) + create_file( + 'main.c', + r''' #include #include #include @@ -3887,11 +4145,11 @@ def test_dlfcn_preload(self): return 0; } - ''') + ''', + ) self.do_runf('main.c', 'done\n') - def dylink_test(self, main, side, expected=None, header=None, force_c=False, - main_module=2, **kwargs): + def dylink_test(self, main, side, expected=None, header=None, force_c=False, main_module=2, **kwargs): # Same as dylink_testf but take source code in string form if not isinstance(side, list): side_file = 'liblib.cpp' if not force_c else 'liblib.c' @@ -3906,11 +4164,18 @@ def dylink_test(self, main, side, expected=None, header=None, force_c=False, return self.dylink_testf(main, side, expected, main_module=main_module, **kwargs) - def dylink_testf(self, main, side=None, expected=None, force_c=False, main_emcc_args=None, - main_module=2, - so_dir='', - so_name='liblib.so', - **kwargs): + def dylink_testf( + self, + main, + side=None, + expected=None, + force_c=False, + main_emcc_args=None, + main_module=2, + so_dir='', + so_name='liblib.so', + **kwargs, + ): main_emcc_args = main_emcc_args or [] if getattr(self, 'dylink_reversed', False): # Test the reverse case. There we flip the role of the side module and main module. @@ -3961,7 +4226,8 @@ def dylink_testf(self, main, side=None, expected=None, force_c=False, main_emcc_ self.emcc_args = old_args def do_basic_dylink_test(self, **kwargs): - self.dylink_test(r''' + self.dylink_test( + r''' #include #include "header.h" @@ -3969,13 +4235,19 @@ def do_basic_dylink_test(self, **kwargs): printf("other says %d.\n", sidey()); return 0; } - ''', ''' + ''', + ''' #include "header.h" int sidey() { return 11; } - ''', 'other says 11.', 'int sidey();', force_c=True, **kwargs) + ''', + 'other says 11.', + 'int sidey();', + force_c=True, + **kwargs, + ) @needs_dylink @crossplatform @@ -4015,7 +4287,9 @@ def test_dylink_locate_file(self): so_dir = 'so_dir' so_name = 'liblib.so' os.mkdir(so_dir) - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module['locateFile'] = function(f) { if (f === '%s') { return '%s/' + f; @@ -4023,12 +4297,15 @@ def test_dylink_locate_file(self): return f; } }; - ''' % (so_name, so_dir)) + ''' + % (so_name, so_dir), + ) self.do_basic_dylink_test(so_dir=so_dir, so_name=so_name, main_emcc_args=['--pre-js', 'pre.js']) @with_dylink_reversed def test_dylink_function_pointer_equality(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include #include "header.h" @@ -4042,31 +4319,42 @@ def test_dylink_function_pointer_equality(self): printf("failure\n"); return 0; } - ''', ''' + ''', + ''' #include #include "header.h" void* get_address() { return (void*)&puts; } - ''', 'success', header='void* get_address();', force_c=True) + ''', + 'success', + header='void* get_address();', + force_c=True, + ) @with_dylink_reversed def test_dylink_floats(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include extern float sidey(); int main() { printf("other says %.2f.\n", sidey()+1); return 0; } - ''', ''' + ''', + ''' float sidey() { return 11.5; } - ''', 'other says 12.50', force_c=True) + ''', + 'other says 12.50', + force_c=True, + ) @with_dylink_reversed def test_dylink_printf(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include void sidey(); int main() { @@ -4074,12 +4362,16 @@ def test_dylink_printf(self): sidey(); return 0; } - ''', r''' + ''', + r''' #include void sidey() { printf("hello from side\n"); } - ''', 'hello from main\nhello from side\n', force_c=True) + ''', + 'hello from main\nhello from side\n', + force_c=True, + ) # Verify that a function pointer can be passed back and forth and invoked # on both sides. @@ -4104,7 +4396,9 @@ def test_dylink_funcpointer(self): intfunc sidey(intfunc f) { f(1); return f; } ''', expected='hello from funcptr: 1\nhello from funcptr: 0\n', - header='typedef void (*intfunc)(int );', force_c=True) + header='typedef void (*intfunc)(int );', + force_c=True, + ) @with_dylink_reversed # test dynamic linking of a module with multiple function pointers, stored @@ -4130,7 +4424,9 @@ def test_dylink_static_funcpointers(self): void sidey(voidfunc f) { f(); } ''', expected='hello 0\nhello 1\nhello 2\n', - header='typedef void (*voidfunc)(); void sidey(voidfunc f);', force_c=True) + header='typedef void (*voidfunc)(); void sidey(voidfunc f);', + force_c=True, + ) @with_dylink_reversed def test_dylink_funcpointers_wrapper(self): @@ -4157,7 +4453,9 @@ def test_dylink_funcpointers_wrapper(self): #include typedef void (*charfunc)(const char*); extern charfunc get(); - ''', force_c=True) + ''', + force_c=True, + ) @with_dylink_reversed def test_dylink_static_funcpointer_float(self): @@ -4179,11 +4477,14 @@ def test_dylink_static_funcpointer_float(self): int sidey(floatfunc f) { f(56.78); return 1; } ''', expected='hello 1: 56.779999\ngot: 1\nhello 1: 12.340000\n', - header='typedef float (*floatfunc)(float);', force_c=True) + header='typedef float (*floatfunc)(float);', + force_c=True, + ) @with_dylink_reversed def test_dylink_global_init(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include struct Class { Class() { printf("a new Class\n"); } @@ -4192,28 +4493,37 @@ def test_dylink_global_init(self): int main() { return 0; } - ''', r''' + ''', + r''' void nothing() {} - ''', 'a new Class\n') + ''', + 'a new Class\n', + ) @with_dylink_reversed def test_dylink_global_inits(self): def test(): - self.dylink_test(header=r''' + self.dylink_test( + header=r''' #include struct Class { Class(const char *name) { printf("new %s\n", name); } }; - ''', main=r''' + ''', + main=r''' #include "header.h" static Class c("main"); int main() { return 0; } - ''', side=r''' + ''', + side=r''' #include "header.h" static Class c("side"); - ''', expected=['new main\nnew side\n', 'new side\nnew main\n']) + ''', + expected=['new main\nnew side\n', 'new side\nnew main\n'], + ) + test() print('check warnings') @@ -4225,7 +4535,8 @@ def test(): @with_dylink_reversed def test_dylink_i64(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include #include extern int64_t sidey(); @@ -4233,17 +4544,22 @@ def test_dylink_i64(self): printf("other says %lld.\n", sidey()); return 0; } - ''', ''' + ''', + ''' #include int64_t sidey() { return 42; } - ''', 'other says 42.', force_c=True) + ''', + 'other says 42.', + force_c=True, + ) @with_dylink_reversed @all_engines def test_dylink_i64_b(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include #include extern int64_t sidey(); @@ -4264,7 +4580,8 @@ def test_dylink_i64_b(self): int64_t rb = hb(42); printf("my second fp says: %lld.\n", r); } - ''', ''' + ''', + ''' #include int64_t sidey() { volatile int64_t x = 0x12345678abcdef12LL; @@ -4272,12 +4589,16 @@ def test_dylink_i64_b(self): x = 18 - x; return x; } - ''', 'other says -1311768467750121224.\nmy fp says: 43.\nmy second fp says: 43.', force_c=True) + ''', + 'other says -1311768467750121224.\nmy fp says: 43.\nmy second fp says: 43.', + force_c=True, + ) @with_dylink_reversed @also_with_wasm_bigint def test_dylink_i64_c(self): - self.dylink_test(r''' + self.dylink_test( + r''' #include #include #include "header.h" @@ -4308,7 +4629,8 @@ def test_dylink_i64_c(self): printf("res64 - external %" PRId64 "\n", eres64); return 0; } - ''', '''\ + ''', + '''\ #include "header.h" int32_t function_ret_32(int32_t i, int32_t j, int32_t k) { return 32; @@ -4316,21 +4638,27 @@ def test_dylink_i64_c(self): int64_t function_ret_64(int32_t i, int32_t j, int32_t k) { return 64; } - ''', '''\ + ''', + '''\ res32 - internal 32 res32 - external 32 res64 - internal 64 -res64 - external 64\n''', header='''\ +res64 - external 64\n''', + header='''\ #include #include EMSCRIPTEN_KEEPALIVE int32_t function_ret_32(int32_t i, int32_t j, int32_t k); EMSCRIPTEN_KEEPALIVE int64_t function_ret_64(int32_t i, int32_t j, int32_t k); - ''', force_c=True) + ''', + force_c=True, + ) - @parameterized({ - '': (False,), - 'rtld_local': (True,), - }) + @parameterized( + { + '': (False,), + 'rtld_local': (True,), + } + ) @needs_dylink @also_with_wasm_bigint def test_dylink_i64_invoke(self, rtld_local): @@ -4338,7 +4666,8 @@ def test_dylink_i64_invoke(self, rtld_local): self.set_setting('NO_AUTOLOAD_DYLIBS') self.emcc_args.append('-DUSE_DLOPEN') self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) - self.dylink_test(r'''\ + self.dylink_test( + r'''\ #include #include #include @@ -4362,7 +4691,8 @@ def test_dylink_i64_invoke(self, rtld_local): printf("got %lld\n", sidey(temp)); printf("got %lld\n", sidey(0)); return 0; - }''', r'''\ + }''', + r'''\ #include #include #include @@ -4382,42 +4712,55 @@ def test_dylink_i64_invoke(self, rtld_local): return 0; } } - }''', 'got 84\ngot 0') + }''', + 'got 84\ngot 0', + ) @with_dylink_reversed def test_dylink_class(self): - self.dylink_test(header=r''' + self.dylink_test( + header=r''' #include struct Class { Class(const char *name); }; - ''', main=r''' + ''', + main=r''' #include "header.h" int main() { Class c("main"); return 0; } - ''', side=r''' + ''', + side=r''' #include "header.h" Class::Class(const char *name) { printf("new %s\n", name); } - ''', expected=['new main\n']) + ''', + expected=['new main\n'], + ) @with_dylink_reversed def test_dylink_global_var(self): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include extern int x; int main() { printf("extern is %d.\n", x); return 0; } - ''', side=r''' + ''', + side=r''' int x = 123; - ''', expected=['extern is 123.\n'], force_c=True) + ''', + expected=['extern is 123.\n'], + force_c=True, + ) @needs_dylink def test_dylink_global_var_export(self): - self.do_run(r''' + self.do_run( + r''' #include #include #include @@ -4434,34 +4777,43 @@ def test_dylink_global_var_export(self): assert(js_address == &my_number); return 0; } - ''', emcc_args=['-sMAIN_MODULE'], force_c=True) + ''', + emcc_args=['-sMAIN_MODULE'], + force_c=True, + ) @with_dylink_reversed def test_dylink_global_var_modded(self): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include extern int x; int main() { printf("extern is %d.\n", x); return 0; } - ''', side=r''' + ''', + side=r''' int x = 123; struct Initter { Initter() { x = 456; } }; Initter initter; - ''', expected=['extern is 456.\n']) - + ''', + expected=['extern is 456.\n'], + ) + @with_dylink_reversed def test_dylink_stdlib(self): - self.dylink_test(header=r''' + self.dylink_test( + header=r''' #include #include #include char *side(const char *data); double pow_two(double x); - ''', main=r''' + ''', + main=r''' #include #include "header.h" int main() { @@ -4475,7 +4827,8 @@ def test_dylink_stdlib(self): free(temp); return 0; } - ''', side=r''' + ''', + side=r''' #include "header.h" char *side(const char *data) { char *ret = (char*)malloc(strlen(data)+1); @@ -4485,20 +4838,28 @@ def test_dylink_stdlib(self): double pow_two(double x) { return pow(2, x); } - ''', expected=['hello through side\n\npow_two: 59.'], force_c=True) + ''', + expected=['hello through side\n\npow_two: 59.'], + force_c=True, + ) @with_dylink_reversed def test_dylink_jslib(self): - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ test_lib_func: function(x) { return x + 17.2; } }); - ''') - self.dylink_test(header=r''' + ''', + ) + self.dylink_test( + header=r''' extern double test_lib_func(int input); - ''', main=r''' + ''', + main=r''' #include #include "header.h" extern double sidey(); @@ -4510,7 +4871,8 @@ def test_dylink_jslib(self): printf("more: %.5f, %d\n", temp, input); return 0; } - ''', side=r''' + ''', + side=r''' #include #include "header.h" extern int main2(); @@ -4520,44 +4882,62 @@ def test_dylink_jslib(self): printf("main2 sed: %u, %c\n", temp, temp/2); return test_lib_func(temp); } - ''', expected='other says 45.2', main_emcc_args=['--js-library', 'lib.js'], force_c=True) + ''', + expected='other says 45.2', + main_emcc_args=['--js-library', 'lib.js'], + force_c=True, + ) @with_dylink_reversed def test_dylink_many_postsets(self): NUM = 1234 - self.dylink_test(header=r''' + self.dylink_test( + header=r''' #include typedef void (*voidfunc)(); static void simple() { printf("simple.\n"); } - static volatile voidfunc funcs[''' + str(NUM) + '] = { ' + ','.join(['simple'] * NUM) + r''' }; + static volatile voidfunc funcs[''' + + str(NUM) + + '] = { ' + + ','.join(['simple'] * NUM) + + r''' }; static void test() { - volatile int i = ''' + str(NUM - 1) + r'''; + volatile int i = ''' + + str(NUM - 1) + + r'''; funcs[i](); i = 0; funcs[i](); } extern void more(); - ''', main=r''' + ''', + main=r''' #include "header.h" int main() { test(); more(); return 0; } - ''', side=r''' + ''', + side=r''' #include "header.h" void more() { test(); } - ''', expected=['simple.\nsimple.\nsimple.\nsimple.\n'], force_c=True) + ''', + expected=['simple.\nsimple.\nsimple.\nsimple.\n'], + force_c=True, + ) @with_dylink_reversed def test_dylink_postsets_chunking(self): - self.dylink_test(header=r''' + self.dylink_test( + header=r''' extern int global_var; - ''', main=r''' + ''', + main=r''' #include #include "header.h" @@ -4581,19 +4961,25 @@ def test_dylink_postsets_chunking(self): int main(int argc, char *argv[]) { printf("%d\n", *ptr); } - ''', side=r''' + ''', + side=r''' #include "header.h" int global_var = 12345; - ''', expected=['12345\n'], force_c=True) + ''', + expected=['12345\n'], + force_c=True, + ) @with_dylink_reversed - @parameterized({ - 'libcxx': ('libc,libc++,libmalloc,libc++abi',), - 'all': ('1',), - 'missing': ('libc,libmalloc,libc++abi', False, False, False), - 'missing_assertions': ('libc,libmalloc,libc++abi', False, False, True), - }) + @parameterized( + { + 'libcxx': ('libc,libc++,libmalloc,libc++abi',), + 'all': ('1',), + 'missing': ('libc,libmalloc,libc++abi', False, False, False), + 'missing_assertions': ('libc,libmalloc,libc++abi', False, False, True), + } + ) def test_dylink_syslibs(self, syslibs, expect_pass=True, with_reversed=True, assertions=True): # one module uses libcxx, need to force its inclusion when it isn't the main if not with_reversed and self.dylink_reversed: @@ -4615,38 +5001,50 @@ def test_dylink_syslibs(self, syslibs, expect_pass=True, with_reversed=True, ass assert_returncode = NON_ZERO with env_modify({'EMCC_FORCE_STDLIBS': syslibs, 'EMCC_ONLY_FORCED_STDLIBS': '1'}): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' void side(); int main() { side(); return 0; } - ''', side=r''' + ''', + side=r''' #include void side() { std::cout << "cout hello from side\n"; } - ''', expected=expected, main_module=1, assert_returncode=assert_returncode) + ''', + expected=expected, + main_module=1, + assert_returncode=assert_returncode, + ) @with_dylink_reversed @with_env_modify({'EMCC_FORCE_STDLIBS': 'libc++'}) def test_dylink_iostream(self): - self.dylink_test(header=r''' + self.dylink_test( + header=r''' #include #include std::string side(); - ''', main=r''' + ''', + main=r''' #include "header.h" int main() { std::cout << "hello from main " << side() << std::endl; return 0; } - ''', side=r''' + ''', + side=r''' #include "header.h" std::string side() { return "and hello from side"; } - ''', expected=['hello from main and hello from side\n']) + ''', + expected=['hello from main and hello from side\n'], + ) @with_dylink_reversed - def test_dylink_dynamic_cast(self): # issue 3465 - self.dylink_test(header=r''' + def test_dylink_dynamic_cast(self): # issue 3465 + self.dylink_test( + header=r''' class Base { public: virtual void printName(); @@ -4656,7 +5054,8 @@ class Derived : public Base { public: void printName(); }; - ''', main=r''' + ''', + main=r''' #include "header.h" #include @@ -4678,7 +5077,8 @@ class Derived : public Base { delete derived; return 0; } - ''', side=r''' + ''', + side=r''' #include "header.h" #include @@ -4689,18 +5089,22 @@ class Derived : public Base { void Derived::printName() { printf("Derived\n"); } - ''', expected=['starting main\nBase\nDerived\nOK']) + ''', + expected=['starting main\nBase\nDerived\nOK'], + ) @with_all_eh_sjlj @with_dylink_reversed def test_dylink_raii_exceptions(self): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include extern int side(); int main() { printf("from side: %d.\n", side()); } - ''', side=r''' + ''', + side=r''' #include typedef int (*ifdi)(float, double, int); int func_with_special_sig(float a, double b, int c) { @@ -4720,12 +5124,15 @@ def test_dylink_raii_exceptions(self): volatile ifdi p = func_with_special_sig; return p(2.18281, 3.14159, 42); } - ''', expected=['special 2.182810 3.141590 42\ndestroy\nfrom side: 1337.\n']) + ''', + expected=['special 2.182810 3.141590 42\ndestroy\nfrom side: 1337.\n'], + ) @with_all_eh_sjlj @with_dylink_reversed def test_dylink_exceptions_try_catch(self): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include extern void side(); int main() { @@ -4737,7 +5144,8 @@ def test_dylink_exceptions_try_catch(self): side(); return 0; } - ''', side=r''' + ''', + side=r''' #include void side() { try { @@ -4746,12 +5154,15 @@ def test_dylink_exceptions_try_catch(self): printf("side: caught %.1f\n", f); } } - ''', expected=['main: caught 3\nside: caught 5.3\n']) + ''', + expected=['main: caught 3\nside: caught 5.3\n'], + ) @with_all_eh_sjlj @with_dylink_reversed def test_dylink_exceptions_try_catch_2(self): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include extern void side_throw_int(); int main() { @@ -4765,7 +5176,8 @@ def test_dylink_exceptions_try_catch_2(self): void main_throw_float() { throw 5.3f; } - ''', side=r''' + ''', + side=r''' #include extern void main_throw_float(); void side_throw_int() { @@ -4776,12 +5188,16 @@ def test_dylink_exceptions_try_catch_2(self): } throw 3; } - ''', expected=['side: caught 5.3\nmain: caught 3\n']) + ''', + expected=['side: caught 5.3\nmain: caught 3\n'], + ) @with_all_eh_sjlj @needs_dylink def test_dylink_exceptions_try_catch_6(self): - create_file('main.cpp', r''' + create_file( + 'main.cpp', + r''' #include int main() { void* handle = dlopen("liblib.so", RTLD_LAZY); @@ -4789,14 +5205,17 @@ def test_dylink_exceptions_try_catch_6(self): (side)(); return 0; } - ''') + ''', + ) # Create a dependency on __cxa_find_matching_catch_6 (6 = num clauses + 2) # which is one higher than the default set of __cxa_find_matching_catch # functions created in library_exceptions.js. # This means we end up depending on dynamic linking code to redirect # __cxa_find_matching_catch_6 to __cxa_find_matching_catch. - create_file('liblib.cpp', r''' + create_file( + 'liblib.cpp', + r''' #include extern "C" void side() { try { @@ -4811,7 +5230,8 @@ def test_dylink_exceptions_try_catch_6(self): printf("side: caught short %hd\n", x); } } - ''') + ''', + ) self.maybe_closure() @@ -4834,7 +5254,9 @@ def test_dylink_hyper_dupe(self): self.set_setting('ASSERTIONS', 2) # test hyper-dynamic linking, and test duplicate warnings - create_file('third.cpp', r''' + create_file( + 'third.cpp', + r''' #include int sidef() { return 36; } int sideg = 49; @@ -4853,9 +5275,11 @@ def test_dylink_hyper_dupe(self): void only_in_third_1(int x) { printf("only_in_third_1: %d, %d, %d, %d\n", sidef(), sideg, second_to_third, x); } - ''') + ''', + ) self.run_process([EMCC, 'third.cpp', '-o', 'third.wasm', '-sSIDE_MODULE'] + self.get_emcc_args()) - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include #include extern int sidef(); @@ -4874,7 +5298,7 @@ def test_dylink_hyper_dupe(self): only_in_third_0(); } ''', - side=r''' + side=r''' #include int sidef() { return 10; } // third will try to override these, but fail! int sideg = 20; @@ -4891,7 +5315,10 @@ def test_dylink_hyper_dupe(self): printf("only_in_second_1: %d, %d, %d, %d\n", sidef(), sideg, third_to_second, x); } ''', - expected=['sidef: 10, sideg: 20.\nbsidef: 536.\nonly_in_second_0: 10, 20, 1337\nonly_in_third_1: 36, 49, 500, 1221\nonly_in_third_0: 36, 49, 500\nonly_in_second_1: 10, 20, 1337, 2112\n']) + expected=[ + 'sidef: 10, sideg: 20.\nbsidef: 536.\nonly_in_second_0: 10, 20, 1337\nonly_in_third_1: 36, 49, 500, 1221\nonly_in_third_0: 36, 49, 500\nonly_in_second_1: 10, 20, 1337, 2112\n' + ], + ) print('check warnings') full = self.run_js('src.js') @@ -4909,7 +5336,8 @@ def test_dylink_load_compiled_side_module(self): # startup. self.set_setting('NO_AUTOLOAD_DYLIBS') - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include #include extern int sidef(); @@ -4926,16 +5354,19 @@ def test_dylink_load_compiled_side_module(self): printf("sidef: %d.\n", sidef()); } ''', - side=r''' + side=r''' #include int sidef() { return 10; } - ''', expected=['sidef: 10']) + ''', + expected=['sidef: 10'], + ) @needs_dylink def test_dylink_dso_needed(self): def do_run(src, expected_output, emcc_args=None): create_file('main.c', src + 'int main() { return test_main(); }') self.do_runf('main.c', expected_output, emcc_args=emcc_args) + self._test_dylink_dso_needed(do_run) @with_dylink_reversed @@ -4948,7 +5379,8 @@ def test_dylink_dot_a(self): self.run_process([EMCC, '-fPIC', '-c', 'fourth.c', '-o', 'fourth.o'] + self.get_emcc_args(compile_only=True)) self.run_process([EMAR, 'rc', 'libfourth.a', 'fourth.o']) - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include #include int sidef(); @@ -4957,13 +5389,16 @@ def test_dylink_dot_a(self): printf("sidef: %d, sideg: %d.\n", sidef(), sideg()); } ''', - # contents of libfourth.a must be included, even if they aren't referred to! - side=['libfourth.a', 'third.o'], - expected=['sidef: 36, sideg: 17.\n'], force_c=True) + # contents of libfourth.a must be included, even if they aren't referred to! + side=['libfourth.a', 'third.o'], + expected=['sidef: 36, sideg: 17.\n'], + force_c=True, + ) @with_dylink_reversed def test_dylink_spaghetti(self): - self.dylink_test(main=r''' + self.dylink_test( + main=r''' #include int main_x = 72; extern int side_x; @@ -4979,7 +5414,8 @@ def test_dylink_spaghetti(self): printf("main main sees %d, %d, %d.\n", adjust, *ptr, main_x); return 0; } - ''', side=r''' + ''', + side=r''' #include extern int main_x; int side_x = -534; @@ -4991,15 +5427,20 @@ def test_dylink_spaghetti(self): } }; SideClass cs; - ''', expected=['''\ + ''', + expected=[ + '''\ side init sees 82, 72, -534. main init sees -524, -534, 72. main main sees -524, -534, 72. -''', '''\ +''', + '''\ main init sees -524, -534, 72. side init sees 82, 72, -534. main main sees -524, -534, 72. -''']) +''', + ], + ) @needs_make('mingw32-make') @with_dylink_reversed @@ -5009,10 +5450,12 @@ def test_dylink_zlib(self): # example.c uses K&R style function declarations self.emcc_args.append('-Wno-deprecated-non-prototype') self.emcc_args.append('-I' + test_file('third_party/zlib')) - self.dylink_test(main=read_file(test_file('third_party/zlib/example.c')), - side=zlib_archive, - expected=read_file(test_file('core/test_zlib.out')), - force_c=True) + self.dylink_test( + main=read_file(test_file('third_party/zlib/example.c')), + side=zlib_archive, + expected=read_file(test_file('core/test_zlib.out')), + force_c=True, + ) # @with_dylink_reversed # def test_dylink_bullet(self): @@ -5069,10 +5512,7 @@ class Bar : public Foo { } ''' - self.dylink_test(main=main, - side=side, - header=header, - expected='success') + self.dylink_test(main=main, side=side, header=header, expected='success') @needs_dylink def test_dylink_argv_argc(self): @@ -5080,12 +5520,15 @@ def test_dylink_argv_argc(self): self.emcc_args += ['--extern-pre-js', 'pre.js'] - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' var Module = { arguments: ['hello', 'world!'] } - ''') + ''', + ) self.dylink_test( - '', # main module is empty. + '', # main module is empty. r''' #include int main(int argc, char const *argv[]) { @@ -5095,7 +5538,8 @@ def test_dylink_argv_argc(self): return 0; } ''', - expected='3 hello world!') + expected='3 hello world!', + ) @needs_dylink def test_dylink_weak(self): @@ -5153,7 +5597,7 @@ def test_strtol(self): def test_transtrcase(self): self.do_core_test('test_transtrcase.c') - @also_with_wasmfs # tests EXIT_RUNTIME flushing + @also_with_wasmfs # tests EXIT_RUNTIME flushing @no_wasm2js('very slow to compile: https://github.com/emscripten-core/emscripten/issues/21048') @is_slow_test def test_printf(self): @@ -5246,17 +5690,23 @@ def test_sscanf_2(self): } ''' if ftype == 'float': - self.do_run(src.replace('%lf', '%f').replace('double', 'float'), '''Pass: 1.234568 1.234568 + self.do_run( + src.replace('%lf', '%f').replace('double', 'float'), + '''Pass: 1.234568 1.234568 Pass: 123456.789062 123456.789062 Pass: 123456.789062 123456.789062 Pass: 0.000012 0.000012 -Pass: 0.000012 0.000012''') +Pass: 0.000012 0.000012''', + ) else: - self.do_run(src, '''Pass: 1.234568 1.234568 + self.do_run( + src, + '''Pass: 1.234568 1.234568 Pass: 123456.789000 123456.789000 Pass: 123456.789000 123456.789000 Pass: 0.000012 0.000012 -Pass: 0.000012 0.000012''') +Pass: 0.000012 0.000012''', + ) def test_sscanf_n(self): self.do_core_test('test_sscanf_n.c') @@ -5300,7 +5750,7 @@ def test_files(self): # Use closure here, to test we don't break FS stuff if '-O3' in self.emcc_args and self.is_wasm2js(): print('closure 2') - self.emcc_args += ['--closure', '2'] # Use closure 2 here for some additional coverage + self.emcc_args += ['--closure', '2'] # Use closure 2 here for some additional coverage # Sadly --closure=2 is not yet free of closure warnings # FIXME(https://github.com/emscripten-core/emscripten/issues/17080) self.ldflags.append('-Wno-error=closure') @@ -5310,7 +5760,9 @@ def test_files(self): self.emcc_args += ['--pre-js', 'pre.js'] self.set_setting('FORCE_FILESYSTEM') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' /** @suppress{checkTypes}*/ Module = { 'noFSInit': true, @@ -5325,20 +5777,24 @@ def test_files(self): }); } }; -''') +''', + ) create_file('test.file', 'some data') self.do_run_in_out_file_test('test_files.c') def test_module_stdin(self): - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' var data = [10, 20, 40, 30]; Module = { stdin: () => { return data.pop() || null }, stdout: (x) => out('got: ' + x) }; - ''') + ''', + ) self.emcc_args += ['--pre-js', 'pre.js'] src = r''' @@ -5356,13 +5812,16 @@ def test_module_stdin(self): } ''' - self.do_run(src, '''\ + self.do_run( + src, + '''\ isatty? in=0,out=0,err=1 got: 30 got: 40 got: 20 got: 10 -''') +''', + ) def test_mount(self): self.set_setting('FORCE_FILESYSTEM') @@ -5453,7 +5912,8 @@ def test_fscanf(self): def test_fscanf_2(self): create_file('a.txt', '1/2/3 4/5/6 7/8/9\n') self.emcc_args += ['--embed-file', 'a.txt'] - self.do_run(r'''\ + self.do_run( + r'''\ #include int main(int argv, char** argc) { @@ -5474,7 +5934,9 @@ def test_fscanf_2(self): printf("matches: %d\n", matches); return 0; } - ''', 'fscanf test\nmatches: 9\n') + ''', + 'fscanf test\nmatches: 9\n', + ) def test_fileno(self): create_file('empty.txt', '') @@ -5575,7 +6037,9 @@ def test_utime(self): def test_futimens(self): self.do_runf('utime/test_futimens.c', 'success') - @no_minimal_runtime('MINIMAL_RUNTIME does not have getValue() and setValue() (TODO add it to a JS library function to get it in)') + @no_minimal_runtime( + 'MINIMAL_RUNTIME does not have getValue() and setValue() (TODO add it to a JS library function to get it in)' + ) @requires_node # only node handles utf well def test_utf(self): self.set_setting('EXPORTED_FUNCTIONS', ['_main', '_malloc', '_free']) @@ -5604,19 +6068,23 @@ def test_utf8_textdecoder(self): self.do_runf('benchmark/benchmark_utf8.c', 'OK.') # Test that invalid character in UTF8 does not cause decoding to crash. - @parameterized({ - '': [[]], - 'textdecoder': [['-sTEXTDECODER']], - }) + @parameterized( + { + '': [[]], + 'textdecoder': [['-sTEXTDECODER']], + } + ) def test_utf8_invalid(self, args): self.do_runf('utf8_invalid.cpp', 'OK.', emcc_args=args) # Test that invalid character in UTF8 does not cause decoding to crash. @no_asan('TODO: ASan support in minimal runtime') - @parameterized({ - '': [[]], - 'textdecoder': [['-sTEXTDECODER']], - }) + @parameterized( + { + '': [[]], + 'textdecoder': [['-sTEXTDECODER']], + } + ) def test_minimal_runtime_utf8_invalid(self, args): self.set_setting('MINIMAL_RUNTIME') self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')] @@ -5640,7 +6108,7 @@ def test_std_function_incomplete_return(self): self.do_core_test('test_std_function_incomplete_return.cpp') def test_istream(self): - for linkable in [0]: # , 1]: + for linkable in [0]: # , 1]: print(linkable) # regression check for issue #273 self.set_setting('LINKABLE', linkable) @@ -5775,14 +6243,13 @@ def test_fs_mmap(self): self.do_run_in_out_file_test('fs/test_mmap.c') @no_wasmfs('wasmfs will (?) need a non-JS mechanism to ignore permissions during startup') - @parameterized({ - '': [], - 'minimal_runtime': ['-sMINIMAL_RUNTIME=1'] - }) + @parameterized({'': [], 'minimal_runtime': ['-sMINIMAL_RUNTIME=1']}) def test_fs_no_main(self, *args): # library_fs.js uses hooks to enable ignoring of permisions up until ATMAINs are run. This # test verified that they work correctly, even in programs without a main function. - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.preRun = () => { assert(FS.ignorePermissions, "ignorePermissions not set during preRun"); } @@ -5790,7 +6257,8 @@ def test_fs_no_main(self, *args): assert(!FS.ignorePermissions, "ignorePermissions not unset during onRuntimeInitialized"); assert(_foo() == 42); } -''') +''', + ) self.set_setting('EXPORTED_FUNCTIONS', '_foo') self.set_setting('FORCE_FILESYSTEM') self.emcc_args += ['--pre-js', 'pre.js'] + list(args) @@ -5805,7 +6273,8 @@ def test_fs_errorstack(self): self.set_setting('FORCE_FILESYSTEM') self.set_setting('ASSERTIONS') - self.do_run(r''' + self.do_run( + r''' #include #include int main(void) { @@ -5820,7 +6289,10 @@ def test_fs_errorstack(self): ); return 0; } - ''', 'at Object.readFile', assert_returncode=NON_ZERO) # engines has different error stack format + ''', + 'at Object.readFile', + assert_returncode=NON_ZERO, + ) # engines has different error stack format @also_with_noderawfs def test_fs_llseek(self): @@ -5888,10 +6360,7 @@ def test_sigalrm(self): def test_signals(self): self.do_core_test('test_signals.c') - @parameterized({ - 'sigint': (EM_SIGINT, 128 + EM_SIGINT, True), - 'sigabrt': (EM_SIGABRT, 1, False) - }) + @parameterized({'sigint': (EM_SIGINT, 128 + EM_SIGINT, True), 'sigabrt': (EM_SIGABRT, 1, False)}) @crossplatform def test_sigaction_default(self, signal, exit_code, assert_identical): self.set_setting('EXIT_RUNTIME') @@ -5901,7 +6370,7 @@ def test_sigaction_default(self, signal, exit_code, assert_identical): test_file('test_sigaction_default.c'), args=[str(signal)], assert_identical=assert_identical, - assert_returncode=exit_code + assert_returncode=exit_code, ) @crossplatform @@ -6006,7 +6475,9 @@ def test_unistd_unlink(self): def test_unistd_links(self): nodefs = '-DNODEFS' in self.emcc_args if nodefs and WINDOWS: - self.skipTest('Skipping NODEFS part of this test for test_unistd_links on Windows, since it would require administrative privileges.') + self.skipTest( + 'Skipping NODEFS part of this test for test_unistd_links on Windows, since it would require administrative privileges.' + ) # Also, other detected discrepancies if you do end up running this test on NODEFS: # test expects /, but Windows gives \ as path slashes. # Calling readlink() on a non-link gives error 22 EINVAL on Unix, but simply error 0 OK on Windows. @@ -6086,10 +6557,13 @@ def test_nl_types(self): def test_799(self): src = test_file('799.cpp') - self.do_runf(src, '''Set PORT family: 0, port: 3979 + self.do_runf( + src, + '''Set PORT family: 0, port: 3979 Get PORT family: 0 PORT: 3979 -''') +''', + ) def test_ctype(self): self.do_core_test('test_ctype.c') @@ -6121,14 +6595,17 @@ def test_main_module_static_align(self): # libc++ tests def test_iostream_and_determinism(self): - create_file('src.cpp', ''' + create_file( + 'src.cpp', + ''' #include int main() { std::cout << "hello world" << std::endl << 77 << "." << std::endl; return 0; } - ''') + ''', + ) num = 5 for i in range(num): @@ -6161,7 +6638,9 @@ def test_reinterpreted_ptrs(self): self.do_core_test('test_reinterpreted_ptrs.cpp') def test_js_libraries(self): - create_file('main.cpp', ''' + create_file( + 'main.cpp', + ''' #include extern "C" { extern void printey(); @@ -6172,17 +6651,24 @@ def test_js_libraries(self): printf("*%d*\\n", calcey(10, 22)); return 0; } - ''') - create_file('mylib1.js', ''' + ''', + ) + create_file( + 'mylib1.js', + ''' addToLibrary({ printey: () => out('hello from lib!') }); - ''') - create_file('mylib2.js', ''' + ''', + ) + create_file( + 'mylib2.js', + ''' addToLibrary({ calcey: (x, y) => x + y }); - ''') + ''', + ) self.emcc_args += ['--js-library', 'mylib1.js', '--js-library', 'mylib2.js'] self.do_runf('main.cpp', 'hello from lib!\n*32*\n') @@ -6199,7 +6685,15 @@ def test_unicode_js_library(self): err = self.expect_fail([PYTHON, 'expect_fail.py'], expect_traceback=True) self.assertContained('UnicodeDecodeError', err) - self.emcc_args += ['-sMODULARIZE', '--js-library', test_file('unicode_library.js'), '--extern-post-js', test_file('modularize_post_js.js'), '--post-js', test_file('unicode_postjs.js')] + self.emcc_args += [ + '-sMODULARIZE', + '--js-library', + test_file('unicode_library.js'), + '--extern-post-js', + test_file('modularize_post_js.js'), + '--post-js', + test_file('unicode_postjs.js'), + ] self.do_run_in_out_file_test('test_unicode_js_library.c') def test_funcptr_import_type(self): @@ -6210,7 +6704,8 @@ def test_funcptr_import_type(self): def test_constglobalunion(self): self.set_setting('EXPORT_ALL') - self.do_run(r''' + self.do_run( + r''' #include struct one_const { @@ -6239,7 +6734,9 @@ def test_constglobalunion(self): printf("%li\n", (long)!!addr_of_my_consts.a); return 0; } - ''', '1') + ''', + '1', + ) ### 'Medium' tests @@ -6258,14 +6755,24 @@ def test_raytrace(self): output = read_file(test_file('raytrace.ppm')) self.do_run(src, output, args=['3', '16']) - @parameterized({ - '': ('double',), - 'float': ('float',), - }) + @parameterized( + { + '': ('double',), + 'float': ('float',), + } + ) def test_fasta(self, float_type): - results = [('1', '''GG\nctt\n\ntgagc\n'''), - ('20', '''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT\ncttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg\n\ntacgtgtagcctagtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaa\n\ntgacgtcttttgatctgacggcgttaacaaagatactctg\n'''), - ('50', '''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\nTCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT\ncttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg\n\ntactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa\n\nNtactMcSMtYtcMgRtacttctWBacgaa\n\nagatactctgggcaacacacatacttctctcatgttgtttcttcggacctttcataacct\n\nttcctggcacatggttagctgcacatcacaggattgtaagggtctagtggttcagtgagc\n\nggaatatcattcgtcggtggtgttaatctatctcggtgtagcttataaatgcatccgtaa\n\ngaatattatgtttatttgtcggtacgttcatggtagtggtgtcgccgatttagacgtaaa\n\nggcatgtatg\n''')] + results = [ + ('1', '''GG\nctt\n\ntgagc\n'''), + ( + '20', + '''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT\ncttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg\n\ntacgtgtagcctagtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaa\n\ntgacgtcttttgatctgacggcgttaacaaagatactctg\n''', + ), + ( + '50', + '''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\nTCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT\ncttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg\n\ntactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa\n\nNtactMcSMtYtcMgRtacttctWBacgaa\n\nagatactctgggcaacacacatacttctctcatgttgtttcttcggacctttcataacct\n\nttcctggcacatggttagctgcacatcacaggattgtaagggtctagtggttcagtgagc\n\nggaatatcattcgtcggtggtgttaatctatctcggtgtagcttataaatgcatccgtaa\n\ngaatattatgtttatttgtcggtacgttcatggtagtggtgtcgccgatttagacgtaaa\n\nggcatgtatg\n''', + ), + ] orig_src = read_file(test_file('fasta.cpp')) @@ -6314,7 +6821,11 @@ def test_dlmalloc(self): # emcc should build in dlmalloc automatically, and do all the sign correction etc. for it delete_file('src.js') - self.run_process([EMCC, test_file('dlmalloc_test.c'), '-sINITIAL_MEMORY=128MB', '-o', 'src.js'], stdout=PIPE, stderr=self.stderr_redirect) + self.run_process( + [EMCC, test_file('dlmalloc_test.c'), '-sINITIAL_MEMORY=128MB', '-o', 'src.js'], + stdout=PIPE, + stderr=self.stderr_redirect, + ) self.do_run(None, '*1,0*', ['200', '1'], no_build=True) self.do_run(None, '*400,0*', ['400', '400'], no_build=True) @@ -6343,7 +6854,9 @@ def test_dlmalloc_large(self): @no_lsan('lsan also changes malloc, and that ends up linking in new twice') def test_dlmalloc_partial(self): # present part of the symbols of dlmalloc, not all - src = read_file(test_file('new.cpp')).replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + ''' + src = ( + read_file(test_file('new.cpp')).replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + + ''' #include #include @@ -6352,6 +6865,7 @@ def test_dlmalloc_partial(self): return malloc(size); } ''' + ) self.do_run(src, 'new!\n*1,0*') @no_asan('asan also changes malloc, and that ends up linking in new twice') @@ -6363,10 +6877,13 @@ def test_dlmalloc_partial_2(self): self.do_core_test('test_dlmalloc_partial_2.c', assert_returncode=NON_ZERO) def test_libcxx(self): - self.do_runf('core/test_libcxx_hash.cpp', - 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march') + self.do_runf( + 'core/test_libcxx_hash.cpp', + 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march', + ) - self.do_run(''' + self.do_run( + ''' #include #include int main() { @@ -6375,7 +6892,9 @@ def test_libcxx(self): printf("hello world\\n"); return 0; } - ''', 'hello world') + ''', + 'hello world', + ) def test_typeid(self): self.do_core_test('test_typeid.cpp') @@ -6407,11 +6926,13 @@ def test_mmap_anon_pthreads(self): self.do_core_test('test_mmap_anon.c') @no_lsan('Test code contains memory leaks') - @parameterized({ + @parameterized( + { '': (0,), 'asyncify': (1,), 'jspi': (2,), - }) + } + ) def test_cubescript(self, asyncify): # uses register keyword self.emcc_args += ['-std=c++03', '-Wno-dynamic-class-memaccess'] @@ -6439,6 +6960,7 @@ def test_relocatable_void_function(self): def test_wasm_intrinsics_simd(self): def run(): self.do_runf('test_wasm_intrinsics_simd.c', 'Success!') + # Improves test readability self.emcc_args.append('-Wno-c++11-narrowing') self.emcc_args = ['-Wpedantic', '-Werror', '-Wall', '-xc++'] + self.emcc_args @@ -6460,13 +6982,14 @@ def test_neon_wasm_simd(self): @requires_native_clang @no_safe_heap('has unaligned 64-bit operations in wasm') @no_ubsan('test contains UB') - @parameterized({ - '': ([],), - 'nontrapping': (['-mnontrapping-fptoint'],) - }) + @parameterized({'': ([],), 'nontrapping': (['-mnontrapping-fptoint'],)}) def test_sse1(self, args): src = test_file('sse/test_sse1.cpp') - self.run_process([shared.CLANG_CXX, src, '-msse', '-o', 'test_sse1', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [shared.CLANG_CXX, src, '-msse', '-o', 'test_sse1', '-D_CRT_SECURE_NO_WARNINGS=1'] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_sse1', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), '-msse'] + args @@ -6481,15 +7004,16 @@ def test_sse1(self, args): @is_slow_test @no_ubsan('https://github.com/emscripten-core/emscripten/issues/19688') @no_asan('local count too large') - @parameterized({ - '': ([],), - 'nontrapping': (['-mnontrapping-fptoint'],) - }) + @parameterized({'': ([],), 'nontrapping': (['-mnontrapping-fptoint'],)}) def test_sse2(self, args): if self.is_wasm64(): self.require_node_canary() src = test_file('sse/test_sse2.cpp') - self.run_process([shared.CLANG_CXX, src, '-msse2', '-Wno-argument-outside-range', '-o', 'test_sse2', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [shared.CLANG_CXX, src, '-msse2', '-Wno-argument-outside-range', '-o', 'test_sse2', '-D_CRT_SECURE_NO_WARNINGS=1'] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_sse2', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), '-msse2', '-Wno-argument-outside-range', '-sSTACK_SIZE=1MB'] + args @@ -6501,7 +7025,11 @@ def test_sse2(self, args): @requires_native_clang def test_sse3(self): src = test_file('sse/test_sse3.cpp') - self.run_process([shared.CLANG_CXX, src, '-msse3', '-Wno-argument-outside-range', '-o', 'test_sse3', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [shared.CLANG_CXX, src, '-msse3', '-Wno-argument-outside-range', '-o', 'test_sse3', '-D_CRT_SECURE_NO_WARNINGS=1'] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_sse3', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), '-msse3', '-Wno-argument-outside-range'] @@ -6513,7 +7041,19 @@ def test_sse3(self): @requires_native_clang def test_ssse3(self): src = test_file('sse/test_ssse3.cpp') - self.run_process([shared.CLANG_CXX, src, '-mssse3', '-Wno-argument-outside-range', '-o', 'test_ssse3', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [ + shared.CLANG_CXX, + src, + '-mssse3', + '-Wno-argument-outside-range', + '-o', + 'test_ssse3', + '-D_CRT_SECURE_NO_WARNINGS=1', + ] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_ssse3', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), '-mssse3', '-Wno-argument-outside-range'] @@ -6533,7 +7073,19 @@ def test_sse4_1(self): # ASan with -O0 fails with: # Compiling function #69:"__original_main" failed: local count too large self.emcc_args.append('-O1') - self.run_process([shared.CLANG_CXX, src, '-msse4.1', '-Wno-argument-outside-range', '-o', 'test_sse4_1', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [ + shared.CLANG_CXX, + src, + '-msse4.1', + '-Wno-argument-outside-range', + '-o', + 'test_sse4_1', + '-D_CRT_SECURE_NO_WARNINGS=1', + ] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_sse4_1', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), '-msse4.1', '-Wno-argument-outside-range', '-sSTACK_SIZE=1MB'] @@ -6543,14 +7095,15 @@ def test_sse4_1(self): # Tests invoking the SIMD API via x86 SSE4.2 nmmintrin.h header (_mm_x() functions) @wasm_simd @requires_native_clang - @parameterized({ - '': (False,), - '2': (True,) - }) + @parameterized({'': (False,), '2': (True,)}) def test_sse4(self, use_4_2): msse4 = '-msse4.2' if use_4_2 else '-msse4' src = test_file('sse/test_sse4_2.cpp') - self.run_process([shared.CLANG_CXX, src, msse4, '-Wno-argument-outside-range', '-o', 'test_sse4_2', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [shared.CLANG_CXX, src, msse4, '-Wno-argument-outside-range', '-o', 'test_sse4_2', '-D_CRT_SECURE_NO_WARNINGS=1'] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_sse4_2', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), msse4, '-Wno-argument-outside-range'] @@ -6563,13 +7116,23 @@ def test_sse4(self, use_4_2): @is_slow_test @no_asan('local count too large') @no_ubsan('local count too large') - @parameterized({ - '': ([],), - 'nontrapping': (['-mnontrapping-fptoint'],) - }) + @parameterized({'': ([],), 'nontrapping': (['-mnontrapping-fptoint'],)}) def test_avx(self, args): src = test_file('sse/test_avx.cpp') - self.run_process([shared.CLANG_CXX, src, '-mavx', '-Wno-argument-outside-range', '-Wpedantic', '-o', 'test_avx', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) + self.run_process( + [ + shared.CLANG_CXX, + src, + '-mavx', + '-Wno-argument-outside-range', + '-Wpedantic', + '-o', + 'test_avx', + '-D_CRT_SECURE_NO_WARNINGS=1', + ] + + clang_native.get_clang_native_args(), + stdout=PIPE, + ) native_result = self.run_process('./test_avx', stdout=PIPE).stdout self.emcc_args += ['-I' + test_file('sse'), '-mavx', '-Wno-argument-outside-range', '-sSTACK_SIZE=1MB'] + args @@ -6581,9 +7144,7 @@ def test_sse_diagnostics(self): self.emcc_args.remove('-Werror') src = test_file('sse/test_sse_diagnostic.cpp') - p = self.run_process( - [shared.EMXX, src, '-msse', '-DWASM_SIMD_COMPAT_SLOW'] + self.get_emcc_args(), - stderr=PIPE) + p = self.run_process([shared.EMXX, src, '-msse', '-DWASM_SIMD_COMPAT_SLOW'] + self.get_emcc_args(), stderr=PIPE) self.assertContained('Instruction emulated via slow path.', p.stderr) @requires_native_clang @@ -6596,7 +7157,11 @@ def test_relaxed_simd_implies_simd128(self): def test_gcc_unmangler(self): self.emcc_args += ['-I' + test_file('third_party/libiberty')] - self.do_runf('third_party/libiberty/cp-demangle.c', '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj']) + self.do_runf( + 'third_party/libiberty/cp-demangle.c', + '*d_demangle(char const*, int, unsigned int*)*', + args=['_ZL10d_demanglePKciPj'], + ) @needs_make('make') @crossplatform @@ -6604,18 +7169,22 @@ def test_lua(self): self.emcc_args.remove('-Werror') env_init = { 'SYSCFLAGS': ' '.join(self.get_emcc_args(compile_only=True)), - 'SYSLDFLAGS': ' '.join(self.get_emcc_args()) + 'SYSLDFLAGS': ' '.join(self.get_emcc_args()), } - libs = self.get_library('third_party/lua', - [Path('src/lua.o'), Path('src/liblua.a')], - make=['make', 'echo', 'generic'], - env_init=env_init, - configure=None) - self.do_run('', - 'hello lua world!\n17\n1\n2\n3\n4\n7', - args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], - libraries=libs, - includes=[test_file('lua')]) + libs = self.get_library( + 'third_party/lua', + [Path('src/lua.o'), Path('src/liblua.a')], + make=['make', 'echo', 'generic'], + env_init=env_init, + configure=None, + ) + self.do_run( + '', + 'hello lua world!\n17\n1\n2\n3\n4\n7', + args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], + libraries=libs, + includes=[test_file('lua')], + ) @no_asan('issues with freetype itself') @needs_make('configure script') @@ -6624,47 +7193,58 @@ def test_freetype(self): if self.get_setting('WASMFS'): self.emcc_args += ['-sFORCE_FILESYSTEM'] - self.add_pre_run("FS.createDataFile('/', 'font.ttf', %s, true, false, false);" % str( - list(bytearray(read_binary(test_file('freetype/LiberationSansBold.ttf')))) - )) + self.add_pre_run( + "FS.createDataFile('/', 'font.ttf', %s, true, false, false);" + % str(list(bytearray(read_binary(test_file('freetype/LiberationSansBold.ttf'))))) + ) # Not needed for js, but useful for debugging shutil.copy(test_file('freetype/LiberationSansBold.ttf'), 'font.ttf') ftlib = self.get_freetype_library() # Main - self.do_run_in_out_file_test('freetype/main.c', - args=['font.ttf', 'test!', '150', '120', '25'], - libraries=ftlib, - includes=[test_file('third_party/freetype/include')]) + self.do_run_in_out_file_test( + 'freetype/main.c', + args=['font.ttf', 'test!', '150', '120', '25'], + libraries=ftlib, + includes=[test_file('third_party/freetype/include')], + ) # github issue 324 print('[issue 324]') - self.do_run_in_out_file_test('freetype/main_2.c', - args=['font.ttf', 'w', '32', '32', '25'], - libraries=ftlib, - includes=[test_file('third_party/freetype/include')]) + self.do_run_in_out_file_test( + 'freetype/main_2.c', + args=['font.ttf', 'w', '32', '32', '25'], + libraries=ftlib, + includes=[test_file('third_party/freetype/include')], + ) print('[issue 324 case 2]') - self.do_run_in_out_file_test('freetype/main_3.c', - args=['font.ttf', 'W', '32', '32', '0'], - libraries=ftlib, - includes=[test_file('third_party/freetype/include')]) + self.do_run_in_out_file_test( + 'freetype/main_3.c', + args=['font.ttf', 'W', '32', '32', '0'], + libraries=ftlib, + includes=[test_file('third_party/freetype/include')], + ) print('[issue 324 case 3]') - self.do_run_in_out_file_test('freetype/main_3.c', - out_suffix='_alt', - args=['font.ttf', 'ea', '40', '32', '0'], - libraries=ftlib, - includes=[test_file('third_party/freetype/include')]) + self.do_run_in_out_file_test( + 'freetype/main_3.c', + out_suffix='_alt', + args=['font.ttf', 'ea', '40', '32', '0'], + libraries=ftlib, + includes=[test_file('third_party/freetype/include')], + ) @no_asan('local count too large for VMs') @no_ubsan('local count too large for VMs') @is_slow_test - @parameterized({ - '': (False,), - 'pthreads': (True,), - }) + @parameterized( + { + '': (False,), + 'pthreads': (True,), + } + ) def test_sqlite(self, use_pthreads): if use_pthreads: self.emcc_args.append('-pthread') @@ -6674,17 +7254,14 @@ def test_sqlite(self, use_pthreads): @needs_make('mingw32-make') @is_slow_test - @parameterized({ - 'cmake': (True,), - 'configure': (False,) - }) + @parameterized({'cmake': (True,), 'configure': (False,)}) def test_zlib(self, use_cmake): if WINDOWS and not use_cmake: self.skipTest("Windows cannot run configure sh scripts") self.maybe_closure() if '-g' in self.emcc_args: - self.emcc_args.append('-gsource-map') # more source maps coverage + self.emcc_args.append('-gsource-map') # more source maps coverage zlib = self.get_zlib_library(use_cmake) @@ -6695,10 +7272,7 @@ def test_zlib(self, use_cmake): @needs_make('make') @is_slow_test @no_ubsan('it seems that bullet contains UB') - @parameterized({ - 'cmake': (True,), - 'autoconf': (False,) - }) + @parameterized({'cmake': (True,), 'autoconf': (False,)}) # Called thus so it runs late in the alphabetical cycle... it is long def test_bullet(self, use_cmake): if WINDOWS and not use_cmake: @@ -6720,13 +7294,17 @@ def test_bullet(self, use_cmake): self.set_setting('ASSERTIONS', 2) self.emcc_args.append('-Wno-unused-command-line-argument') - self.do_runf('third_party/bullet/Demos/HelloWorld/HelloWorld.cpp', - [read_file(test_file('bullet/output.txt')), # different roundings - read_file(test_file('bullet/output2.txt')), - read_file(test_file('bullet/output3.txt')), - read_file(test_file('bullet/output4.txt'))], - libraries=self.get_bullet_library(use_cmake), - includes=[test_file('third_party/bullet/src')]) + self.do_runf( + 'third_party/bullet/Demos/HelloWorld/HelloWorld.cpp', + [ + read_file(test_file('bullet/output.txt')), # different roundings + read_file(test_file('bullet/output2.txt')), + read_file(test_file('bullet/output3.txt')), + read_file(test_file('bullet/output4.txt')), + ], + libraries=self.get_bullet_library(use_cmake), + includes=[test_file('third_party/bullet/src')], + ) @no_asan('issues with freetype itself') @no_ubsan('local count too large') @@ -6740,7 +7318,9 @@ def test_poppler(self): poppler = self.get_poppler_library() shutil.copy(test_file('poppler/paper.pdf'), '.') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.preRun = () => { FS.createDataFile('/', 'paper.pdf', readBinary('paper.pdf'), true, false, false); }; @@ -6748,13 +7328,12 @@ def test_poppler(self): var FileData = Array.from(MEMFS.getFileDataAsTypedArray(FS.root.contents['filename-1.ppm'])); out("Data: " + JSON.stringify(FileData.map(function(x) { return unSign(x, 8) }))); }; - ''') + ''', + ) self.emcc_args += ['--pre-js', 'pre.js', '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$unSign'] ppm_data = str(list(bytearray(read_binary(test_file('poppler/ref.ppm'))))) - self.do_run('', ppm_data.replace(' ', ''), - libraries=poppler, - args=['-scale-to', '512', 'paper.pdf', 'filename']) + self.do_run('', ppm_data.replace(' ', ''), libraries=poppler, args=['-scale-to', '512', 'paper.pdf', 'filename']) @needs_make('make') @is_slow_test @@ -6778,12 +7357,16 @@ def line_splitter(data): original_j2k = test_file('openjpeg/syntensity_lobby_s.j2k') image_bytes = list(bytearray(read_binary(original_j2k))) - create_file('pre.js', """ + create_file( + 'pre.js', + """ Module.preRun = () => FS.createDataFile('/', 'image.j2k', %s, true, false, false); Module.postRun = () => { out('Data: ' + JSON.stringify(Array.from(FS.readFile('image.raw')))); }; - """ % line_splitter(str(image_bytes))) + """ + % line_splitter(str(image_bytes)), + ) # ensure libpng is built so that openjpeg's configure step can detect it. # If we don't do this then we don't know what the state of the cache will be @@ -6794,15 +7377,19 @@ def line_splitter(data): builder_cmd.append('--wasm64') self.emcc_args.append('-Wno-pointer-to-int-cast') self.run_process(builder_cmd) - lib = self.get_library('third_party/openjpeg', - [Path('codec/CMakeFiles/j2k_to_image.dir/index.c.o'), - Path('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'), - Path('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'), - Path('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'), - Path('bin/libopenjpeg.a')], - configure=['cmake', '.'], - # configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'], - make_args=[]) # no -j 2, since parallel builds can fail + lib = self.get_library( + 'third_party/openjpeg', + [ + Path('codec/CMakeFiles/j2k_to_image.dir/index.c.o'), + Path('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'), + Path('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'), + Path('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'), + Path('bin/libopenjpeg.a'), + ], + configure=['cmake', '.'], + # configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'], + make_args=[], + ) # no -j 2, since parallel builds can fail # We use doubles in JS, so we get slightly different values than native code. So we # check our output by comparing the average pixel difference @@ -6814,7 +7401,7 @@ def image_compare(output): # Evaluate the output as a python array js_data = eval(m.group(0)) - js_data = [x if x >= 0 else 256 + x for x in js_data] # Our output may be signed, so unsign it + js_data = [x if x >= 0 else 256 + x for x in js_data] # Our output may be signed, so unsign it # Get the correct output true_data = bytearray(read_binary(test_file('openjpeg/syntensity_lobby_s.raw'))) @@ -6836,18 +7423,22 @@ def image_compare(output): assert abs(true_mean - image_mean) < 0.01, [true_mean, image_mean] assert diff_mean < 0.01, diff_mean - self.emcc_args += ['--minify=0'] # to compare the versions + self.emcc_args += ['--minify=0'] # to compare the versions self.emcc_args += ['--pre-js', 'pre.js'] - output = self.do_runf('third_party/openjpeg/codec/j2k_to_image.c', - 'Successfully generated', # The real test for valid output is in image_compare - args='-i image.j2k -o image.raw'.split(), - emcc_args=['-sUSE_LIBPNG'], - libraries=lib, - includes=[test_file('third_party/openjpeg/libopenjpeg'), - test_file('third_party/openjpeg/codec'), - test_file('third_party/openjpeg/common'), - Path(self.get_build_dir(), 'third_party/openjpeg')]) + output = self.do_runf( + 'third_party/openjpeg/codec/j2k_to_image.c', + 'Successfully generated', # The real test for valid output is in image_compare + args='-i image.j2k -o image.raw'.split(), + emcc_args=['-sUSE_LIBPNG'], + libraries=lib, + includes=[ + test_file('third_party/openjpeg/libopenjpeg'), + test_file('third_party/openjpeg/codec'), + test_file('third_party/openjpeg/common'), + Path(self.get_build_dir(), 'third_party/openjpeg'), + ], + ) image_compare(output) @also_with_standalone_wasm(impure=True) @@ -6875,7 +7466,9 @@ def test_ccall(self): self.emcc_args.append('-Wno-return-stack-address') self.set_setting('EXPORTED_RUNTIME_METHODS', ['ccall', 'cwrap', 'STACK_SIZE']) self.set_setting('WASM_ASYNC_COMPILATION', 0) - create_file('post.js', ''' + create_file( + 'post.js', + ''' out('*'); var ret; ret = Module['ccall']('get_int', 'number'); out([typeof ret, ret].join(',')); @@ -6906,10 +7499,27 @@ def test_ccall(self): } out('stack is ok.'); ccall('call_ccall_again', null); - ''') + ''', + ) self.emcc_args += ['--post-js', 'post.js'] - self.set_setting('EXPORTED_FUNCTIONS', ['_get_int', '_get_float', '_get_bool', '_get_string', '_print_int', '_print_float', '_print_bool', '_print_string', '_multi', '_pointer', '_call_ccall_again', '_malloc']) + self.set_setting( + 'EXPORTED_FUNCTIONS', + [ + '_get_int', + '_get_float', + '_get_bool', + '_get_string', + '_print_int', + '_print_float', + '_print_bool', + '_print_string', + '_multi', + '_pointer', + '_call_ccall_again', + '_malloc', + ], + ) self.do_core_test('test_ccall.cpp') if self.maybe_closure(): @@ -6920,10 +7530,13 @@ def test_ccall_cwrap_fast_path(self): self.set_setting('EXPORTED_RUNTIME_METHODS', ['ccall', 'cwrap']) self.set_setting('WASM_ASYNC_COMPILATION', 0) self.set_setting('ASSERTIONS', 0) - create_file('post.js', ''' + create_file( + 'post.js', + ''' var printBool = Module['cwrap']('print_bool', null, ['boolean']); out(Module['_print_bool'] === printBool); // the function should be the exact raw function in the module rather than a wrapped one - ''') + ''', + ) self.emcc_args += ['--post-js', 'post.js'] self.set_setting('EXPORTED_FUNCTIONS', ['_print_bool']) @@ -6934,13 +7547,12 @@ def test_EXPORTED_RUNTIME_METHODS(self): self.do_core_test('EXPORTED_RUNTIME_METHODS.c') # test dyncall (and other runtime methods) can be exported self.emcc_args += ['-DEXPORTED'] - self.set_setting('EXPORTED_RUNTIME_METHODS', ['dynCall', 'addFunction', 'lengthBytesUTF8', 'getTempRet0', 'setTempRet0']) + self.set_setting( + 'EXPORTED_RUNTIME_METHODS', ['dynCall', 'addFunction', 'lengthBytesUTF8', 'getTempRet0', 'setTempRet0'] + ) self.do_core_test('EXPORTED_RUNTIME_METHODS.c') - @parameterized({ - '': [], - 'minimal_runtime': ['-sMINIMAL_RUNTIME=1'] - }) + @parameterized({'': [], 'minimal_runtime': ['-sMINIMAL_RUNTIME=1']}) def test_dyncall_specific(self, *args): if self.get_setting('MEMORY64'): self.skipTest('not compatible with MEMORY64') @@ -6950,26 +7562,28 @@ def test_dyncall_specific(self, *args): # more without them - we don't need to legalize) args = list(args) + ['-sDYNCALLS', '-DWASM_BIGINT'] cases = [ - ('DIRECT', []), - ('DYNAMIC_SIG', ['-sDYNCALLS']), - ] + ('DIRECT', []), + ('DYNAMIC_SIG', ['-sDYNCALLS']), + ] if '-sMINIMAL_RUNTIME=1' in args: self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')] else: cases += [ ('EXPORTED', []), ('EXPORTED_DYNAMIC_SIG', ['-sDYNCALLS', '-sEXPORTED_RUNTIME_METHODS=dynCall']), - ('FROM_OUTSIDE', ['-sEXPORTED_RUNTIME_METHODS=dynCall_iiji']) + ('FROM_OUTSIDE', ['-sEXPORTED_RUNTIME_METHODS=dynCall_iiji']), ] for which, extra_args in cases: print(str(args) + ' ' + which) self.do_core_test('test_dyncall_specific.c', emcc_args=['-D' + which] + list(args) + extra_args) - @parameterized({ - '': ([],), - 'legacy': (['-sDYNCALLS'],), - }) + @parameterized( + { + '': ([],), + 'legacy': (['-sDYNCALLS'],), + } + ) def test_dyncall_pointers(self, args): self.do_core_test('test_dyncall_pointers.c', emcc_args=args) @@ -6986,10 +7600,9 @@ def test(args=None, asserts=False): if self.get_setting('WASM_BIGINT'): out_suffix += '_bigint' assert_returncode = 0 if not asserts else NON_ZERO - self.do_run_in_out_file_test('core/test_getValue_setValue.cpp', - out_suffix=out_suffix, - assert_returncode=assert_returncode, - emcc_args=args) + self.do_run_in_out_file_test( + 'core/test_getValue_setValue.cpp', out_suffix=out_suffix, assert_returncode=assert_returncode, emcc_args=args + ) if self.get_setting('WASM_BIGINT'): self.emcc_args += ['-DWASM_BIGINT'] @@ -7012,19 +7625,21 @@ def test(args=None, asserts=False): self.set_setting('EXPORTED_RUNTIME_METHODS', ['getValue', 'setValue']) test() - @parameterized({ - '': ([],), - '_files': (['-DUSE_FILES'],) - }) + @parameterized({'': ([],), '_files': (['-DUSE_FILES'],)}) def test_FS_exports(self, extra_args): # these used to be exported, but no longer are by default def test(output_prefix='', args=None, assert_returncode=0): args += extra_args print(args) - self.do_runf('core/FS_exports.cpp', - (read_file(test_file('core/FS_exports' + output_prefix + '.out')), - read_file(test_file('core/FS_exports' + output_prefix + '_2.out'))), - assert_returncode=assert_returncode, emcc_args=args) + self.do_runf( + 'core/FS_exports.cpp', + ( + read_file(test_file('core/FS_exports' + output_prefix + '.out')), + read_file(test_file('core/FS_exports' + output_prefix + '_2.out')), + ), + assert_returncode=assert_returncode, + emcc_args=args, + ) # see that direct usage (not on module) works. we don't export, but the use # keeps it alive through JSDCE @@ -7041,8 +7656,9 @@ def test(output_prefix='', args=None, assert_returncode=0): def test_legacy_exported_runtime_numbers(self): # these used to be exported, but no longer are by default def test(expected, args=None, assert_returncode=0): - self.do_runf('core/legacy_exported_runtime_numbers.cpp', expected, - assert_returncode=assert_returncode, emcc_args=args) + self.do_runf( + 'core/legacy_exported_runtime_numbers.cpp', expected, assert_returncode=assert_returncode, emcc_args=args + ) # Without assertion indirect usages (via Module) result in `undefined` and direct usage # generates a builtin (not very helpful) JS error. @@ -7052,7 +7668,9 @@ def test(expected, args=None, assert_returncode=0): test('ALLOC_STACK is not defined', args=['-DDIRECT'], assert_returncode=NON_ZERO) # When assertions are enabled direct and indirect usage both abort with a useful error message. - not_exported = "Aborted('ALLOC_STACK' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ))" + not_exported = ( + "Aborted('ALLOC_STACK' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ))" + ) not_included = "`ALLOC_STACK` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='$ALLOC_STACK')" self.set_setting('ASSERTIONS') test(not_exported, assert_returncode=NON_ZERO) @@ -7155,10 +7773,7 @@ def test_emulate_function_pointer_casts(self): self.do_core_test('test_emulate_function_pointer_casts.cpp') @no_wasm2js('TODO: nicely printed names in wasm2js') - @parameterized({ - 'normal': ([],), - 'noexcept': (['-fno-exceptions'],) - }) + @parameterized({'normal': ([],), 'noexcept': (['-fno-exceptions'],)}) def test_demangle_stacks(self, extra_args): self.emcc_args += extra_args self.set_setting('ASSERTIONS') @@ -7205,7 +7820,11 @@ def test_demangle_stacks_symbol_map(self): # we may see the full one, if -g, or the short one if not if ' ' + short_aborter + ' ' not in output and ' ' + full_aborter + ' ' not in output: # stack traces may also be ' name ' or 'name@' etc - if '\n' + short_aborter + ' ' not in output and '\n' + full_aborter + ' ' not in output and 'wasm-function[' + short_aborter + ']' not in output: + if ( + '\n' + short_aborter + ' ' not in output + and '\n' + full_aborter + ' ' not in output + and 'wasm-function[' + short_aborter + ']' not in output + ): if '\n' + short_aborter + '@' not in output and '\n' + full_aborter + '@' not in output: self.assertContained(' ' + short_aborter + ' ' + '\n' + ' ' + full_aborter + ' ', output) @@ -7222,14 +7841,17 @@ def test_eval_ctors(self): print('leave printf in ctor') self.set_setting('EVAL_CTORS') - self.do_run(r''' + self.do_run( + r''' #include struct C { C() { printf("constructing!\n"); } // don't remove this! }; C c; int main() {} - ''', "constructing!\n") + ''', + "constructing!\n", + ) def do_test(test, level=1, prefix='src'): def get_code_size(): @@ -7252,7 +7874,8 @@ def get_code_size(): print('remove ctor of just assigns to memory') def test1(): - self.do_run(r''' + self.do_run( + r''' #include struct C { int x; @@ -7266,7 +7889,9 @@ def test1(): int main() { printf("x: %d\n", c.x); } - ''', "x: 11\n") + ''', + "x: 11\n", + ) do_test(test1) @@ -7284,13 +7909,17 @@ def test2(): do_test(test2, level=2, prefix='hello_libcxx') - @parameterized({ - '': (['-lembind', '-sDYNAMIC_EXECUTION=0'],), - 'flag': (['--bind'],), - }) + @parameterized( + { + '': (['-lembind', '-sDYNAMIC_EXECUTION=0'],), + 'flag': (['--bind'],), + } + ) def test_embind_val_basics(self, args): self.maybe_closure() - create_file('test.cpp', r''' + create_file( + 'test.cpp', + r''' #include #include @@ -7305,23 +7934,33 @@ def test_embind_val_basics(self, args): return 0; } - ''') + ''', + ) self.do_runf('test.cpp', 'abs(-10): 10\nabs(-11): 11', emcc_args=args) @node_pthreads def test_embind_basics(self): self.maybe_closure() self.emcc_args += [ - '-lembind', '--post-js', 'post.js', + '-lembind', + '--post-js', + 'post.js', # for extra coverage, test using pthreads - '-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME' + '-pthread', + '-sPROXY_TO_PTHREAD', + '-sEXIT_RUNTIME', ] - create_file('post.js', ''' + create_file( + 'post.js', + ''' function printLerp() { out('lerp ' + Module['lerp'](100, 200, 66) + '.'); } - ''') - create_file('test.cpp', r''' + ''', + ) + create_file( + 'test.cpp', + r''' #include #include #include @@ -7338,12 +7977,15 @@ def test_embind_basics(self): EM_ASM(printLerp()); return 0; } - ''') + ''', + ) self.do_runf('test.cpp', 'lerp 166') def test_embind_unbound_types(self): self.emcc_args += ['-lembind', '--post-js', 'post.js'] - create_file('post.js', ''' + create_file( + 'post.js', + ''' function ready() { try { Module['compute'](new Uint8Array([1,2,3])); @@ -7351,8 +7993,11 @@ def test_embind_unbound_types(self): out(e); } } - ''') - create_file('test.cpp', r''' + ''', + ) + create_file( + 'test.cpp', + r''' #include #include using namespace emscripten; @@ -7366,17 +8011,23 @@ def test_embind_unbound_types(self): EM_ASM(ready()); return 0; } - ''') + ''', + ) self.do_runf('test.cpp', 'UnboundTypeError: Cannot call compute due to unbound types: Pi') def test_embind_memory_view(self): self.emcc_args += ['-lembind', '--post-js', 'post.js'] - create_file('post.js', ''' + create_file( + 'post.js', + ''' function printFirstElement() { out(Module['getBufferView']()[0]); } - ''') - create_file('test.cpp', r''' + ''', + ) + create_file( + 'test.cpp', + r''' #include #include #include @@ -7398,7 +8049,8 @@ def test_embind_memory_view(self): EM_ASM(printFirstElement()); return 0; } - ''') + ''', + ) self.do_runf('test.cpp', '107') def test_embind_inheritance(self): @@ -7431,7 +8083,9 @@ def test_embind_val_assignment(self): @node_pthreads def test_embind_val_cross_thread(self): self.emcc_args += ['--bind'] - create_file('test_embind_val_cross_thread.cpp', r''' + create_file( + 'test_embind_val_cross_thread.cpp', + r''' #include #include #include @@ -7452,13 +8106,16 @@ def test_embind_val_cross_thread(self): // resolves to different values on different threads. printf("%d\n", value.as()); } - ''') + ''', + ) self.do_runf('test_embind_val_cross_thread.cpp', 'val accessed from wrong thread', assert_returncode=NON_ZERO) @node_pthreads def test_embind_val_cross_thread_deleted(self): self.emcc_args += ['--bind'] - create_file('test_embind_val_cross_thread.cpp', r''' + create_file( + 'test_embind_val_cross_thread.cpp', + r''' #include #include #include @@ -7480,24 +8137,31 @@ def test_embind_val_cross_thread_deleted(self): // There should be no cross-thread error here when it tries to free that value, // because the value has already been deleted on the correct thread. } - ''') + ''', + ) self.do_runf('test_embind_val_cross_thread.cpp') def test_embind_val_coro(self): - create_file('post.js', r'''Module.onRuntimeInitialized = () => { + create_file( + 'post.js', + r'''Module.onRuntimeInitialized = () => { Module.asyncCoro().then(console.log); - }''') + }''', + ) self.emcc_args += ['-std=c++20', '--bind', '--post-js=post.js'] self.do_runf('embind/test_val_coro.cpp', '34\n') def test_embind_val_coro_caught(self): self.set_setting('EXCEPTION_STACK_TRACES') - create_file('post.js', r'''Module.onRuntimeInitialized = () => { + create_file( + 'post.js', + r'''Module.onRuntimeInitialized = () => { Module.throwingCoro().then( console.log, err => console.error(`rejected with: ${err.stack}`) ); - }''') + }''', + ) self.emcc_args += ['-std=c++20', '--bind', '--post-js=post.js', '-fexceptions'] self.do_runf('embind/test_val_coro.cpp', 'rejected with: std::runtime_error: bang from throwingCoro!\n') @@ -7520,7 +8184,9 @@ def test_embind_i64_binding(self): self.do_run_in_out_file_test('embind/test_i64_binding.cpp', assert_identical=True) def test_embind_no_rtti(self): - create_file('main.cpp', r''' + create_file( + 'main.cpp', + r''' #include #include #include @@ -7543,14 +8209,17 @@ def test_embind_no_rtti(self): EMSCRIPTEN_BINDINGS(my_module) { emscripten::function("dotest", &test); } - ''') + ''', + ) self.emcc_args += ['-lembind', '-fno-rtti', '-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0'] self.do_runf('main.cpp', '418\ndotest returned: 42\n') - @parameterized({ - '': ([],), - 'no_rtti': (['-fno-rtti', '-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0'],), - }) + @parameterized( + { + '': ([],), + 'no_rtti': (['-fno-rtti', '-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0'],), + } + ) def test_embind_polymorphic_class(self, args): self.do_core_test('test_embind_polymorphic_class_no_rtti.cpp', emcc_args=args + ['-lembind']) @@ -7582,13 +8251,15 @@ def test_embind_no_rtti_followed_by_rtti(self): self.emcc_args += ['-lembind', '-fno-rtti', '-frtti'] self.do_run(src, '418\ndotest returned: 42\n') - @parameterized({ - '': ('DEFAULT', False), - 'all': ('ALL', False), - 'fast': ('FAST', False), - 'default': ('DEFAULT', False), - 'all_growth': ('ALL', True), - }) + @parameterized( + { + '': ('DEFAULT', False), + 'all': ('ALL', False), + 'fast': ('FAST', False), + 'default': ('DEFAULT', False), + 'all_growth': ('ALL', True), + } + ) def test_webidl(self, mode, allow_memory_growth): self.set_setting('WASM_ASYNC_COMPILATION', 0) if self.maybe_closure(): @@ -7625,7 +8296,12 @@ def test_webidl(self, mode, allow_memory_growth): # Export things on "TheModule". This matches the typical use pattern of # the bound library being used as Box2D.* or Ammo.*, and we cannot rely # on "Module" being always present (closure may remove it). - self.emcc_args += ['-sEXPORTED_FUNCTIONS=_malloc,_free', '-sEXPORTED_RUNTIME_METHODS=stringToUTF8', '--post-js=glue.js', '--extern-post-js=extern-post.js'] + self.emcc_args += [ + '-sEXPORTED_FUNCTIONS=_malloc,_free', + '-sEXPORTED_RUNTIME_METHODS=stringToUTF8', + '--post-js=glue.js', + '--extern-post-js=extern-post.js', + ] if mode == 'ALL': self.emcc_args += ['-sASSERTIONS'] if allow_memory_growth: @@ -7650,10 +8326,12 @@ def test_embind_sync_if_pthread_delayed(self): ### Tests for tools @no_wasm2js('TODO: source maps in wasm2js') - @parameterized({ - '': ([],), - 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), - }) + @parameterized( + { + '': ([],), + 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), + } + ) @requires_node def test_source_map(self, args): if '-g' not in self.emcc_args: @@ -7690,9 +8368,7 @@ def test_source_map(self, args): no_maps_file = re.sub(' *//[@#].*$', '', no_maps_file, flags=re.MULTILINE) self.emcc_args.append('-gsource-map') - self.emcc(os.path.abspath('src.cpp'), - self.get_emcc_args(), - out_filename) + self.emcc(os.path.abspath('src.cpp'), self.get_emcc_args(), out_filename) map_referent = out_filename if self.is_wasm2js() else wasm_filename # after removing the @line and @sourceMappingURL comments, the build # result should be identical to the non-source-mapped debug version. @@ -7713,9 +8389,7 @@ def test_source_map(self, args): # the sourcesContent attribute is optional, but if it is present it # needs to containt valid source text. self.assertTextDataIdentical(src, data['sourcesContent'][src_index]) - mappings = json.loads(self.run_js( - path_from_root('test/sourcemap2json.js'), - args=[map_filename])) + mappings = json.loads(self.run_js(path_from_root('test/sourcemap2json.js'), args=[map_filename])) seen_lines = set() for m in mappings: if m['source'] == 'src.cpp': @@ -7806,8 +8480,9 @@ def get_dwarf_addr(line, col): self.assertLess(get_dwarf_addr(7, 3), get_dwarf_addr(8, 3)) # Get the wat, printing with -g which has binary offsets - wat = self.run_process([Path(building.get_binaryen_bin(), 'wasm-opt'), - wasm_filename, '-g', '--print'], stdout=PIPE).stdout + wat = self.run_process( + [Path(building.get_binaryen_bin(), 'wasm-opt'), wasm_filename, '-g', '--print'], stdout=PIPE + ).stdout # We expect to see a pattern like this in optimized builds (there isn't # much that can change with such calls to JS (they can't be reordered or @@ -7875,8 +8550,10 @@ def test_modularize_closure_pre(self): self.ldflags.append('-Wno-error=closure') self.emcc_args += [ - '--pre-js', test_file('core/modularize_closure_pre.js'), - '--extern-post-js', test_file('modularize_post_js.js'), + '--pre-js', + test_file('core/modularize_closure_pre.js'), + '--extern-post-js', + test_file('modularize_post_js.js'), '--closure=1', '-g1', '-sMODULARIZE', @@ -7892,7 +8569,7 @@ def test_emscripten_log(self): self.do_run_in_out_file_test('emscripten_log/emscripten_log.cpp', interleaved_output=False) # test closure compiler as well if self.maybe_closure(): - self.emcc_args += ['-g1'] # extra testing + self.emcc_args += ['-g1'] # extra testing self.do_run_in_out_file_test('emscripten_log/emscripten_log_with_closure.cpp', interleaved_output=False) def test_float_literals(self): @@ -7901,7 +8578,9 @@ def test_float_literals(self): def test_exit_status(self): # needs to flush stdio streams self.set_setting('EXIT_RUNTIME') - create_file('exit.c', r''' + create_file( + 'exit.c', + r''' #include #include #include @@ -7926,17 +8605,23 @@ def test_exit_status(self): _Exit(119); #endif } - ''') - create_file('pre.js', ''' + ''', + ) + create_file( + 'pre.js', + ''' Module.onExit = (status) => { out('I see exit status: ' + status); // The EXITSTATUS global should match what we are passed assert(status == EXITSTATUS); }; - ''') + ''', + ) self.emcc_args += ['--pre-js', 'pre.js'] print('.. exit') - self.do_runf('exit.c', 'hello, world!\ncleanup\nI see exit status: 117', assert_returncode=117, emcc_args=['-DNORMAL_EXIT']) + self.do_runf( + 'exit.c', 'hello, world!\ncleanup\nI see exit status: 117', assert_returncode=117, emcc_args=['-DNORMAL_EXIT'] + ) print('.. _exit') self.do_runf('exit.c', 'hello, world!\nI see exit status: 118', assert_returncode=118, emcc_args=['-DUNDER_EXIT']) print('.. _Exit') @@ -7967,14 +8652,17 @@ def test_asyncify_longjmp(self): # Test that a main with arguments is automatically asyncified. @with_asyncify_and_jspi def test_async_main(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main(int argc, char **argv) { emscripten_sleep(1); printf("argc=%d argv=%s\n", argc, argv[1]); } -''') +''', + ) self.do_runf('main.c', 'argc=2 argv=hello', args=['hello']) @@ -7983,7 +8671,9 @@ def test_async_hello(self): # needs to flush stdio streams self.set_setting('EXIT_RUNTIME') - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include void f(void *p) { @@ -7998,13 +8688,16 @@ def test_async_hello(self): emscripten_sleep(100); printf("%d\n", i); } -''') +''', + ) self.do_runf('main.c', 'HelloWorld!99') @with_asyncify_and_jspi def test_async_loop(self): - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main() { @@ -8013,7 +8706,8 @@ def test_async_loop(self): printf("hello %d\n", i); } } -''') +''', + ) self.do_runf('main.c', 'hello 0\nhello 1\nhello 2\nhello 3\nhello 4\n') @@ -8028,7 +8722,9 @@ def test_async_ccall_bad(self): self.set_setting('ASYNCIFY') self.set_setting('ASSERTIONS') self.set_setting('INVOKE_RUN', 0) - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main() { @@ -8036,8 +8732,11 @@ def test_async_ccall_bad(self): emscripten_sleep(100); printf("World\n"); } -''') - create_file('pre.js', ''' +''', + ) + create_file( + 'pre.js', + ''' Module.onRuntimeInitialized = () => { try { ccall('main', 'number', ['number', 'string'], [2, 'waka']); @@ -8047,7 +8746,8 @@ def test_async_ccall_bad(self): assert(!never); } }; -''') +''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'The call to main is running asynchronously.') @@ -8058,7 +8758,9 @@ def test_async_ccall_good(self): self.set_setting('ASSERTIONS') self.set_setting('INVOKE_RUN', 0) self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$ccall']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include int main() { @@ -8066,21 +8768,27 @@ def test_async_ccall_good(self): emscripten_sleep(100); printf("World\n"); } -''') - create_file('pre.js', ''' +''', + ) + create_file( + 'pre.js', + ''' Module.onRuntimeInitialized = () => { ccall('main', null, ['number', 'string'], [2, 'waka'], { async: true }); }; -''') +''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'HelloWorld') - @parameterized({ - 'asyncify': (False, 1), - 'exit_runtime_asyncify': (True, 1), - 'jspi': (False, 2), - 'exit_runtime_jspi': (True, 2), - }) + @parameterized( + { + 'asyncify': (False, 1), + 'exit_runtime_asyncify': (True, 1), + 'jspi': (False, 2), + 'exit_runtime_jspi': (True, 2), + } + ) def test_async_ccall_promise(self, exit_runtime, asyncify): if asyncify == 2: self.require_jspi() @@ -8091,7 +8799,9 @@ def test_async_ccall_promise(self, exit_runtime, asyncify): self.set_setting('EXIT_RUNTIME', exit_runtime) self.set_setting('EXPORTED_FUNCTIONS', ['_stringf', '_floatf']) self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$maybeExit', '$ccall']) - create_file('main.c', r''' + create_file( + 'main.c', + r''' #include #include const char* stringf(char* param) { @@ -8104,8 +8814,11 @@ def test_async_ccall_promise(self, exit_runtime, asyncify): emscripten_sleep(20); return 6.4; } -''') - create_file('pre.js', r''' +''', + ) + create_file( + 'pre.js', + r''' Module.onRuntimeInitialized = () => { runtimeKeepalivePush(); ccall('stringf', 'string', ['string'], ['first\n'], { async: true }) @@ -8118,7 +8831,8 @@ def test_async_ccall_promise(self, exit_runtime, asyncify): }); }); }; -''') +''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'stringf: first\nsecond\n6.4') @@ -8132,18 +8846,26 @@ def test_asyncify_unused(self): # test a program not using asyncify, but the pref is set self.do_core_test('test_hello_world.c') - @parameterized({ - 'normal': ([], True), - 'removelist_a': (['-sASYNCIFY_REMOVE=["foo(int, double)"]'], False), - 'removelist_b': (['-sASYNCIFY_REMOVE=["bar()"]'], True), - 'removelist_c': (['-sASYNCIFY_REMOVE=["baz()"]'], False), - 'onlylist_a': (['-sASYNCIFY_ONLY=["main","__original_main","foo(int, double)","baz()","c_baz","Structy::funcy()","bar()"]'], True), - 'onlylist_b': (['-sASYNCIFY_ONLY=["main","__original_main","foo(int, double)","baz()","c_baz","Structy::funcy()"]'], True), - 'onlylist_c': (['-sASYNCIFY_ONLY=["main","__original_main","foo(int, double)","baz()","c_baz"]'], False), - 'onlylist_d': (['-sASYNCIFY_ONLY=["foo(int, double)","baz()","c_baz","Structy::funcy()"]'], False), - 'onlylist_b_response': ([], True, 'main\n__original_main\nfoo(int, double)\nbaz()\nc_baz\nStructy::funcy()\n'), - 'onlylist_c_response': ([], False, 'main\n__original_main\nfoo(int, double)\nbaz()\nc_baz\n'), - }) + @parameterized( + { + 'normal': ([], True), + 'removelist_a': (['-sASYNCIFY_REMOVE=["foo(int, double)"]'], False), + 'removelist_b': (['-sASYNCIFY_REMOVE=["bar()"]'], True), + 'removelist_c': (['-sASYNCIFY_REMOVE=["baz()"]'], False), + 'onlylist_a': ( + ['-sASYNCIFY_ONLY=["main","__original_main","foo(int, double)","baz()","c_baz","Structy::funcy()","bar()"]'], + True, + ), + 'onlylist_b': ( + ['-sASYNCIFY_ONLY=["main","__original_main","foo(int, double)","baz()","c_baz","Structy::funcy()"]'], + True, + ), + 'onlylist_c': (['-sASYNCIFY_ONLY=["main","__original_main","foo(int, double)","baz()","c_baz"]'], False), + 'onlylist_d': (['-sASYNCIFY_ONLY=["foo(int, double)","baz()","c_baz","Structy::funcy()"]'], False), + 'onlylist_b_response': ([], True, 'main\n__original_main\nfoo(int, double)\nbaz()\nc_baz\nStructy::funcy()\n'), + 'onlylist_c_response': ([], False, 'main\n__original_main\nfoo(int, double)\nbaz()\nc_baz\n'), + } + ) def test_asyncify_lists(self, args, should_pass, response=None): if response is not None: create_file('response.file', response) @@ -8154,7 +8876,7 @@ def test_asyncify_lists(self, args, should_pass, response=None): if should_pass: self.do_core_test('test_asyncify_lists.cpp', assert_identical=True) else: - self.do_runf('core/test_asyncify_lists.cpp', ('RuntimeError', 'Thrown at'), assert_returncode=NON_ZERO) + self.do_runf('core/test_asyncify_lists.cpp', ('RuntimeError', 'Thrown at'), assert_returncode=NON_ZERO) # use of ASYNCIFY_* options may require intermediate debug info. that should # not end up emitted in the final binary @@ -8170,14 +8892,23 @@ def test_asyncify_lists(self, args, should_pass, response=None): binary = read_binary(filename) self.assertFalse(b'main' in binary) - @parameterized({ - 'normal': ([], True), - 'ignoreindirect': (['-sASYNCIFY_IGNORE_INDIRECT'], False), - 'add': (['-sASYNCIFY_IGNORE_INDIRECT', '-sASYNCIFY_ADD=["virt()"]'], True), - # If ASYNCIFY_PROPAGATE_ADD is disabled then we must specify the callers of - # virt() manually, rather than have them inferred automatically. - 'add_no_prop': (['-sASYNCIFY_IGNORE_INDIRECT', '-sASYNCIFY_ADD=["__original_main","main","virt()"]', '-sASYNCIFY_PROPAGATE_ADD=0'], True), - }) + @parameterized( + { + 'normal': ([], True), + 'ignoreindirect': (['-sASYNCIFY_IGNORE_INDIRECT'], False), + 'add': (['-sASYNCIFY_IGNORE_INDIRECT', '-sASYNCIFY_ADD=["virt()"]'], True), + # If ASYNCIFY_PROPAGATE_ADD is disabled then we must specify the callers of + # virt() manually, rather than have them inferred automatically. + 'add_no_prop': ( + [ + '-sASYNCIFY_IGNORE_INDIRECT', + '-sASYNCIFY_ADD=["__original_main","main","virt()"]', + '-sASYNCIFY_PROPAGATE_ADD=0', + ], + True, + ), + } + ) def test_asyncify_indirect_lists(self, args, should_pass): self.set_setting('ASYNCIFY') self.emcc_args += args @@ -8198,7 +8929,8 @@ def test_asyncify_indirect_lists(self, args, should_pass): def test_asyncify_side_module(self): self.set_setting('ASYNCIFY') self.set_setting('ASYNCIFY_IMPORTS', ['my_sleep']) - self.dylink_test(r''' + self.dylink_test( + r''' #include #include "header.h" @@ -8208,7 +8940,8 @@ def test_asyncify_side_module(self): printf("after sleep\n"); return 0; } - ''', r''' + ''', + r''' #include #include #include "header.h" @@ -8221,7 +8954,11 @@ def test_asyncify_side_module(self): // variable on stack in side module function should be restored. printf("%d\n", value); } - ''', 'before sleep\n42\n42\nafter sleep\n', header='void my_sleep(int);', force_c=True) + ''', + 'before sleep\n42\n42\nafter sleep\n', + header='void my_sleep(int);', + force_c=True, + ) @no_asan('asyncify stack operations confuse asan') def test_emscripten_scan_registers(self): @@ -8259,24 +8996,27 @@ def test_asyncify_main_module(self): def test_pthread_join_and_asyncify(self): # TODO Test with ASYNCIFY=1 https://github.com/emscripten-core/emscripten/issues/17552 self.require_jspi() - self.do_runf('core/test_pthread_join_and_asyncify.c', 'joining thread!\njoined thread!', - emcc_args=['-sJSPI', - '-sEXIT_RUNTIME=1', - '-pthread', '-sPROXY_TO_PTHREAD']) + self.do_runf( + 'core/test_pthread_join_and_asyncify.c', + 'joining thread!\njoined thread!', + emcc_args=['-sJSPI', '-sEXIT_RUNTIME=1', '-pthread', '-sPROXY_TO_PTHREAD'], + ) @no_asan('asyncify stack operations confuse asan') @no_wasm2js('TODO: lazy loading in wasm2js') - @parameterized({ - 'conditional': (True,), - 'unconditional': (False,), - }) + @parameterized( + { + 'conditional': (True,), + 'unconditional': (False,), + } + ) def test_emscripten_lazy_load_code(self, conditional): if self.get_setting('STACK_OVERFLOW_CHECK'): self.skipTest('https://github.com/emscripten-core/emscripten/issues/16828') self.set_setting('ASYNCIFY_LAZY_LOAD_CODE') self.set_setting('ASYNCIFY_IGNORE_INDIRECT') self.set_setting('MALLOC', 'emmalloc') - self.emcc_args += ['--profiling-funcs'] # so that we can find the functions for the changes below + self.emcc_args += ['--profiling-funcs'] # so that we can find the functions for the changes below if conditional: self.emcc_args += ['-DCONDITIONAL'] self.do_core_test('emscripten_lazy_load_code.cpp', args=['0']) @@ -8289,10 +9029,13 @@ def test_emscripten_lazy_load_code(self, conditional): # For the purposes of this test we don't consider O1 to be optimizing is_optimizing = self.is_optimizing() and '-O1' not in self.emcc_args - if not conditional and is_optimizing and \ - '-g' not in self.emcc_args and \ - '-fsanitize=leak' not in self.emcc_args and \ - not self.get_setting('WASMFS'): + if ( + not conditional + and is_optimizing + and '-g' not in self.emcc_args + and '-fsanitize=leak' not in self.emcc_args + and not self.get_setting('WASMFS') + ): # TODO: WasmFS has not yet been optimized for code size, and the general # increase it causes mixes up code size measurements like this. # See https://github.com/emscripten-core/emscripten/issues/16005 @@ -8331,7 +9074,9 @@ def verify_working(args): self.assertContained('foo_end\n', self.run_js('emscripten_lazy_load_code.js', args=args)) def verify_broken(args): - self.assertNotContained('foo_end\n', self.run_js('emscripten_lazy_load_code.js', args=args, assert_returncode=NON_ZERO)) + self.assertNotContained( + 'foo_end\n', self.run_js('emscripten_lazy_load_code.js', args=args, assert_returncode=NON_ZERO) + ) # the first-loaded wasm will not reach the second call, since we call it after lazy-loading. # verify that by changing the first wasm to throw in that function @@ -8388,10 +9133,12 @@ def test_maybe_wasm2js(self): @no_asan('no wasm2js support yet in asan') @requires_wasm2js - @parameterized({ - '': ([],), - 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), - }) + @parameterized( + { + '': ([],), + 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), + } + ) def test_wasm2js_fallback(self, args): if self.is_wasm2js(): self.skipTest('redundant to test wasm2js in wasm2js* mode') @@ -8407,12 +9154,13 @@ def test_wasm2js_fallback(self, args): # Then disable WebAssembly support in VM, and try again.. Should still work with Wasm2JS fallback. create_file('b.out.js', 'WebAssembly = undefined;\n' + read_file('a.out.js')) - os.remove('a.out.wasm') # Also delete the Wasm file to test that it is not attempted to be loaded. + os.remove('a.out.wasm') # Also delete the Wasm file to test that it is not attempted to be loaded. self.assertContained('hello!', self.run_js('b.out.js')) def test_cxx_self_assign(self): # See https://github.com/emscripten-core/emscripten/pull/2688 and http://llvm.org/bugs/show_bug.cgi?id=18735 - self.do_run(r''' + self.do_run( + r''' #include #include @@ -8425,20 +9173,27 @@ def test_cxx_self_assign(self): printf("ok.\n"); } } - ''', 'ok.') + ''', + 'ok.', + ) def test_memprof_requirements(self): # This test checks for the global variables required to run the memory # profiler. It would fail if these variables were made no longer global # or if their identifiers were changed. - create_file('main.c', ''' + create_file( + 'main.c', + ''' int check_memprof_requirements(); int main() { return check_memprof_requirements(); } - ''') - create_file('lib.js', ''' + ''', + ) + create_file( + 'lib.js', + ''' addToLibrary({ check_memprof_requirements: () => { if (typeof _emscripten_stack_get_base === 'function' && @@ -8453,7 +9208,8 @@ def test_memprof_requirements(self): } } }); - ''') + ''', + ) self.emcc_args += ['--memoryprofiler', '--js-library', 'lib.js'] self.do_runf('main.c', 'able to run memprof') @@ -8461,7 +9217,9 @@ def test_fs_dict(self): self.set_setting('FORCE_FILESYSTEM') self.emcc_args += ['-lidbfs.js'] self.emcc_args += ['-lnodefs.js'] - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.preRun = () => { out(typeof FS.filesystems['MEMFS']); out(typeof FS.filesystems['IDBFS']); @@ -8471,7 +9229,8 @@ def test_fs_dict(self): out(typeof IDBFS); out(typeof NODEFS); }; - ''') + ''', + ) self.emcc_args += ['--pre-js', 'pre.js'] self.do_run('int main() { return 0; }', 'object\nobject\nobject\nobject\nobject\nobject') @@ -8479,7 +9238,9 @@ def test_fs_dict_none(self): # if IDBFS and NODEFS are not enabled, they are not present. self.set_setting('FORCE_FILESYSTEM') self.set_setting('ASSERTIONS') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' Module.preRun = () => { out(typeof FS.filesystems['MEMFS']); out(typeof FS.filesystems['IDBFS']); @@ -8495,7 +9256,8 @@ def test_fs_dict_none(self): out('|' + e + '|'); } }; - ''') + ''', + ) self.emcc_args += ['--pre-js', 'pre.js'] expected = '''\ object @@ -8544,12 +9306,14 @@ def test_mallinfo(self): @no_asan('cannot replace malloc/free with ASan') @no_lsan('cannot replace malloc/free with LSan') - @parameterized({ - '': ([],), - 'emmalloc': (['-sMALLOC=emmalloc'],), - # FIXME(https://github.com/emscripten-core/emscripten/issues/23090) - # 'mimalloc': (['-sMALLOC=mimalloc'],), - }) + @parameterized( + { + '': ([],), + 'emmalloc': (['-sMALLOC=emmalloc'],), + # FIXME(https://github.com/emscripten-core/emscripten/issues/23090) + # 'mimalloc': (['-sMALLOC=mimalloc'],), + } + ) def test_wrap_malloc(self, args): self.do_runf('core/test_wrap_malloc.c', 'OK.', emcc_args=args) @@ -8559,7 +9323,9 @@ def test_environment(self): def test(assert_returncode=0): self.do_core_test('test_hello_world.c', assert_returncode=assert_returncode) js = read_file('test_hello_world.js') - assert ('require(' in js) == ('node' in self.get_setting('ENVIRONMENT')), 'we should have require() calls only if node js specified' + assert ('require(' in js) == ( + 'node' in self.get_setting('ENVIRONMENT') + ), 'we should have require() calls only if node js specified' for engine in config.JS_ENGINES: print(f'engine: {engine}') @@ -8600,9 +9366,12 @@ def test_postrun_exception(self): self.assertContained('ThisFunctionDoesNotExist is not defined', output) def test_postrun_exit_runtime(self): - create_file('post.js', ''' + create_file( + 'post.js', + ''' addOnPostRun(() => err('post run\\n')); - ''') + ''', + ) self.set_setting('EXIT_RUNTIME') self.emcc_args.append('--post-js=post.js') self.do_runf('hello_world.c', 'post run') @@ -8638,12 +9407,14 @@ def test_minimal_runtime_no_declare_asm_module_exports(self): # Tests that -sMINIMAL_RUNTIME works well in different build modes @no_wasmfs('https://github.com/emscripten-core/emscripten/issues/16816') - @parameterized({ - 'default': ([],), - 'streaming': (['-sMINIMAL_RUNTIME_STREAMING_WASM_COMPILATION'],), - 'streaming_inst': (['-sMINIMAL_RUNTIME_STREAMING_WASM_INSTANTIATION'],), - 'no_export': (['-sDECLARE_ASM_MODULE_EXPORTS=0'],) - }) + @parameterized( + { + 'default': ([],), + 'streaming': (['-sMINIMAL_RUNTIME_STREAMING_WASM_COMPILATION'],), + 'streaming_inst': (['-sMINIMAL_RUNTIME_STREAMING_WASM_INSTANTIATION'],), + 'no_export': (['-sDECLARE_ASM_MODULE_EXPORTS=0'],), + } + ) @requires_node # TODO: Support for non-Node.js shells under MINIMAL_RUNTIME def test_minimal_runtime_hello_world(self, args): self.emcc_args = args @@ -8653,10 +9424,12 @@ def test_minimal_runtime_hello_world(self, args): # Test that printf() works in MINIMAL_RUNTIME=1 @no_wasmfs('https://github.com/emscripten-core/emscripten/issues/16816') - @parameterized({ - 'fs': ('FORCE_FILESYSTEM',), - 'nofs': ('NO_FILESYSTEM',), - }) + @parameterized( + { + 'fs': ('FORCE_FILESYSTEM',), + 'nofs': ('NO_FILESYSTEM',), + } + ) @no_asan('TODO: ASan support in minimal runtime') def test_minimal_runtime_hello_printf(self, extra_setting): self.set_setting('MINIMAL_RUNTIME') @@ -8701,24 +9474,30 @@ def test_return_address(self): @no_lsan('-fsanitize-minimal-runtime cannot be used with LSan') def test_ubsan_minimal_too_many_errors(self): self.emcc_args += ['-fsanitize=undefined', '-fsanitize-minimal-runtime'] - self.do_runf('core/test_ubsan_minimal_too_many_errors.c', - expected_output='ubsan: add-overflow by 0x[0-9a-f]*\n' * 20 + 'ubsan: too many errors\n', - regex=True) + self.do_runf( + 'core/test_ubsan_minimal_too_many_errors.c', + expected_output='ubsan: add-overflow by 0x[0-9a-f]*\n' * 20 + 'ubsan: too many errors\n', + regex=True, + ) @no_wasm2js('TODO: sanitizers in wasm2js') @no_asan('-fsanitize-minimal-runtime cannot be used with ASan') @no_lsan('-fsanitize-minimal-runtime cannot be used with LSan') def test_ubsan_minimal_errors_same_place(self): self.emcc_args += ['-fsanitize=undefined', '-fsanitize-minimal-runtime'] - self.do_runf('core/test_ubsan_minimal_errors_same_place.c', - expected_output='ubsan: add-overflow by 0x[0-9a-z]*\n' * 5, - regex=True) - - @parameterized({ - 'fsanitize_undefined': (['-fsanitize=undefined'],), - 'fsanitize_integer': (['-fsanitize=integer'],), - 'fsanitize_overflow': (['-fsanitize=signed-integer-overflow'],), - }) + self.do_runf( + 'core/test_ubsan_minimal_errors_same_place.c', + expected_output='ubsan: add-overflow by 0x[0-9a-z]*\n' * 5, + regex=True, + ) + + @parameterized( + { + 'fsanitize_undefined': (['-fsanitize=undefined'],), + 'fsanitize_integer': (['-fsanitize=integer'],), + 'fsanitize_overflow': (['-fsanitize=signed-integer-overflow'],), + } + ) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_full_overflow(self, args): self.emcc_args += args @@ -8728,23 +9507,31 @@ def test_ubsan_full_overflow(self, args): expected_output=[ ".c:3:5: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'", ".c:7:7: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'", - ]) + ], + ) - @parameterized({ - 'fsanitize_undefined': (['-fsanitize=undefined'],), - 'fsanitize_return': (['-fsanitize=return'],), - }) + @parameterized( + { + 'fsanitize_undefined': (['-fsanitize=undefined'],), + 'fsanitize_return': (['-fsanitize=return'],), + } + ) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_full_no_return(self, args): self.emcc_args += ['-Wno-return-type'] + args - self.do_runf('core/test_ubsan_full_no_return.cpp', - expected_output='.cpp:1:5: runtime error: execution reached the end of a value-returning function without returning a value', assert_returncode=NON_ZERO) - - @parameterized({ - 'fsanitize_undefined': (['-fsanitize=undefined'],), - 'fsanitize_integer': (['-fsanitize=integer'],), - 'fsanitize_shift': (['-fsanitize=shift'],), - }) + self.do_runf( + 'core/test_ubsan_full_no_return.cpp', + expected_output='.cpp:1:5: runtime error: execution reached the end of a value-returning function without returning a value', + assert_returncode=NON_ZERO, + ) + + @parameterized( + { + 'fsanitize_undefined': (['-fsanitize=undefined'],), + 'fsanitize_integer': (['-fsanitize=integer'],), + 'fsanitize_shift': (['-fsanitize=shift'],), + } + ) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_full_left_shift(self, args): self.emcc_args += args @@ -8753,14 +9540,17 @@ def test_ubsan_full_left_shift(self, args): assert_all=True, expected_output=[ '.c:3:5: runtime error: left shift of negative value -1', - ".c:7:5: runtime error: left shift of 16 by 29 places cannot be represented in type 'int'" - ]) - - @parameterized({ - 'fsanitize_undefined': (['-fsanitize=undefined'],), - 'fsanitize_null': (['-fsanitize=null'],), - 'dylink': (['-fsanitize=null', '-sMAIN_MODULE=2'],), - }) + ".c:7:5: runtime error: left shift of 16 by 29 places cannot be represented in type 'int'", + ], + ) + + @parameterized( + { + 'fsanitize_undefined': (['-fsanitize=undefined'],), + 'fsanitize_null': (['-fsanitize=null'],), + 'dylink': (['-fsanitize=null', '-sMAIN_MODULE=2'],), + } + ) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_full_null_ref(self, args): if '-sMAIN_MODULE=2' in args: @@ -8775,12 +9565,15 @@ def test_ubsan_full_null_ref(self, args): ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", ".cpp:4:13: runtime error: reference binding to null pointer of type 'int'", ".cpp:5:14: runtime error: reference binding to null pointer of type 'int'", - ]) + ], + ) - @parameterized({ - 'fsanitize_undefined': (['-fsanitize=undefined'],), - 'fsanitize_vptr': (['-fsanitize=vptr'],), - }) + @parameterized( + { + 'fsanitize_undefined': (['-fsanitize=undefined'],), + 'fsanitize_vptr': (['-fsanitize=vptr'],), + } + ) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_full_static_cast(self, args): self.emcc_args += args @@ -8790,19 +9583,24 @@ def test_ubsan_full_static_cast(self, args): expected_output=[ ".cpp:18:10: runtime error: downcast of address", "which does not point to an object of type 'R'", - ]) - - @parameterized({ - 'g': ('-g', [ - ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", - 'in main', - ]), - 'g4': ('-gsource-map', [ - ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", - 'in main ', - '.cpp:3:8' - ]), - }) + ], + ) + + @parameterized( + { + 'g': ( + '-g', + [ + ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", + 'in main', + ], + ), + 'g4': ( + '-gsource-map', + [".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", 'in main ', '.cpp:3:8'], + ), + } + ) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_full_stack_trace(self, g_flag, expected_output): if g_flag == '-gsource-map': @@ -8814,8 +9612,7 @@ def test_ubsan_full_stack_trace(self, g_flag, expected_output): create_file('pre.js', 'Module.UBSAN_OPTIONS = "print_stacktrace=1";') self.emcc_args += ['-fsanitize=null', g_flag, '--pre-js=pre.js'] self.set_setting('ALLOW_MEMORY_GROWTH') - self.do_runf('core/test_ubsan_full_null_ref.cpp', - assert_all=True, expected_output=expected_output) + self.do_runf('core/test_ubsan_full_null_ref.cpp', assert_all=True, expected_output=expected_output) @no_wasm2js('TODO: sanitizers in wasm2js') def test_ubsan_typeinfo_eq(self): @@ -8840,10 +9637,12 @@ def test_template_class_deduction(self): @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm64('TODO: ASAN in memory64') @no_2gb('asan doesnt support GLOBAL_BASE') - @parameterized({ - 'c': ['test_asan_no_error.c'], - 'cpp': ['test_asan_no_error.cpp'], - }) + @parameterized( + { + 'c': ['test_asan_no_error.c'], + 'cpp': ['test_asan_no_error.cpp'], + } + ) def test_asan_no_error(self, name): self.emcc_args.append('-fsanitize=address') self.set_setting('ALLOW_MEMORY_GROWTH') @@ -8857,63 +9656,101 @@ def test_asan_no_error(self, name): @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm64('TODO: ASAN in memory64') @no_2gb('asan doesnt support GLOBAL_BASE') - @parameterized({ - 'use_after_free_c': ('test_asan_use_after_free.c', [ - 'AddressSanitizer: heap-use-after-free on address', - ]), - 'use_after_free_cpp': ('test_asan_use_after_free.cpp', [ - 'AddressSanitizer: heap-use-after-free on address', - ]), - 'use_after_return': ('test_asan_use_after_return.c', [ - 'AddressSanitizer: stack-use-after-return on address', - ], ['-Wno-return-stack-address']), - 'static_buffer_overflow': ('test_asan_static_buffer_overflow.c', [ - 'AddressSanitizer: global-buffer-overflow on address', - ], ['-fno-builtin-memset']), - 'heap_buffer_overflow_c': ('test_asan_heap_buffer_overflow.c', [ - 'AddressSanitizer: heap-buffer-overflow on address', - ], ['-fno-builtin-memset']), - 'heap_buffer_overflow_cpp': ('test_asan_heap_buffer_overflow.cpp', [ - 'AddressSanitizer: heap-buffer-overflow on address', - ], ['-fno-builtin-memset']), - 'stack_buffer_overflow': ('test_asan_stack_buffer_overflow.c', [ - 'AddressSanitizer: stack-buffer-overflow' - ], ['-fno-builtin-memset']), - 'stack_buffer_overflow_js': ('test_asan_stack_buffer_overflow_js.c', [ - 'AddressSanitizer: stack-buffer-overflow' - ], ['-fno-builtin-memset']), - 'bitfield_unround_size': ('test_asan_bitfield_unround_size.c', [ - 'AddressSanitizer: stack-buffer-overflow' - ], ['-fno-builtin-memset']), - 'bitfield_unround_offset': ('test_asan_bitfield_unround_offset.c', [ - 'AddressSanitizer: stack-buffer-overflow' - ], ['-fno-builtin-memset']), - 'bitfield_round': ('test_asan_bitfield_round.c', [ - 'AddressSanitizer: stack-buffer-overflow' - ], ['-fno-builtin-memset']), - 'memset_null': ('test_asan_memset_null.c', [ - 'AddressSanitizer: null-pointer-dereference on address 0x00000001' - ], ['-fno-builtin-memset']), - 'memset_freed': ('test_asan_memset_freed.c', [ - 'AddressSanitizer: heap-use-after-free on address' - ], ['-fno-builtin-memset']), - 'strcpy': ('test_asan_strcpy.c', [ - 'AddressSanitizer: heap-buffer-overflow on address' - ], ['-fno-builtin-strcpy']), - 'memcpy': ('test_asan_memcpy.c', [ - 'AddressSanitizer: heap-buffer-overflow on address' - ], ['-fno-builtin-memcpy']), - 'memchr': ('test_asan_memchr.c', [ - 'AddressSanitizer: global-buffer-overflow on address' - ], ['-fno-builtin-memchr']), - 'vector': ('test_asan_vector.cpp', [ - 'AddressSanitizer: container-overflow on address' - ]), - # some coverage for mimalloc as well - 'use_after_free_c_mimalloc': ('test_asan_use_after_free.c', [ - 'AddressSanitizer: heap-use-after-free on address', - ], ['-sMALLOC=mimalloc']), - }) + @parameterized( + { + 'use_after_free_c': ( + 'test_asan_use_after_free.c', + [ + 'AddressSanitizer: heap-use-after-free on address', + ], + ), + 'use_after_free_cpp': ( + 'test_asan_use_after_free.cpp', + [ + 'AddressSanitizer: heap-use-after-free on address', + ], + ), + 'use_after_return': ( + 'test_asan_use_after_return.c', + [ + 'AddressSanitizer: stack-use-after-return on address', + ], + ['-Wno-return-stack-address'], + ), + 'static_buffer_overflow': ( + 'test_asan_static_buffer_overflow.c', + [ + 'AddressSanitizer: global-buffer-overflow on address', + ], + ['-fno-builtin-memset'], + ), + 'heap_buffer_overflow_c': ( + 'test_asan_heap_buffer_overflow.c', + [ + 'AddressSanitizer: heap-buffer-overflow on address', + ], + ['-fno-builtin-memset'], + ), + 'heap_buffer_overflow_cpp': ( + 'test_asan_heap_buffer_overflow.cpp', + [ + 'AddressSanitizer: heap-buffer-overflow on address', + ], + ['-fno-builtin-memset'], + ), + 'stack_buffer_overflow': ( + 'test_asan_stack_buffer_overflow.c', + ['AddressSanitizer: stack-buffer-overflow'], + ['-fno-builtin-memset'], + ), + 'stack_buffer_overflow_js': ( + 'test_asan_stack_buffer_overflow_js.c', + ['AddressSanitizer: stack-buffer-overflow'], + ['-fno-builtin-memset'], + ), + 'bitfield_unround_size': ( + 'test_asan_bitfield_unround_size.c', + ['AddressSanitizer: stack-buffer-overflow'], + ['-fno-builtin-memset'], + ), + 'bitfield_unround_offset': ( + 'test_asan_bitfield_unround_offset.c', + ['AddressSanitizer: stack-buffer-overflow'], + ['-fno-builtin-memset'], + ), + 'bitfield_round': ( + 'test_asan_bitfield_round.c', + ['AddressSanitizer: stack-buffer-overflow'], + ['-fno-builtin-memset'], + ), + 'memset_null': ( + 'test_asan_memset_null.c', + ['AddressSanitizer: null-pointer-dereference on address 0x00000001'], + ['-fno-builtin-memset'], + ), + 'memset_freed': ( + 'test_asan_memset_freed.c', + ['AddressSanitizer: heap-use-after-free on address'], + ['-fno-builtin-memset'], + ), + 'strcpy': ('test_asan_strcpy.c', ['AddressSanitizer: heap-buffer-overflow on address'], ['-fno-builtin-strcpy']), + 'memcpy': ('test_asan_memcpy.c', ['AddressSanitizer: heap-buffer-overflow on address'], ['-fno-builtin-memcpy']), + 'memchr': ( + 'test_asan_memchr.c', + ['AddressSanitizer: global-buffer-overflow on address'], + ['-fno-builtin-memchr'], + ), + 'vector': ('test_asan_vector.cpp', ['AddressSanitizer: container-overflow on address']), + # some coverage for mimalloc as well + 'use_after_free_c_mimalloc': ( + 'test_asan_use_after_free.c', + [ + 'AddressSanitizer: heap-use-after-free on address', + ], + ['-sMALLOC=mimalloc'], + ), + } + ) def test_asan(self, name, expected_output, cflags=None): if '-Oz' in self.emcc_args: self.skipTest('-Oz breaks source maps') @@ -8926,9 +9763,13 @@ def test_asan(self, name, expected_output, cflags=None): self.set_setting('INITIAL_MEMORY', '300mb') if cflags: self.emcc_args += cflags - self.do_runf('core/' + name, - expected_output=expected_output, assert_all=True, - check_for_error=False, assert_returncode=NON_ZERO) + self.do_runf( + 'core/' + name, + expected_output=expected_output, + assert_all=True, + check_for_error=False, + assert_returncode=NON_ZERO, + ) @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm2js('TODO: ASAN in wasm2js') @@ -8938,8 +9779,7 @@ def test_asan_js_stack_op(self): self.emcc_args.append('-fsanitize=address') self.set_setting('ALLOW_MEMORY_GROWTH') self.set_setting('INITIAL_MEMORY', '300mb') - self.do_runf('core/test_asan_js_stack_op.c', - expected_output='Hello, World!') + self.do_runf('core/test_asan_js_stack_op.c', expected_output='Hello, World!') @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm2js('TODO: ASAN in wasm2js') @@ -8957,7 +9797,10 @@ def test_asan_api(self): def test_asan_modularized_with_closure(self): # the bug is that createModule() returns undefined, instead of the # proper Promise object. - create_file('post.js', 'if (!(createModule() instanceof Promise)) throw `Promise was not returned (${typeof createModule()})`;\n') + create_file( + 'post.js', + 'if (!(createModule() instanceof Promise)) throw `Promise was not returned (${typeof createModule()})`;\n', + ) self.emcc_args += ['-fsanitize=address', '--extern-post-js=post.js'] self.set_setting('MODULARIZE') self.set_setting('EXPORT_NAME', 'createModule') @@ -8970,22 +9813,27 @@ def test_asan_modularized_with_closure(self): @no_2gb('asan doesnt support GLOBAL_BASE') def test_safe_heap_user_js(self): self.set_setting('SAFE_HEAP') - self.do_runf('core/test_safe_heap_user_js.c', - expected_output=['Aborted(segmentation fault storing 1 bytes to address 0)'], assert_returncode=NON_ZERO) + self.do_runf( + 'core/test_safe_heap_user_js.c', + expected_output=['Aborted(segmentation fault storing 1 bytes to address 0)'], + assert_returncode=NON_ZERO, + ) def test_safe_stack(self): self.set_setting('STACK_OVERFLOW_CHECK', 2) self.set_setting('STACK_SIZE', 1024) if self.is_optimizing(): - expected = [r'Aborted\(stack overflow \(Attempt to set SP to 0x[0-9a-fA-F]+, with stack limits \[0x[0-9a-fA-F]+ - 0x[0-9a-fA-F]+\]\)'] + expected = [ + r'Aborted\(stack overflow \(Attempt to set SP to 0x[0-9a-fA-F]+, with stack limits \[0x[0-9a-fA-F]+ - 0x[0-9a-fA-F]+\]\)' + ] else: - expected = [r'Aborted\(stack overflow \(Attempt to set SP to 0x[0-9a-fA-F]+, with stack limits \[0x[0-9a-fA-F]+ - 0x[0-9a-fA-F]+\]\)', - '__handle_stack_overflow'] - self.do_runf('core/test_safe_stack.c', - expected_output=expected, - regex=True, - assert_all=True, - assert_returncode=NON_ZERO) + expected = [ + r'Aborted\(stack overflow \(Attempt to set SP to 0x[0-9a-fA-F]+, with stack limits \[0x[0-9a-fA-F]+ - 0x[0-9a-fA-F]+\]\)', + '__handle_stack_overflow', + ] + self.do_runf( + 'core/test_safe_stack.c', expected_output=expected, regex=True, assert_all=True, assert_returncode=NON_ZERO + ) @node_pthreads def test_safe_stack_pthread(self): @@ -8997,9 +9845,7 @@ def test_safe_stack_pthread(self): expected = ['Aborted(stack overflow'] else: expected = ['Aborted(stack overflow', '__handle_stack_overflow'] - self.do_runf('core/test_safe_stack.c', - expected_output=expected, - assert_returncode=NON_ZERO, assert_all=True) + self.do_runf('core/test_safe_stack.c', expected_output=expected, assert_returncode=NON_ZERO, assert_all=True) def test_safe_stack_alloca(self): self.set_setting('STACK_OVERFLOW_CHECK', 2) @@ -9008,21 +9854,21 @@ def test_safe_stack_alloca(self): expected = ['Aborted(stack overflow'] else: expected = ['Aborted(stack overflow', '__handle_stack_overflow'] - self.do_runf('core/test_safe_stack_alloca.c', - expected_output=expected, - assert_returncode=NON_ZERO, assert_all=True) + self.do_runf('core/test_safe_stack_alloca.c', expected_output=expected, assert_returncode=NON_ZERO, assert_all=True) @with_dylink_reversed def test_safe_stack_dylink(self): self.set_setting('STACK_OVERFLOW_CHECK', 2) self.set_setting('STACK_SIZE', 65536) - self.dylink_test(r''' + self.dylink_test( + r''' #include extern void sidey(); int main() { sidey(); } - ''', ''' + ''', + ''' #include static long accumulator = 0; @@ -9038,7 +9884,11 @@ def test_safe_stack_dylink(self): void sidey() { f(NULL); } - ''', ['Aborted(stack overflow', '__handle_stack_overflow'], assert_returncode=NON_ZERO, force_c=True) + ''', + ['Aborted(stack overflow', '__handle_stack_overflow'], + assert_returncode=NON_ZERO, + force_c=True, + ) def test_fpic_static(self): self.emcc_args.append('-fPIC') @@ -9060,11 +9910,13 @@ def test_pthread_create(self): @flaky('https://github.com/emscripten-core/emscripten/issues/22617') @node_pthreads - @parameterized({ - '': ([],), - 'pooled': (['-sPTHREAD_POOL_SIZE=1'],), - 'proxied': (['-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), - }) + @parameterized( + { + '': ([],), + 'pooled': (['-sPTHREAD_POOL_SIZE=1'],), + 'proxied': (['-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), + } + ) def test_pthread_c11_threads(self, args): self.emcc_args += args self.set_setting('PTHREADS_DEBUG') @@ -9075,19 +9927,23 @@ def test_pthread_c11_threads(self, args): self.do_run_in_out_file_test('pthread/test_pthread_c11_threads.c') @node_pthreads - @parameterized({ - '': (0,), - 'pooled': (1,), - }) + @parameterized( + { + '': (0,), + 'pooled': (1,), + } + ) def test_pthread_cxx_threads(self, pthread_pool_size): self.set_setting('PTHREAD_POOL_SIZE', pthread_pool_size) self.do_run_in_out_file_test('pthread/test_pthread_cxx_threads.cpp') @node_pthreads - @parameterized({ - '': (0,), - 'pooled': (1,), - }) + @parameterized( + { + '': (0,), + 'pooled': (1,), + } + ) def test_pthread_busy_wait(self, pthread_pool_size): self.set_setting('PTHREAD_POOL_SIZE', pthread_pool_size) self.do_run_in_out_file_test('pthread/test_pthread_busy_wait.cpp') @@ -9190,7 +10046,9 @@ def test_emscripten_atomics(self): @node_pthreads def test_emscripten_futexes(self): self.emcc_args.append('-pthread') - self.emcc_args += ['-Wno-nonnull'] # This test explicitly checks behavior of passing NULL to emscripten_futex_wake(). + self.emcc_args += [ + '-Wno-nonnull' + ] # This test explicitly checks behavior of passing NULL to emscripten_futex_wake(). self.do_run_in_out_file_test('core/pthread/emscripten_futexes.c') @node_pthreads @@ -9217,13 +10075,9 @@ def test_pthread_dylink(self): # where we had a bug with long names + TextDecoder + pthreads + dylink very_long_name = 'very_very_very_very_very_very_very_very_very_long.so' - self.dylink_testf(main, so_name=very_long_name, - main_emcc_args=['-sPTHREAD_POOL_SIZE=2']) + self.dylink_testf(main, so_name=very_long_name, main_emcc_args=['-sPTHREAD_POOL_SIZE=2']) - @parameterized({ - '': (['-sNO_AUTOLOAD_DYLIBS'],), - 'autoload': ([],) - }) + @parameterized({'': (['-sNO_AUTOLOAD_DYLIBS'],), 'autoload': ([],)}) @needs_dylink @node_pthreads def test_pthread_dylink_entry_point(self, args): @@ -9248,15 +10102,15 @@ def test_pthread_dlopen(self): self.prep_dlfcn_main() self.set_setting('EXIT_RUNTIME') self.set_setting('PROXY_TO_PTHREAD') - self.do_runf('core/pthread/test_pthread_dlopen.c', - ['side module ctor', 'done join', 'side module atexit'], - assert_all=True) + self.do_runf( + 'core/pthread/test_pthread_dlopen.c', ['side module ctor', 'done join', 'side module atexit'], assert_all=True + ) @needs_dylink @node_pthreads def test_pthread_dlopen_many(self): if self.is_wasm64(): - self.skipTest('https://github.com/emscripten-core/emscripten/issues/18887') + self.skipTest('https://github.com/emscripten-core/emscripten/issues/18887') nthreads = 10 self.emcc_args += ['-Wno-experimental', '-pthread'] @@ -9268,17 +10122,22 @@ def test_pthread_dlopen_many(self): self.set_setting('EXIT_RUNTIME') self.set_setting('PROXY_TO_PTHREAD') self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', 'jslib_func') - create_file('lib.js', r''' + create_file( + 'lib.js', + r''' addToLibrary({ jslib_func__sig: 'v', jslib_func: () => err('hello from js') }); - ''') + ''', + ) self.emcc_args.append('--js-library=lib.js') - self.do_runf('core/pthread/test_pthread_dlopen_many.c', - ['side module ctor', 'main done', 'side module atexit'], - emcc_args=[f'-DNUM_THREADS={nthreads}'], - assert_all=True) + self.do_runf( + 'core/pthread/test_pthread_dlopen_many.c', + ['side module ctor', 'main done', 'side module atexit'], + emcc_args=[f'-DNUM_THREADS={nthreads}'], + assert_all=True, + ) @needs_dylink @node_pthreads @@ -9313,10 +10172,7 @@ def test_pthread_dylink_main_module_1(self): self.do_runf('hello_world.c') @with_dylink_reversed - @parameterized({ - '': ([],), - 'pthreads': (['-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-pthread', '-Wno-experimental'],) - }) + @parameterized({'': ([],), 'pthreads': (['-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-pthread', '-Wno-experimental'],)}) def test_Module_dynamicLibraries(self, args): # test that Module.dynamicLibraries works with pthreads self.emcc_args += args @@ -9327,15 +10183,20 @@ def test_Module_dynamicLibraries(self, args): # do without this setting) self.set_setting('NO_AUTOLOAD_DYLIBS') - create_file('pre.js', ''' + create_file( + 'pre.js', + ''' if (typeof ENVIRONMENT_IS_PTHREAD == 'undefined' || !ENVIRONMENT_IS_PTHREAD) { // Load liblib.so on the main thread, this would be equivalent to // defining it outside the module (e.g. in MODULARIZE mode). Module['dynamicLibraries'] = ['liblib.so']; } - ''') + ''', + ) - create_file('lib.js', ''' + create_file( + 'lib.js', + ''' addToLibrary({ mainCallback: () => { #if PTHREADS @@ -9345,7 +10206,8 @@ def test_Module_dynamicLibraries(self, args): #endif }, }) - ''') + ''', + ) if args: self.setup_node_pthreads() @@ -9366,7 +10228,8 @@ def test_Module_dynamicLibraries(self, args): int side() { return 42; } ''', 'result is 42', - force_c=True) + force_c=True, + ) # Tests the emscripten_get_exported_function() API. def test_get_exported_function(self): @@ -9488,17 +10351,15 @@ def test_emscripten_async_call(self): self.do_run_in_out_file_test('core/test_emscripten_async_call.c') @no_asan('asyncify stack operations confuse asan') - @parameterized({ - '': ([],), - 'no_dynamic_execution': (['-sDYNAMIC_EXECUTION=0'],) - }) + @parameterized({'': ([],), 'no_dynamic_execution': (['-sDYNAMIC_EXECUTION=0'],)}) def test_embind_lib_with_asyncify(self, args): self.emcc_args += [ '-lembind', '-sASYNCIFY', '-sASYNCIFY_IMPORTS=sleep_and_return', '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$ASSERTIONS', - '--post-js', test_file('core/embind_lib_with_asyncify.test.js'), + '--post-js', + test_file('core/embind_lib_with_asyncify.test.js'), ] self.emcc_args += args self.do_core_test('embind_lib_with_asyncify.cpp') @@ -9516,15 +10377,14 @@ def test_em_async_js(self): @no_wasm2js('wasm2js does not support reference types') @no_sanitize('.s files cannot be sanitized') def test_externref(self): - self.run_process([EMCC, '-c', test_file('core/test_externref.s'), '-o', 'asm.o'] + self.get_emcc_args(asm_only=True)) + self.run_process( + [EMCC, '-c', test_file('core/test_externref.s'), '-o', 'asm.o'] + self.get_emcc_args(asm_only=True) + ) self.emcc_args += ['--js-library', test_file('core/test_externref.js')] self.emcc_args += ['-mreference-types'] self.do_core_test('test_externref.c', libraries=['asm.o']) - @parameterized({ - '': [False], - 'dynlink': [True] - }) + @parameterized({'': [False], 'dynlink': [True]}) @requires_node @no_wasm2js('wasm2js does not support reference types') @no_asan('https://github.com/llvm/llvm-project/pull/83196') @@ -9546,7 +10406,10 @@ def test_js_library_i64_params(self): self.do_core_test('js_library_i64_params.c') def test_main_reads_args(self): - self.run_process([EMCC, '-c', test_file('core/test_main_reads_args_real.c'), '-o', 'real.o'] + self.get_emcc_args(compile_only=True)) + self.run_process( + [EMCC, '-c', test_file('core/test_main_reads_args_real.c'), '-o', 'real.o'] + + self.get_emcc_args(compile_only=True) + ) self.do_core_test('test_main_reads_args.c', emcc_args=['real.o'], regex=True) @requires_node @@ -9554,7 +10417,9 @@ def test_promise(self): # This test depends on Promise.any, which in turn requires a modern target. Check that it # fails to even build on old targets. err = self.expect_fail([EMCC, test_file('core/test_promise.c'), '-sMIN_CHROME_VERSION=75']) - self.assertContained('error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration', err) + self.assertContained( + 'error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration', err + ) self.do_core_test('test_promise.c') @with_asyncify_and_jspi @@ -9563,16 +10428,21 @@ def test_promise_await(self): def test_promise_await_error(self): # Check that the API is not available when ASYNCIFY is not set - self.do_runf('core/test_promise_await.c', 'Aborted(emscripten_promise_await is only available with ASYNCIFY)', - assert_returncode=NON_ZERO) + self.do_runf( + 'core/test_promise_await.c', + 'Aborted(emscripten_promise_await is only available with ASYNCIFY)', + assert_returncode=NON_ZERO, + ) def test_emscripten_async_load_script(self): - create_file('script1.js', 'Module._set(456);''') + create_file('script1.js', 'Module._set(456);' '') create_file('file1.txt', 'first') create_file('file2.txt', 'second') # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the # global `Module`. - self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt', '--from-emcc', '--js-output=script2.js']) + self.run_process( + [FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt', '--from-emcc', '--js-output=script2.js'] + ) self.do_runf('test_emscripten_async_load_script.c', emcc_args=['-sFORCE_FILESYSTEM']) @node_pthreads @@ -9589,11 +10459,18 @@ def test_wasm_worker_wait_async(self): # Generate tests for everything -def make_run(name, emcc_args, settings=None, env=None, - require_v8=False, v8_args=None, - require_node=False, node_args=None, - require_wasm64=False, - init=None): +def make_run( + name, + emcc_args, + settings=None, + env=None, + require_v8=False, + v8_args=None, + require_node=False, + node_args=None, + require_wasm64=False, + init=None, +): if env is None: env = {} if settings is None: @@ -9620,7 +10497,7 @@ def setUp(self): assert k not in os.environ, k + ' should not be in environment' os.environ[k] = v - os.chdir(self.get_dir()) # Ensure the directory exists and go there + os.chdir(self.get_dir()) # Ensure the directory exists and go there for k, v in settings.items(): self.set_setting(k, v) @@ -9666,23 +10543,40 @@ def setUp(self): corez = make_run('corez', emcc_args=['-Oz']) # Test >2gb memory addresses -core_2gb = make_run('core_2gb', emcc_args=['--profiling-funcs'], - settings={'INITIAL_MEMORY': '2200mb', 'GLOBAL_BASE': '2gb'}) +core_2gb = make_run( + 'core_2gb', emcc_args=['--profiling-funcs'], settings={'INITIAL_MEMORY': '2200mb', 'GLOBAL_BASE': '2gb'} +) # MEMORY64=1 -wasm64 = make_run('wasm64', emcc_args=['-O1', '-Wno-experimental', '--profiling-funcs'], - settings={'MEMORY64': 1}, require_wasm64=True, require_node=True) -wasm64_v8 = make_run('wasm64_v8', emcc_args=['-Wno-experimental', '--profiling-funcs'], - settings={'MEMORY64': 1}, require_wasm64=True, require_v8=True) +wasm64 = make_run( + 'wasm64', + emcc_args=['-O1', '-Wno-experimental', '--profiling-funcs'], + settings={'MEMORY64': 1}, + require_wasm64=True, + require_node=True, +) +wasm64_v8 = make_run( + 'wasm64_v8', + emcc_args=['-Wno-experimental', '--profiling-funcs'], + settings={'MEMORY64': 1}, + require_wasm64=True, + require_v8=True, +) # Run the wasm64 tests with all memory offsets > 4gb. Be careful running this test # suite with any kind of parallelism. -wasm64_4gb = make_run('wasm64_4gb', emcc_args=['-Wno-experimental', '--profiling-funcs'], - settings={'MEMORY64': 1, 'INITIAL_MEMORY': '4200mb', 'GLOBAL_BASE': '4gb'}, - require_wasm64=True) +wasm64_4gb = make_run( + 'wasm64_4gb', + emcc_args=['-Wno-experimental', '--profiling-funcs'], + settings={'MEMORY64': 1, 'INITIAL_MEMORY': '4200mb', 'GLOBAL_BASE': '4gb'}, + require_wasm64=True, +) # MEMORY64=2, or "lowered" -wasm64l = make_run('wasm64l', emcc_args=['-O1', '-Wno-experimental', '--profiling-funcs'], - settings={'MEMORY64': 2}, - init=lambda self: shared.node_bigint_flags(self.get_nodejs())) +wasm64l = make_run( + 'wasm64l', + emcc_args=['-O1', '-Wno-experimental', '--profiling-funcs'], + settings={'MEMORY64': 2}, + init=lambda self: shared.node_bigint_flags(self.get_nodejs()), +) lto0 = make_run('lto0', emcc_args=['-flto', '-O0']) lto1 = make_run('lto1', emcc_args=['-flto', '-O1']) @@ -9718,8 +10612,12 @@ def setUp(self): core2s = make_run('core2s', emcc_args=['-O2'], settings={'SAFE_HEAP': 1}) core2ss = make_run('core2ss', emcc_args=['-O2'], settings={'STACK_OVERFLOW_CHECK': 2}) -bigint = make_run('bigint', emcc_args=['--profiling-funcs'], settings={'WASM_BIGINT': 1}, - init=lambda self: shared.node_bigint_flags(self.get_nodejs())) +bigint = make_run( + 'bigint', + emcc_args=['--profiling-funcs'], + settings={'WASM_BIGINT': 1}, + init=lambda self: shared.node_bigint_flags(self.get_nodejs()), +) # Add DEFAULT_TO_CXX=0 strict = make_run('strict', emcc_args=[], settings={'STRICT': 1}) @@ -9728,11 +10626,19 @@ def setUp(self): ubsan = make_run('ubsan', emcc_args=['-fsanitize=undefined', '--profiling']) lsan = make_run('lsan', emcc_args=['-fsanitize=leak', '--profiling'], settings={'ALLOW_MEMORY_GROWTH': 1}) asan = make_run('asan', emcc_args=['-fsanitize=address', '--profiling'], settings={'ALLOW_MEMORY_GROWTH': 1}) -asani = make_run('asani', emcc_args=['-fsanitize=address', '--profiling', '--pre-js', os.path.join(os.path.dirname(__file__), 'asan-no-leak.js')], - settings={'ALLOW_MEMORY_GROWTH': 1}) +asani = make_run( + 'asani', + emcc_args=[ + '-fsanitize=address', + '--profiling', + '--pre-js', + os.path.join(os.path.dirname(__file__), 'asan-no-leak.js'), + ], + settings={'ALLOW_MEMORY_GROWTH': 1}, +) # Experimental modes (not tested by CI) minimal0 = make_run('minimal0', emcc_args=['-g'], settings={'MINIMAL_RUNTIME': 1}) # TestCoreBase is just a shape for the specific subclasses, we don't test it itself -del TestCoreBase # noqa +del TestCoreBase # noqa diff --git a/test/test_interactive.py b/test/test_interactive.py index 511ba785ce831..673b76bc2c20f 100644 --- a/test/test_interactive.py +++ b/test/test_interactive.py @@ -25,7 +25,16 @@ def setUpClass(cls): print() def test_html5_fullscreen(self): - self.btest('test_html5_fullscreen.c', expected='0', args=['-sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR', '-sEXPORTED_FUNCTIONS=_requestFullscreen,_enterSoftFullscreen,_main', '--shell-file', test_file('test_html5_fullscreen.html')]) + self.btest( + 'test_html5_fullscreen.c', + expected='0', + args=[ + '-sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR', + '-sEXPORTED_FUNCTIONS=_requestFullscreen,_enterSoftFullscreen,_main', + '--shell-file', + test_file('test_html5_fullscreen.html'), + ], + ) def test_html5_emscripten_exit_with_escape(self): self.btest('test_html5_emscripten_exit_fullscreen.c', expected='1', args=['-DEXIT_WITH_F']) @@ -65,7 +74,21 @@ def test_sdl_audio(self): create_file('bad.ogg', 'I claim to be audio, but am lying') # use closure to check for a possible bug with closure minifying away newer Audio() attributes - self.btest_exit('test_sdl_audio.c', args=['--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--embed-file', 'the_entertainer.ogg', '--preload-file', 'noise.ogg', '--preload-file', 'bad.ogg']) + self.btest_exit( + 'test_sdl_audio.c', + args=[ + '--preload-file', + 'sound.ogg', + '--preload-file', + 'sound2.wav', + '--embed-file', + 'the_entertainer.ogg', + '--preload-file', + 'noise.ogg', + '--preload-file', + 'bad.ogg', + ], + ) # print('SDL2') # check sdl2 as well @@ -76,10 +99,12 @@ def test_sdl_audio(self): # self.run_process([EMCC, '-O1', '--closure', '0', '--minify=0', 'sdl_audio.c', '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--embed-file', 'the_entertainer.ogg', '--preload-file', 'noise.ogg', '--preload-file', 'bad.ogg', '-o', 'page.html', '-sEXPORTED_FUNCTIONS=[_main,_play,_play2', '-sUSE_SDL=2', '-DUSE_SDL2']).communicate() # self.run_browser('page.html', '', '/report_result?1') - @parameterized({ - '': ([],), - 'wasmfs': (['-sWASMFS'],), - }) + @parameterized( + { + '': ([],), + 'wasmfs': (['-sWASMFS'],), + } + ) def test_sdl_audio_mix_channels(self, args): shutil.copy(test_file('sounds/noise.ogg'), 'sound.ogg') @@ -88,111 +113,241 @@ def test_sdl_audio_mix_channels(self, args): def test_sdl_audio_mix_channels_halt(self): shutil.copy(test_file('sounds/the_entertainer.ogg'), '.') - self.btest_exit('test_sdl_audio_mix_channels_halt.c', args=['-O2', '--minify=0', '--preload-file', 'the_entertainer.ogg']) + self.btest_exit( + 'test_sdl_audio_mix_channels_halt.c', args=['-O2', '--minify=0', '--preload-file', 'the_entertainer.ogg'] + ) def test_sdl_audio_mix_playing(self): shutil.copy(test_file('sounds/noise.ogg'), '.') self.btest_exit('test_sdl_audio_mix_playing.c', args=['-O2', '--minify=0', '--preload-file', 'noise.ogg']) - @parameterized({ - '': ([],), - 'wasmfs': (['-sWASMFS'],), - }) + @parameterized( + { + '': ([],), + 'wasmfs': (['-sWASMFS'],), + } + ) def test_sdl_audio_mix(self, args): shutil.copy(test_file('sounds/pluck.ogg'), 'sound.ogg') shutil.copy(test_file('sounds/the_entertainer.ogg'), 'music.ogg') shutil.copy(test_file('sounds/noise.ogg'), 'noise.ogg') - self.btest_exit('test_sdl_audio_mix.c', args=['-O2', '--minify=0', '--preload-file', 'sound.ogg', '--preload-file', 'music.ogg', '--preload-file', 'noise.ogg'] + args) + self.btest_exit( + 'test_sdl_audio_mix.c', + args=[ + '-O2', + '--minify=0', + '--preload-file', + 'sound.ogg', + '--preload-file', + 'music.ogg', + '--preload-file', + 'noise.ogg', + ] + + args, + ) def test_sdl_audio_panning(self): shutil.copy(test_file('sounds/the_entertainer.wav'), '.') # use closure to check for a possible bug with closure minifying away newer Audio() attributes - self.btest_exit('test_sdl_audio_panning.c', args=['-O2', '--closure=1', '--minify=0', '--preload-file', 'the_entertainer.wav', '-sEXPORTED_FUNCTIONS=_main,_play']) + self.btest_exit( + 'test_sdl_audio_panning.c', + args=[ + '-O2', + '--closure=1', + '--minify=0', + '--preload-file', + 'the_entertainer.wav', + '-sEXPORTED_FUNCTIONS=_main,_play', + ], + ) def test_sdl_audio_beeps(self): # use closure to check for a possible bug with closure minifying away newer Audio() attributes - self.btest_exit('test_sdl_audio_beep.cpp', args=['-O2', '--closure=1', '--minify=0', '-sDISABLE_EXCEPTION_CATCHING=0', '-o', 'page.html']) + self.btest_exit( + 'test_sdl_audio_beep.cpp', + args=['-O2', '--closure=1', '--minify=0', '-sDISABLE_EXCEPTION_CATCHING=0', '-o', 'page.html'], + ) def test_sdl2_mixer_wav(self): shutil.copy(test_file('sounds/the_entertainer.wav'), 'sound.wav') - self.btest_exit('browser/test_sdl2_mixer_wav.c', args=[ - '-O2', - '-sUSE_SDL=2', - '-sUSE_SDL_MIXER=2', - '-sINITIAL_MEMORY=33554432', - '--preload-file', 'sound.wav' - ]) - - @parameterized({ - 'wav': ([], '0', 'the_entertainer.wav'), - 'ogg': (['ogg'], 'MIX_INIT_OGG', 'alarmvictory_1.ogg'), - 'mp3': (['mp3'], 'MIX_INIT_MP3', 'pudinha.mp3'), - }) + self.btest_exit( + 'browser/test_sdl2_mixer_wav.c', + args=['-O2', '-sUSE_SDL=2', '-sUSE_SDL_MIXER=2', '-sINITIAL_MEMORY=33554432', '--preload-file', 'sound.wav'], + ) + + @parameterized( + { + 'wav': ([], '0', 'the_entertainer.wav'), + 'ogg': (['ogg'], 'MIX_INIT_OGG', 'alarmvictory_1.ogg'), + 'mp3': (['mp3'], 'MIX_INIT_MP3', 'pudinha.mp3'), + } + ) def test_sdl2_mixer_music(self, formats, flags, music_name): shutil.copy(test_file('sounds', music_name), '.') - self.btest('browser/test_sdl2_mixer_music.c', expected='exit:0', args=[ - '-O2', - '--minify=0', - '--preload-file', music_name, - '-DSOUND_PATH=' + json.dumps(music_name), - '-DFLAGS=' + flags, - '-sUSE_SDL=2', - '-sUSE_SDL_MIXER=2', - '-sSDL2_MIXER_FORMATS=' + json.dumps(formats), - '-sINITIAL_MEMORY=33554432' - ]) + self.btest( + 'browser/test_sdl2_mixer_music.c', + expected='exit:0', + args=[ + '-O2', + '--minify=0', + '--preload-file', + music_name, + '-DSOUND_PATH=' + json.dumps(music_name), + '-DFLAGS=' + flags, + '-sUSE_SDL=2', + '-sUSE_SDL_MIXER=2', + '-sSDL2_MIXER_FORMATS=' + json.dumps(formats), + '-sINITIAL_MEMORY=33554432', + ], + ) def test_sdl2_audio_beeps(self): # use closure to check for a possible bug with closure minifying away newer Audio() attributes # TODO: investigate why this does not pass - self.btest_exit('browser/test_sdl2_audio_beep.cpp', args=['-O2', '--closure=1', '--minify=0', '-sDISABLE_EXCEPTION_CATCHING=0', '-sUSE_SDL=2']) - - @parameterized({ - '': ([],), - 'proxy_to_pthread': (['-sPROXY_TO_PTHREAD', '-pthread'],), - }) + self.btest_exit( + 'browser/test_sdl2_audio_beep.cpp', + args=['-O2', '--closure=1', '--minify=0', '-sDISABLE_EXCEPTION_CATCHING=0', '-sUSE_SDL=2'], + ) + + @parameterized( + { + '': ([],), + 'proxy_to_pthread': (['-sPROXY_TO_PTHREAD', '-pthread'],), + } + ) def test_openal_playback(self, args): shutil.copy(test_file('sounds/audio.wav'), '.') self.btest('openal/test_openal_playback.c', '1', args=['-O2', '--preload-file', 'audio.wav'] + args) def test_openal_buffers(self): - self.btest_exit('openal/test_openal_buffers.c', args=['--preload-file', test_file('sounds/the_entertainer.wav') + '@/'],) + self.btest_exit( + 'openal/test_openal_buffers.c', + args=['--preload-file', test_file('sounds/the_entertainer.wav') + '@/'], + ) def test_openal_buffers_animated_pitch(self): - self.btest_exit('openal/test_openal_buffers.c', args=['-DTEST_ANIMATED_PITCH=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/'],) + self.btest_exit( + 'openal/test_openal_buffers.c', + args=['-DTEST_ANIMATED_PITCH=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/'], + ) def test_openal_looped_pitched_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=['-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'], + ) def test_openal_looped_seek_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_LOOPED_SEEK_PLAYBACK=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_LOOPED_SEEK_PLAYBACK=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_animated_looped_pitched_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_ANIMATED_LOOPED_PITCHED_PLAYBACK=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_ANIMATED_LOOPED_PITCHED_PLAYBACK=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_animated_looped_distance_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_ANIMATED_LOOPED_DISTANCE_PLAYBACK=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_ANIMATED_LOOPED_DISTANCE_PLAYBACK=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_animated_looped_doppler_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_ANIMATED_LOOPED_DOPPLER_PLAYBACK=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_ANIMATED_LOOPED_DOPPLER_PLAYBACK=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_animated_looped_panned_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_ANIMATED_LOOPED_PANNED_PLAYBACK=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_ANIMATED_LOOPED_PANNED_PLAYBACK=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_animated_looped_relative_playback(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_ANIMATED_LOOPED_RELATIVE_PLAYBACK=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_ANIMATED_LOOPED_RELATIVE_PLAYBACK=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_al_soft_loop_points(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_AL_SOFT_LOOP_POINTS=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_AL_SOFT_LOOP_POINTS=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_alc_soft_pause_device(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_ALC_SOFT_PAUSE_DEVICE=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_ALC_SOFT_PAUSE_DEVICE=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_al_soft_source_spatialize(self): - self.btest('openal/test_openal_playback.c', '1', args=['-DTEST_AL_SOFT_SOURCE_SPATIALIZE=1', '-DTEST_LOOPED_PLAYBACK=1', '--preload-file', test_file('sounds/the_entertainer.wav') + '@/audio.wav'],) + self.btest( + 'openal/test_openal_playback.c', + '1', + args=[ + '-DTEST_AL_SOFT_SOURCE_SPATIALIZE=1', + '-DTEST_LOOPED_PLAYBACK=1', + '--preload-file', + test_file('sounds/the_entertainer.wav') + '@/audio.wav', + ], + ) def test_openal_capture(self): self.btest_exit('openal/test_openal_capture.c') @@ -200,9 +355,18 @@ def test_openal_capture(self): def get_freealut_library(self): self.emcc_args += ['-Wno-pointer-sign'] if WINDOWS and shutil.which('cmake'): - return self.get_library(os.path.join('third_party', 'freealut'), 'libalut.a', configure=['cmake', '.'], configure_args=['-DBUILD_TESTS=ON']) + return self.get_library( + os.path.join('third_party', 'freealut'), + 'libalut.a', + configure=['cmake', '.'], + configure_args=['-DBUILD_TESTS=ON'], + ) else: - return self.get_library(os.path.join('third_party', 'freealut'), os.path.join('src', '.libs', 'libalut.a'), configure_args=['--disable-shared']) + return self.get_library( + os.path.join('third_party', 'freealut'), + os.path.join('src', '.libs', 'libalut.a'), + configure_args=['--disable-shared'], + ) def test_freealut(self): src = test_file('third_party/freealut/examples/hello_world.c') @@ -232,42 +396,58 @@ def test_glut_fullscreen(self): self.btest_exit('glut_fullscreen.c', args=['-lglut', '-lGL']) def test_cpuprofiler_memoryprofiler(self): - self.btest('hello_world_gles.c', expected='0', args=['-DLONGTEST=1', '-DTEST_MEMORYPROFILER_ALLOCATIONS_MAP=1', '-O2', '--cpuprofiler', '--memoryprofiler']) + self.btest( + 'hello_world_gles.c', + expected='0', + args=['-DLONGTEST=1', '-DTEST_MEMORYPROFILER_ALLOCATIONS_MAP=1', '-O2', '--cpuprofiler', '--memoryprofiler'], + ) def test_threadprofiler(self): - args = ['-O2', '--threadprofiler', - '-pthread', - '-sASSERTIONS', - '-DTEST_THREAD_PROFILING=1', - '-sPTHREAD_POOL_SIZE=16', - '-sINITIAL_MEMORY=64mb', - '--shell-file', test_file('pthread/test_pthread_mandelbrot_shell.html')] + args = [ + '-O2', + '--threadprofiler', + '-pthread', + '-sASSERTIONS', + '-DTEST_THREAD_PROFILING=1', + '-sPTHREAD_POOL_SIZE=16', + '-sINITIAL_MEMORY=64mb', + '--shell-file', + test_file('pthread/test_pthread_mandelbrot_shell.html'), + ] self.btest_exit('pthread/test_pthread_mandelbrot.cpp', args=args) # Test that event backproxying works. def test_html5_callbacks_on_calling_thread(self): # TODO: Make this automatic by injecting mouse event in e.g. shell html file. for args in ([], ['-DTEST_SYNC_BLOCKING_LOOP=1']): - self.btest('html5_callbacks_on_calling_thread.c', expected='1', args=args + ['-sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR', '-pthread', '-sPROXY_TO_PTHREAD']) + self.btest( + 'html5_callbacks_on_calling_thread.c', + expected='1', + args=args + ['-sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR', '-pthread', '-sPROXY_TO_PTHREAD'], + ) # Test that it is possible to register HTML5 event callbacks on either main browser thread, or # application main thread, and that the application can manually proxy the event from main browser # thread to the application main thread, to implement event suppression capabilities. - @parameterized({ - '': ([],), - 'pthread': (['-pthread'],), - 'proxy_to_pthread': (['-pthread', '-sPROXY_TO_PTHREAD'],), - }) + @parameterized( + { + '': ([],), + 'pthread': (['-pthread'],), + 'proxy_to_pthread': (['-pthread', '-sPROXY_TO_PTHREAD'],), + } + ) def test_html5_event_callback_in_two_threads(self, args): # TODO: Make this automatic by injecting enter key press in e.g. shell html file. self.btest_exit('html5_event_callback_in_two_threads.c', args=args) # Test that emscripten_hide_mouse() is callable from pthreads (and proxies to main # thread to obtain the proper window.devicePixelRatio value). - @parameterized({ - '': ([],), - 'threads': (['-pthread'],), - }) + @parameterized( + { + '': ([],), + 'threads': (['-pthread'],), + } + ) def test_emscripten_hide_mouse(self, args): self.btest('emscripten_hide_mouse.c', expected='0', args=args) @@ -275,12 +455,16 @@ def test_emscripten_hide_mouse(self, args): # thread has exited). The intent of this is to stress graceful deinit semantics, so that it is not # possible to "taint" a Canvas to a bad state after a rendering thread in a program quits and # restarts. (perhaps e.g. between level loads, or subsystem loads/restarts or something like that) - @parameterized({ - '': (['-sOFFSCREENCANVAS_SUPPORT', '-DTEST_OFFSCREENCANVAS=1'],), - 'ofb': (['-sOFFSCREEN_FRAMEBUFFER'],), - }) + @parameterized( + { + '': (['-sOFFSCREENCANVAS_SUPPORT', '-DTEST_OFFSCREENCANVAS=1'],), + 'ofb': (['-sOFFSCREEN_FRAMEBUFFER'],), + } + ) def test_webgl_offscreen_canvas_in_two_pthreads(self, args): - self.btest('gl_in_two_pthreads.c', expected='1', args=args + ['-pthread', '-lGL', '-sGL_DEBUG', '-sPROXY_TO_PTHREAD']) + self.btest( + 'gl_in_two_pthreads.c', expected='1', args=args + ['-pthread', '-lGL', '-sGL_DEBUG', '-sPROXY_TO_PTHREAD'] + ) # Tests creating a Web Audio context using Emscripten library_webaudio.js feature. @also_with_minimal_runtime @@ -290,13 +474,21 @@ def test_web_audio(self): # Tests simple AudioWorklet noise generation @also_with_minimal_runtime def test_audio_worklet(self): - self.btest('webaudio/audioworklet.c', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '--preload-file', test_file('hello_world.c') + '@/']) + self.btest( + 'webaudio/audioworklet.c', + expected='0', + args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '--preload-file', test_file('hello_world.c') + '@/'], + ) self.btest('webaudio/audioworklet.c', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread']) # Tests AudioWorklet with emscripten_futex_wake(). @also_with_minimal_runtime def test_audio_worklet_emscripten_futex_wake(self): - self.btest('webaudio/audioworklet_emscripten_futex_wake.cpp', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-sPTHREAD_POOL_SIZE=2']) + self.btest( + 'webaudio/audioworklet_emscripten_futex_wake.cpp', + expected='0', + args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-sPTHREAD_POOL_SIZE=2'], + ) # Tests a second AudioWorklet example: sine wave tone generator. def test_audio_worklet_tone_generator(self): @@ -304,7 +496,11 @@ def test_audio_worklet_tone_generator(self): # Tests that AUDIO_WORKLET+MINIMAL_RUNTIME+MODULARIZE combination works together. def test_audio_worklet_modularize(self): - self.btest('webaudio/audioworklet.c', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-sMINIMAL_RUNTIME', '-sMODULARIZE']) + self.btest( + 'webaudio/audioworklet.c', + expected='0', + args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-sMINIMAL_RUNTIME', '-sMODULARIZE'], + ) class interactive64(interactive): diff --git a/test/test_other.py b/test/test_other.py index 05350ec01aa20..232133fb17b98 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 @@ -119,8 +119,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 @@ -134,9 +133,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 @@ -354,29 +351,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) @@ -385,18 +405,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')) @@ -404,9 +441,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) @@ -421,49 +458,71 @@ 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) - @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(); @@ -473,7 +532,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')) @@ -484,10 +544,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)]) @@ -499,10 +561,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) @@ -516,8 +581,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]) @@ -537,10 +602,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']): @@ -565,10 +627,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']) @@ -598,37 +657,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() @@ -653,7 +712,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' @@ -759,23 +820,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() @@ -807,11 +875,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 @@ -827,11 +897,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 @@ -853,11 +925,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) @@ -900,20 +974,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') @@ -925,11 +1005,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] @@ -951,14 +1031,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'): @@ -975,10 +1062,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 @@ -1004,10 +1095,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 @@ -1024,13 +1117,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 @@ -1059,8 +1156,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 @@ -1113,14 +1209,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() @@ -1209,7 +1307,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]) @@ -1220,7 +1318,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 @@ -1229,7 +1329,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"); }') @@ -1238,23 +1339,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']) @@ -1274,20 +1384,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 @@ -1295,19 +1407,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') @@ -1336,17 +1454,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" @@ -1354,7 +1480,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']) @@ -1362,10 +1489,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. @@ -1377,25 +1506,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') @@ -1411,7 +1544,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(); @@ -1420,12 +1555,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']) @@ -1435,18 +1571,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) @@ -1464,7 +1603,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; @@ -1475,7 +1616,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): @@ -1498,32 +1640,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']) @@ -1537,14 +1691,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') @@ -1559,11 +1716,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''' @@ -1573,12 +1731,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. @@ -1586,16 +1747,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']) @@ -1607,10 +1774,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. @@ -1634,18 +1804,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'; @@ -1661,7 +1838,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): @@ -1675,27 +1853,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') @@ -1711,24 +1896,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 = []; @@ -1740,14 +1930,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 = ''; @@ -1759,12 +1952,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[]) { @@ -1781,7 +1977,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) @@ -1789,15 +1986,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)' @@ -1808,17 +2007,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')) @@ -1832,19 +2037,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']) @@ -1856,55 +2067,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') @@ -1917,14 +2143,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')) @@ -1945,20 +2174,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']) @@ -1968,18 +2203,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() { @@ -1993,17 +2232,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') @@ -2012,7 +2254,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) { @@ -2030,10 +2274,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') @@ -2043,7 +2287,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"); @@ -2053,7 +2299,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(), '') @@ -2066,23 +2313,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); @@ -2092,7 +2340,8 @@ def test_dylink_exceptions_and_assertions(self): printf("\n"); return 0; } - ''') + ''', + ) self.do_runf( 'main.cpp', @@ -2102,7 +2351,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 @@ -2114,7 +2364,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(); @@ -2127,16 +2379,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() { @@ -2144,12 +2402,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('...') @@ -2159,8 +2420,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): @@ -2171,7 +2432,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; @@ -2179,15 +2442,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(); @@ -2198,18 +2459,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')]) @@ -2231,14 +2495,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(); @@ -2247,8 +2515,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 @@ -2265,8 +2536,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 @@ -2274,7 +2548,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' @@ -2282,31 +2557,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']) @@ -2322,15 +2597,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 @@ -2340,30 +2620,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.']) @@ -2372,7 +2661,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 @@ -2380,37 +2671,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 @@ -2418,11 +2724,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 @@ -2430,11 +2739,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 @@ -2446,14 +2758,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): @@ -2469,52 +2785,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): @@ -2529,10 +2872,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 @@ -2562,7 +2903,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): @@ -2584,22 +2927,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 @@ -2607,11 +2977,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) { @@ -2634,10 +3008,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 @@ -2648,13 +3024,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) @@ -2674,10 +3049,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) @@ -2691,18 +3063,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" @@ -2717,13 +3089,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: @@ -2750,13 +3125,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) @@ -2767,29 +3145,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')) @@ -2826,37 +3222,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. @@ -2874,37 +3296,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'), - 'emitDCEGraph-dynCall': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph-eval': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph-sig': (['emitDCEGraph', '--no-print'],), - 'emitDCEGraph-prefixing': (['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'), + 'emitDCEGraph-dynCall': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph-eval': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph-sig': (['emitDCEGraph', '--no-print'],), + 'emitDCEGraph-prefixing': (['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: @@ -2913,7 +3337,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: @@ -2929,10 +3355,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 @@ -2951,12 +3374,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) @@ -3025,8 +3450,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) @@ -3055,6 +3480,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') @@ -3066,7 +3492,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), @@ -3128,26 +3554,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]) @@ -3157,16 +3587,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]) @@ -3184,16 +3616,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]) @@ -3204,29 +3638,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'] @@ -3235,12 +3679,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; @@ -3258,17 +3707,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 @@ -3282,33 +3737,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() @@ -3324,8 +3793,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 @@ -3352,10 +3823,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') @@ -3368,19 +3842,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 @@ -3393,19 +3864,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') @@ -3425,33 +3901,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. @@ -3459,8 +3944,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')) @@ -3473,14 +3957,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() {} @@ -3489,28 +3981,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): @@ -3525,24 +4021,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): @@ -3552,30 +4062,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): @@ -3601,21 +4130,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']) @@ -3625,11 +4160,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'] @@ -3664,12 +4202,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, '') @@ -3686,7 +4228,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') @@ -3694,20 +4249,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 @@ -3719,7 +4299,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): @@ -3754,7 +4335,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): @@ -3766,12 +4349,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() { @@ -3783,7 +4370,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) @@ -3794,13 +4382,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) @@ -3814,7 +4404,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() { @@ -3826,11 +4418,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) @@ -3867,7 +4470,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 @@ -3898,13 +4503,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) @@ -3921,7 +4528,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') @@ -3929,7 +4538,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 @@ -3944,7 +4555,8 @@ def test_demangle_cpp(self): printf("%s\\n", out); return 0; } - ''') + ''', + ) self.do_runf('src.cpp', 'Waka::f::a23412341234::point()') @@ -3955,7 +4567,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): @@ -3965,11 +4577,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')) @@ -3983,11 +4602,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 @@ -4001,45 +4628,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 = () => { @@ -4049,10 +4685,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') @@ -4063,21 +4709,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 @@ -4107,7 +4758,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) @@ -4116,7 +4769,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 @@ -4126,7 +4781,8 @@ def test_node_emscripten_num_logical_cores(self): assert(num != 0); puts("ok"); } -''') +''', + ) self.do_runf('src.c', 'ok') def test_proxyfs(self): @@ -4146,7 +4802,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'); @@ -4243,15 +4901,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 @@ -4377,14 +5041,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') @@ -4436,16 +5110,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') @@ -4476,7 +5156,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(); @@ -4485,29 +5167,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(); @@ -4516,23 +5210,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); @@ -4540,18 +5242,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, @@ -4562,7 +5270,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']) @@ -4571,7 +5280,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'], @@ -4580,8 +5291,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() { @@ -4589,33 +5303,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); @@ -4625,12 +5353,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), @@ -4642,53 +5376,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) => {}, @@ -4698,91 +5452,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 @@ -4792,21 +5584,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') @@ -4814,7 +5613,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 @@ -4828,14 +5629,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') @@ -4843,17 +5648,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) @@ -4865,25 +5676,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') @@ -4922,29 +5738,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({ @@ -4958,7 +5782,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: @@ -4974,17 +5799,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 @@ -5006,13 +5835,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') @@ -5032,7 +5862,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) { @@ -5045,8 +5877,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() { @@ -5060,7 +5895,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): @@ -5068,7 +5904,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'] @@ -5105,24 +5944,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) @@ -5137,7 +5978,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 @@ -5153,9 +5996,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; @@ -5170,9 +6016,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; @@ -5180,7 +6029,8 @@ def test_global_inits(self): Waste<3> *getMore() { return &sw3; } -''') +''', + ) for opts, has_global in [ (['-O2', '-g', '-sEXIT_RUNTIME'], True), @@ -5209,7 +6059,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) @@ -5219,25 +6070,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): @@ -5264,15 +6141,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) @@ -5301,7 +6182,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, (), { @@ -5320,7 +6203,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}') @@ -5341,15 +6225,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 @@ -5364,12 +6256,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 @@ -5396,14 +6290,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, ...); @@ -5418,7 +6316,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): @@ -5434,7 +6333,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 @@ -5469,8 +6368,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) @@ -5480,27 +6378,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; @@ -5518,7 +6425,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") @@ -5529,23 +6437,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() { @@ -5555,11 +6472,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: @@ -5575,23 +6503,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 @@ -5615,11 +6551,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 @@ -5629,23 +6567,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 @@ -5656,10 +6603,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 @@ -5675,13 +6626,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 @@ -5696,7 +6654,8 @@ def test_symlink_silly(self): printf("ok\n"); } } - ''') + ''', + ) self.run_process([EMCC, 'src.c']) # cannot symlink nonexistents @@ -5706,7 +6665,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 @@ -5717,7 +6678,8 @@ def test_rename_silly(self): printf("ok\n"); } } -''') +''', + ) self.run_process([EMCC, 'src.c']) # cannot symlink nonexistents @@ -5727,7 +6689,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 @@ -5832,9 +6796,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 @@ -5850,10 +6817,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() { @@ -5861,7 +6832,8 @@ def test_emversion(self): printf("minor: %d\n", __EMSCRIPTEN_minor__); printf("tiny: %d\n", __EMSCRIPTEN_tiny__); } - ''') + ''', + ) expected = '''\ major: %d minor: %d @@ -5873,22 +6845,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): @@ -5939,28 +6917,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 @@ -5974,7 +6961,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 @@ -6080,7 +7069,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 @@ -6097,17 +7087,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): @@ -6122,7 +7114,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 @@ -6136,7 +7130,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')) @@ -6151,11 +7146,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}): @@ -6207,7 +7204,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: @@ -6219,7 +7216,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 @@ -6320,8 +7319,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 @@ -6331,10 +7333,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 @@ -6401,19 +7406,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() { @@ -6427,16 +7438,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 @@ -6451,14 +7465,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 @@ -6472,45 +7489,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 @@ -6541,18 +7570,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 @@ -6566,7 +7602,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) @@ -6586,6 +7623,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']) @@ -6629,7 +7667,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']) @@ -6637,7 +7677,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) @@ -6645,7 +7685,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' @@ -6672,18 +7712,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; } @@ -6691,15 +7740,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']) @@ -6761,19 +7814,24 @@ def test_modularize_new_misuse(self): err = self.run_js('run.js', assert_returncode=NON_ZERO) self.assertContained('Error: Foo() should not be called with `new Foo()`', err) - @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) @@ -6788,15 +7846,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() { @@ -6806,7 +7869,8 @@ def test_pthread_print_override_modularize(self): }); } main(); - ''') + ''', + ) self.emcc('main.c', output_filename='test.js') output = self.run_js('main.js') @@ -6819,12 +7883,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) @@ -6841,7 +7908,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. @@ -6851,22 +7920,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 { @@ -6885,7 +7959,8 @@ class Descriptor { }; Descriptor desc; - ''') + ''', + ) self.run_process([EMXX, 'src.cpp', '-O2', '-sEXPORT_ALL']) self.assertExists('a.out.js') @@ -6897,6 +7972,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']) @@ -6906,17 +7982,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; }') @@ -6939,15 +8021,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({ @@ -6955,7 +8040,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)) @@ -6972,12 +8058,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')) @@ -6991,12 +8080,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 @@ -7004,7 +8097,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'] @@ -7014,20 +8108,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 @@ -7066,7 +8168,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'] @@ -7092,15 +8196,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 @@ -7115,7 +8225,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')) @@ -7124,7 +8235,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 @@ -7146,11 +8259,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; @@ -7159,7 +8285,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']) @@ -7172,18 +8299,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 @@ -7192,10 +8323,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() { @@ -7211,7 +8358,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') @@ -7233,29 +8382,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 @@ -7267,44 +8442,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 @@ -7312,13 +8502,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 @@ -7363,18 +8559,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) @@ -7383,7 +8600,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 @@ -7396,13 +8615,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 @@ -7420,8 +8642,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 @@ -7435,7 +8660,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')) @@ -7449,7 +8675,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; @@ -7459,8 +8687,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; @@ -7472,8 +8703,11 @@ def test_dlopen_rtld_global(self): f = hello1; f(i); } -''') - create_file('main.c', r''' +''', + ) + create_file( + 'main.c', + r''' #include #include #include @@ -7493,13 +8727,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) @@ -7508,11 +8753,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']) @@ -7523,13 +8771,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) @@ -7544,13 +8794,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 @@ -7602,18 +8857,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 @@ -7630,11 +8891,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']) @@ -7647,7 +8906,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 @@ -7660,8 +8921,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 @@ -7678,26 +8942,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 @@ -7727,10 +8996,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| @@ -7742,10 +9013,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 @@ -7775,19 +9050,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): @@ -7799,17 +9079,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')) @@ -7823,15 +9106,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 @@ -7841,18 +9129,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) @@ -7863,15 +9155,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*); @@ -7881,14 +9178,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) => { @@ -7896,7 +9196,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 @@ -7907,11 +9208,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']) @@ -7933,7 +9236,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() { @@ -7942,7 +9247,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 @@ -7974,6 +9280,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']) @@ -7990,8 +9297,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 @@ -8016,12 +9322,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', @@ -8032,10 +9346,12 @@ def test_malloc_multithreading(self, allocator, args): ] self.do_other_test('test_malloc_multithreading.cpp', emcc_args=args) - @parameterized({ - '': ([], 'testbind.js'), - 'nobigint': (['-sWASM_BIGINT=0'], 'testbind_nobigint.js'), - }) + @parameterized( + { + '': ([], 'testbind.js'), + 'nobigint': (['-sWASM_BIGINT=0'], 'testbind_nobigint.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 @@ -8043,33 +9359,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')]) @@ -8113,21 +9449,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) @@ -8148,7 +9484,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']) @@ -8175,21 +9511,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 { @@ -8203,7 +9544,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') @@ -8221,9 +9563,7 @@ def test_EM_ASM_i64(self): self.set_setting('WASM_BIGINT', 0) 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) def test_eval_ctor_ordering(self): # ensure order of execution remains correct, even with a bad ctor @@ -8261,15 +9601,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) @@ -8277,19 +9617,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) @@ -8297,14 +9643,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' @@ -8316,7 +9664,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({ @@ -8326,7 +9676,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']) @@ -8335,7 +9686,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} @@ -8346,28 +9697,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')) @@ -8385,7 +9748,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() { @@ -8393,7 +9758,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 @@ -8408,22 +9775,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) @@ -8437,16 +9808,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]' @@ -8463,7 +9842,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 @@ -8471,7 +9852,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')) @@ -8479,7 +9861,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() { @@ -8490,7 +9874,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 @@ -8527,24 +9912,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("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 @@ -8561,10 +9984,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) @@ -8588,15 +10011,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): @@ -8605,7 +10032,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', '.']) @@ -8621,7 +10050,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!"); } @@ -8632,7 +10063,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']): @@ -8645,18 +10077,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 @@ -8665,16 +10097,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)) @@ -8704,39 +10138,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 @@ -8748,7 +10197,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(',') @@ -8819,22 +10268,24 @@ 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 - 'esm': (['-Oz', '-sEXPORT_ES6'], [], []), # 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 + 'esm': (['-Oz', '-sEXPORT_ES6'], [], []), # noqa + } + ) def test_codesize_minimal(self, *args): self.set_setting('STRICT') self.emcc_args.append('--no-entry') @@ -8844,114 +10295,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) - @parameterized({ - 'legal_side_O1': (['-sLEGALIZE_JS_FFI=1', '-sSIDE_MODULE', '-O1'], True), - 'nolegal_side_O1': (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O1'], False), - 'nolegal_side_O0': (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O0'], False), - 'legal_O0': (['-sLEGALIZE_JS_FFI=1', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], True), - 'nolegal_O0': (['-sLEGALIZE_JS_FFI=0', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], False), - }) + @parameterized( + { + 'legal_side_O1': (['-sLEGALIZE_JS_FFI=1', '-sSIDE_MODULE', '-O1'], True), + 'nolegal_side_O1': (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O1'], False), + 'nolegal_side_O0': (['-sLEGALIZE_JS_FFI=0', '-sSIDE_MODULE', '-O0'], False), + 'legal_O0': (['-sLEGALIZE_JS_FFI=1', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], True), + 'nolegal_O0': (['-sLEGALIZE_JS_FFI=0', '-sWARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], False), + } + ) def test_legalize_js_ffi(self, args, js_ffi): # test disabling of JS FFI legalization when not using bigint print(args) @@ -8969,14 +10424,16 @@ def test_legalize_js_ffi(self, args, js_ffi): 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') @@ -9019,23 +10476,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) @@ -9067,10 +10534,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() @@ -9104,24 +10573,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 @@ -9151,12 +10626,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)) @@ -9170,7 +10647,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. @@ -9183,10 +10662,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') @@ -9236,7 +10717,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 @@ -9253,14 +10735,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) @@ -9331,14 +10811,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 @@ -9383,25 +10866,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 @@ -9457,8 +10947,12 @@ 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', ] @@ -9477,14 +10971,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 @@ -9552,12 +11047,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) @@ -9577,7 +11075,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): @@ -9619,7 +11119,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; @@ -9629,7 +11131,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 @@ -9645,15 +11148,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) @@ -9668,32 +11173,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 @@ -9735,12 +11246,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 @@ -9754,10 +11262,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): @@ -9781,7 +11289,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() { @@ -9803,16 +11313,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) @@ -9866,12 +11381,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')]) @@ -9882,9 +11400,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') @@ -9915,7 +11431,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): @@ -9956,19 +11472,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 '<' @@ -9976,12 +11497,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): @@ -9992,16 +11519,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) @@ -10011,35 +11532,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({ @@ -10049,7 +11574,8 @@ def test_EM_ASM_ES6(self, args): return x; }); } -''') +''', + ) self.do_runf('src.c', 'hello!', emcc_args=args) def test_check_sourcemapurl(self): @@ -10058,7 +11584,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) @@ -10074,10 +11605,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') @@ -10085,20 +11618,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) @@ -10109,12 +11654,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 @@ -10129,11 +11678,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') @@ -10154,14 +11699,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. @@ -10181,8 +11721,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: @@ -10195,26 +11734,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() @@ -10236,8 +11771,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]) @@ -10246,28 +11780,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')) @@ -10295,9 +11825,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 @@ -10318,9 +11846,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) @@ -10338,8 +11864,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) @@ -10364,9 +11889,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) @@ -10374,8 +11899,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 @@ -10387,17 +11918,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("/emsdk/emscripten/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 @@ -10409,13 +11942,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) @@ -10427,12 +11962,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) @@ -10482,7 +12017,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 @@ -10492,22 +12029,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) @@ -10517,9 +12061,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('''