Codebase list emscripten / 44054dc
New upstream version 2.0.25~dfsg Jonas Smedegaard 2 years ago
204 changed file(s) with 4595 addition(s) and 4352 deletion(s). Raw diff Collapse all Expand all
174174 - run:
175175 name: download firefox
176176 command: |
177 # Temporarily pinned to beta rather then dev.
178 # See https://github.com/emscripten-core/emscripten/issues/14401
179 wget -O ~/ff.tar.bz2 "https://download.mozilla.org/?product=firefox-beta-latest-ssl&os=linux64&lang=en-US"
177 wget -O ~/ff.tar.bz2 "https://download.mozilla.org/?product=firefox-devedition-latest-ssl&os=linux64&lang=en-US"
180178 tar -C ~ -xf ~/ff.tar.bz2
181179 - run:
182180 name: configure firefox
186184 user_pref("gfx.offscreencanvas.enabled", true);
187185 user_pref("javascript.options.shared_memory", true);
188186 user_pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true);
189 EOF
190 - run:
191 name: configure openbox
192 command: |
193 # Set up X and Openbox config (if we move to a headless browser, this may not be needed).
194 mkdir -p ~/.config/X11
195 cat > ~/.config/X11/xorg.conf \<<EOF
196 Section "ServerLayout"
197 Identifier "X.org Configured"
198 Screen 0 "Screen0" 0 0
199 EndSection
200
201 Section "Monitor"
202 Identifier "Monitor0"
203 HorizSync 72
204 Modeline "1920x1080@60" 144 1920 1920 1960 2000 1080 1080 1140 1200
205 EndSection
206
207 Section "Device"
208 Identifier "Card0"
209 Driver "dummy"
210 VideoRam 1048576
211 EndSection
212
213 Section "Screen"
214 Identifier "Screen0"
215 Device "Card0"
216 Monitor "Monitor0"
217 DefaultDepth 24
218 SubSection "Display"
219 Depth 24
220 Modes "1920x1080@60"
221 EndSubSection
222 EndSection
223 EOF
224 mkdir -p ~/.config/openbox
225 echo "[ -f \"\$EXTRA_AUTOSTART\" ] && sh \"\$EXTRA_AUTOSTART\"" > ~/.config/openbox/autostart
226 mkdir -p ~/.config/autostart
227 cat > ~/.config/autostart/at-spi-dbus-bus.desktop \<<EOF
228 [Desktop Entry]
229 Type=Application
230 Name=AT-SPI D-Bus Bus
231 Hidden=true # do not auto-start AT-SPI to suppress one warning
232187 EOF
233188 - run:
234189 # browser.test_sdl2_mouse and/or SDL2 should be fixed. The case happens
240195 # browser.test_webgl_offscreen_canvas_in_mainthread_after_pthread
241196 # are crashing Firefox (bugzil.la/1281796). The former case is
242197 # further blocked by issue #6897.
243 # TODO: use Firefox headless mode when https://bugzil.la/1375585 resolves
198 # browser.test_sdl2_misc_main_module: Requires PIC version of libSDL
199 # which is not included in emsdk (not compatible with FROZEN_CACHE).
244200 name: run tests
245201 environment:
246202 GALLIUM_DRIVER: softpipe # TODO: use the default llvmpipe when it supports more extensions
203 # TODO: Do GL testing when https://bugzil.la/1375585 (lack of WebGL
204 # support in headless mode) resolves
205 EMTEST_LACKS_GRAPHICS_HARDWARE: "1"
247206 EMTEST_LACKS_SOUND_HARDWARE: "1"
248207 # OffscreenCanvas support is not yet done in Firefox.
249208 EMTEST_LACKS_OFFSCREEN_CANVAS: "1"
250209 EMTEST_DETECT_TEMPFILE_LEAKS: "0"
251210 DISPLAY: ":0"
252211 command: |
253 export EMTEST_BROWSER="$HOME/firefox/firefox -profile $HOME/tmp-firefox-profile/"
254 # Start an X session. Openbox might be optional for now, but
255 # an ICCCM/EWMH compliant window manager is potentially needed
256 # for tests with fullscreen toggling (if we move to a headless
257 # browser, this may not be needed eventually).
258 TMPDIR=`mktemp -d`
259 mkfifo $TMPDIR/fifo
260 echo "echo -n > $TMPDIR/fifo" > $TMPDIR/autostart
261 EXTRA_AUTOSTART=$TMPDIR/autostart startx /usr/bin/openbox-session -- $DISPLAY -config ~/.config/X11/xorg.conf -nolisten tcp &
262 cat $TMPDIR/fifo > /dev/null # wait until $EXTRA_AUTOSTART is spawned, which indicates the end of Openbox initialization
263 rm -r $TMPDIR
264 tests/runner browser posixtest_browser.test_pthread_create_1_1 skip:browser.test_sdl2_mouse skip:browser.test_html5_webgl_create_context skip:browser.test_webgl_offscreen_canvas_in_pthread skip:browser.test_webgl_offscreen_canvas_in_mainthread_after_pthread skip:browser.test_glut_glutget
212 export EMTEST_BROWSER="$HOME/firefox/firefox -headless -profile $HOME/tmp-firefox-profile/"
265213 echo "-----"
266 echo "Running emrun tests"
214 echo "Running browser tests"
267215 echo "-----"
268 # test_no_browser seems to cause the xsession to go down when run in github CI.
269 tests/runner emrun skip:emrun.test_no_browser
270 openbox --exit
271 wait || true # wait for startx to shutdown cleanly, or not
216 tests/runner browser skip:browser.test_sdl2_mouse skip:browser.test_html5_webgl_create_context skip:browser.test_webgl_offscreen_canvas_in_pthread skip:browser.test_webgl_offscreen_canvas_in_mainthread_after_pthread skip:browser.test_glut_glutget skip:browser.test_sdl2_misc_main_module
217 # posix and emrun suites are disabled because firefox errors on
218 # "Firefox is already running, but is not responding."
219 # TODO: find out a way to shut down and restart firefox
272220 test-chrome:
273221 description: "Runs emscripten browser tests under chrome"
274222 steps:
302250 command: |
303251 export EMTEST_BROWSER="/usr/bin/google-chrome $CHROME_FLAGS_BASE $CHROME_FLAGS_HEADLESS $CHROME_FLAGS_WASM $CHROME_FLAGS_NOCACHE"
304252 # skip test_zzz_zzz_4gb_fail as it OOMs on the current bot
305 tests/runner browser posixtest_browser.test_pthread_create_1_1 skip:browser.test_zzz_zzz_4gb_fail
253 # browser.test_sdl2_misc_main_module: Requires PIC version of libSDL
254 # which is not included in emsdk (not compatible with FROZEN_CACHE).
255 tests/runner browser posixtest_browser.test_pthread_create_1_1 skip:browser.test_zzz_zzz_4gb_fail skip:browser.test_sdl2_misc_main_module
306256 tests/runner emrun
307257 test-sockets-chrome:
308258 description: "Runs emscripten sockets tests under chrome"
569569 * Bobbie Chen <bobbie.chen75@gmail.com>
570570 * Nicholas Hollander <nhollander98@gmail.com>
571571 * Camillo Lugaresi <camillol@google.com> (copyright owned by Google LLC)
572 * Chris Craig <emscripten@goldwave.com>
573 * Le Yao <le.yao@intel.com> (copyright owned by Intel Corporation)
574 * José Cadete <crudelios@gmail.com>
1717
1818 See docs/process.md for more on how version tagging works.
1919
20 2.0.24
20 2.0.25
2121 ------
22 - Support for the 'shell' environment is now disabled by default. Running under
23 `d8`, `js`, or `jsc` is not something that most emscripten users ever want to
24 do, so including the support code is, more often than not, unnecessary. Users
25 who want shell support can enable it by including 'shell' in `-s ENVIRONMENT`
26 (#14535).
27 - A new setting called `ALLOW_UNIMPLEMENTED_SYSCALLS` was added. This setting
28 is enabled by default but, if disabled, will generate link-time errors if
29 a program references an unimplemented syscall. This setting is disabled
30 by default in `STRICT` mode.
31 - By default (unless `EXIT_RUNTIME=1` is specified) emscripten programs running
32 under node will no longer call `process.exit()` on `exit()`. Instead they
33 will simply unwind the stack and return to the event loop, much like they do
34 on the web. In many cases the node process will then exit naturally if there
35 is nothing keeping the event loop going.
36 Note for users of node + pthreads: Because of the way that threads are
37 implemented under node multi-threaded programs now require `EXIT_RUNTIME=1`
38 (or call `emscripten_force_exit`) in order to actually bring down the process.
39 - Drop support for node versions older than v5.10.0. We now assume the
40 existence of `Buffer.from` which was added in v5.10.0. If it turns out
41 there is still a need to support these older node versions we can
42 add a polyfil under LEGACY_VM_SUPPORT (#14447).
43
44 2.0.24 - 06/10/2021
45 -------------------
2246 - Support `--preload-file` in Node.js. (#11785)
2347 - System libraries are now passed to the linker internally via `-lfoo` rather
2448 than using their full path. This is in line with how gcc and clang pass system
4872 setting its value in `ENV` to `undefined`. This is useful for variables, such
4973 as `LANG`, for which Emscripten normally provides a default value.
5074
51 2.0.23
52 ------
75 2.0.23 - 05/26/2021
76 -------------------
5377 - libcxxabi updated to llvm-12. (#14288)
5478 - libcxx updated to llvm-12. (#14249)
5579 - compiler-rt updated to llvm-12. (#14280)
102102 3. Run `make install EMSCRIPTEN_SITE=\[path-to-a-checkout-of-the-site-repo\]`
103103 3. Go to the site repo, commit the changes, and push.
104104
105 You will need the specific sphinx version installed, which you can do using
106 `pip3 install -r requirements-dev.txt` (depending on your system, you may then
107 need to add `~/.local/bin` to your path, if pip installs to there).
105108
106109
107110 Updating the `emcc.py` help text
114117 1. In your emscripten repo checkout, enter `site`.
115118 2. Run `make clean` (without this, it may not emit the right output).
116119 2. Run `make text`.
117 3. Add the changes to your PR.
120 3. Copy the output `build/text/docs/tools_reference/emcc.txt` to
121 `../docs/emcc.txt` (both paths relative to the `site/` directory in
122 emscripten that you entered in step 1), and add that change to your PR.
123
124 See notes above on installing sphinx.
118125
119126
120127 [site_repo]: https://github.com/kripken/emscripten-site
5050 from tools import webassembly
5151 from tools import config
5252 from tools.settings import settings, MEM_SIZE_SETTINGS, COMPILE_TIME_SETTINGS
53 from tools.utils import read_file, write_file, read_binary
5354
5455 logger = logging.getLogger('emcc')
5556
157158 if not DEBUG:
158159 return
159160 if not final_js:
160 logger.debug('(not saving intermediate %s because not generating JS)' % name)
161 logger.debug(f'(not saving intermediate {name} because not generating JS)')
161162 return
162 building.save_intermediate(final_js, name + '.' + suffix)
163 building.save_intermediate(final_js, f'{name}.{suffix}')
163164
164165
165166 def save_intermediate_with_wasm(name, wasm_binary):
269270 # Environment setting based on user input
270271 environments = settings.ENVIRONMENT.split(',')
271272 if any([x for x in environments if x not in VALID_ENVIRONMENTS]):
272 exit_with_error('Invalid environment specified in "ENVIRONMENT": ' + settings.ENVIRONMENT + '. Should be one of: ' + ','.join(VALID_ENVIRONMENTS))
273 exit_with_error(f'Invalid environment specified in "ENVIRONMENT": {settings.ENVIRONMENT}. Should be one of: {",".join(VALID_ENVIRONMENTS)}')
273274
274275 settings.ENVIRONMENT_MAY_BE_WEB = not settings.ENVIRONMENT or 'web' in environments
275276 settings.ENVIRONMENT_MAY_BE_WEBVIEW = not settings.ENVIRONMENT or 'webview' in environments
356357 filename = strip_prefix(value, '@')
357358 if not os.path.exists(filename):
358359 exit_with_error('%s: file not found parsing argument: %s=%s' % (filename, key, value))
359 value = open(filename).read().strip()
360 value = read_file(filename).strip()
360361 else:
361362 value = value.replace('\\', '\\\\')
362363
552553 def check_human_readable_list(items):
553554 for item in items:
554555 if item.count('(') != item.count(')'):
555 logger.warning('''emcc: ASYNCIFY list contains an item without balanced parentheses ("(", ")"):''')
556 logger.warning(''' ''' + item)
557 logger.warning('''This may indicate improper escaping that led to splitting inside your names.''')
558 logger.warning('''Try to quote the entire argument, like this: -s 'ASYNCIFY_ONLY=["foo(int, char)", "bar"]' ''')
556 logger.warning('emcc: ASYNCIFY list contains an item without balanced parentheses ("(", ")"):')
557 logger.warning(' ' + item)
558 logger.warning('This may indicate improper escaping that led to splitting inside your names.')
559 logger.warning('Try using a response file. e.g: -sASYNCIFY_ONLY=@funcs.txt. The format is a simple')
560 logger.warning('text file, one line per function.')
559561 break
560562
561563 if settings.ASYNCIFY_REMOVE:
588590
589591
590592 def make_js_executable(script):
591 src = open(script).read()
593 src = read_file(script)
592594 cmd = shared.shlex_join(config.JS_ENGINE)
593595 if not os.path.isabs(config.JS_ENGINE[0]):
594596 # TODO: use whereis etc. And how about non-*NIX?
945947 cmd = shared.shlex_join(args)
946948 if EMCC_CFLAGS:
947949 cmd += ' + ' + EMCC_CFLAGS
948 logger.warning('invocation: ' + cmd + ' (in ' + os.getcwd() + ')')
950 logger.warning(f'invocation: {cmd} (in {os.getcwd()})')
949951 if EMCC_CFLAGS:
950952 args.extend(shlex.split(EMCC_CFLAGS))
951953
10711073 settings.limit_settings(None)
10721074
10731075 if options.output_file and options.output_file.startswith('-'):
1074 exit_with_error('invalid output filename: `%s`' % options.output_file)
1076 exit_with_error(f'invalid output filename: `{options.output_file}`')
10751077
10761078 target, wasm_target = phase_linker_setup(options, state, newargs, settings_map)
10771079
10791081 linker_arguments = phase_calculate_linker_inputs(options, state, linker_inputs)
10801082
10811083 if options.oformat == OFormat.OBJECT:
1082 with ToolchainProfiler.profile_block('linking to object file'):
1083 logger.debug('link_to_object: ' + str(linker_arguments) + ' -> ' + target)
1084 building.link_to_object(linker_arguments, target)
1085 logger.debug('stopping after linking to object file')
1086 return 0
1084 logger.debug(f'link_to_object: {linker_arguments} -> {target}')
1085 building.link_to_object(linker_arguments, target)
1086 logger.debug('stopping after linking to object file')
1087 return 0
10871088
10881089 phase_calculate_system_libraries(state, linker_arguments, linker_inputs, newargs)
10891090
12301231 has_header_inputs = True
12311232 if file_suffix in STATICLIB_ENDINGS and not building.is_ar(arg):
12321233 if building.is_bitcode(arg):
1233 message = arg + ': File has a suffix of a static library ' + str(STATICLIB_ENDINGS) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files use .bc or .o.'
1234 message = f'{arg}: File has a suffix of a static library {STATICLIB_ENDINGS}, but instead is an LLVM bitcode file! When linking LLVM bitcode files use .bc or .o.'
12341235 else:
12351236 message = arg + ': Unknown format, not a static library!'
12361237 exit_with_error(message)
13491350 add_link_flag(state, sys.maxsize, f)
13501351
13511352 if options.emrun:
1352 options.pre_js += open(shared.path_from_root('src', 'emrun_prejs.js')).read() + '\n'
1353 options.post_js += open(shared.path_from_root('src', 'emrun_postjs.js')).read() + '\n'
1353 options.pre_js += read_file(shared.path_from_root('src', 'emrun_prejs.js')) + '\n'
1354 options.post_js += read_file(shared.path_from_root('src', 'emrun_postjs.js')) + '\n'
13541355 # emrun mode waits on program exit
13551356 settings.EXIT_RUNTIME = 1
13561357
13571358 if options.cpu_profiler:
1358 options.post_js += open(shared.path_from_root('src', 'cpuprofiler.js')).read() + '\n'
1359 options.post_js += read_file(shared.path_from_root('src', 'cpuprofiler.js')) + '\n'
13591360
13601361 if options.memory_profiler:
13611362 settings.MEMORYPROFILER = 1
13621363
13631364 if options.thread_profiler:
1364 options.post_js += open(shared.path_from_root('src', 'threadprofiler.js')).read() + '\n'
1365 options.post_js += read_file(shared.path_from_root('src', 'threadprofiler.js')) + '\n'
13651366
13661367 if options.memory_init_file is None:
13671368 options.memory_init_file = settings.OPT_LEVEL >= 2
15351536 default_setting('AUTO_ARCHIVE_INDEXES', 0)
15361537 default_setting('IGNORE_MISSING_MAIN', 0)
15371538 default_setting('DEFAULT_TO_CXX', 0)
1539 default_setting('ALLOW_UNIMPLEMENTED_SYSCALLS', 0)
15381540
15391541 # Default to TEXTDECODER=2 (always use TextDecoder to decode UTF-8 strings)
15401542 # in -Oz builds, since custom decoder for UTF-8 takes up space.
18001802 # In non-MINIMAL_RUNTIME, the core runtime depends on these functions to be present. (In MINIMAL_RUNTIME, they are
18011803 # no longer always bundled in)
18021804 settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += [
1803 '$keepRuntimeAlive',
18041805 '$demangle',
18051806 '$demangleAll',
18061807 '$jsStackTrace',
19181919 include_and_export('establishStackSpace')
19191920 include_and_export('invokeEntryPoint')
19201921 if not settings.MINIMAL_RUNTIME:
1921 # noExitRuntime does not apply to MINIMAL_RUNTIME.
1922 include_and_export('keepRuntimeAlive')
1922 # keepRuntimeAlive does not apply to MINIMAL_RUNTIME.
1923 settings.EXPORTED_RUNTIME_METHODS += ['keepRuntimeAlive']
19231924
19241925 if settings.MODULARIZE:
19251926 if not settings.EXPORT_ES6 and settings.EXPORT_NAME == 'Module':
20182019 if settings.MODULARIZE and not (settings.EXPORT_ES6 and not settings.SINGLE_FILE) and \
20192020 settings.EXPORT_NAME == 'Module' and options.oformat == OFormat.HTML and \
20202021 (options.shell_path == shared.path_from_root('src', 'shell.html') or options.shell_path == shared.path_from_root('src', 'shell_minimal.html')):
2021 exit_with_error('Due to collision in variable name "Module", the shell file "' + options.shell_path + '" is not compatible with build options "-s MODULARIZE=1 -s EXPORT_NAME=Module". Either provide your own shell file, change the name of the export to something else to avoid the name collision. (see https://github.com/emscripten-core/emscripten/issues/7950 for details)')
2022 exit_with_error(f'Due to collision in variable name "Module", the shell file "{options.shell_path}" is not compatible with build options "-s MODULARIZE=1 -s EXPORT_NAME=Module". Either provide your own shell file, change the name of the export to something else to avoid the name collision. (see https://github.com/emscripten-core/emscripten/issues/7950 for details)')
20222023
20232024 if settings.STANDALONE_WASM:
20242025 if settings.USE_PTHREADS:
23382339 headers = [header for _, header in input_files]
23392340 for header in headers:
23402341 if not header.endswith(HEADER_ENDINGS):
2341 exit_with_error('cannot mix precompile headers with non-header inputs: ' + str(headers) + ' : ' + header)
2342 exit_with_error(f'cannot mix precompiled headers with non-header inputs: {headers} : {header}')
23422343 cmd = get_clang_command(header)
23432344 if options.output_file:
23442345 cmd += ['-o', options.output_file]
2345 logger.debug("running (for precompiled headers): " + cmd[0] + ' ' + ' '.join(cmd[1:]))
2346 logger.debug(f"running (for precompiled headers): {cmd[0]} {' '.join(cmd[1:])}")
23462347 shared.check_call(cmd)
23472348 return []
23482349
23782379 if not state.has_dash_c:
23792380 cmd += ['-c']
23802381 cmd += ['-o', output_file]
2382 if state.mode == Mode.COMPILE_AND_LINK and '-gsplit-dwarf' in newargs:
2383 # When running in COMPILE_AND_LINK mode we compile to temporary location
2384 # but we want the `.dwo` file to be generated in the current working directory,
2385 # like it is under clang. We could avoid this hack if we use the clang driver
2386 # to generate the temporary files, but that would also involve using the clang
2387 # driver to perform linking which would be big change.
2388 cmd += ['-Xclang', '-split-dwarf-file', '-Xclang', unsuffixed_basename(input_file) + '.dwo']
2389 cmd += ['-Xclang', '-split-dwarf-output', '-Xclang', unsuffixed_basename(input_file) + '.dwo']
23812390 shared.check_call(cmd)
23822391 if output_file not in ('-', os.devnull):
23832392 assert os.path.exists(output_file)
24252434
24262435 @ToolchainProfiler.profile_block('link')
24272436 def phase_link(linker_arguments, wasm_target):
2428 logger.debug('linking: ' + str(linker_arguments))
2437 logger.debug(f'linking: {linker_arguments}')
24292438
24302439 # Make a final pass over settings.EXPORTED_FUNCTIONS to remove any
24312440 # duplication between functions added by the driver/libraries and function
25202529 file_args.append('--lz4')
25212530 if options.use_preload_plugins:
25222531 file_args.append('--use-preload-plugins')
2532 if not settings.ENVIRONMENT_MAY_BE_NODE:
2533 file_args.append('--no-node')
25232534 file_code = shared.check_call([shared.FILE_PACKAGER, unsuffixed(target) + '.data'] + file_args, stdout=PIPE).stdout
25242535 options.pre_js = js_manipulation.add_files_pre_js(options.pre_js, file_code)
25252536
25262537 # Apply pre and postjs files
25272538 if final_js and (options.pre_js or options.post_js):
25282539 logger.debug('applying pre/postjses')
2529 src = open(final_js).read()
2540 src = read_file(final_js)
25302541 final_js += '.pp.js'
25312542 with open(final_js, 'w') as f:
25322543 # pre-js code goes right after the Module integration code (so it
25522563 # is set the memory initializer url.
25532564 global final_js
25542565
2555 src = open(final_js).read()
2566 src = read_file(final_js)
25562567 src = do_replace(src, '// {{MEM_INITIALIZER}}', 'var memoryInitializer = "%s";' % os.path.basename(memfile))
2557 open(final_js + '.mem.js', 'w').write(src)
2568 write_file(final_js + '.mem.js', src)
25582569 final_js += '.mem.js'
25592570
25602571
25642575
25652576 # Remove some trivial whitespace
25662577 # TODO: do not run when compress has already been done on all parts of the code
2567 # src = open(final_js).read()
2578 # src = read_file(final_js)
25682579 # src = re.sub(r'\n+[ \n]*\n+', '\n', src)
2569 # open(final_js, 'w').write(src)
2580 # write_file(final_js, src)
25702581
25712582 if settings.USE_PTHREADS:
25722583 target_dir = os.path.dirname(os.path.abspath(target))
25772588 # Minify the worker.js file in optimized builds
25782589 if (settings.OPT_LEVEL >= 1 or settings.SHRINK_LEVEL >= 1) and not settings.DEBUG_LEVEL:
25792590 minified_worker = building.acorn_optimizer(worker_output, ['minifyWhitespace'], return_output=True)
2580 open(worker_output, 'w').write(minified_worker)
2591 write_file(worker_output, minified_worker)
25812592
25822593 # track files that will need native eols
25832594 generated_text_files_with_native_eols = []
25982609 # Unmangle previously mangled `import.meta` references in both main code and libraries.
25992610 # See also: `preprocess` in parseTools.js.
26002611 if settings.EXPORT_ES6 and settings.USE_ES6_IMPORT_META:
2601 src = open(final_js).read()
2612 src = read_file(final_js)
26022613 final_js += '.esmeta.js'
2603 with open(final_js, 'w') as f:
2604 f.write(src.replace('EMSCRIPTEN$IMPORT$META', 'import.meta'))
2614 write_file(final_js, src.replace('EMSCRIPTEN$IMPORT$META', 'import.meta'))
26052615 save_intermediate('es6-import-meta')
26062616
26072617 # Apply pre and postjs files
26082618 if options.extern_pre_js or options.extern_post_js:
26092619 logger.debug('applying extern pre/postjses')
2610 src = open(final_js).read()
2620 src = read_file(final_js)
26112621 final_js += '.epp.js'
26122622 with open(final_js, 'w') as f:
26132623 f.write(fix_windows_newlines(options.extern_pre_js))
27522762 elif check_arg('--js-transform'):
27532763 options.js_transform = consume_arg()
27542764 elif check_arg('--pre-js'):
2755 options.pre_js += open(consume_arg_file()).read() + '\n'
2765 options.pre_js += read_file(consume_arg_file()) + '\n'
27562766 elif check_arg('--post-js'):
2757 options.post_js += open(consume_arg_file()).read() + '\n'
2767 options.post_js += read_file(consume_arg_file()) + '\n'
27582768 elif check_arg('--extern-pre-js'):
2759 options.extern_pre_js += open(consume_arg_file()).read() + '\n'
2769 options.extern_pre_js += read_file(consume_arg_file()) + '\n'
27602770 elif check_arg('--extern-post-js'):
2761 options.extern_post_js += open(consume_arg_file()).read() + '\n'
2771 options.extern_post_js += read_file(consume_arg_file()) + '\n'
27622772 elif check_arg('--compiler-wrapper'):
27632773 config.COMPILER_WRAPPER = consume_arg()
27642774 elif check_flag('--post-link'):
28972907 # that are e.g. x86 specific and non-portable. The emscripten bundled
28982908 # headers are modified to be portable, local system ones are generally not.
28992909 diagnostics.warning(
2900 'absolute-paths', '-I or -L of an absolute path "' + arg +
2901 '" encountered. If this is to a local system header/library, it may '
2910 'absolute-paths', f'-I or -L of an absolute path "{arg}" '
2911 'encountered. If this is to a local system header/library, it may '
29022912 'cause problems (local system files make sense for compiling natively '
29032913 'on your system, but not necessarily to JavaScript).')
29042914 elif check_flag('--emrun'):
29312941 elif style.lower() == 'linux':
29322942 options.output_eol = '\n'
29332943 else:
2934 exit_with_error('Invalid value "' + style + '" to --output_eol!')
2944 exit_with_error(f'Invalid value "{style}" to --output_eol!')
29352945 elif check_arg('--generate-config'):
29362946 optarg = consume_arg()
29372947 path = os.path.expanduser(optarg)
29382948 if os.path.exists(path):
2939 exit_with_error('File ' + optarg + ' passed to --generate-config already exists!')
2949 exit_with_error(f'File {optarg} passed to --generate-config already exists!')
29402950 else:
29412951 config.generate_config(optarg)
29422952 should_exit = True
29572967 else:
29582968 value = '1'
29592969 if key in settings.keys():
2960 exit_with_error(arg + ': cannot change built-in settings values with a -jsD directive. Pass -s ' + key + '=' + value + ' instead!')
2970 exit_with_error(f'{arg}: cannot change built-in settings values with a -jsD directive. Pass -s {key}={value} instead!')
29612971 user_js_defines += [(key, value)]
29622972 newargs[i] = ''
29632973 elif check_flag('-shared'):
31763186
31773187 # replace placeholder strings with correct subresource locations
31783188 if final_js and settings.SINGLE_FILE and not settings.WASM2JS:
3179 js = open(final_js).read()
3189 js = read_file(final_js)
31803190
31813191 if settings.MINIMAL_RUNTIME:
3182 js = do_replace(js, '<<< WASM_BINARY_DATA >>>', base64_encode(open(wasm_target, 'rb').read()))
3192 js = do_replace(js, '<<< WASM_BINARY_DATA >>>', base64_encode(read_binary(wasm_target)))
31833193 else:
31843194 js = do_replace(js, '<<< WASM_BINARY_FILE >>>', shared.JS.get_subresource_location(wasm_target))
31853195 shared.try_delete(wasm_target)
31893199
31903200 def modularize():
31913201 global final_js
3192 logger.debug('Modularizing, assigning to var ' + settings.EXPORT_NAME)
3193 src = open(final_js).read()
3202 logger.debug(f'Modularizing, assigning to var {settings.EXPORT_NAME}')
3203 src = read_file(final_js)
31943204
31953205 return_value = settings.EXPORT_NAME
31963206 if settings.WASM_ASYNC_COMPILATION:
32653275
32663276 def module_export_name_substitution():
32673277 global final_js
3268 logger.debug('Private module export name substitution with ' + settings.EXPORT_NAME)
3278 logger.debug(f'Private module export name substitution with {settings.EXPORT_NAME}')
32693279 with open(final_js) as f:
32703280 src = f.read()
32713281 final_js += '.module_export_name_substitution.js'
33853395 if settings.SINGLE_FILE:
33863396 js_contents = script.inline or ''
33873397 if script.src:
3388 js_contents += open(js_target).read()
3398 js_contents += read_file(js_target)
33893399 shared.try_delete(js_target)
33903400 script.src = None
33913401 script.inline = js_contents
34343444 # '--remove-empty-elements': removes all elements with empty contents.
34353445 # (Breaks at least browser.test_asm_swapping)
34363446
3437 logger.debug('minifying HTML file ' + filename)
3447 logger.debug(f'minifying HTML file {filename}')
34383448 size_before = os.path.getsize(filename)
34393449 start_time = time.time()
34403450 shared.check_call(shared.get_npm_cmd('html-minifier-terser') + [filename, '-o', filename] + opts, env=shared.env_with_node_in_path())
34423452 elapsed_time = time.time() - start_time
34433453 size_after = os.path.getsize(filename)
34443454 delta = size_after - size_before
3445 logger.debug('HTML minification took {:.2f}'.format(elapsed_time) + ' seconds, and shrunk size of ' + filename + ' from ' + str(size_before) + ' to ' + str(size_after) + ' bytes, delta=' + str(delta) + ' ({:+.2f}%)'.format(delta * 100.0 / size_before))
3455 logger.debug(f'HTML minification took {elapsed_time:.2f} seconds, and shrunk size of {filename} from {size_before} to {size_after} bytes, delta={delta} ({delta * 100.0 / size_before:+.2f}%)')
34463456
34473457
34483458 def generate_html(target, options, js_target, target_basename,
34783488 proxy_worker_filename = (settings.PROXY_TO_WORKER_FILENAME or worker_target_basename) + '.js'
34793489
34803490 target_contents = worker_js_script(proxy_worker_filename)
3481 open(target, 'w').write(target_contents)
3491 write_file(target, target_contents)
34823492
34833493
34843494 def worker_js_script(proxy_worker_filename):
3485 web_gl_client_src = open(shared.path_from_root('src', 'webGLClient.js')).read()
3486 idb_store_src = open(shared.path_from_root('src', 'IDBStore.js')).read()
3487 proxy_client_src = open(shared.path_from_root('src', 'proxyClient.js')).read()
3495 web_gl_client_src = read_file(shared.path_from_root('src', 'webGLClient.js'))
3496 idb_store_src = read_file(shared.path_from_root('src', 'IDBStore.js'))
3497 proxy_client_src = read_file(shared.path_from_root('src', 'proxyClient.js'))
34883498 proxy_client_src = do_replace(proxy_client_src, '{{{ filename }}}', proxy_worker_filename)
34893499 proxy_client_src = do_replace(proxy_client_src, '{{{ IDBStore.js }}}', idb_store_src)
34903500 return web_gl_client_src + '\n' + proxy_client_src
690690 except OSError:
691691 pass
692692 filename = os.path.join(dump_out_directory, os.path.normpath(filename))
693 open(filename, 'wb').write(data)
693 with open(filename, 'wb') as fh:
694 fh.write(data)
694695 logi('Wrote ' + str(len(data)) + ' bytes to file "' + filename + '".')
695696 have_received_messages = True
696697 elif path == '/system_info':
10591060 model = check_output(cmd)
10601061 model = re.search('<configCode>(.*)</configCode>', model)
10611062 model = model.group(1).strip()
1062 open(os.path.join(os.getenv("HOME"), '.emrun.hwmodel.cached'), 'w').write(model) # Cache the hardware model to disk
1063 with open(os.path.join(os.getenv("HOME"), '.emrun.hwmodel.cached'), 'w') as fh:
1064 fh.write(model) # Cache the hardware model to disk
10631065 return model
10641066 except Exception:
10651067 hwmodel = check_output(['sysctl', 'hw.model'])
13841386 return info.strip()
13851387 else:
13861388 try:
1387 unique_system_id = open(os.path.expanduser('~/.emrun.generated.guid'), 'r').read().strip()
1389 with open(os.path.expanduser('~/.emrun.generated.guid')) as fh:
1390 unique_system_id = fh.read().strip()
13881391 except Exception:
13891392 import uuid
13901393 unique_system_id = str(uuid.uuid4())
0 "2.0.24"
0 "2.0.25"
203203 # standalone mode doesn't use main, and it always reports missing entry point at link time.
204204 # In this mode we never expect _main in the export list.
205205 return
206
207 # PROXY_TO_PTHREAD only makes sense with a main(), so error if one is
208 # missing. note that when main() might arrive from another module we cannot
209 # error here.
210 if settings.PROXY_TO_PTHREAD and '_main' not in defined_symbols and \
211 not settings.RELOCATABLE:
212 exit_with_error('PROXY_TO_PTHREAD proxies main() for you, but no main exists')
206213
207214 if settings.IGNORE_MISSING_MAIN:
208215 # The default mode for emscripten is to ignore the missing main function allowing
1717
1818 import sys
1919 import os
20 from pathlib import Path
2021
2122
2223 # At the top. #HamishW https://pypi.python.org/pypi/sphinx-bootstrap-theme/ ...
9293 # |version| and |release|, also used in various other places throughout the
9394 # built documents.
9495 #
95
96 emscripten_version = open(os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'emscripten-version.txt'))).read().strip().replace('"', '')
96 emscripten_version = Path(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'emscripten-version.txt').resolve().read_text().strip().replace('"', '')
9797
9898 # The short X.Y version.
9999 version = emscripten_version[:emscripten_version.rindex('.')]
1111
1212 .. note::
1313
14 In order to use the Fetch API, you would need to compile your code with **-s
15 FETCH=1**.
14 In order to use the Fetch API, you would need to compile your code with ``-s
15 FETCH=1``.
1616
1717 Introduction
1818 ============
192192 restrictions, depending on which Emscripten build mode (linker flags) is used:
193193
194194 - **No flags**: Only asynchronous Fetch operations are available.
195 - **--proxy-to-worker**: Synchronous Fetch operations are allowed for fetches
195 - ``--proxy-to-worker``: Synchronous Fetch operations are allowed for fetches
196196 that only do an XHR but do not interact with IndexedDB.
197 - **-s USE_PTHREADS=1**: Synchronous Fetch operations are available on
197 - ``-s USE_PTHREADS=1``: Synchronous Fetch operations are available on
198198 pthreads, but not on the main thread.
199 - **--proxy-to-worker** + **-s USE_PTHREADS=1**: Synchronous Fetch operations
199 - ``--proxy-to-worker`` + ``-s USE_PTHREADS=1``: Synchronous Fetch operations
200200 are available both on the main thread and pthreads.
201201
202202 Waitable Fetches
240240
241241 Waitable fetches are available only in certain build modes:
242242
243 - **No flags** or **--proxy-to-worker**: Waitable fetches are not available.
244 - **-s USE_PTHREADS=1**: Waitable fetches are available on pthreads, but not
243 - **No flags** or ``--proxy-to-worker``: Waitable fetches are not available.
244 - ``-s USE_PTHREADS=1``: Waitable fetches are available on pthreads, but not
245245 on the main thread.
246 - **--proxy-to-worker** + **-s USE_PTHREADS=1**: Waitable fetches are
246 - ``--proxy-to-worker`` + ``-s USE_PTHREADS=1``: Waitable fetches are
247247 available on all threads.
248248
249249 Tracking Progress
158158
159159 - Simulate lack of any special APIs that the page might need, e.g. Gamepad, Acceleration or Touch Events, and make sure that appropriate error flow is handled in those cases as well.
160160
161 If you have good tips or suggestsions to share, please help improve this guide by posting feedback to the `Emscripten bug tracker <https://github.com/emscripten-core/emscripten/issues>`_ or the `emscripten-discuss <https://groups.google.com/forum/#!forum/emscripten-discuss>`_ mailing list.
161 If you have good tips or suggestions to share, please help improve this guide by posting feedback to the `Emscripten bug tracker <https://github.com/emscripten-core/emscripten/issues>`_ or the `emscripten-discuss <https://groups.google.com/forum/#!forum/emscripten-discuss>`_ mailing list.
176176 EMCC_DEBUG=2 tests/runner test_hello_world
177177
178178
179 You can also specify ``EMTEST_SAVE_DIR=1`` in the environment to save the
180 temporary directory that the test runner uses into **/tmp/emscripten_test/**.
181 This is a test suite-specific feature, and is useful for inspecting test
182 outputs as well as temporary files generated by the test. By default,
183 the temporary directory will be cleaned between each test run, but setting
184 ``EMTEST_SAVE_DIR=2`` will preserve the directory even when a new test is
185 started.
179 You can also specify ``--save-dir`` to save the temporary directory that the
180 test runner uses into **/tmp/emscripten_test/**. This is a test suite-specific
181 feature, and is useful for inspecting test outputs as well as temporary files
182 generated by the test. By default, the temporary directory will be cleaned
183 between each test run, but you can add ``--no-clean`` to avoid this.
186184
187185
188186 The :ref:`Debugging` topic provides more guidance on how to debug Emscripten-generated code.
234234 `this MDN example <https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Basic_example>`_
235235 ).
236236
237 Note that we must propagate the value returned from ``handleSleep()``. The calling C code then
237 Note that we must propagate the value returned from ``handleAsync()``. The calling C code then
238238 gets it normally, after the Promise completes.
239239
240240 If you're using the ``handleSleep`` API, the value needs to be also passed to the ``wakeUp`` callback, instead of being returned from our handler:
5959 `Binaryen <https://github.com/WebAssembly/binaryen/>`_ is a WebAssembly compiler toolkit, which Emscripten uses to modify and optimize wasm.
6060
6161 node.js
62 **Node.js** is a cross-platform runtime environment for server-side and networking applications written in JavaScript. Essentially it allows you to run JavaScript applications outside of a browser context.
62 `Node.js <https://nodejs.org/en/>`_ is a cross-platform runtime environment for server-side and networking applications written in JavaScript. Essentially it allows you to run JavaScript applications outside of a browser context.
6363
6464 Python
6565 Python is a scripting language used to write many of Emscripten's tools. The required version is listed in the :ref:`toolchain requirements <central-list-of-emscripten-tools-and-dependencies>`.
2121 import stat
2222 import sys
2323 import time
24 from pathlib import Path
2425
2526 import api_items
2627
9091 continue
9192
9293 inputfilename = wiki_checkout + file
93 markdown = open(inputfilename).read()
94 markdown = Path(inputfilename).read_text()
9495 if 'This article has moved from the wiki to the new site' in markdown:
9596 continue
9697 if 'This page has been migrated to the main site' in markdown:
3737 function base64Decode(b64) {
3838 #if ENVIRONMENT_MAY_BE_NODE
3939 if (typeof ENVIRONMENT_IS_NODE !== 'undefined' && ENVIRONMENT_IS_NODE) {
40 try {
41 var buf = Buffer.from(b64, 'base64');
42 } catch (_) {
43 var buf = new Buffer(b64, 'base64');
44 }
40 var buf = Buffer.from(b64, 'base64');
4541 return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
4642 }
4743 #endif
4343 function intArrayFromBase64(s) {
4444 #if ENVIRONMENT_MAY_BE_NODE
4545 if (typeof ENVIRONMENT_IS_NODE === 'boolean' && ENVIRONMENT_IS_NODE) {
46 var buf;
47 try {
48 // TODO: Update Node.js externs, Closure does not recognize the following Buffer.from()
49 /**@suppress{checkTypes}*/
50 buf = Buffer.from(s, 'base64');
51 } catch (_) {
52 buf = new Buffer(s, 'base64');
53 }
46 var buf = Buffer.from(s, 'base64');
5447 return new Uint8Array(buf['buffer'], buf['byteOffset'], buf['byteLength']);
5548 }
5649 #endif
108108 }
109109 },
110110
111 _emval_run_destructors__sig: 'vi',
111112 _emval_run_destructors__deps: ['_emval_decref', '$emval_handle_array', '$runDestructors'],
112113 _emval_run_destructors: function(handle) {
113114 var destructors = emval_handle_array[handle].value;
125126 return __emval_register({});
126127 },
127128
129 _emval_new_cstring__sig: 'ii',
128130 _emval_new_cstring__deps: ['$getStringOrSymbol', '_emval_register'],
129131 _emval_new_cstring: function(v) {
130132 return __emval_register(getStringOrSymbol(v));
240242 })()('return this')();
241243 },
242244 #endif
245 _emval_get_global__sig: 'ii',
243246 _emval_get_global__deps: ['_emval_register', '$getStringOrSymbol', '$emval_get_global'],
244247 _emval_get_global: function(name) {
245248 if (name===0) {
256259 return __emval_register(Module[name]);
257260 },
258261
262 _emval_get_property__sig: 'iii',
259263 _emval_get_property__deps: ['_emval_register', '$requireHandle'],
260264 _emval_get_property: function(handle, key) {
261265 handle = requireHandle(handle);
263267 return __emval_register(handle[key]);
264268 },
265269
270 _emval_set_property__sig: 'viii',
266271 _emval_set_property__deps: ['$requireHandle'],
267272 _emval_set_property: function(handle, key, value) {
268273 handle = requireHandle(handle);
270275 value = requireHandle(value);
271276 handle[key] = value;
272277 },
273
278
279 _emval_as__sig: 'iiii',
274280 _emval_as__deps: ['_emval_register', '$requireHandle', '$requireRegisteredType'],
275281 _emval_as: function(handle, returnType, destructorsRef) {
276282 handle = requireHandle(handle);
9696 // It is possible that when printing the function as a string on Windows, the js interpreter we are in returns the string with Windows
9797 // line endings \r\n. This is undesirable, since line endings are managed in the form \n in the output for binary file writes, so
9898 // make sure the endings are uniform.
99 snippet = snippet.toString().replace(/\r\n/gm,"\n");
99 snippet = snippet.toString().replace(/\r\n/gm,'\n');
100100
101101 // name the function; overwrite if it's already named
102102 snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function ' + finalName + '(');
103103
104104 // apply LIBRARY_DEBUG if relevant
105 if (LIBRARY_DEBUG) {
105 if (LIBRARY_DEBUG && !isJsOnlyIdentifier(ident)) {
106106 snippet = modifyFunction(snippet, (name, args, body) => {
107107 return 'function ' + name + '(' + args + ') {\n' +
108108 'var ret = (function() { if (runtimeDebug) err("[library call:' + finalName + ': " + Array.prototype.slice.call(arguments).map(prettyPrint) + "]");\n' +
191191 LibraryManager.library[ident] = new Function(functionBody);
192192 noExport = true;
193193 }
194 }
195
196 if (!ALLOW_UNIMPLEMENTED_SYSCALLS && LibraryManager.library[ident + '__unimplemented']) {
197 error(`attempt to link unsupport syscall: ${ident} (use -s ALLOW_UNIMPLEMENTED_SYSCALLS (the default) to allow linking with a stub version`);
194198 }
195199
196200 var original = LibraryManager.library[ident];
393397 print(preprocess(read('arrayUtils.js')));
394398 }
395399
396 if (SUPPORT_BASE64_EMBEDDING && !MINIMAL_RUNTIME) {
400 if ((SUPPORT_BASE64_EMBEDDING || FORCE_FILESYSTEM) && !MINIMAL_RUNTIME) {
397401 print(preprocess(read('base64Utils.js')));
398402 }
399403
3535 setTempRet0__sig: 'vi',
3636 setTempRet0: function(val) {
3737 setTempRet0(val);
38 },
39
40 $zeroMemory: function(address, size) {
41 #if LEGACY_VM_SUPPORT
42 if (!HEAPU8.fill) {
43 for (var i = 0; i < size; i++) {
44 HEAPU8[address + i] = 0;
45 }
46 return;
47 }
48 #endif
49 HEAPU8.fill(0, address, address + size);
3850 },
3951
4052 #if SAFE_HEAP
112124 // sys/file.h
113125 // ==========================================================================
114126
127 flock__unimplemented: true,
115128 flock: function(fd, operation) {
116129 // int flock(int fd, int operation);
117130 // Pretend to succeed
121134 chroot__deps: ['$setErrNo'],
122135 chroot__proxy: 'sync',
123136 chroot__sig: 'ii',
137 chroot__unimplemented: true,
124138 chroot: function(path) {
125139 // int chroot(const char *path);
126140 // http://pubs.opengroup.org/onlinepubs/7908799/xsh/chroot.html
130144
131145 execve__deps: ['$setErrNo'],
132146 execve__sig: 'iiii',
147 execve__unimplemented: true,
133148 execve: function(path, argv, envp) {
134149 // int execve(const char *pathname, char *const argv[],
135150 // char *const envp[]);
150165 #endif
151166 },
152167
153 _exit__sig: 'vi',
154 _exit: 'exit',
155
156 _Exit__sig: 'vi',
157 _Exit: 'exit',
158
159168 #if MINIMAL_RUNTIME
160169 $exit: function(status) {
161170 throw 'exit(' + status + ')';
166175 // processes.
167176 fork__deps: ['$setErrNo'],
168177 fork__sig: 'i',
178 fork__unimplemented: true,
169179 fork: function() {
170180 // pid_t fork(void);
171181 // http://pubs.opengroup.org/onlinepubs/000095399/functions/fork.html
177187 posix_spawn: 'fork',
178188
179189 setgroups__deps: ['$setErrNo', 'sysconf'],
190 setgroups__unimplemented: true,
180191 setgroups: function(ngroups, gidset) {
181192 // int setgroups(int ngroups, const gid_t *gidset);
182193 // https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/setgroups.2.html
183194 if (ngroups < 1 || ngroups > _sysconf({{{ cDefine('_SC_NGROUPS_MAX') }}})) {
184195 setErrNo({{{ cDefine('EINVAL') }}});
185196 return -1;
186 } else {
187 // We have just one process/user/group, so it makes no sense to set groups.
188 setErrNo({{{ cDefine('EPERM') }}});
189 return -1;
190 }
197 }
198 // We have just one process/user/group, so it makes no sense to set groups.
199 setErrNo({{{ cDefine('EPERM') }}});
200 return -1;
191201 },
192202
193203 emscripten_get_heap_max: function() {
418428 // stdlib.h
419429 // ==========================================================================
420430
421 _ZSt9terminatev__deps: ['exit'],
422 _ZSt9terminatev: function() {
423 _exit(-1234);
424 },
425
426431 #if MINIMAL_RUNTIME && !EXIT_RUNTIME
427432 atexit__sig: 'v', // atexit unsupported in MINIMAL_RUNTIME
428433 atexit: function(){},
437442 },
438443 __cxa_atexit: 'atexit',
439444
440 #endif
441
442 // used in rust, clang when doing thread_local statics
443 #if USE_PTHREADS
444 __cxa_thread_atexit: 'pthread_cleanup_push',
445 __cxa_thread_atexit_impl: 'pthread_cleanup_push',
446 #else
447 __cxa_thread_atexit: 'atexit',
448 __cxa_thread_atexit_impl: 'atexit',
449445 #endif
450446
451447 // TODO: There are currently two abort() functions that get imported to asm module scope: the built-in runtime function abort(),
511507 __assert_fail: function(condition, filename, line, func) {
512508 abort('Assertion failed: ' + UTF8ToString(condition) + ', at: ' + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']);
513509 },
514
515 // ==========================================================================
516 // pwd.h
517 // ==========================================================================
518
519 // TODO: Implement.
520 // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/pwd.h.html
521 getpwuid: function(uid) {
522 return 0; // NULL
523 },
524
525510
526511 // ==========================================================================
527512 // time.h
766751 },
767752
768753 stime__deps: ['$setErrNo'],
754 stime__unimplemented: true,
769755 stime: function(when) {
770756 setErrNo({{{ cDefine('EPERM') }}});
771757 return -1;
14001386 return _strptime(buf, format, tm); // no locale support yet
14011387 },
14021388
1389 getdate__unimplemented: true,
14031390 getdate: function(string) {
14041391 // struct tm *getdate(const char *string);
14051392 // http://pubs.opengroup.org/onlinepubs/009695399/functions/getdate.html
14891476 // sys/times.h
14901477 // ==========================================================================
14911478
1479 times__deps: ['$zeroMemory'],
1480 times__unimplemented: true,
14921481 times: function(buffer) {
14931482 // clock_t times(struct tms *buffer);
14941483 // http://pubs.opengroup.org/onlinepubs/009695399/functions/times.html
14951484 // NOTE: This is fake, since we can't calculate real CPU time usage in JS.
14961485 if (buffer !== 0) {
1497 _memset(buffer, 0, {{{ C_STRUCTS.tms.__size__ }}});
1486 zeroMemory(buffer, {{{ C_STRUCTS.tms.__size__ }}});
14981487 }
14991488 return 0;
15001489 },
1501
1502 // ==========================================================================
1503 // sys/types.h
1504 // ==========================================================================
1505 // http://www.kernel.org/doc/man-pages/online/pages/man3/minor.3.html
1506 makedev__sig: 'iii',
1507 makedev: function(maj, min) {
1508 return ((maj) << 8 | (min));
1509 },
1510 gnu_dev_makedev: 'makedev',
1511 major__sig: 'ii',
1512 major: function(dev) {
1513 return ((dev) >> 8);
1514 },
1515 gnu_dev_major: 'major',
1516 minor__sig: 'ii',
1517 minor: function(dev) {
1518 return ((dev) & 0xff);
1519 },
1520 gnu_dev_minor: 'minor',
15211490
15221491 // ==========================================================================
15231492 // setjmp.h
15431512 return this.longjmp__deps;
15441513 },
15451514 // will never be emitted, as the dep errors at compile time
1515 longjmp__unimplemented: true,
15461516 longjmp: function(env, value) {
15471517 abort('longjmp not supported');
15481518 },
1519 setjmp__unimplemented: true,
15491520 setjmp: function(env, value) {
15501521 abort('setjmp not supported');
15511522 },
15571528
15581529 wait__deps: ['$setErrNo'],
15591530 wait__sig: 'ii',
1531 wait__unimplemented: true,
15601532 wait: function(stat_loc) {
15611533 // pid_t wait(int *stat_loc);
15621534 // http://pubs.opengroup.org/onlinepubs/009695399/functions/wait.html
20392011
20402012 return { family: family, addr: addr, port: port };
20412013 },
2042 $writeSockaddr__deps: ['$Sockets', '$inetPton4', '$inetPton6'],
2014 $writeSockaddr__deps: ['$Sockets', '$inetPton4', '$inetPton6', '$zeroMemory'],
20432015 $writeSockaddr: function (sa, family, addr, port, addrlen) {
20442016 switch (family) {
20452017 case {{{ cDefine('AF_INET') }}}:
20462018 addr = inetPton4(addr);
2019 zeroMemory(sa, {{{ C_STRUCTS.sockaddr_in.__size__ }}});
20472020 if (addrlen) {
20482021 {{{ makeSetValue('addrlen', 0, C_STRUCTS.sockaddr_in.__size__, 'i32') }}};
20492022 }
20502023 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'family', 'i16') }}};
20512024 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}};
20522025 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_port, '_htons(port)', 'i16') }}};
2053 /* Use makeSetValue instead of memset to avoid adding memset dependency for all users of writeSockaddr. */
2054 {{{ assert(C_STRUCTS.sockaddr_in.__size__ - C_STRUCTS.sockaddr_in.sin_zero == 8), '' }}}
2055 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_zero, '0', 'i64') }}};
20562026 break;
20572027 case {{{ cDefine('AF_INET6') }}}:
20582028 addr = inetPton6(addr);
2029 zeroMemory(sa, {{{ C_STRUCTS.sockaddr_in6.__size__ }}});
20592030 if (addrlen) {
20602031 {{{ makeSetValue('addrlen', 0, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}};
20612032 }
20652036 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'addr[2]', 'i32') }}};
20662037 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'addr[3]', 'i32') }}};
20672038 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_port, '_htons(port)', 'i16') }}};
2068 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_flowinfo, '0', 'i32') }}};
2069 {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_scope_id, '0', 'i32') }}};
20702039 break;
20712040 default:
20722041 return {{{ cDefine('EAFNOSUPPORT') }}};
25652534
25662535 // pwd.h
25672536
2537 getpwnam__unimplemented: true,
25682538 getpwnam: function() { throw 'getpwnam: TODO' },
2539 getpwnam_r__unimplemented: true,
25692540 getpwnam_r: function() { throw 'getpwnam_r: TODO' },
2541 getpwuid__unimplemented: true,
25702542 getpwuid: function() { throw 'getpwuid: TODO' },
2543 getpwuid_r__unimplemented: true,
25712544 getpwuid_r: function() { throw 'getpwuid_r: TODO' },
2545 setpwent__unimplemented: true,
25722546 setpwent: function() { throw 'setpwent: TODO' },
2547 getpwent__unimplemented: true,
25732548 getpwent: function() { throw 'getpwent: TODO' },
2549 endpwent__unimplemented: true,
25742550 endpwent: function() { throw 'endpwent: TODO' },
25752551
25762552 // grp.h
25772553
2554 getgrgid__unimplemented: true,
25782555 getgrgid: function() { throw 'getgrgid: TODO' },
2556 getgrgid_r__unimplemented: true,
25792557 getgrgid_r: function() { throw 'getgrgid_r: TODO' },
2558 getgrnam__unimplemented: true,
25802559 getgrnam: function() { throw 'getgrnam: TODO' },
2560 getgrnam_r__unimplemented: true,
25812561 getgrnam_r: function() { throw 'getgrnam_r: TODO' },
2562 getgrent__unimplemented: true,
25822563 getgrent: function() { throw 'getgrent: TODO' },
2564 endgrent__unimplemented: true,
25832565 endgrent: function() { throw 'endgrent: TODO' },
2566 setgrent__unimplemented: true,
25842567 setgrent: function() { throw 'setgrent: TODO' },
25852568
25862569 // random.h
35583541 throw 'unwind';
35593542 },
35603543
3561 emscripten_force_exit__deps: ['$runtimeKeepaliveCounter'],
35623544 emscripten_force_exit__proxy: 'sync',
35633545 emscripten_force_exit__sig: 'vi',
35643546 emscripten_force_exit: function(status) {
35753557 },
35763558
35773559 #if !MINIMAL_RUNTIME
3578 $runtimeKeepaliveCounter: 0,
3579
3580 $keepRuntimeAlive__deps: ['$runtimeKeepaliveCounter'],
3581 $keepRuntimeAlive: function() {
3582 return noExitRuntime || runtimeKeepaliveCounter > 0;
3583 },
3584
35853560 // Callable in pthread without __proxy needed.
35863561 $runtimeKeepalivePush__sig: 'v',
3587 $runtimeKeepalivePush__deps: ['$runtimeKeepaliveCounter'],
35883562 $runtimeKeepalivePush: function() {
35893563 runtimeKeepaliveCounter += 1;
35903564 #if RUNTIME_DEBUG
35933567 },
35943568
35953569 $runtimeKeepalivePop__sig: 'v',
3596 $runtimeKeepalivePop__deps: ['$runtimeKeepaliveCounter'],
35973570 $runtimeKeepalivePop: function() {
35983571 #if ASSERTIONS
35993572 assert(runtimeKeepaliveCounter > 0);
36033576 err('runtimeKeepalivePop -> counter=' + runtimeKeepaliveCounter);
36043577 #endif
36053578 },
3606
36073579
36083580 // Used to call user callbacks from the embedder / event loop. For example
36093581 // setTimeout or any other kind of event handler that calls into user case
36803652 },
36813653 #endif
36823654
3655 $safeSetTimeout: function(func, timeout) {
3656 {{{ runtimeKeepalivePush() }}}
3657 return setTimeout(function() {
3658 {{{ runtimeKeepalivePop() }}}
3659 callUserCallback(func);
3660 }, timeout);
3661 },
3662
36833663 $asmjsMangle: function(x) {
36843664 var unmangledSymbols = {{{ buildStringArray(WASM_SYSTEM_EXPORTS) }}};
36853665 return x.indexOf('dynCall_') == 0 || unmangledSymbols.includes(x) ? x : '_' + x;
3666 },
3667
3668 $asyncLoad: function(url, onload, onerror, noRunDep) {
3669 var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : '';
3670 readAsync(url, function(arrayBuffer) {
3671 assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
3672 onload(new Uint8Array(arrayBuffer));
3673 if (dep) removeRunDependency(dep);
3674 }, function(event) {
3675 if (onerror) {
3676 onerror();
3677 } else {
3678 throw 'Loading data file "' + url + '" failed.';
3679 }
3680 });
3681 if (dep) addRunDependency(dep);
3682 },
3683
3684 // Allocate memory for an mmap operation. This allocates space of the right
3685 // page-aligned size, and clears the allocated space.
3686 $mmapAlloc__deps: ['$zeroMemory'],
3687 $mmapAlloc: function(size) {
3688 #if hasExportedFunction('_memalign')
3689 size = alignMemory(size, {{{ WASM_PAGE_SIZE }}});
3690 var ptr = _memalign({{{ WASM_PAGE_SIZE }}}, size);
3691 if (!ptr) return 0;
3692 zeroMemory(ptr, size);
3693 return ptr;
3694 #elif ASSERTIONS
3695 abort('internal error: mmapAlloc called but `memalign` native symbol not exported');
3696 #else
3697 abort();
3698 #endif
36863699 },
36873700
36883701 #if RELOCATABLE
1919 },
2020
2121 #if ASYNCIFY
22 $Asyncify__deps: ['$runAndAbortIfError'],
22 $Asyncify__deps: ['$runAndAbortIfError', '$callUserCallback',
23 #if !MINIMAL_RUNTIME
24 '$runtimeKeepalivePush', '$runtimeKeepalivePop'
25 #endif
26 ],
2327 $Asyncify: {
2428 State: {
2529 Normal: 0,
129133 #if ASYNCIFY_DEBUG
130134 err('ASYNCIFY: stop unwind');
131135 #endif
136 {{{ runtimeKeepalivePush(); }}}
132137 Asyncify.state = Asyncify.State.Normal;
138 // Keep the runtime alive so that a re-wind can be done later.
133139 runAndAbortIfError(Module['_asyncify_stop_unwind']);
134140 if (typeof Fibers !== 'undefined') {
135141 Fibers.trampoline();
177183 return func;
178184 },
179185
186 doRewind: function(ptr) {
187 var start = Asyncify.getDataRewindFunc(ptr);
188 #if ASYNCIFY_DEBUG
189 err('ASYNCIFY: start:', start);
190 #endif
191 // Once we have rewound and the stack we no longer need to artificially keep
192 // the runtime alive.
193 {{{ runtimeKeepalivePop(); }}}
194 return start();
195 },
196
180197 handleSleep: function(startAsync) {
181198 #if ASSERTIONS
182199 assert(Asyncify.state !== Asyncify.State.Disabled, 'Asyncify cannot be done during or after the runtime exits');
183200 #endif
184201 if (ABORT) return;
185 #if !MINIMAL_RUNTIME
186 noExitRuntime = true;
187 #endif
188202 #if ASYNCIFY_DEBUG
189203 err('ASYNCIFY: handleSleep ' + Asyncify.state);
190204 #endif
222236 if (typeof Browser !== 'undefined' && Browser.mainLoop.func) {
223237 Browser.mainLoop.resume();
224238 }
225 var start = Asyncify.getDataRewindFunc(Asyncify.currData);
226 #if ASYNCIFY_DEBUG
227 err('ASYNCIFY: start:', start);
228 #endif
229 var asyncWasmReturnValue = start();
239 var asyncWasmReturnValue = Asyncify.doRewind(Asyncify.currData);
230240 if (!Asyncify.currData) {
231241 // All asynchronous execution has finished.
232242 // `asyncWasmReturnValue` now contains the final
272282 Asyncify.currData = null;
273283 // Call all sleep callbacks now that the sleep-resume is all done.
274284 Asyncify.sleepCallbacks.forEach(function(func) {
275 func();
285 callUserCallback(func);
276286 });
277287 } else {
278288 abort('invalid state: ' + Asyncify.state);
293303 },
294304 },
295305
296 emscripten_sleep__deps: ['$Browser'],
306 emscripten_sleep__deps: ['$safeSetTimeout'],
297307 emscripten_sleep: function(ms) {
298308 Asyncify.handleSleep(function(wakeUp) {
299 Browser.safeSetTimeout(wakeUp, ms);
309 safeSetTimeout(wakeUp, ms);
300310 });
301311 },
302312
323333 });
324334 },
325335
326 emscripten_wget_data__deps: ['$Browser'],
336 emscripten_wget_data__deps: ['$asyncLoad', 'malloc'],
327337 emscripten_wget_data: function(url, pbuffer, pnum, perror) {
328338 Asyncify.handleSleep(function(wakeUp) {
329 Browser.asyncLoad(UTF8ToString(url), function(byteArray) {
339 asyncLoad(UTF8ToString(url), function(byteArray) {
330340 // can only allocate the buffer after the wakeUp, not during an asyncing
331341 var buffer = _malloc(byteArray.length); // must be freed by caller!
332342 HEAPU8.set(byteArray, buffer);
420430 #endif
421431 Asyncify.state = Asyncify.State.Rewinding;
422432 Module['_asyncify_start_rewind'](asyncifyData);
423 var start = Asyncify.getDataRewindFunc(asyncifyData);
424 #if ASYNCIFY_DEBUG
425 err('ASYNCIFY/FIBER: start: ' + start);
426 #endif
427 start();
433 Asyncify.doRewind(asyncifyData);
428434 }
429435 },
430436 },
459465 emscripten_fiber_swap__deps: ["$Asyncify", "$Fibers"],
460466 emscripten_fiber_swap: function(oldFiber, newFiber) {
461467 if (ABORT) return;
462 #if !MINIMAL_RUNTIME
463 noExitRuntime = true;
464 #endif
465468 #if ASYNCIFY_DEBUG
466469 err('ASYNCIFY/FIBER: swap', oldFiber, '->', newFiber, 'state:', Asyncify.state);
467470 #endif
1313 assert(!LibraryManager.library);
1414 LibraryManager.library = {
1515 $callRuntimeCallbacks: function() {},
16 $keepRuntimeAlive: function() { return false }
1716 };
88 $Browser__deps: [
99 '$setMainLoop',
1010 '$callUserCallback',
11 '$safeSetTimeout',
1112 'emscripten_set_main_loop_timing',
1213 #if !MINIMAL_RUNTIME
1314 '$runtimeKeepalivePush',
229230 };
230231 audio.src = url;
231232 // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
232 Browser.safeSetTimeout(function() {
233 safeSetTimeout(function() {
233234 finish(audio); // try to use it even though it is not necessarily ready to play
234235 }, 10000);
235236 } else {
487488
488489 // abort and pause-aware versions TODO: build main loop on top of this?
489490
491 safeSetTimeout: function(func) {
492 // Legacy function, this is used by the SDL2 port so we need to keep it
493 // around at least until that is updated.
494 return safeSetTimeout(func);
495 },
490496 safeRequestAnimationFrame: function(func) {
491497 {{{ runtimeKeepalivePush() }}}
492498 return Browser.requestAnimationFrame(function() {
493499 {{{ runtimeKeepalivePop() }}}
494500 callUserCallback(func);
495501 });
496 },
497 safeSetTimeout: function(func, timeout) {
498 {{{ runtimeKeepalivePush() }}}
499 return setTimeout(function() {
500 {{{ runtimeKeepalivePop() }}}
501 callUserCallback(func);
502 }, timeout);
503502 },
504503
505504 getMimetype: function(name) {
672671 }
673672 },
674673
675 asyncLoad: function(url, onload, onerror, noRunDep) {
676 var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : '';
677 readAsync(url, function(arrayBuffer) {
678 assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
679 onload(new Uint8Array(arrayBuffer));
680 if (dep) removeRunDependency(dep);
681 }, function(event) {
682 if (onerror) {
683 onerror();
684 } else {
685 throw 'Loading data file "' + url + '" failed.';
686 }
687 });
688 if (dep) addRunDependency(dep);
689 },
690
691674 resizeListeners: [],
692675
693676 updateResizeListeners: function() {
772755 }
773756 }
774757 },
775
776 wgetRequests: {},
777 nextWgetRequestHandle: 0,
778
779 getNextWgetRequestHandle: function() {
780 var handle = Browser.nextWgetRequestHandle;
781 Browser.nextWgetRequestHandle++;
782 return handle;
783 }
784 },
785
786 emscripten_async_wget__deps: ['$PATH_FS',
787 #if !MINIMAL_RUNTIME
788 '$runtimeKeepalivePush', '$runtimeKeepalivePop',
789 #endif
790 ],
791 emscripten_async_wget__proxy: 'sync',
792 emscripten_async_wget__sig: 'viiii',
793 emscripten_async_wget: function(url, file, onload, onerror) {
794 {{{ runtimeKeepalivePush() }}}
795
796 var _url = UTF8ToString(url);
797 var _file = UTF8ToString(file);
798 _file = PATH_FS.resolve(_file);
799 function doCallback(callback) {
800 if (callback) {
801 {{{ runtimeKeepalivePop() }}}
802 callUserCallback(function() {
803 var stack = stackSave();
804 {{{ makeDynCall('vi', 'callback') }}}(allocate(intArrayFromString(_file), ALLOC_STACK));
805 stackRestore(stack);
806 });
807 }
808 }
809 var destinationDirectory = PATH.dirname(_file);
810 FS.createPreloadedFile(
811 destinationDirectory,
812 PATH.basename(_file),
813 _url, true, true,
814 function() {
815 doCallback(onload);
816 },
817 function() {
818 doCallback(onerror);
819 },
820 false, // dontCreateFile
821 false, // canOwn
822 function() { // preFinish
823 // if a file exists there, we overwrite it
824 try {
825 FS.unlink(_file);
826 } catch (e) {}
827 // if the destination directory does not yet exist, create it
828 FS.mkdirTree(destinationDirectory);
829 }
830 );
831758 },
832759
833760 $funcWrappers: {},
858785 }
859786 }
860787 return sigCache[func];
861 },
862
863 emscripten_async_wget_data__proxy: 'sync',
864 emscripten_async_wget_data__sig: 'viiii',
865 emscripten_async_wget_data: function(url, arg, onload, onerror) {
866 {{{ runtimeKeepalivePush() }}}
867 Browser.asyncLoad(UTF8ToString(url), function(byteArray) {
868 {{{ runtimeKeepalivePop() }}}
869 callUserCallback(function() {
870 var buffer = _malloc(byteArray.length);
871 HEAPU8.set(byteArray, buffer);
872 {{{ makeDynCall('viii', 'onload') }}}(arg, buffer, byteArray.length);
873 _free(buffer);
874 });
875 }, function() {
876 if (onerror) {
877 {{{ runtimeKeepalivePop() }}}
878 callUserCallback(function() {
879 {{{ makeDynCall('vi', 'onerror') }}}(arg);
880 });
881 }
882 }, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
883 },
884
885 emscripten_async_wget2__deps: ['$PATH_FS',
886 #if !MINIMAL_RUNTIME
887 '$runtimeKeepalivePush', '$runtimeKeepalivePop',
888 #endif
889 ],
890 emscripten_async_wget2__proxy: 'sync',
891 emscripten_async_wget2__sig: 'iiiiiiiii',
892 emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) {
893 {{{ runtimeKeepalivePush() }}}
894
895 var _url = UTF8ToString(url);
896 var _file = UTF8ToString(file);
897 _file = PATH_FS.resolve(_file);
898 var _request = UTF8ToString(request);
899 var _param = UTF8ToString(param);
900 var index = _file.lastIndexOf('/');
901
902 var http = new XMLHttpRequest();
903 http.open(_request, _url, true);
904 http.responseType = 'arraybuffer';
905
906 var handle = Browser.getNextWgetRequestHandle();
907
908 var destinationDirectory = PATH.dirname(_file);
909
910 // LOAD
911 http.onload = function http_onload(e) {
912 {{{ runtimeKeepalivePop() }}}
913 if (http.status >= 200 && http.status < 300) {
914 // if a file exists there, we overwrite it
915 try {
916 FS.unlink(_file);
917 } catch (e) {}
918 // if the destination directory does not yet exist, create it
919 FS.mkdirTree(destinationDirectory);
920
921 FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(/** @type{ArrayBuffer}*/(http.response)), true, true, false);
922 if (onload) {
923 var stack = stackSave();
924 {{{ makeDynCall('viii', 'onload') }}}(handle, arg, allocate(intArrayFromString(_file), ALLOC_STACK));
925 stackRestore(stack);
926 }
927 } else {
928 if (onerror) {{{ makeDynCall('viii', 'onerror') }}}(handle, arg, http.status);
929 }
930
931 delete Browser.wgetRequests[handle];
932 };
933
934 // ERROR
935 http.onerror = function http_onerror(e) {
936 {{{ runtimeKeepalivePop() }}}
937 if (onerror) {{{ makeDynCall('viii', 'onerror') }}}(handle, arg, http.status);
938 delete Browser.wgetRequests[handle];
939 };
940
941 // PROGRESS
942 http.onprogress = function http_onprogress(e) {
943 if (e.lengthComputable || (e.lengthComputable === undefined && e.total != 0)) {
944 var percentComplete = (e.loaded / e.total)*100;
945 if (onprogress) {{{ makeDynCall('viii', 'onprogress') }}}(handle, arg, percentComplete);
946 }
947 };
948
949 // ABORT
950 http.onabort = function http_onabort(e) {
951 {{{ runtimeKeepalivePop() }}}
952 delete Browser.wgetRequests[handle];
953 };
954
955 if (_request == "POST") {
956 //Send the proper header information along with the request
957 http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
958 http.send(_param);
959 } else {
960 http.send(null);
961 }
962
963 Browser.wgetRequests[handle] = http;
964
965 return handle;
966 },
967
968 emscripten_async_wget2_data__proxy: 'sync',
969 emscripten_async_wget2_data__sig: 'iiiiiiiii',
970 emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) {
971 var _url = UTF8ToString(url);
972 var _request = UTF8ToString(request);
973 var _param = UTF8ToString(param);
974
975 var http = new XMLHttpRequest();
976 http.open(_request, _url, true);
977 http.responseType = 'arraybuffer';
978
979 var handle = Browser.getNextWgetRequestHandle();
980
981 function onerrorjs() {
982 if (onerror) {
983 var statusText = 0;
984 if (http.statusText) {
985 var len = lengthBytesUTF8(http.statusText) + 1;
986 statusText = stackAlloc(len);
987 stringToUTF8(http.statusText, statusText, len);
988 }
989 {{{ makeDynCall('viiii', 'onerror') }}}(handle, arg, http.status, statusText);
990 }
991 }
992
993 // LOAD
994 http.onload = function http_onload(e) {
995 if (http.status >= 200 && http.status < 300 || (http.status === 0 && _url.substr(0,4).toLowerCase() != "http")) {
996 var byteArray = new Uint8Array(/** @type{ArrayBuffer} */(http.response));
997 var buffer = _malloc(byteArray.length);
998 HEAPU8.set(byteArray, buffer);
999 if (onload) {{{ makeDynCall('viiii', 'onload') }}}(handle, arg, buffer, byteArray.length);
1000 if (free) _free(buffer);
1001 } else {
1002 onerrorjs();
1003 }
1004 delete Browser.wgetRequests[handle];
1005 };
1006
1007 // ERROR
1008 http.onerror = function http_onerror(e) {
1009 onerrorjs();
1010 delete Browser.wgetRequests[handle];
1011 };
1012
1013 // PROGRESS
1014 http.onprogress = function http_onprogress(e) {
1015 if (onprogress) {{{ makeDynCall('viiii', 'onprogress') }}}(handle, arg, e.loaded, e.lengthComputable || e.lengthComputable === undefined ? e.total : 0);
1016 };
1017
1018 // ABORT
1019 http.onabort = function http_onabort(e) {
1020 delete Browser.wgetRequests[handle];
1021 };
1022
1023 if (_request == "POST") {
1024 //Send the proper header information along with the request
1025 http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
1026 http.send(_param);
1027 } else {
1028 http.send(null);
1029 }
1030
1031 Browser.wgetRequests[handle] = http;
1032
1033 return handle;
1034 },
1035
1036 emscripten_async_wget2_abort__proxy: 'sync',
1037 emscripten_async_wget2_abort__sig: 'vi',
1038 emscripten_async_wget2_abort: function(handle) {
1039 var http = Browser.wgetRequests[handle];
1040 if (http) {
1041 http.abort();
1042 }
1043788 },
1044789
1045790 emscripten_run_preload_plugins__deps: ['$PATH',
1104849 },
1105850
1106851 // Callable from pthread, executes in pthread context.
1107 emscripten_async_run_script__deps: ['emscripten_run_script'],
852 emscripten_async_run_script__deps: ['emscripten_run_script', '$safeSetTimeout'],
1108853 emscripten_async_run_script: function(script, millis) {
1109854 // TODO: cache these to avoid generating garbage
1110 Browser.safeSetTimeout(function() {
855 safeSetTimeout(function() {
1111856 _emscripten_run_script(script);
1112857 }, millis);
1113858 },
14201165
14211166 // Runs natively in pthread, no __proxy needed.
14221167 emscripten_async_call__sig: 'viii',
1168 emscripten_async_call__deps: ['$safeSetTimeout'],
14231169 emscripten_async_call: function(func, arg, millis) {
14241170 function wrapper() {
14251171 {{{ makeDynCall('vi', 'func') }}}(arg);
14261172 }
14271173
1428 if (millis >= 0) {
1429 Browser.safeSetTimeout(wrapper, millis);
1174 if (millis >= 0
1175 #if ENVIRONMENT_MAY_BE_NODE
1176 // node does not support requestAnimationFrame
1177 || ENVIRONMENT_IS_NODE
1178 #endif
1179 ) {
1180 safeSetTimeout(wrapper, millis);
14301181 } else {
14311182 Browser.safeRequestAnimationFrame(wrapper);
14321183 }
247247 ___heap_base = end;
248248 GOT['__heap_base'].value = end;
249249 return ret;
250 },
251
252 // fetchBinary fetches binary data @ url. (async)
253 $fetchBinary: function(url) {
254 return fetch(url, { credentials: 'same-origin' }).then(function(response) {
255 if (!response['ok']) {
256 throw "failed to load binary file at '" + url + "'";
257 }
258 return response['arrayBuffer']();
259 }).then(function(buffer) {
260 return new Uint8Array(buffer);
261 });
262250 },
263251
264252 // returns the side module metadata as an object
575563 // If a library was already loaded, it is not loaded a second time. However
576564 // flags.global and flags.nodelete are handled every time a load request is made.
577565 // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded.
578 $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$asmjsMangle', '$fetchBinary', '$isInternalSym', '$mergeLibSymbols'],
566 $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$asmjsMangle', '$isInternalSym', '$mergeLibSymbols'],
579567 $loadDynamicLibrary: function(lib, flags) {
580568 if (lib == '__main__' && !LDSO.loadedLibNames[lib]) {
581569 LDSO.loadedLibs[-1] = {
627615 // libData <- libFile
628616 function loadLibData(libFile) {
629617 // for wasm, we can use fetch for async, but for fs mode we can only imitate it
630 if (flags.fs) {
618 if (flags.fs && flags.fs.findObject(libFile)) {
631619 var libData = flags.fs.readFile(libFile, {encoding: 'binary'});
632620 if (!(libData instanceof Uint8Array)) {
633621 libData = new Uint8Array(libData);
636624 }
637625
638626 if (flags.loadAsync) {
639 return fetchBinary(libFile);
640 }
627 return new Promise(function(resolve, reject) {
628 readAsync(libFile, function(data) { resolve(new Uint8Array(data)); }, reject);
629 });
630 }
631
641632 // load the binary synchronously
633 if (!readBinary) {
634 throw new Error(libFile + ': file not found, and synchronous loading of external files is not available');
635 }
642636 return readBinary(libFile);
643637 }
644638
673667 return getLibModule().then(function(libModule) {
674668 moduleLoaded(libModule);
675669 return handle;
676 })
670 });
677671 }
678672
679673 moduleLoaded(getLibModule());
693687 return;
694688 }
695689
696 // if we can load dynamic libraries synchronously, do so, otherwise, preload
697 if (!readBinary) {
698 // we can't read binary data synchronously, so preload
699 addRunDependency('preloadDylibs');
700 dynamicLibraries.reduce(function(chain, lib) {
701 return chain.then(function() {
702 return loadDynamicLibrary(lib, {loadAsync: true, global: true, nodelete: true, allowUndefined: true});
703 });
704 }, Promise.resolve()).then(function() {
705 // we got them all, wonderful
706 removeRunDependency('preloadDylibs');
707 reportUndefinedSymbols();
690 // Load binaries asynchronously
691 addRunDependency('preloadDylibs');
692 dynamicLibraries.reduce(function(chain, lib) {
693 return chain.then(function() {
694 return loadDynamicLibrary(lib, {loadAsync: true, global: true, nodelete: true, allowUndefined: true});
708695 });
709 return;
710 }
711
712 dynamicLibraries.forEach(function(lib) {
713 // libraries linked to main never go away
714 loadDynamicLibrary(lib, {global: true, nodelete: true, allowUndefined: true});
696 }, Promise.resolve()).then(function() {
697 // we got them all, wonderful
698 reportUndefinedSymbols();
699 removeRunDependency('preloadDylibs');
700 #if DYLINK_DEBUG
701 err('preloadDylibs done!');
702 #endif
715703 });
716 reportUndefinedSymbols();
717704 },
718705
719706 // void* dlopen(const char* filename, int flags);
720707 dlopen__deps: ['$DLFCN', '$FS', '$ENV'],
721 dlopen__proxy: 'sync',
722708 dlopen__sig: 'iii',
723709 dlopen: function(filenameAddr, flags) {
724710 // void *dlopen(const char *file, int mode);
776762
777763 // int dlclose(void* handle);
778764 dlclose__deps: ['$DLFCN'],
779 dlclose__proxy: 'sync',
780765 dlclose__sig: 'ii',
781766 dlclose: function(handle) {
782767 // int dlclose(void *handle);
795780
796781 // void* dlsym(void* handle, const char* symbol);
797782 dlsym__deps: ['$DLFCN'],
798 dlsym__proxy: 'sync',
799783 dlsym__sig: 'iii',
800784 dlsym: function(handle, symbol) {
801785 // void *dlsym(void *restrict handle, const char *restrict name);
839823
840824 // char* dlerror(void);
841825 dlerror__deps: ['$DLFCN', '$stringToNewUTF8'],
842 dlerror__proxy: 'sync',
843826 dlerror__sig: 'i',
844827 dlerror: function() {
845828 // char *dlerror(void);
854837 },
855838
856839 dladdr__deps: ['$stringToNewUTF8', '$getExecutableName'],
857 dladdr__proxy: 'sync',
858840 dladdr__sig: 'iii',
859841 dladdr: function(addr, info) {
860842 // report all function pointers as coming from this program itself XXX not really correct in any way
88 $exceptionLast: '0',
99 $exceptionCaught: ' []',
1010
11 // Static fields for ExceptionInfo class.
12 $ExceptionInfoAttrs: {
13 // ExceptionInfo native structure layout.
14 DESTRUCTOR_OFFSET: 0,
15 REFCOUNT_OFFSET: Runtime.POINTER_SIZE,
16 TYPE_OFFSET: Runtime.POINTER_SIZE + 4,
17 CAUGHT_OFFSET: Runtime.POINTER_SIZE + 8,
18 RETHROWN_OFFSET: Runtime.POINTER_SIZE + 9,
19
20 // Total structure size with padding, should be multiple of allocation alignment.
21 SIZE: alignMemory(Runtime.POINTER_SIZE + 10)
22 },
23
24 $ExceptionInfo__deps: ['$ExceptionInfoAttrs'],
2511 // This class is the exception metadata which is prepended to each thrown object (in WASM memory).
2612 // It is allocated in one block among with a thrown object in __cxa_allocate_exception and freed
2713 // in ___cxa_free_exception. It roughly corresponds to __cxa_exception structure in libcxxabi. The
3622 // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it.
3723 $ExceptionInfo: function(excPtr) {
3824 this.excPtr = excPtr;
39 this.ptr = excPtr - ExceptionInfoAttrs.SIZE;
25 this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}};
4026
4127 this.set_type = function(type) {
42 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.TYPE_OFFSET', 'type', '*') }}};
28 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionType, 'type', '*') }}};
4329 };
4430
4531 this.get_type = function() {
46 return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.TYPE_OFFSET', '*') }}};
32 return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionType, '*') }}};
4733 };
4834
4935 this.set_destructor = function(destructor) {
50 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.DESTRUCTOR_OFFSET', 'destructor', '*') }}};
36 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, 'destructor', '*') }}};
5137 };
5238
5339 this.get_destructor = function() {
54 return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.DESTRUCTOR_OFFSET', '*') }}};
40 return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}};
5541 };
5642
5743 this.set_refcount = function(refcount) {
58 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'refcount', 'i32') }}};
44 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}};
5945 };
6046
6147 this.set_caught = function (caught) {
6248 caught = caught ? 1 : 0;
63 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.CAUGHT_OFFSET', 'caught', 'i8') }}};
49 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}};
6450 };
6551
6652 this.get_caught = function () {
67 return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.CAUGHT_OFFSET', 'i8') }}} != 0;
53 return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'i8') }}} != 0;
6854 };
6955
7056 this.set_rethrown = function (rethrown) {
7157 rethrown = rethrown ? 1 : 0;
72 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.RETHROWN_OFFSET', 'rethrown', 'i8') }}};
58 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.rethrown, 'rethrown', 'i8') }}};
7359 };
7460
7561 this.get_rethrown = function () {
76 return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.RETHROWN_OFFSET', 'i8') }}} != 0;
62 return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.rethrown, 'i8') }}} != 0;
7763 };
7864
7965 // Initialize native structure fields. Should be called once after allocated.
8773
8874 this.add_ref = function() {
8975 #if USE_PTHREADS
90 Atomics.add(HEAP32, (this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET) >> 2, 1);
76 Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
9177 #else
92 var value = {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'i32') }}};
93 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'value + 1', 'i32') }}};
78 var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
79 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}};
9480 #endif
9581 };
9682
9783 // Returns true if last reference released.
9884 this.release_ref = function() {
9985 #if USE_PTHREADS
100 var prev = Atomics.sub(HEAP32, (this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET) >> 2, 1);
86 var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
10187 #else
102 var prev = {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'i32') }}};
103 {{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'prev - 1', 'i32') }}};
88 var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
89 {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}};
10490 #endif
10591 #if ASSERTIONS
10692 assert(prev > 0);
133119 };
134120
135121 this.set_adjusted_ptr = function(adjustedPtr) {
136 var ptrSize = {{{ Runtime.POINTER_SIZE }}};
137 {{{ makeSetValue('this.ptr', 'ptrSize', 'adjustedPtr', '*') }}};
138 };
122 {{{ makeSetValue('this.ptr', Runtime.POINTER_SIZE, 'adjustedPtr', '*') }}};
123 };
124
125 this.get_adjusted_ptr_addr = function() {
126 return this.ptr + {{{ Runtime.POINTER_SIZE }}};
127 }
139128
140129 this.get_adjusted_ptr = function() {
141 var ptrSize = {{{ Runtime.POINTER_SIZE }}};
142 return {{{ makeGetValue('this.ptr', 'ptrSize', '*') }}};
130 return {{{ makeGetValue('this.ptr', Runtime.POINTER_SIZE, '*') }}};
143131 };
144132
145133 // Get pointer which is expected to be received by catch clause in C++ code. It may be adjusted
204192 },
205193
206194 // Exceptions
207 __cxa_allocate_exception__deps: ['$ExceptionInfoAttrs'],
208195 __cxa_allocate_exception__sig: 'vi',
209196 __cxa_allocate_exception: function(size) {
210197 // Thrown object is prepended by exception metadata block
211 return _malloc(size + ExceptionInfoAttrs.SIZE) + ExceptionInfoAttrs.SIZE;
198 return _malloc(size + {{{ C_STRUCTS.__cxa_exception.__size__ }}}) + {{{ C_STRUCTS.__cxa_exception.__size__ }}};
212199 },
213200
214201 __cxa_free_exception__deps: ['$ExceptionInfo'],
392379 var thrownType = info.get_type();
393380 var catchInfo = new CatchInfo();
394381 catchInfo.set_base_ptr(thrown);
382 catchInfo.set_adjusted_ptr(thrown);
395383 if (!thrownType) {
396384 // just pass through the thrown ptr
397385 {{{ makeStructuralReturn(['catchInfo.ptr', 0]) }}};
402390 #if EXCEPTION_DEBUG
403391 out("can_catch on " + [thrown]);
404392 #endif
405 var stackTop = stackSave();
406 var exceptionThrowBuf = stackAlloc(4);
407 {{{ makeSetValue('exceptionThrowBuf', '0', 'thrown', '*') }}};
408393 // The different catch blocks are denoted by different types.
409394 // Due to inheritance, those types may not precisely match the
410395 // type of the thrown object. Find one which matches, and
415400 // Catch all clause matched or exactly the same type is caught
416401 break;
417402 }
418 if ({{{ exportedAsmFunc('___cxa_can_catch') }}}(caughtType, thrownType, exceptionThrowBuf)) {
419 var adjusted = {{{ makeGetValue('exceptionThrowBuf', '0', '*') }}};
420 if (thrown !== adjusted) {
421 catchInfo.set_adjusted_ptr(adjusted);
422 }
423 #if EXCEPTION_DEBUG
424 out(" can_catch found " + [adjusted, caughtType]);
403 if ({{{ exportedAsmFunc('___cxa_can_catch') }}}(caughtType, thrownType, catchInfo.get_adjusted_ptr_addr())) {
404 #if EXCEPTION_DEBUG
405 out(" can_catch found " + [catchInfo.get_adjusted_ptr(), caughtType]);
425406 #endif
426407 {{{ makeStructuralReturn(['catchInfo.ptr', 'caughtType']) }}};
427408 }
428409 }
429 stackRestore(stackTop);
430410 {{{ makeStructuralReturn(['catchInfo.ptr', 'thrownType']) }}};
431411 },
432412
2828 '$Fetch',
2929 '$fetchXHR',
3030 '$callUserCallback',
31 'emscripten_is_main_browser_thread',
3231 #if !MINIMAL_RUNTIME
3332 '$runtimeKeepalivePush',
3433 '$runtimeKeepalivePop',
44 */
55
66 mergeInto(LibraryManager.library, {
7 $FS__deps: ['$getRandomDevice', '$PATH', '$PATH_FS', '$TTY', '$MEMFS',
7 $FS__deps: ['$getRandomDevice', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', '$asyncLoad',
88 #if LibraryManager.has('library_idbfs.js')
99 '$IDBFS',
1010 #endif
18751875 }
18761876 addRunDependency(dep);
18771877 if (typeof url == 'string') {
1878 Browser.asyncLoad(url, function(byteArray) {
1878 asyncLoad(url, function(byteArray) {
18791879 processData(byteArray);
18801880 }, onerror);
18811881 } else {
19921992 },
19931993 #endif
19941994 },
1995
1996 // Allocate memory for an mmap operation. This allocates space of the right
1997 // page-aligned size, and clears the padding.
1998 $mmapAlloc: function(size) {
1999 var alignedSize = alignMemory(size, {{{ WASM_PAGE_SIZE }}});
2000 var ptr = {{{ makeMalloc('mmapAlloc', 'alignedSize') }}};
2001 while (size < alignedSize) HEAP8[ptr + size++] = 0;
2002 return ptr;
2003 },
20041995 });
20051996
20061997 if (FORCE_FILESYSTEM) {
417417 },
418418
419419 glutIdleFunc__proxy: 'sync',
420 glutIdleFunc__deps: ['$safeSetTimeout'],
420421 glutIdleFunc__sig: 'vi',
421422 glutIdleFunc: function(func) {
422423 function callback() {
423424 if (GLUT.idleFunc) {
424425 {{{ makeDynCall('v', 'GLUT.idleFunc') }}}();
425 Browser.safeSetTimeout(callback, 4); // HTML spec specifies a 4ms minimum delay on the main thread; workers might get more, but we standardize here
426 safeSetTimeout(callback, 4); // HTML spec specifies a 4ms minimum delay on the main thread; workers might get more, but we standardize here
426427 }
427428 }
428429 if (!GLUT.idleFunc) {
429 Browser.safeSetTimeout(callback, 0);
430 safeSetTimeout(callback, 0);
430431 }
431432 GLUT.idleFunc = func;
432433 },
433434
434435 glutTimerFunc__proxy: 'sync',
436 glutTimerFunc__deps: ['$safeSetTimeout'],
435437 glutTimerFunc__sig: 'viii',
436438 glutTimerFunc: function(msec, func, value) {
437 Browser.safeSetTimeout(function() { {{{ makeDynCall('vi', 'func') }}}(value); }, msec);
439 safeSetTimeout(function() { {{{ makeDynCall('vi', 'func') }}}(value); }, msec);
438440 },
439441
440442 glutDisplayFunc__proxy: 'sync',
2626 "{{{ cDefine('O_TRUNC') }}}": flags["O_TRUNC"],
2727 "{{{ cDefine('O_WRONLY') }}}": flags["O_WRONLY"]
2828 };
29 },
30 bufferFrom: function (arrayBuffer) {
31 // Node.js < 4.5 compatibility: Buffer.from does not support ArrayBuffer
32 // Buffer.from before 4.5 was just a method inherited from Uint8Array
33 // Buffer.alloc has been added with Buffer.from together, so check it instead
34 return Buffer["alloc"] ? Buffer.from(arrayBuffer) : new Buffer(arrayBuffer);
3529 },
3630 convertNodeCode: function(e) {
3731 var code = e.code;
261255 // Node.js < 6 compatibility: node errors on 0 length reads
262256 if (length === 0) return 0;
263257 try {
264 return fs.readSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
258 return fs.readSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
265259 } catch (e) {
266260 throw new FS.ErrnoError(NODEFS.convertNodeCode(e));
267261 }
268262 },
269263 write: function (stream, buffer, offset, length, position) {
270264 try {
271 return fs.writeSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
265 return fs.writeSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
272266 } catch (e) {
273267 throw new FS.ErrnoError(NODEFS.convertNodeCode(e));
274268 }
9797 }
9898 var seeking = typeof position !== 'undefined';
9999 if (!seeking && stream.seekable) position = stream.position;
100 var bytesRead = fs.readSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
100 var bytesRead = fs.readSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
101101 // update position marker when non-seeking
102102 if (!seeking) stream.position += bytesRead;
103103 return bytesRead;
113113 }
114114 var seeking = typeof position !== 'undefined';
115115 if (!seeking && stream.seekable) position = stream.position;
116 var bytesWritten = fs.writeSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
116 var bytesWritten = fs.writeSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
117117 // update position marker when non-seeking
118118 if (!seeking) stream.position += bytesWritten;
119119 return bytesWritten;
169169 }
170170
171171 // Call into the musl function that runs destructors of all thread-specific data.
172 if (ENVIRONMENT_IS_PTHREAD && _pthread_self()) ___pthread_tsd_run_dtors();
172 #if ASSERTIONS
173 assert(_pthread_self())
174 #endif
175 ___pthread_tsd_run_dtors();
173176 },
174177
175178 runExitHandlersAndDeinitThread: function(tb, exitCode) {
657660 #endif
658661 return navigator['hardwareConcurrency'];
659662 },
660
663
664 {{{ USE_LSAN || USE_ASAN ? 'emscripten_builtin_' : '' }}}pthread_create__sig: 'iiiii',
661665 {{{ USE_LSAN || USE_ASAN ? 'emscripten_builtin_' : '' }}}pthread_create__deps: ['$spawnThread', 'pthread_self', 'memalign', 'emscripten_sync_run_in_main_thread_4'],
662666 {{{ USE_LSAN || USE_ASAN ? 'emscripten_builtin_' : '' }}}pthread_create: function(pthread_ptr, attr, start_routine, arg) {
663667 if (typeof SharedArrayBuffer === 'undefined') {
10541058 if (!ENVIRONMENT_IS_PTHREAD) _exit(status);
10551059 else PThread.threadExit(status);
10561060 // pthread_exit is marked noReturn, so we must not return from it.
1057 if (ENVIRONMENT_IS_NODE) {
1058 // exit the pthread properly on node, as a normal JS exception will halt
1059 // the entire application.
1060 process.exit(status);
1061 }
10621061 throw 'unwind';
10631062 },
10641063
1065 pthread_cleanup_push__sig: 'vii',
1066 pthread_cleanup_push: function(routine, arg) {
1067 PThread.threadExitHandlers.push(function() { {{{ makeDynCall('vi', 'routine') }}}(arg) });
1068 },
1069
1070 pthread_cleanup_pop: function(execute) {
1071 var routine = PThread.threadExitHandlers.pop();
1072 if (execute) routine();
1073 },
1064 __cxa_thread_atexit__sig: 'vii',
1065 __cxa_thread_atexit: function(routine, arg) {
1066 PThread.threadExitHandlers.push(function() { {{{ makeDynCall('vi', 'routine') }}}(arg) });
1067 },
1068 __cxa_thread_atexit_impl: '__cxa_thread_atexit',
1069
10741070
10751071 // Returns 0 on success, or one of the values -ETIMEDOUT, -EWOULDBLOCK or -EINVAL on error.
10761072 emscripten_futex_wait__deps: ['emscripten_main_thread_process_queued_calls'],
1616 #endif
1717 },
1818
19 pthread_cleanup_push__sig: 'vii',
20 pthread_cleanup_push: function(routine, arg) {
21 __ATEXIT__.push({ func: routine, arg: arg });
22 _pthread_cleanup_push.level = __ATEXIT__.length;
23 },
24
25 pthread_cleanup_pop__deps: ['pthread_cleanup_push'],
26 pthread_cleanup_pop__sig: 'vi',
27 pthread_cleanup_pop: function(execute) {
28 assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!');
29 var callback = __ATEXIT__.pop();
30 if (execute) {
31 {{{ makeDynCall('vi', 'callback.func') }}}(callback.arg)
32 }
33 _pthread_cleanup_push.level = __ATEXIT__.length;
34 },
35
3619 // When pthreads is not enabled, we can't use the Atomics futex api to do
3720 // proper sleeps, so simulate a busy spin wait loop instead.
3821 emscripten_thread_sleep__deps: ['emscripten_get_now'],
4225 // Do nothing.
4326 }
4427 },
28
29 __cxa_thread_atexit: 'atexit',
30 __cxa_thread_atexit_impl: 'atexit',
4531 };
4632
4733 mergeInto(LibraryManager.library, LibraryPThreadStub);
13471347 return SDL.version;
13481348 },
13491349
1350 SDL_Init__deps: ['$zeroMemory'],
13501351 SDL_Init__proxy: 'sync',
13511352 SDL_Init__sig: 'ii',
13521353 SDL_Init__docs: '/** @param{number=} initFlags */',
13671368
13681369 window.addEventListener("unload", SDL.receiveEvent);
13691370 SDL.keyboardState = _malloc(0x10000); // Our SDL needs 512, but 64K is safe for older SDLs
1370 _memset(SDL.keyboardState, 0, 0x10000);
1371 zeroMemory(SDL.keyboardState, 0x10000);
13711372 // Initialize this structure carefully for closure
13721373 SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */;
13731374 SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */;
24132414
24142415 // SDL_Audio
24152416
2416 SDL_OpenAudio__deps: ['$autoResumeAudioContext'],
2417 SDL_OpenAudio__deps: ['$autoResumeAudioContext', '$safeSetTimeout'],
24172418 SDL_OpenAudio__proxy: 'sync',
24182419 SDL_OpenAudio__sig: 'iii',
24192420 SDL_OpenAudio: function(desired, obtained) {
25352536
25362537 if (SDL.audio.numAudioTimersPending < SDL.audio.numSimultaneouslyQueuedBuffers) {
25372538 ++SDL.audio.numAudioTimersPending;
2538 SDL.audio.timer = Browser.safeSetTimeout(SDL.audio.caller, Math.max(0.0, 1000.0*(secsUntilNextPlayStart-preemptBufferFeedSecs)));
2539 SDL.audio.timer = safeSetTimeout(SDL.audio.caller, Math.max(0.0, 1000.0*(secsUntilNextPlayStart-preemptBufferFeedSecs)));
25392540
25402541 // If we are risking starving, immediately queue an extra buffer.
25412542 if (SDL.audio.numAudioTimersPending < SDL.audio.numSimultaneouslyQueuedBuffers) {
25422543 ++SDL.audio.numAudioTimersPending;
2543 Browser.safeSetTimeout(SDL.audio.caller, 1.0);
2544 safeSetTimeout(SDL.audio.caller, 1.0);
25442545 }
25452546 }
25462547 };
26372638 },
26382639
26392640 SDL_PauseAudio__proxy: 'sync',
2641 SDL_PauseAudio__deps: ['$safeSetTimeout'],
26402642 SDL_PauseAudio__sig: 'vi',
26412643 SDL_PauseAudio: function(pauseOn) {
26422644 if (!SDL.audio) {
26512653 } else if (!SDL.audio.timer) {
26522654 // Start the audio playback timer callback loop.
26532655 SDL.audio.numAudioTimersPending = 1;
2654 SDL.audio.timer = Browser.safeSetTimeout(SDL.audio.caller, 1);
2656 SDL.audio.timer = safeSetTimeout(SDL.audio.caller, 1);
26552657 }
26562658 SDL.audio.paused = pauseOn;
26572659 },
44 */
55
66 // 'use strict'
7 var funs = {
7 var LibrarySignals = {
88 _sigalrm_handler: 0,
99
10 signal__deps: ['_sigalrm_handler'],
11 signal: function(sig, func) {
10 __sigaction__deps: ['_sigalrm_handler'],
11 __sigaction: function(sig, act, oldact) {
12 //int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
1213 if (sig == {{{ cDefine('SIGALRM') }}}) {
13 __sigalrm_handler = func;
14 } else {
14 __sigalrm_handler = {{{ makeGetValue('act', '0', 'i32') }}};
15 return 0;
16 }
1517 #if ASSERTIONS
16 err('Calling stub instead of signal()');
17 #endif
18 }
19 return 0;
20 },
21 bsd_signal__sig: 'iii',
22 bsd_signal: 'signal',
23 sigemptyset: function(set) {
24 {{{ makeSetValue('set', '0', '0', 'i32') }}};
25 return 0;
26 },
27 sigfillset: function(set) {
28 {{{ makeSetValue('set', '0', '-1>>>0', 'i32') }}};
29 return 0;
30 },
31 sigaddset: function(set, signum) {
32 {{{ makeSetValue('set', '0', makeGetValue('set', '0', 'i32') + '| (1 << (signum-1))', 'i32') }}};
33 return 0;
34 },
35 sigdelset: function(set, signum) {
36 {{{ makeSetValue('set', '0', makeGetValue('set', '0', 'i32') + '& (~(1 << (signum-1)))', 'i32') }}};
37 return 0;
38 },
39 sigismember: function(set, signum) {
40 return {{{ makeGetValue('set', '0', 'i32') }}} & (1 << (signum-1));
41 },
42 sigaction: function(signum, act, oldact) {
43 //int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
44 #if ASSERTIONS
45 err('Calling stub instead of sigaction()');
18 err('sigaction: signal type not supported: this is a no-op.');
4619 #endif
4720 return 0;
4821 },
49 sigprocmask: function() {
50 #if ASSERTIONS
51 err('Calling stub instead of sigprocmask()');
52 #endif
53 return 0;
54 },
22 sigaction__sig: 'viii',
23 sigaction: '__sigaction',
24
5525 // pthread_sigmask - examine and change mask of blocked signals
5626 pthread_sigmask: function(how, set, oldset) {
5727 err('pthread_sigmask() is not supported: this is a no-op.');
5828 return 0;
5929 },
60 __libc_current_sigrtmin: function() {
61 #if ASSERTIONS
62 err('Calling stub instead of __libc_current_sigrtmin');
63 #endif
64 return 0;
65 },
66 __libc_current_sigrtmax: function() {
67 #if ASSERTIONS
68 err('Calling stub instead of __libc_current_sigrtmax');
69 #endif
70 return 0;
71 },
30
7231 kill__deps: ['$ERRNO_CODES', '$setErrNo'],
7332 kill: function(pid, sig) {
7433 // http://pubs.opengroup.org/onlinepubs/000095399/functions/kill.html
7534 // Makes no sense in a single-process environment.
76 // Should kill itself somtimes depending on `pid`
35 // Should kill itself somtimes depending on `pid`
7736 #if ASSERTIONS
7837 err('Calling stub instead of kill()');
7938 #endif
8140 return -1;
8241 },
8342
84 killpg__deps: ['$ERRNO_CODES', '$setErrNo'],
85 killpg: function() {
86 #if ASSERTIONS
87 err('Calling stub instead of killpg()');
88 #endif
89 setErrNo(ERRNO_CODES.EPERM);
90 return -1;
91 },
9243 siginterrupt: function() {
9344 #if ASSERTIONS
9445 err('Calling stub instead of siginterrupt()');
10152 #if ASSERTIONS
10253 err('Calling stub instead of raise()');
10354 #endif
104 setErrNo(ERRNO_CODES.ENOSYS);
105 #if ASSERTIONS
106 warnOnce('raise() returning an error as we do not support it');
107 #endif
55 setErrNo(ERRNO_CODES.ENOSYS);
10856 return -1;
10957 },
11058
11563 if (__sigalrm_handler) {{{ makeDynCall('vi', '__sigalrm_handler') }}}(0);
11664 }, seconds*1000);
11765 },
118 ualarm: function() {
119 throw 'ualarm() is not implemented yet';
120 },
121 setitimer: function() {
122 throw 'setitimer() is not implemented yet';
123 },
124 getitimer: function() {
125 throw 'getitimer() is not implemented yet';
126 },
127
128 pause__deps: ['$setErrNo', '$ERRNO_CODES'],
129 pause: function() {
130 // int pause(void);
131 // http://pubs.opengroup.org/onlinepubs/000095399/functions/pause.html
132 // We don't support signals, so we return immediately.
133 #if ASSERTIONS
134 err('Calling stub instead of pause()');
135 #endif
136 setErrNo(ERRNO_CODES.EINTR);
137 return -1;
138 },
13966
14067 sigpending: function(set) {
14168 {{{ makeSetValue('set', 0, 0, 'i32') }}};
14269 return 0;
14370 },
14471
145 sigwait: function(set, sig) {
72 //int sigtimedwait(const sigset_t *restrict mask, siginfo_t *restrict si, const struct timespec *restrict timeout)
73 sigtimedwait: function(set, sig, timeout) {
14674 // POSIX SIGNALS are not supported
14775 // if set contains an invalid signal number, EINVAL is returned
14876 // in our case we return EINVAL all the time
15179 #endif
15280 return {{{ cDefine('EINVAL') }}};
15381 }
154
155 //signalfd
156 //ppoll
157 //epoll_pwait
158 //pselect
159 //sigvec
160 //sigmask
161 //sigblock
162 //sigsetmask
163 //siggetmask
164 //sigsuspend
165 //siginterrupt
166 //sigqueue
167 //sysv_signal
168 //signal
169 //pthread_kill
170 //gsignal
171 //ssignal
172 //psignal
173 //psiginfo
174 //sigpause
175 //sigisemptyset
176 //sigtimedwait
177 //sigwaitinfo
178 //sigreturn
179 //sigstack
180 //sigaltstack(2)
181 //sigsetops(3),
182 //sighold
183 //sigrelse
184 //sigignore
185 //sigset
18682 };
18783
188 mergeInto(LibraryManager.library, funs);
84 mergeInto(LibraryManager.library, LibrarySignals);
225225 }
226226 },
227227
228 $syscallMmap2__deps: ['$SYSCALLS',
228 $syscallMmap2__deps: ['$SYSCALLS', '$zeroMemory', '$mmapAlloc',
229229 #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM
230230 '$FS',
231231 #endif
244244 // but it is widely used way to allocate memory pages on Linux, BSD and Mac.
245245 // In this case fd argument is ignored.
246246 if ((flags & {{{ cDefine('MAP_ANONYMOUS') }}}) !== 0) {
247 ptr = _memalign({{{ WASM_PAGE_SIZE }}}, len);
247 ptr = mmapAlloc(len);
248248 if (!ptr) return -{{{ cDefine('ENOMEM') }}};
249 _memset(ptr, 0, len);
250249 allocated = true;
251250 } else {
252251 #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM
275274 #if CAN_ADDRESS_2GB
276275 addr >>>= 0;
277276 #endif
278 if ((addr | 0) === {{{ cDefine('MAP_FAILED') }}} || len === 0) {
279 return -{{{ cDefine('EINVAL') }}};
280 }
281277 // TODO: support unmmap'ing parts of allocations
282278 var info = SYSCALLS.mappings[addr];
283 if (!info) return 0;
279 if (len === 0 || !info) {
280 return -{{{ cDefine('EINVAL') }}};
281 }
284282 if (len === info.len) {
285283 #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM
286284 var stream = FS.getStream(info.fd);
304302 return 0;
305303 },
306304
307 __sys_exit: function(status) {
308 exit(status);
309 // no return
310 },
311305 __sys_open: function(path, flags, varargs) {
312306 var pathname = SYSCALLS.getStr(path);
313307 var mode = varargs ? SYSCALLS.get() : 0;
393387 {{{ makeSetValue('fdPtr', 4, 'res.writable_fd', 'i32') }}};
394388
395389 return 0;
396 },
397 __sys_acct__nothrow: true,
398 __sys_acct__proxy: false,
399 __sys_acct: function(filename) {
400 return -{{{ cDefine('ENOSYS') }}}; // unsupported features
401390 },
402391 __sys_ioctl: function(fd, op, varargs) {
403392 #if SYSCALLS_REQUIRE_FILESYSTEM == 0
493482 __sys_setrlimit: function(varargs) {
494483 return 0; // no-op
495484 },
485 __sys_getrusage__deps: ['$zeroMemory'],
496486 __sys_getrusage: function(who, usage) {
497 #if SYSCALL_DEBUG
498 err('warning: untested syscall');
499 #endif
500 _memset(usage, 0, {{{ C_STRUCTS.rusage.__size__ }}});
487 zeroMemory(usage, {{{ C_STRUCTS.rusage.__size__ }}});
501488 {{{ makeSetValue('usage', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}}; // fake some values
502489 {{{ makeSetValue('usage', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}};
503490 {{{ makeSetValue('usage', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}};
572559 assert(!errno);
573560 #endif
574561 return 0;
575 },
576 __sys_socketpair: function() {
577 #if SYSCALL_DEBUG
578 err('unsupported syscall: __sys_socketpair');
579 #endif
580 return -{{{ cDefine('ENOSYS') }}};
581562 },
582563 __sys_setsockopt: function(fd) {
583564 return -{{{ cDefine('ENOPROTOOPT') }}}; // The option is unknown at the level indicated.
762743 return bytesRead;
763744 },
764745 #endif // ~PROXY_POSIX_SOCKETS==0
765 __sys_setitimer__nothrow: true,
766 __sys_setitimer__proxy: false,
767 __sys_setitimer: function(which, new_value, old_value) {
768 return -{{{ cDefine('ENOSYS') }}}; // unsupported feature
769 },
770 __sys_wait4__proxy: false,
771 __sys_wait4: function(pid, wstart, options, rusage) {
772 return -{{{ cDefine('ENOSYS') }}}; // unsupported feature
773 },
774746 __sys_setdomainname__nothrow: true,
775747 __sys_setdomainname__proxy: false,
776748 __sys_setdomainname: function(name, size) {
798770 #endif
799771 return 0;
800772 },
801 __sys_mprotect__nothrow: true,
802 __sys_mprotect__proxy: false,
803773 __sys_mprotect: function(addr, len, size) {
804774 return 0; // let's not and say we did
805775 },
914884 var stream = SYSCALLS.getStreamFromFD(fd);
915885 return 0; // we can't do anything synchronously; the in-memory FS is already synced to
916886 },
917 __sys_mlock__nothrow: true,
918 __sys_mlock__proxy: false,
919887 __sys_mlock__sig: 'iii',
920888 __sys_mlock: function(addr, len) {
921889 return 0;
922890 },
923 __sys_munlock__nothrow: true,
924 __sys_munlock__proxy: false,
925891 __sys_munlock__sig: 'iii',
926892 __sys_munlock: function(addr, len) {
927893 return 0;
928894 },
929 __sys_mlockall__nothrow: true,
930 __sys_mlockall__proxy: false,
931895 __sys_mlockall__sig: 'ii',
932896 __sys_mlockall: function(flags) {
933897 return 0;
934898 },
935 __sys_munlockall__nothrow: true,
936 __sys_munlockall__proxy: false,
937899 __sys_munlockall__sig: 'i',
938900 __sys_munlockall: function() {
939901 return 0;
940902 },
941 __sys_mremap__nothrow: true,
942 __sys_mremap__proxy: false,
943903 __sys_mremap: function(old_addr, old_size, new_size, flags) {
944904 return -{{{ cDefine('ENOMEM') }}}; // never succeed
945905 },
963923 }
964924 return nonzero;
965925 },
966 __sys_rt_sigqueueinfo__nothrow: true,
967 __sys_rt_sigqueueinfo__proxy: false,
968926 __sys_rt_sigqueueinfo: function(tgid, pid, uinfo) {
969 #if SYSCALL_DEBUG
970 err('warning: ignoring SYS_rt_sigqueueinfo');
971 #endif
972927 return 0;
973928 },
974929
981936 return buf;
982937 },
983938 __sys_ugetrlimit: function(resource, rlim) {
984 #if SYSCALL_DEBUG
985 err('warning: untested syscall');
986 #endif
987939 {{{ makeSetValue('rlim', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}}; // RLIM_INFINITY
988940 {{{ makeSetValue('rlim', C_STRUCTS.rlimit.rlim_cur + 4, '-1', 'i32') }}}; // RLIM_INFINITY
989941 {{{ makeSetValue('rlim', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}}; // RLIM_INFINITY
10911043 __sys_getresuid32__nothrow: true,
10921044 __sys_getresuid32__proxy: false,
10931045 __sys_getresuid32: '__sys_getresgid32',
1094 __sys_getresgid32__nothrow: true,
1095 __sys_getresgid32__proxy: false,
10961046 __sys_getresgid32: function(ruid, euid, suid) {
1097 #if SYSCALL_DEBUG
1098 err('warning: untested syscall');
1099 #endif
11001047 {{{ makeSetValue('ruid', '0', '0', 'i32') }}};
11011048 {{{ makeSetValue('euid', '0', '0', 'i32') }}};
11021049 {{{ makeSetValue('suid', '0', '0', 'i32') }}};
11031050 return 0;
11041051 },
1105 __sys_mincore__nothrow: true,
1106 __sys_mincore__proxy: false,
1107 __sys_mincore: function(addr, length, vec) {
1108 return -{{{ cDefine('ENOSYS') }}}; // unsupported feature
1109 },
1110 __sys_madvise1__nothrow: true,
1111 __sys_madvise1__proxy: false,
11121052 __sys_madvise1: function(addr, length, advice) {
1113 return 0; // advice is welcome, but ignored
1053 // advice is welcome, but ignored
1054 return 0;
11141055 },
11151056 __sys_getdents64: function(fd, dirp, count) {
11161057 var stream = SYSCALLS.getStreamFromFD(fd)
12121153 #endif // SYSCALLS_REQUIRE_FILESYSTEM
12131154 },
12141155
1215 #if MINIMAL_RUNTIME
1216 __sys_exit_group__deps: ['$exit'],
1217 #endif
1218 __sys_exit_group: function(status) {
1219 exit(status);
1220 return 0;
1221 },
12221156 __sys_statfs64: function(path, size, buf) {
12231157 path = SYSCALLS.getStr(path);
12241158 #if ASSERTIONS
13591293 path = SYSCALLS.calculateAt(dirfd, path);
13601294 return SYSCALLS.doAccess(path, amode);
13611295 },
1362 __sys_pselect6__nothrow: true,
1363 __sys_pselect6__proxy: false,
1364 __sys_pselect6: function() {
1365 return -{{{ cDefine('ENOSYS') }}}; // unsupported feature
1366 },
13671296 __sys_utimensat: function(dirfd, path, times, flags) {
1368 #if SYSCALL_DEBUG
1369 err('warning: untested syscall');
1370 #endif
13711297 path = SYSCALLS.getStr(path);
13721298 #if ASSERTIONS
13731299 assert(flags === 0);
13811307 nanoseconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
13821308 var mtime = (seconds*1000) + (nanoseconds/(1000*1000));
13831309 FS.utime(path, atime, mtime);
1384 return 0;
1310 return 0;
13851311 },
13861312 __sys_fallocate: function(fd, mode, off_low, off_high, len_low, len_high) {
13871313 var stream = SYSCALLS.getStreamFromFD(fd)
13951321 },
13961322 __sys_dup3: function(fd, suggestFD, flags) {
13971323 #if SYSCALL_DEBUG
1398 err('warning: untested syscall');
1324 err('warning: untested syscall: dup3');
13991325 #endif
14001326 var old = SYSCALLS.getStreamFromFD(fd);
14011327 #if ASSERTIONS
14041330 if (old.fd === suggestFD) return -{{{ cDefine('EINVAL') }}};
14051331 return SYSCALLS.doDup(old.path, old.flags, suggestFD);
14061332 },
1407 __sys_pipe2__nothrow: true,
1408 __sys_pipe2__proxy: false,
1409 __sys_pipe2: function(fds, flags) {
1410 return -{{{ cDefine('ENOSYS') }}}; // unsupported feature
1411 },
1412
1413 __sys_recvmmsg__nothrow: true,
1414 __sys_recvmmsg__proxy: false,
1415 __sys_recvmmsg: function(sockfd, msgvec, vlen, flags) {
1416 #if SYSCALL_DEBUG
1417 err('warning: ignoring SYS_recvmmsg');
1418 #endif
1419 return 0;
1420 },
1333
14211334 __sys_prlimit64: function(pid, resource, new_limit, old_limit) {
14221335 if (old_limit) { // just report no limits
14231336 {{{ makeSetValue('old_limit', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}}; // RLIM_INFINITY
14251338 {{{ makeSetValue('old_limit', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}}; // RLIM_INFINITY
14261339 {{{ makeSetValue('old_limit', C_STRUCTS.rlimit.rlim_max + 4, '-1', 'i32') }}}; // RLIM_INFINITY
14271340 }
1428 return 0;
1429 },
1430 __sys_sendmmsg__nothrow: true,
1431 __sys_sendmmsg__proxy: false,
1432 __sys_sendmmsg: function(sockfd, msg, flags) {
1433 #if SYSCALL_DEBUG
1434 err('warning: ignoring SYS_sendmmsg');
1435 #endif
14361341 return 0;
14371342 },
14381343 };
15411446 wrapSyscallFunction(x, SyscallsLibrary, false);
15421447 }
15431448
1449 function unimplementedSycall(name) {
1450 SyscallsLibrary[name + '__nothrow'] = true;
1451 SyscallsLibrary[name + '__proxy'] = false;
1452 SyscallsLibrary[name + '__unimplemented'] = true;
1453 msg = `\n err('warning: unsupported syscall: ${name}');`;
1454 if (SyscallsLibrary[name]) {
1455 SyscallsLibrary[name] = modifyFunction(SyscallsLibrary[name].toString(), (name, args, body) => {
1456 return `function(${args}) {\n ${msg}${body}\n}\n`;
1457 });
1458 } else {
1459 errcode = cDefine('ENOSYS');
1460 SyscallsLibrary[name] = `function() {\n ${msg}return -${errcode};\n}`;
1461 }
1462 }
1463
1464 [
1465 '__sys_acct',
1466 '__sys_getresgid32',
1467 '__sys_getrusage',
1468 '__sys_madvise1',
1469 '__sys_mincore',
1470 '__sys_mlock',
1471 '__sys_mlockall',
1472 '__sys_mprotect',
1473 '__sys_mremap',
1474 '__sys_munlock',
1475 '__sys_munlockall',
1476 '__sys_pipe2',
1477 '__sys_prlimit64',
1478 '__sys_pselect6',
1479 '__sys_recvmmsg',
1480 '__sys_rt_sigqueueinfo',
1481 '__sys_sendmmsg',
1482 '__sys_setitimer',
1483 '__sys_getitimer',
1484 '__sys_shutdown',
1485 '__sys_socketpair',
1486 '__sys_setsockopt',
1487 '__sys_ugetrlimit',
1488 '__sys_wait4',
1489 '__sys_pause',
1490 ].forEach(unimplementedSycall);
1491
15441492 mergeInto(LibraryManager.library, SyscallsLibrary);
107107 if (ENVIRONMENT_IS_NODE) {
108108 // we will read data by chunks of BUFSIZE
109109 var BUFSIZE = 256;
110 var buf = Buffer.alloc ? Buffer.alloc(BUFSIZE) : new Buffer(BUFSIZE);
110 var buf = Buffer.alloc(BUFSIZE);
111111 var bytesRead = 0;
112112
113113 try {
77
88 mergeInto(LibraryManager.library, {
99 // Clear a 'compact' UUID.
10 uuid_clear__deps: ['$zeroMemory'],
1011 uuid_clear: function(uu) {
1112 // void uuid_clear(uuid_t uu);
12 _memset(uu, 0, 16);
13 zeroMemory(uu, 16);
1314 },
1415
1516 // Compare whether or not two 'compact' UUIDs are the same.
0 /**
1 * @license
2 * Copyright 2011 The Emscripten Authors
3 * SPDX-License-Identifier: MIT
4 */
5
6 var LibraryWget = {
7 $wget: {
8 wgetRequests: {},
9 nextWgetRequestHandle: 0,
10
11 getNextWgetRequestHandle: function() {
12 var handle = wget.nextWgetRequestHandle;
13 wget.nextWgetRequestHandle++;
14 return handle;
15 },
16 },
17
18 emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser',
19 #if !MINIMAL_RUNTIME
20 '$runtimeKeepalivePush', '$runtimeKeepalivePop',
21 #endif
22 ],
23 emscripten_async_wget__proxy: 'sync',
24 emscripten_async_wget__sig: 'viiii',
25 emscripten_async_wget: function(url, file, onload, onerror) {
26 {{{ runtimeKeepalivePush() }}}
27
28 var _url = UTF8ToString(url);
29 var _file = UTF8ToString(file);
30 _file = PATH_FS.resolve(_file);
31 function doCallback(callback) {
32 if (callback) {
33 {{{ runtimeKeepalivePop() }}}
34 callUserCallback(function() {
35 var stack = stackSave();
36 {{{ makeDynCall('vi', 'callback') }}}(allocate(intArrayFromString(_file), ALLOC_STACK));
37 stackRestore(stack);
38 });
39 }
40 }
41 var destinationDirectory = PATH.dirname(_file);
42 FS.createPreloadedFile(
43 destinationDirectory,
44 PATH.basename(_file),
45 _url, true, true,
46 function() {
47 doCallback(onload);
48 },
49 function() {
50 doCallback(onerror);
51 },
52 false, // dontCreateFile
53 false, // canOwn
54 function() { // preFinish
55 // if a file exists there, we overwrite it
56 try {
57 FS.unlink(_file);
58 } catch (e) {}
59 // if the destination directory does not yet exist, create it
60 FS.mkdirTree(destinationDirectory);
61 }
62 );
63 },
64
65 emscripten_async_wget_data__deps: ['$asyncLoad', 'malloc', 'free', '$callUserCallback',
66 #if !MINIMAL_RUNTIME
67 '$runtimeKeepalivePush', '$runtimeKeepalivePop',
68 #endif
69 ],
70 emscripten_async_wget_data__proxy: 'sync',
71 emscripten_async_wget_data__sig: 'viiii',
72 emscripten_async_wget_data: function(url, arg, onload, onerror) {
73 {{{ runtimeKeepalivePush() }}}
74 asyncLoad(UTF8ToString(url), function(byteArray) {
75 {{{ runtimeKeepalivePop() }}}
76 callUserCallback(function() {
77 var buffer = _malloc(byteArray.length);
78 HEAPU8.set(byteArray, buffer);
79 {{{ makeDynCall('viii', 'onload') }}}(arg, buffer, byteArray.length);
80 _free(buffer);
81 });
82 }, function() {
83 if (onerror) {
84 {{{ runtimeKeepalivePop() }}}
85 callUserCallback(function() {
86 {{{ makeDynCall('vi', 'onerror') }}}(arg);
87 });
88 }
89 }, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
90 },
91
92 emscripten_async_wget2__deps: ['$PATH_FS', '$wget',
93 #if !MINIMAL_RUNTIME
94 '$runtimeKeepalivePush', '$runtimeKeepalivePop',
95 #endif
96 ],
97 emscripten_async_wget2__proxy: 'sync',
98 emscripten_async_wget2__sig: 'iiiiiiiii',
99 emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) {
100 {{{ runtimeKeepalivePush() }}}
101
102 var _url = UTF8ToString(url);
103 var _file = UTF8ToString(file);
104 _file = PATH_FS.resolve(_file);
105 var _request = UTF8ToString(request);
106 var _param = UTF8ToString(param);
107 var index = _file.lastIndexOf('/');
108
109 var http = new XMLHttpRequest();
110 http.open(_request, _url, true);
111 http.responseType = 'arraybuffer';
112
113 var handle = wget.getNextWgetRequestHandle();
114
115 var destinationDirectory = PATH.dirname(_file);
116
117 // LOAD
118 http.onload = function http_onload(e) {
119 {{{ runtimeKeepalivePop() }}}
120 if (http.status >= 200 && http.status < 300) {
121 // if a file exists there, we overwrite it
122 try {
123 FS.unlink(_file);
124 } catch (e) {}
125 // if the destination directory does not yet exist, create it
126 FS.mkdirTree(destinationDirectory);
127
128 FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(/** @type{ArrayBuffer}*/(http.response)), true, true, false);
129 if (onload) {
130 var stack = stackSave();
131 {{{ makeDynCall('viii', 'onload') }}}(handle, arg, allocate(intArrayFromString(_file), ALLOC_STACK));
132 stackRestore(stack);
133 }
134 } else {
135 if (onerror) {{{ makeDynCall('viii', 'onerror') }}}(handle, arg, http.status);
136 }
137
138 delete wget.wgetRequests[handle];
139 };
140
141 // ERROR
142 http.onerror = function http_onerror(e) {
143 {{{ runtimeKeepalivePop() }}}
144 if (onerror) {{{ makeDynCall('viii', 'onerror') }}}(handle, arg, http.status);
145 delete wget.wgetRequests[handle];
146 };
147
148 // PROGRESS
149 http.onprogress = function http_onprogress(e) {
150 if (e.lengthComputable || (e.lengthComputable === undefined && e.total != 0)) {
151 var percentComplete = (e.loaded / e.total)*100;
152 if (onprogress) {{{ makeDynCall('viii', 'onprogress') }}}(handle, arg, percentComplete);
153 }
154 };
155
156 // ABORT
157 http.onabort = function http_onabort(e) {
158 {{{ runtimeKeepalivePop() }}}
159 delete wget.wgetRequests[handle];
160 };
161
162 if (_request == "POST") {
163 //Send the proper header information along with the request
164 http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
165 http.send(_param);
166 } else {
167 http.send(null);
168 }
169
170 wget.wgetRequests[handle] = http;
171
172 return handle;
173 },
174
175 emscripten_async_wget2_data__deps: ['$wget', 'malloc', 'free'],
176 emscripten_async_wget2_data__proxy: 'sync',
177 emscripten_async_wget2_data__sig: 'iiiiiiiii',
178 emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) {
179 var _url = UTF8ToString(url);
180 var _request = UTF8ToString(request);
181 var _param = UTF8ToString(param);
182
183 var http = new XMLHttpRequest();
184 http.open(_request, _url, true);
185 http.responseType = 'arraybuffer';
186
187 var handle = wget.getNextWgetRequestHandle();
188
189 function onerrorjs() {
190 if (onerror) {
191 var statusText = 0;
192 if (http.statusText) {
193 var len = lengthBytesUTF8(http.statusText) + 1;
194 statusText = stackAlloc(len);
195 stringToUTF8(http.statusText, statusText, len);
196 }
197 {{{ makeDynCall('viiii', 'onerror') }}}(handle, arg, http.status, statusText);
198 }
199 }
200
201 // LOAD
202 http.onload = function http_onload(e) {
203 if (http.status >= 200 && http.status < 300 || (http.status === 0 && _url.substr(0,4).toLowerCase() != "http")) {
204 var byteArray = new Uint8Array(/** @type{ArrayBuffer} */(http.response));
205 var buffer = _malloc(byteArray.length);
206 HEAPU8.set(byteArray, buffer);
207 if (onload) {{{ makeDynCall('viiii', 'onload') }}}(handle, arg, buffer, byteArray.length);
208 if (free) _free(buffer);
209 } else {
210 onerrorjs();
211 }
212 delete wget.wgetRequests[handle];
213 };
214
215 // ERROR
216 http.onerror = function http_onerror(e) {
217 onerrorjs();
218 delete wget.wgetRequests[handle];
219 };
220
221 // PROGRESS
222 http.onprogress = function http_onprogress(e) {
223 if (onprogress) {{{ makeDynCall('viiii', 'onprogress') }}}(handle, arg, e.loaded, e.lengthComputable || e.lengthComputable === undefined ? e.total : 0);
224 };
225
226 // ABORT
227 http.onabort = function http_onabort(e) {
228 delete wget.wgetRequests[handle];
229 };
230
231 if (_request == "POST") {
232 //Send the proper header information along with the request
233 http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
234 http.send(_param);
235 } else {
236 http.send(null);
237 }
238
239 wget.wgetRequests[handle] = http;
240
241 return handle;
242 },
243
244 emscripten_async_wget2_abort__deps: ['$wget'],
245 emscripten_async_wget2_abort__proxy: 'sync',
246 emscripten_async_wget2_abort__sig: 'vi',
247 emscripten_async_wget2_abort: function(handle) {
248 var http = wget.wgetRequests[handle];
249 if (http) {
250 http.abort();
251 }
252 },
253 };
254
255 mergeInto(LibraryManager.library, LibraryWget);
8585 libraries.push('library_strings.js');
8686 } else {
8787 libraries.push('library_browser.js');
88 libraries.push('library_wget.js');
8889 }
8990
9091 if (USE_PTHREADS) { // TODO: Currently WebGL proxying makes pthreads library depend on WebGL.
415416 'setTempRet0',
416417 'callMain',
417418 'abort',
419 'keepRuntimeAlive',
418420 ];
419421
420422 if (USE_OFFSET_CONVERTER) {
2424 assert(ret.buffer);
2525 return ret;
2626 };
27
28 readAsync = function readAsync(filename, onload, onerror) {
29 #if SUPPORT_BASE64_EMBEDDING
30 var ret = tryParseAsDataURI(filename);
31 if (ret) {
32 onload(ret);
33 }
34 #endif
35 if (!nodeFS) nodeFS = require('fs');
36 if (!nodePath) nodePath = require('path');
37 filename = nodePath['normalize'](filename);
38 nodeFS['readFile'](filename, function(err, data) {
39 if (err) onerror(err);
40 else onload(data.buffer);
41 });
42 };
189189 assert(ret == 0, '_emscripten_proxy_main failed to start proxy thread: ' + ret);
190190 #endif
191191 #else
192 #if ASYNCIFY
193 // if we are saving the stack, then do not call exit, we are not
194 // really exiting now, just unwinding the JS stack
195 if (!keepRuntimeAlive()) {
196 #endif // ASYNCIFY
197 // if we're not running an evented main loop, it's time to exit
198 exit(ret, /* implicit = */ true);
199 #if ASYNCIFY
200 }
201 #endif // ASYNCIFY
202 }
203 catch(e) {
204 if (e instanceof ExitStatus) {
205 // exit() throws this once it's done to make sure execution
206 // has been stopped completely
192 // if we're not running an evented main loop, it's time to exit
193 exit(ret, /* implicit = */ true);
194 }
195 catch (e) {
196 // Certain exception types we do not treat as errors since they are used for
197 // internal control flow.
198 // 1. ExitStatus, which is thrown by exit()
199 // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others
200 // that wish to return to JS event loop.
201 if (e instanceof ExitStatus || e == 'unwind') {
207202 return;
208 } else if (e == 'unwind') {
209 // running an evented main loop, don't immediately exit
210 return;
211 } else {
212 var toLog = e;
213 if (e && typeof e === 'object' && e.stack) {
214 toLog = [e, e.stack];
215 }
216 err('exception thrown: ' + toLog);
217 quit_(1, e);
218 }
203 }
204 // Anything else is an unexpected exception and we treat it as hard error.
205 var toLog = e;
206 if (e && typeof e === 'object' && e.stack) {
207 toLog = [e, e.stack];
208 }
209 err('exception thrown: ' + toLog);
210 quit_(1, e);
219211 #endif // !PROXY_TO_PTHREAD
220212 } finally {
221213 calledMain = true;
424416 #endif // EXIT_RUNTIME
425417 #endif // ASSERTIONS
426418
427 // if this is just main exit-ing implicitly, and the status is 0, then we
428 // don't need to do anything here and can just leave. if the status is
429 // non-zero, though, then we need to report it.
430 // (we may have warned about this earlier, if a situation justifies doing so)
431 if (implicit && keepRuntimeAlive() && status === 0) {
432 return;
433 }
434
435419 #if USE_PTHREADS
436420 if (!implicit) {
437421 if (ENVIRONMENT_IS_PTHREAD) {
2323 var ret = _main();
2424
2525 #if EXIT_RUNTIME
26 #if USE_PTHREADS
27 PThread.runExitHandlers();
28 #endif
2629 callRuntimeCallbacks(__ATEXIT__);
2730 <<< ATEXITS >>>
28 #if USE_PTHREADS
29 PThread.runExitHandlers();
30 #endif
3131 #endif
3232
3333 #if IN_TEST_HARNESS
355355
356356 var runtimeInitialized = false;
357357 var runtimeExited = false;
358 var runtimeKeepaliveCounter = 0;
359
360 function keepRuntimeAlive() {
361 return noExitRuntime || runtimeKeepaliveCounter > 0;
362 }
358363
359364 function preRun() {
360365 #if USE_PTHREADS
418423 checkStackCookie();
419424 #endif
420425 #if USE_PTHREADS
426 #if EXIT_RUNTIME
427 PThread.runExitHandlers();
428 #endif
421429 if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
422430 #endif
423431 #if EXIT_RUNTIME
424432 callRuntimeCallbacks(__ATEXIT__);
425433 <<< ATEXITS >>>
426 #if USE_PTHREADS
427 PThread.runExitHandlers();
428 #endif
429434 #endif
430435 runtimeExited = true;
431436 }
501506 }
502507
503508 function addRunDependency(id) {
504 #if USE_PTHREADS
505 // We should never get here in pthreads (could no-op this out if called in pthreads, but that might indicate a bug in caller side,
506 // so good to be very explicit)
507 assert(!ENVIRONMENT_IS_PTHREAD, "addRunDependency cannot be used in a pthread worker");
508 #endif
509509 runDependencies++;
510510
511511 #if expectToReceiveOnModule('monitorRunDependencies')
835835 #endif
836836
837837 #if SPLIT_MODULE
838 {{{ makeModuleReceiveWithVar('loadSplitModule', 'loadSplitModule', 'instantiateSync', true) }}}
838839 var splitModuleProxyHandler = {
839840 'get': function(target, prop, receiver) {
840841 return function() {
842843 var imports = {'primary': Module['asm']};
843844 // Replace '.wasm' suffix with '.deferred.wasm'.
844845 var deferred = wasmBinaryFile.slice(0, -5) + '.deferred.wasm'
845 instantiateSync(deferred, imports);
846 loadSplitModule(deferred, imports, prop);
846847 err('instantiated deferred module, continuing');
847848 #if RELOCATABLE
848849 // When the table is dynamically laid out, the placeholder functions names
960961
961962 Module['asm'] = exports;
962963
963 #if MAIN_MODULE && AUTOLOAD_DYLIBS
964 #if MAIN_MODULE
965 #if AUTOLOAD_DYLIBS
964966 var metadata = getDylinkMetadata(module);
965967 if (metadata.neededDynlibs) {
966968 dynamicLibraries = metadata.neededDynlibs.concat(dynamicLibraries);
967969 }
970 #endif
968971 mergeLibSymbols(exports, 'main')
969972 #endif
970973
597597 // * Work around old Chromium WebGL 1 bug (-s WORKAROUND_OLD_WEBGL_UNIFORM_UPLOAD_IGNORED_OFFSET_BUG=1)
598598 // * Disable WebAssembly. (Must be paired with -s WASM=0)
599599 // * Adjusts MIN_X_VERSION settings to 0 to include support for all browser versions.
600 // * Avoid TypedArray.fill, if necessary, in zeroMemory utility function.
600601 // You can also configure the above options individually.
601602 // [link]
602603 var LEGACY_VM_SUPPORT = 0;
603604
604 // By default, emscripten output will run on the web, in a web worker,
605 // in node.js, or in a JS shell like d8, js, or jsc. You can set this option to
606 // specify that the output should only run in one particular environment, which
607 // must be one of
605 // Specify which runtime environments the JS output will be capable of running
606 // in. For maximum portability this can configured to support all envionements
607 // or it can be limited to reduce overall code size. The supported environments
608 // are:
608609 // 'web' - the normal web environment.
609610 // 'webview' - just like web, but in a webview like Cordova;
610611 // considered to be same as "web" in almost every place
611612 // 'worker' - a web worker environment.
612613 // 'node' - Node.js.
613614 // 'shell' - a JS shell like d8, js, or jsc.
614 // Or it can be a comma-separated list of them, e.g., "web,worker". If this is
615 // the empty string, then all runtime environments are supported.
615 // This settings can be a comma-separated list of these environments, e.g.,
616 // "web,worker". If this is the empty string, then all environments are
617 // supported.
616618 //
617619 // Note that the set of environments recognized here is not identical to the
618620 // ones we identify at runtime using ENVIRONMENT_IS_*. Specifically:
621623 // * The webview target is basically a subset of web. It must be specified
622624 // alongside web (e.g. "web,webview") and we only use it for code generation
623625 // at compile time, there is no runtime behavior change.
624 // [link]
625 var ENVIRONMENT = '';
626 //
627 // Note that by default we do not include the 'shell' environment since direct
628 // usage of d8, js, jsc is extremely rare.
629 // [link]
630 var ENVIRONMENT = 'web,webview,worker,node';
626631
627632 // Enable this to support lz4-compressed file packages. They are stored compressed in memory, and
628633 // decompressed on the fly, avoiding storing the entire decompressed data in memory at once.
830835 'buffer', 'canvas', 'doNotCaptureKeyboard', 'dynamicLibraries',
831836 'elementPointerLock', 'extraStackTrace', 'forcedAspectRatio',
832837 'instantiateWasm', 'keyboardListeningElement', 'freePreloadedMediaOnUse',
833 'locateFile', 'logReadFiles', 'mainScriptUrlOrBlob', 'mem',
838 'loadSplitModule', 'locateFile', 'logReadFiles', 'mainScriptUrlOrBlob', 'mem',
834839 'monitorRunDependencies', 'noExitRuntime', 'noInitialRun', 'onAbort',
835840 'onCustomMessage', 'onExit', 'onFree', 'onFullScreen', 'onMalloc',
836841 'onRealloc', 'onRuntimeInitialized', 'postMainLoop', 'postRun', 'preInit',
10261031 // * AUTO_NATIVE_LIBRARIES is disabled.
10271032 // * AUTO_ARCHIVE_INDEXES is disabled.
10281033 // * DEFAULT_TO_CXX is disabled.
1034 // * ALLOW_UNIMPLEMENTED_SYSCALLS is disabled.
10291035 // [compile+link]
10301036 var STRICT = 0;
10311037
19361942 // For MAIN_MODULE builds, automatically load any dynamic library dependencies
19371943 // on startup, before loading the main module.
19381944 var AUTOLOAD_DYLIBS = 1;
1945
1946 // Include unimplemented JS syscalls to be included in the final output. This
1947 // allows programs that depend on these syscalls at runtime to be compiled, even
1948 // though these syscalls will fail (or do nothing) at runtime.
1949 var ALLOW_UNIMPLEMENTED_SYSCALLS = 1;
19391950
19401951 //===========================================
19411952 // Internal, used for testing only, from here
8080 // Determine the runtime environment we are in. You can customize this by
8181 // setting the ENVIRONMENT setting at compile time (see settings.js).
8282
83 #if ENVIRONMENT && ENVIRONMENT.indexOf(',') < 0
83 #if ENVIRONMENT && !ENVIRONMENT.includes(',')
8484 var ENVIRONMENT_IS_WEB = {{{ ENVIRONMENT === 'web' }}};
8585 #if USE_PTHREADS && ENVIRONMENT_MAY_BE_NODE
8686 // node+pthreads always supports workers; detect which we are at runtime
9191 var ENVIRONMENT_IS_NODE = {{{ ENVIRONMENT === 'node' }}};
9292 var ENVIRONMENT_IS_SHELL = {{{ ENVIRONMENT === 'shell' }}};
9393 #else // ENVIRONMENT
94 var ENVIRONMENT_IS_WEB = false;
95 var ENVIRONMENT_IS_WORKER = false;
96 var ENVIRONMENT_IS_NODE = false;
97 var ENVIRONMENT_IS_SHELL = false;
98 ENVIRONMENT_IS_WEB = typeof window === 'object';
99 ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
94 // Attempt to auto-detect the environment
95 var ENVIRONMENT_IS_WEB = typeof window === 'object';
96 var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
10097 // N.b. Electron.js environment is simultaneously a NODE-environment, but
10198 // also a web environment.
102 ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
103 ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
99 var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
100 var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
104101 #endif // ENVIRONMENT
105102
106103 #if ASSERTIONS
200197 process['on']('unhandledRejection', abort);
201198 #endif
202199
203 quit_ = function(status) {
200 quit_ = function(status, toThrow) {
201 if (keepRuntimeAlive()) {
202 process['exitCode'] = status;
203 throw toThrow;
204 }
204205 process['exit'](status);
205206 };
206207
227228
228229 } else
229230 #endif // ENVIRONMENT_MAY_BE_NODE
230 #if ENVIRONMENT_MAY_BE_SHELL
231 #if ENVIRONMENT_MAY_BE_SHELL || ASSERTIONS
231232 if (ENVIRONMENT_IS_SHELL) {
232233
233234 #if ENVIRONMENT
262263 data = read(f, 'binary');
263264 assert(typeof data === 'object');
264265 return data;
266 };
267
268 readAsync = function readAsync(f, onload, onerror) {
269 setTimeout(function() { onload(readBinary(f)); }, 0);
265270 };
266271
267272 if (typeof scriptArgs != 'undefined') {
407412 #if USE_PTHREADS
408413 assert(ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_NODE, 'Pthreads do not work in this environment yet (need Web Workers, or an alternative to them)');
409414 #endif // USE_PTHREADS
415
416 #if !ENVIRONMENT_MAY_BE_WEB
417 assert(!ENVIRONMENT_IS_WEB, "web environment detected but not enabled at build time. Add 'web' to `-s ENVIRONMENT` to enable.");
418 #endif
419
420 #if !ENVIRONMENT_MAY_BE_WORKER
421 assert(!ENVIRONMENT_IS_WORKER, "worker environment detected but not enabled at build time. Add 'worker' to `-s ENVIRONMENT` to enable.");
422 #endif
423
424 #if !ENVIRONMENT_MAY_BE_NODE
425 assert(!ENVIRONMENT_IS_NODE, "node environment detected but not enabled at build time. Add 'node' to `-s ENVIRONMENT` to enable.");
426 #endif
427
428 #if !ENVIRONMENT_MAY_BE_SHELL
429 assert(!ENVIRONMENT_IS_SHELL, "shell environment detected but not enabled at build time. Add 'shell' to `-s ENVIRONMENT` to enable.");
430 #endif
431
410432 #endif // ASSERTIONS
411433
412434 {{BODY}}
3434 #if ASSERTIONS
3535 #if !ENVIRONMENT_MAY_BE_NODE && !ENVIRONMENT_MAY_BE_SHELL
3636 var ENVIRONMENT_IS_WEB = true
37 #elif ENVIRONMENT && !ENVIRONMENT.includes(',')
38 var ENVIRONMENT_IS_WEB = {{{ ENVIRONMENT === 'web' }}};
39 #elif ENVIRONMENT_MAY_BE_SHELL && ENVIRONMENT_IS_NODE
40 var ENVIRONMENT_IS_WEB = !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_SHELL;
41 #elif ENVIRONMENT_MAY_BE_SHELL
42 var ENVIRONMENT_IS_WEB = !ENVIRONMENT_IS_SHELL;
3743 #else
38 #if ENVIRONMENT && ENVIRONMENT.indexOf(',') < 0
39 var ENVIRONMENT_IS_WEB = {{{ ENVIRONMENT === 'web' }}};
44 var ENVIRONMENT_IS_WEB = !ENVIRONMENT_IS_NODE;
4045 #else
41 var ENVIRONMENT_IS_WEB = !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_SHELL;
46
4247 #endif
43 #endif
44 #endif
48 #endif // ASSERTIONS
4549
4650 #if ASSERTIONS && ENVIRONMENT_MAY_BE_NODE && ENVIRONMENT_MAY_BE_SHELL
4751 if (ENVIRONMENT_IS_NODE && ENVIRONMENT_IS_SHELL) {
3939 "global_locale"
4040 ]
4141 }
42 },
43 {
44 "file": "cxa_exception.h",
45 "structs": {
46 "__cxxabiv1::__cxa_exception": [
47 "exceptionDestructor",
48 "referenceCount",
49 "exceptionType",
50 "caught",
51 "rethrown"
52 ]
53 }
4254 }
4355 ]
110110 }
111111
112112 function isJsLibraryConfigIdentifier(ident) {
113 return ident.endsWith('__sig') || ident.endsWith('__proxy') || ident.endsWith('__asm') || ident.endsWith('__inline')
114 || ident.endsWith('__deps') || ident.endsWith('__postset') || ident.endsWith('__docs') || ident.endsWith('__import')
115 || ident.endsWith('__nothrow');
113 suffixes = [
114 '__sig',
115 '__proxy',
116 '__asm',
117 '__inline',
118 '__deps',
119 '__postset',
120 '__docs',
121 '__import',
122 '__nothrow',
123 '__unimplemented'
124 ];
125 return suffixes.some((suffix) => ident.endsWith(suffix));
116126 }
117127
118128 // Sets
0 /*
1 * Copyright 2012 The Emscripten Authors. All rights reserved.
2 * Emscripten is available under two separate licenses, the MIT license and the
3 * University of Illinois/NCSA Open Source License. Both these licenses can be
4 * found in the LICENSE file.
5 */
6
7 #pragma once
8
9 /* Typedefs */
10
11 typedef short __attribute__((aligned(1))) emscripten_align1_short;
12
13 typedef long long __attribute__((aligned(4))) emscripten_align4_int64;
14 typedef long long __attribute__((aligned(2))) emscripten_align2_int64;
15 typedef long long __attribute__((aligned(1))) emscripten_align1_int64;
16
17 typedef int __attribute__((aligned(2))) emscripten_align2_int;
18 typedef int __attribute__((aligned(1))) emscripten_align1_int;
19
20 typedef float __attribute__((aligned(2))) emscripten_align2_float;
21 typedef float __attribute__((aligned(1))) emscripten_align1_float;
22
23 typedef double __attribute__((aligned(4))) emscripten_align4_double;
24 typedef double __attribute__((aligned(2))) emscripten_align2_double;
25 typedef double __attribute__((aligned(1))) emscripten_align1_double;
26
27 typedef void (*em_callback_func)(void);
28 typedef void (*em_arg_callback_func)(void*);
29 typedef void (*em_str_callback_func)(const char *);
2121
2222 #include "em_asm.h"
2323 #include "em_macros.h"
24 #include "em_types.h"
2425 #include "em_js.h"
26 #include "wget.h"
2527
2628 #ifdef __cplusplus
2729 extern "C" {
2830 #endif
29
30 /* Typedefs */
31
32 typedef short __attribute__((aligned(1))) emscripten_align1_short;
33
34 typedef long long __attribute__((aligned(4))) emscripten_align4_int64;
35 typedef long long __attribute__((aligned(2))) emscripten_align2_int64;
36 typedef long long __attribute__((aligned(1))) emscripten_align1_int64;
37
38 typedef int __attribute__((aligned(2))) emscripten_align2_int;
39 typedef int __attribute__((aligned(1))) emscripten_align1_int;
40
41 typedef float __attribute__((aligned(2))) emscripten_align2_float;
42 typedef float __attribute__((aligned(1))) emscripten_align1_float;
43
44 typedef double __attribute__((aligned(4))) emscripten_align4_double;
45 typedef double __attribute__((aligned(2))) emscripten_align2_double;
46 typedef double __attribute__((aligned(1))) emscripten_align1_double;
47
48 typedef void (*em_callback_func)(void);
49 typedef void (*em_arg_callback_func)(void*);
50 typedef void (*em_str_callback_func)(const char *);
5131
5232 void emscripten_run_script(const char *script);
5333 int emscripten_run_script_int(const char *script);
10484 double emscripten_get_now(void);
10585 float emscripten_random(void);
10686
107 // wget
108
109 void emscripten_async_wget(const char* url, const char* file, em_str_callback_func onload, em_str_callback_func onerror);
110
111 typedef void (*em_async_wget_onload_func)(void*, void*, int);
112 void emscripten_async_wget_data(const char* url, void *arg, em_async_wget_onload_func onload, em_arg_callback_func onerror);
113
114 typedef void (*em_async_wget2_onload_func)(unsigned, void*, const char*);
115 typedef void (*em_async_wget2_onstatus_func)(unsigned, void*, int);
116
117 int emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, em_async_wget2_onload_func onload, em_async_wget2_onstatus_func onerror, em_async_wget2_onstatus_func onprogress);
118
119 typedef void (*em_async_wget2_data_onload_func)(unsigned, void*, void*, unsigned);
120 typedef void (*em_async_wget2_data_onerror_func)(unsigned, void*, int, const char*);
121 typedef void (*em_async_wget2_data_onprogress_func)(unsigned, void*, int, int);
122
123 int emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
124
125 void emscripten_async_wget2_abort(int handle);
126
127 // wget "sync"
128
129 void emscripten_wget(const char* url, const char* file);
130 void emscripten_wget_data(const char* url, void** pbuffer, int* pnum, int *perror);
131
13287 // IDB
13388
134 void emscripten_idb_async_load(const char *db_name, const char *file_id, void* arg, em_async_wget_onload_func onload, em_arg_callback_func onerror);
89 typedef void (*em_idb_onload_func)(void*, void*, int);
90 void emscripten_idb_async_load(const char *db_name, const char *file_id, void* arg, em_idb_onload_func onload, em_arg_callback_func onerror);
13591 void emscripten_idb_async_store(const char *db_name, const char *file_id, void* ptr, int num, void* arg, em_arg_callback_func onstore, em_arg_callback_func onerror);
13692 void emscripten_idb_async_delete(const char *db_name, const char *file_id, void* arg, em_arg_callback_func ondelete, em_arg_callback_func onerror);
13793 typedef void (*em_idb_exists_func)(void*, int);
0 /*
1 * Copyright 2012 The Emscripten Authors. All rights reserved.
2 * Emscripten is available under two separate licenses, the MIT license and the
3 * University of Illinois/NCSA Open Source License. Both these licenses can be
4 * found in the LICENSE file.
5 */
6
7 #pragma once
8
9 #include "em_types.h"
10
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14
15 // wget
16
17 void emscripten_async_wget(const char* url, const char* file, em_str_callback_func onload, em_str_callback_func onerror);
18
19 typedef void (*em_async_wget_onload_func)(void*, void*, int);
20 void emscripten_async_wget_data(const char* url, void *arg, em_async_wget_onload_func onload, em_arg_callback_func onerror);
21
22 typedef void (*em_async_wget2_onload_func)(unsigned, void*, const char*);
23 typedef void (*em_async_wget2_onstatus_func)(unsigned, void*, int);
24
25 int emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, em_async_wget2_onload_func onload, em_async_wget2_onstatus_func onerror, em_async_wget2_onstatus_func onprogress);
26
27 typedef void (*em_async_wget2_data_onload_func)(unsigned, void*, void*, unsigned);
28 typedef void (*em_async_wget2_data_onerror_func)(unsigned, void*, int, const char*);
29 typedef void (*em_async_wget2_data_onprogress_func)(unsigned, void*, int, int);
30
31 int emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
32
33 void emscripten_async_wget2_abort(int handle);
34
35 // wget "sync"
36
37 void emscripten_wget(const char* url, const char* file);
38 void emscripten_wget_data(const char* url, void** pbuffer, int* pnum, int *perror);
39
40 #ifdef __cplusplus
41 }
42 #endif
5959 }
6060
6161 static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
62 atomic_uintptr_t *param = reinterpret_cast<atomic_uintptr_t *>(arg);
63 AsanThread *t = nullptr;
64 while ((t = reinterpret_cast<AsanThread *>(
65 atomic_load(param, memory_order_acquire))) == nullptr)
66 internal_sched_yield();
67 emscripten_builtin_free(param);
62 AsanThread *t = (AsanThread *)arg;
6863 SetCurrentThread(t);
6964 return t->ThreadStart(GetTid());
7065 }
7974 int detached = 0;
8075 if (attr && attr != __ATTRP_C11_THREAD)
8176 pthread_attr_getdetachstate(attr, &detached);
82 atomic_uintptr_t *param = (atomic_uintptr_t *)
83 emscripten_builtin_malloc(sizeof(atomic_uintptr_t));
84 atomic_store(param, 0, memory_order_relaxed);
77
78 u32 current_tid = GetCurrentTidOrInvalid();
79 AsanThread *t =
80 AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
81
8582 int result;
8683 {
8784 // Ignore all allocations made by pthread_create: thread stack/TLS may be
9188 #if CAN_SANITIZE_LEAKS
9289 __lsan::ScopedInterceptorDisabler disabler;
9390 #endif
94 result = REAL(pthread_create)(thread, attr, asan_thread_start, param);
91 result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
9592 }
96 if (result == 0) {
97 u32 current_tid = GetCurrentTidOrInvalid();
98 AsanThread *t =
99 AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
100 atomic_store(param, reinterpret_cast<uptr>(t), memory_order_release);
93 if (result != 0) {
94 // If the thread didn't start delete the AsanThread to avoid leaking it.
95 // Note AsanThreadContexts never get destroyed so the AsanThreadContext
96 // that was just created for the AsanThread is wasted.
97 t->Destroy();
10198 }
10299 return result;
103100 }
482482
483483 #if !SANITIZER_NETBSD
484484 void internal__exit(int exitcode) {
485 #if SANITIZER_FREEBSD || SANITIZER_SOLARIS
485 #if SANITIZER_EMSCRIPTEN
486 __wasi_proc_exit(exitcode);
487 #elif SANITIZER_FREEBSD || SANITIZER_SOLARIS
486488 internal_syscall(SYSCALL(exit), exitcode);
487489 #else
488490 internal_syscall(SYSCALL(exit_group), exitcode);
3535 #define a_cas_p a_cas_p
3636 static inline void *a_cas_p(volatile void *p, void *t, void *s)
3737 {
38 void* expected = t;
39 __c11_atomic_compare_exchange_strong((_Atomic uintptr_t*)p, &expected, s, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
40 return expected;
38 uintptr_t expected = (uintptr_t)t;
39 __c11_atomic_compare_exchange_strong((_Atomic uintptr_t*)p, &expected, (uintptr_t)s, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
40 return (void*)expected;
4141 }
4242
4343 #define a_cas_l a_cas_l
3737 #define __NR_getpriority 96
3838 #define __NR_setpriority 97
3939 #define __NR_setitimer 104
40 #define __NR_getitimer 105
4041 #define __NR_wait4 114
4142 #define __NR_setdomainname 121
4243 #define __NR_uname 122
162163 #define SYS_getpriority 96
163164 #define SYS_setpriority 97
164165 #define SYS_setitimer 104
166 #define SYS_getitimer 105
165167 #define SYS_wait4 114
166168 #define SYS_setdomainname 121
167169 #define SYS_uname 122
1313 /* Causes the final import in the wasm binary be named "env.sys_<name>" */
1414 #define SYS_IMPORT(NAME) EM_IMPORT(__sys_##NAME)
1515
16 long SYS_IMPORT(exit) __syscall1(long exit_code);
1716 long SYS_IMPORT(open) __syscall5(long path, long flags, ...); // mode is optional
1817 long SYS_IMPORT(link) __syscall9(long oldpath, long newpath);
1918 long SYS_IMPORT(unlink) __syscall10(long path);
4847 long SYS_IMPORT(setpriority) __syscall97(long which, long who, long prio);
4948 long SYS_IMPORT(socketcall) __syscall102(long call, long args);
5049 long SYS_IMPORT(setitimer) __syscall104(long which, long new_value, long old_value);
50 long SYS_IMPORT(getitimer) __syscall105(long which, long old_value);
5151 long SYS_IMPORT(wait4) __syscall114(long pid, long wstatus, long options, long rusage);
5252 long SYS_IMPORT(setdomainname) __syscall121(long name, long size);
5353 long SYS_IMPORT(uname) __syscall122(long buf);
9595 long SYS_IMPORT(madvise1) __syscall219(long addr, long length, long advice);
9696 long SYS_IMPORT(getdents64) __syscall220(long fd, long dirp, long count);
9797 long SYS_IMPORT(fcntl64) __syscall221(long fd, long cmd, ...);
98 long SYS_IMPORT(exit_group) __syscall252(long status);
9998 long SYS_IMPORT(statfs64) __syscall268(long path, long size, long buf);
10099 long SYS_IMPORT(fstatfs64) __syscall269(long fd, long size, long buf);
101100 long SYS_IMPORT(fadvise64_64)
202202 struct __ptcb *__next;
203203 };
204204
205 #ifdef __EMSCRIPTEN__
206 // For Emscripten, the cleanup stack is not implemented as a macro, since it's currently in the JS side.
207 typedef void (*cleanup_handler_routine)(void *arg);
208 void pthread_cleanup_push(cleanup_handler_routine routine, void *arg);
209 void pthread_cleanup_pop(int execute);
210 #else
211205 void _pthread_cleanup_push(struct __ptcb *, void (*)(void *), void *);
212206 void _pthread_cleanup_pop(struct __ptcb *, int);
213207
214208 #define pthread_cleanup_push(f, x) do { struct __ptcb __cb; _pthread_cleanup_push(&__cb, f, x);
215209 #define pthread_cleanup_pop(r) _pthread_cleanup_pop(&__cb, (r)); } while(0)
216 #endif
217210
218211 #ifdef _GNU_SOURCE
219212 struct cpu_set_t;
22
33 _Noreturn void _Exit(int ec)
44 {
5 #ifdef __EMSCRIPTEN__
6 __wasi_proc_exit(ec);
7 #else
58 __syscall(SYS_exit_group, ec);
69 for (;;) __syscall(SYS_exit, ec);
10 #endif
711 }
00 #define _GNU_SOURCE
11 #include <unistd.h>
22 #include <time.h>
3 #ifdef __EMSCRTIPEN__
4 #include <emscripten/threading.h>
5 #endif
63
74 int usleep(unsigned useconds)
85 {
9 #ifdef __EMSCRTIPEN__
10 emscripten_thread_sleep(usec / 1e3);
11 return 0;
12 #else
136 struct timespec tv = {
147 .tv_sec = useconds/1000000,
158 .tv_nsec = (useconds%1000000)*1000
169 };
1710 return nanosleep(&tv, &tv);
18 #endif
1911 }
1717 #include "unwind.h"
1818
1919 namespace __cxxabiv1 {
20
21 #ifdef __USING_EMSCRIPTEN_EXCEPTIONS__
22
23 struct _LIBCXXABI_HIDDEN __cxa_exception {
24 size_t referenceCount;
25 std::type_info *exceptionType;
26 void (*exceptionDestructor)(void *);
27 uint8_t caught;
28 uint8_t rethrown;
29 };
30
31 #else
2032
2133 static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
2234 static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
163175 extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception ();
164176 extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception);
165177
178 #endif // !__USING_EMSCRIPTEN_EXCEPTIONS__
179
166180 } // namespace __cxxabiv1
167181
168182 #endif // _CXA_EXCEPTION_H
1717 #include "cxa_exception.h"
1818 #include "private_typeinfo.h"
1919 #include "include/atomic_support.h"
20
21 namespace __cxxabiv1 {
22
23 #ifdef __USING_EMSCRIPTEN_EXCEPTIONS__
24 // XXX EMSCRIPTEN: Copied from cxa_exception.cpp since we don't compile that
25 // file in Emscripten EH mode. Note that in no-exceptions builds we include
26 // cxa_noexception.cpp which provides stubs of those anyhow.
27
28 // Is it one of ours?
29 uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
30 // On x86 and some ARM unwinders, unwind_exception->exception_class is
31 // a uint64_t. On other ARM unwinders, it is a char[8]
32 // See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
33 // So we just copy it into a uint64_t to be sure.
34 uint64_t exClass;
35 ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
36 return exClass;
37 }
38
39 bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
40 return (__getExceptionClass(unwind_exception) & get_vendor_and_language) ==
41 (kOurExceptionClass & get_vendor_and_language);
42 }
43 #endif
44
45 }
4620
4721 namespace std
4822 {
9872 void
9973 terminate() _NOEXCEPT
10074 {
101 #ifndef _LIBCXXABI_NO_EXCEPTIONS
75 #if !defined(_LIBCXXABI_NO_EXCEPTIONS) && !defined(__USING_EMSCRIPTEN_EXCEPTIONS__)
10276 // If there might be an uncaught exception
10377 using namespace __cxxabiv1;
10478 __cxa_eh_globals* globals = __cxa_get_globals_fast();
945945 }
946946
947947 weak_alias(__pthread_testcancel, pthread_testcancel);
948
949 // See musl's pthread_create.c
950 void __run_cleanup_handlers(void* _unused) {
951 pthread_t self = __pthread_self();
952 while (self->cancelbuf) {
953 void (*f)(void *) = self->cancelbuf->__f;
954 void *x = self->cancelbuf->__x;
955 self->cancelbuf = self->cancelbuf->__next;
956 f(x);
957 }
958 }
959
960 extern int __cxa_thread_atexit(void (*)(void *), void *, void *);
961
962 extern int8_t __dso_handle;
963
964 // Copied from musl's pthread_create.c
965 void __do_cleanup_push(struct __ptcb *cb) {
966 struct pthread *self = __pthread_self();
967 cb->__next = self->cancelbuf;
968 self->cancelbuf = cb;
969 static thread_local bool registered = false;
970 if (!registered) {
971 __cxa_thread_atexit(__run_cleanup_handlers, NULL, &__dso_handle);
972 registered = true;
973 }
974 }
975
976 // Copied from musl's pthread_create.c
977 void __do_cleanup_pop(struct __ptcb *cb) {
978 __pthread_self()->cancelbuf = cb->__next;
979 }
2323 */
2424
2525 // libc
26
27 void _Exit(int status) {
28 __wasi_proc_exit(status);
29 __builtin_unreachable();
30 }
3126
3227 void abort() {
3328 _Exit(1);
2525
2626 char *randomString(int len) {
2727 if (!utf8_corpus) {
28 // FILE *handle = fopen("ascii_corpus.txt", "rb");
2928 FILE *handle = fopen("utf8_corpus.txt", "rb");
3029 fseek(handle, 0, SEEK_END);
3130 utf8_corpus_length = ftell(handle);
4544 char *s = new char[len+1];
4645 memcpy(s, utf8_corpus + startIdx, len);
4746 s[len] = '\0';
48 while(((unsigned char)s[len-1] & 0xC0) == 0x80) { s[--len] = '\0'; }
49 while(((unsigned char)s[len-1] & 0xC0) == 0xC0) { s[--len] = '\0'; }
47 while(len > 0 && ((unsigned char)s[len-1] & 0xC0) == 0x80) { s[--len] = '\0'; }
48 while(len > 0 && ((unsigned char)s[len-1] & 0xC0) == 0xC0) { s[--len] = '\0'; }
5049 assert(len >= 0);
5150 return s;
5251 }
00 #include <emscripten/html5.h>
11 #include <stdio.h>
2 #include <stdlib.h>
23
3 void timeout(void *userData)
4 {
5 printf("Got timeout handler\n");
6 #ifdef REPORT_RESULT
7 // Test passed
8 REPORT_RESULT(1);
9 #endif
4 void timeout(void *userData) {
5 printf("Got timeout handler\n");
6 // Test passed
7 exit(0);
108 }
119
12 int main()
13 {
14 emscripten_set_timeout(timeout, 2000, 0);
15 emscripten_unwind_to_js_event_loop();
16 printf("This should not be called!\n");
17 #ifdef REPORT_RESULT
18 // Should not reach here
19 REPORT_RESULT(-1);
20 #endif
10 int main() {
11 emscripten_set_timeout(timeout, 2000, 0);
12 emscripten_unwind_to_js_event_loop();
13 // emscripten_unwind_to_js_event_loop should never return
14 __builtin_unreachable();
2115 }
0 // Copyright 2013 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <dlfcn.h>
9 #include <emscripten.h>
10
11 typedef void (*voidfunc)();
12 typedef int (*intfunc)();
13
14 void *lib_handle;
15 voidfunc onefunc;
16 intfunc twofunc;
17
18 void next(const char *x) {
19 lib_handle = dlopen("thelib.wasm", RTLD_NOW);
20 assert(lib_handle != NULL);
21
22 onefunc = (voidfunc)dlsym(lib_handle, "one");
23 twofunc = (intfunc)dlsym(lib_handle, "two");
24 assert(onefunc && twofunc);
25
26 assert(twofunc() == 0);
27 onefunc();
28 assert(twofunc() == 1);
29 onefunc();
30 onefunc();
31 assert(twofunc() == 3);
32 onefunc();
33 onefunc();
34 onefunc();
35 onefunc();
36 assert(twofunc() == 7);
37 onefunc();
38 int result = twofunc();
39 assert(result == 8);
40 exit(0);
41 }
42
43 int main() {
44 emscripten_async_wget("lib.wasm", "thelib.wasm", next, NULL);
45 printf("returning from main\n");
46 return 0;
47 }
48
+0
-48
tests/browser_main.cpp less more
0 // Copyright 2013 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <dlfcn.h>
9 #include <emscripten.h>
10
11 typedef void (*voidfunc)();
12 typedef int (*intfunc)();
13
14 void *lib_handle;
15 voidfunc onefunc;
16 intfunc twofunc;
17
18 void next(const char *x) {
19 lib_handle = dlopen("thelib.wasm", RTLD_NOW);
20 assert(lib_handle != NULL);
21
22 onefunc = (voidfunc)dlsym(lib_handle, "one");
23 twofunc = (intfunc)dlsym(lib_handle, "two");
24 assert(onefunc && twofunc);
25
26 assert(twofunc() == 0);
27 onefunc();
28 assert(twofunc() == 1);
29 onefunc();
30 onefunc();
31 assert(twofunc() == 3);
32 onefunc();
33 onefunc();
34 onefunc();
35 onefunc();
36 assert(twofunc() == 7);
37 onefunc();
38 int result = twofunc();
39 exit(result);
40 }
41
42 int main() {
43 emscripten_async_wget("lib.wasm", "thelib.wasm", next, NULL);
44 printf("returning from main\n");
45 return 0;
46 }
47
0 // Copyright 2013 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 int state = 0;
6
7 void one() {
8 state++;
9 }
10
11 int two() {
12 return state;
13 }
+0
-19
tests/browser_module.cpp less more
0 // Copyright 2013 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 int state = 0;
6
7 extern "C" {
8
9 void one() {
10 state++;
11 }
12
13 int two() {
14 return state;
15 }
16
17 }
18
8080 emscripten_webgl_make_context_current(0);
8181 emscripten_webgl_destroy_context(ctx);
8282 printf("quit\n");
83 #ifdef REPORT_RESULT
84 REPORT_RESULT(1);
85 #endif
8683 exit(0);
8784 }
8885 }
153150 usleep(16*1000);
154151 }
155152 #endif
153 return 99;
156154 }
22 "a.html.gz": 377,
33 "a.js": 4987,
44 "a.js.gz": 2406,
5 "a.wasm": 10343,
6 "a.wasm.gz": 6687,
7 "total": 15893,
8 "total_gz": 9470
5 "a.wasm": 10310,
6 "a.wasm.gz": 6660,
7 "total": 15860,
8 "total_gz": 9443
99 }
00 {
11 "a.html": 588,
22 "a.html.gz": 386,
3 "a.js": 19948,
4 "a.js.gz": 8191,
3 "a.js": 19895,
4 "a.js.gz": 8158,
55 "a.mem": 3171,
66 "a.mem.gz": 2714,
7 "total": 23707,
8 "total_gz": 11291
7 "total": 23654,
8 "total_gz": 11258
99 }
22 "a.html.gz": 377,
33 "a.js": 4471,
44 "a.js.gz": 2236,
5 "a.wasm": 10343,
6 "a.wasm.gz": 6687,
7 "total": 15377,
8 "total_gz": 9300
5 "a.wasm": 10310,
6 "a.wasm.gz": 6660,
7 "total": 15344,
8 "total_gz": 9273
99 }
00 {
11 "a.html": 588,
22 "a.html.gz": 386,
3 "a.js": 19430,
4 "a.js.gz": 8023,
3 "a.js": 19377,
4 "a.js.gz": 7992,
55 "a.mem": 3171,
66 "a.mem.gz": 2714,
7 "total": 23189,
8 "total_gz": 11123
7 "total": 23136,
8 "total_gz": 11092
99 }
00 {
1 "a.html": 12609,
2 "a.html.gz": 6723,
3 "total": 12609,
4 "total_gz": 6723
1 "a.html": 12521,
2 "a.html.gz": 6725,
3 "total": 12521,
4 "total_gz": 6725
55 }
00 {
1 "a.html": 17384,
2 "a.html.gz": 7487,
3 "total": 17384,
4 "total_gz": 7487
1 "a.html": 17343,
2 "a.html.gz": 7450,
3 "total": 17343,
4 "total_gz": 7450
55 }
0 # Copyright 2021 The Emscripten Authors. All rights reserved.
1 # Emscripten is available under two separate licenses, the MIT license and the
2 # University of Illinois/NCSA Open Source License. Both these licenses can be
3 # found in the LICENSE file.
4
5 from enum import Enum
6 from functools import wraps
7 from pathlib import Path
8 from subprocess import PIPE, STDOUT
9 from urllib.parse import unquote, unquote_plus
10 from http.server import HTTPServer, SimpleHTTPRequestHandler
11 import contextlib
12 import difflib
13 import hashlib
14 import logging
15 import multiprocessing
16 import os
17 import shlex
18 import shutil
19 import stat
20 import string
21 import subprocess
22 import sys
23 import tempfile
24 import time
25 import webbrowser
26 import unittest
27
28 import clang_native
29 import jsrun
30 from jsrun import NON_ZERO
31 from tools.shared import TEMP_DIR, EMCC, EMXX, DEBUG, EMCONFIGURE, EMCMAKE
32 from tools.shared import EMSCRIPTEN_TEMP_DIR
33 from tools.shared import EM_BUILD_VERBOSE
34 from tools.shared import get_canonical_temp_dir, try_delete, path_from_root
35 from tools.utils import MACOS, WINDOWS
36 from tools import shared, line_endings, building, config
37
38 logger = logging.getLogger('common')
39
40 # User can specify an environment variable EMTEST_BROWSER to force the browser
41 # test suite to run using another browser command line than the default system
42 # browser. Setting '0' as the browser disables running a browser (but we still
43 # see tests compile)
44 EMTEST_BROWSER = None
45 EMTEST_DETECT_TEMPFILE_LEAKS = None
46 EMTEST_SAVE_DIR = None
47 # generally js engines are equivalent, testing 1 is enough. set this
48 # to force testing on all js engines, good to find js engine bugs
49 EMTEST_ALL_ENGINES = None
50 EMTEST_SKIP_SLOW = None
51 EMTEST_LACKS_NATIVE_CLANG = None
52 EMTEST_VERBOSE = None
53 EMTEST_REBASELINE = None
54
55 TEST_ROOT = path_from_root('tests')
56
57 WEBIDL_BINDER = shared.bat_suffix(path_from_root('tools/webidl_binder'))
58
59 EMBUILDER = shared.bat_suffix(path_from_root('embuilder'))
60 EMMAKE = shared.bat_suffix(path_from_root('emmake'))
61
62
63 def delete_contents(pathname):
64 for entry in os.listdir(pathname):
65 try_delete(os.path.join(pathname, entry))
66
67
68 def test_file(*path_components):
69 """Construct a path relative to the emscripten "tests" directory."""
70 return str(Path(TEST_ROOT, *path_components))
71
72
73 def read_file(*path_components):
74 return Path(*path_components).read_text()
75
76
77 def read_binary(*path_components):
78 return Path(*path_components).read_bytes()
79
80
81 # checks if browser testing is enabled
82 def has_browser():
83 return EMTEST_BROWSER != '0'
84
85
86 def compiler_for(filename, force_c=False):
87 if shared.suffix(filename) in ('.cc', '.cxx', '.cpp') and not force_c:
88 return EMXX
89 else:
90 return EMCC
91
92
93 # Generic decorator that calls a function named 'condition' on the test class and
94 # skips the test if that function returns true
95 def skip_if(func, condition, explanation='', negate=False):
96 assert callable(func)
97 explanation_str = ' : %s' % explanation if explanation else ''
98
99 @wraps(func)
100 def decorated(self, *args, **kwargs):
101 choice = self.__getattribute__(condition)()
102 if negate:
103 choice = not choice
104 if choice:
105 self.skipTest(condition + explanation_str)
106 func(self, *args, **kwargs)
107
108 return decorated
109
110
111 def needs_dylink(func):
112 assert callable(func)
113
114 @wraps(func)
115 def decorated(self):
116 self.check_dylink()
117 return func(self)
118
119 return decorated
120
121
122 def is_slow_test(func):
123 assert callable(func)
124
125 @wraps(func)
126 def decorated(self, *args, **kwargs):
127 if EMTEST_SKIP_SLOW:
128 return self.skipTest('skipping slow tests')
129 return func(self, *args, **kwargs)
130
131 return decorated
132
133
134 def disabled(note=''):
135 assert not callable(note)
136 return unittest.skip(note)
137
138
139 def no_mac(note=''):
140 assert not callable(note)
141 if MACOS:
142 return unittest.skip(note)
143 return lambda f: f
144
145
146 def no_windows(note=''):
147 assert not callable(note)
148 if WINDOWS:
149 return unittest.skip(note)
150 return lambda f: f
151
152
153 def requires_native_clang(func):
154 assert callable(func)
155
156 def decorated(self, *args, **kwargs):
157 if EMTEST_LACKS_NATIVE_CLANG:
158 return self.skipTest('native clang tests are disabled')
159 return func(self, *args, **kwargs)
160
161 return decorated
162
163
164 def require_node(func):
165 assert callable(func)
166
167 def decorated(self, *args, **kwargs):
168 self.require_node()
169 return func(self, *args, **kwargs)
170
171 return decorated
172
173
174 def require_v8(func):
175 assert callable(func)
176
177 def decorated(self, *args, **kwargs):
178 self.require_v8()
179 return func(self, *args, **kwargs)
180
181 return decorated
182
183
184 def node_pthreads(f):
185 def decorated(self):
186 self.set_setting('USE_PTHREADS')
187 self.emcc_args += ['-Wno-pthreads-mem-growth']
188 if self.get_setting('MINIMAL_RUNTIME'):
189 self.skipTest('node pthreads not yet supported with MINIMAL_RUNTIME')
190 self.js_engines = [config.NODE_JS]
191 self.node_args += ['--experimental-wasm-threads', '--experimental-wasm-bulk-memory']
192 f(self)
193 return decorated
194
195
196 @contextlib.contextmanager
197 def env_modify(updates):
198 """A context manager that updates os.environ."""
199 # This could also be done with mock.patch.dict() but taking a dependency
200 # on the mock library is probably not worth the benefit.
201 old_env = os.environ.copy()
202 print("env_modify: " + str(updates))
203 # Seting a value to None means clear the environment variable
204 clears = [key for key, value in updates.items() if value is None]
205 updates = {key: value for key, value in updates.items() if value is not None}
206 os.environ.update(updates)
207 for key in clears:
208 if key in os.environ:
209 del os.environ[key]
210 try:
211 yield
212 finally:
213 os.environ.clear()
214 os.environ.update(old_env)
215
216
217 # Decorator version of env_modify
218 def with_env_modify(updates):
219 def decorated(f):
220 def modified(self):
221 with env_modify(updates):
222 return f(self)
223 return modified
224 return decorated
225
226
227 def ensure_dir(dirname):
228 dirname = Path(dirname)
229 dirname.mkdir(parents=True, exist_ok=True)
230
231
232 def limit_size(string, maxbytes=800000 * 20, maxlines=100000, max_line=5000):
233 lines = string.splitlines()
234 for i, line in enumerate(lines):
235 if len(line) > max_line:
236 lines[i] = line[:max_line] + '[..]'
237 if len(lines) > maxlines:
238 lines = lines[0:maxlines // 2] + ['[..]'] + lines[-maxlines // 2:]
239 string = '\n'.join(lines) + '\n'
240 if len(string) > maxbytes:
241 string = string[0:maxbytes // 2] + '\n[..]\n' + string[-maxbytes // 2:]
242 return string
243
244
245 def create_file(name, contents, binary=False):
246 name = Path(name)
247 assert not name.is_absolute()
248 if binary:
249 name.write_bytes(contents)
250 else:
251 name.write_text(contents)
252
253
254 def make_executable(name):
255 Path(name).chmod(stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
256
257
258 def parameterized(parameters):
259 """
260 Mark a test as parameterized.
261
262 Usage:
263 @parameterized({
264 'subtest1': (1, 2, 3),
265 'subtest2': (4, 5, 6),
266 })
267 def test_something(self, a, b, c):
268 ... # actual test body
269
270 This is equivalent to defining two tests:
271
272 def test_something_subtest1(self):
273 # runs test_something(1, 2, 3)
274
275 def test_something_subtest2(self):
276 # runs test_something(4, 5, 6)
277 """
278 def decorator(func):
279 func._parameterize = parameters
280 return func
281 return decorator
282
283
284 class RunnerMeta(type):
285 @classmethod
286 def make_test(mcs, name, func, suffix, args):
287 """
288 This is a helper function to create new test functions for each parameterized form.
289
290 :param name: the original name of the function
291 :param func: the original function that we are parameterizing
292 :param suffix: the suffix to append to the name of the function for this parameterization
293 :param args: the positional arguments to pass to the original function for this parameterization
294 :returns: a tuple of (new_function_name, new_function_object)
295 """
296
297 # Create the new test function. It calls the original function with the specified args.
298 # We use @functools.wraps to copy over all the function attributes.
299 @wraps(func)
300 def resulting_test(self):
301 return func(self, *args)
302
303 # Add suffix to the function name so that it displays correctly.
304 if suffix:
305 resulting_test.__name__ = f'{name}_{suffix}'
306 else:
307 resulting_test.__name__ = name
308
309 # On python 3, functions have __qualname__ as well. This is a full dot-separated path to the
310 # function. We add the suffix to it as well.
311 resulting_test.__qualname__ = f'{func.__qualname__}_{suffix}'
312
313 return resulting_test.__name__, resulting_test
314
315 def __new__(mcs, name, bases, attrs):
316 # This metaclass expands parameterized methods from `attrs` into separate ones in `new_attrs`.
317 new_attrs = {}
318
319 for attr_name, value in attrs.items():
320 # Check if a member of the new class has _parameterize, the tag inserted by @parameterized.
321 if hasattr(value, '_parameterize'):
322 # If it does, we extract the parameterization information, build new test functions.
323 for suffix, args in value._parameterize.items():
324 new_name, func = mcs.make_test(attr_name, value, suffix, args)
325 assert new_name not in new_attrs, 'Duplicate attribute name generated when parameterizing %s' % attr_name
326 new_attrs[new_name] = func
327 else:
328 # If not, we just copy it over to new_attrs verbatim.
329 assert attr_name not in new_attrs, '%s collided with an attribute from parameterization' % attr_name
330 new_attrs[attr_name] = value
331
332 # We invoke type, the default metaclass, to actually create the new class, with new_attrs.
333 return type.__new__(mcs, name, bases, new_attrs)
334
335
336 class RunnerCore(unittest.TestCase, metaclass=RunnerMeta):
337 # default temporary directory settings. set_temp_dir may be called later to
338 # override these
339 temp_dir = TEMP_DIR
340 canonical_temp_dir = get_canonical_temp_dir(TEMP_DIR)
341
342 # This avoids cluttering the test runner output, which is stderr too, with compiler warnings etc.
343 # Change this to None to get stderr reporting, for debugging purposes
344 stderr_redirect = STDOUT
345
346 def is_wasm(self):
347 return self.get_setting('WASM') != 0
348
349 def check_dylink(self):
350 if self.get_setting('ALLOW_MEMORY_GROWTH') == 1 and not self.is_wasm():
351 self.skipTest('no dynamic linking with memory growth (without wasm)')
352 if not self.is_wasm():
353 self.skipTest('no dynamic linking support in wasm2js yet')
354 if '-fsanitize=address' in self.emcc_args:
355 self.skipTest('no dynamic linking support in ASan yet')
356 if '-fsanitize=leak' in self.emcc_args:
357 self.skipTest('no dynamic linking support in LSan yet')
358
359 def require_v8(self):
360 if not config.V8_ENGINE or config.V8_ENGINE not in config.JS_ENGINES:
361 if 'EMTEST_SKIP_V8' in os.environ:
362 self.skipTest('test requires v8 and EMTEST_SKIP_V8 is set')
363 else:
364 self.fail('d8 required to run this test. Use EMTEST_SKIP_V8 to skip')
365 self.js_engines = [config.V8_ENGINE]
366 self.emcc_args.append('-sENVIRONMENT=shell')
367
368 def require_node(self):
369 if not config.NODE_JS or config.NODE_JS not in config.JS_ENGINES:
370 if 'EMTEST_SKIP_NODE' in os.environ:
371 self.skipTest('test requires node and EMTEST_SKIP_NODE is set')
372 else:
373 self.fail('node required to run this test. Use EMTEST_SKIP_NODE to skip')
374 self.js_engines = [config.NODE_JS]
375
376 def uses_memory_init_file(self):
377 if self.get_setting('SIDE_MODULE') or (self.is_wasm() and not self.get_setting('WASM2JS')):
378 return False
379 elif '--memory-init-file' in self.emcc_args:
380 return int(self.emcc_args[self.emcc_args.index('--memory-init-file') + 1])
381 else:
382 # side modules handle memory differently; binaryen puts the memory in the wasm module
383 opt_supports = any(opt in self.emcc_args for opt in ('-O2', '-O3', '-Os', '-Oz'))
384 return opt_supports
385
386 def set_temp_dir(self, temp_dir):
387 self.temp_dir = temp_dir
388 self.canonical_temp_dir = get_canonical_temp_dir(self.temp_dir)
389 # Explicitly set dedicated temporary directory for parallel tests
390 os.environ['EMCC_TEMP_DIR'] = self.temp_dir
391
392 @classmethod
393 def setUpClass(cls):
394 super().setUpClass()
395 print('(checking sanity from test runner)') # do this after we set env stuff
396 shared.check_sanity(force=True)
397
398 def setUp(self):
399 super().setUp()
400 self.settings_mods = {}
401 self.emcc_args = ['-Werror']
402 self.node_args = []
403 self.v8_args = []
404 self.env = {}
405 self.temp_files_before_run = []
406 self.uses_es6 = False
407 self.js_engines = config.JS_ENGINES.copy()
408 self.wasm_engines = config.WASM_ENGINES.copy()
409 self.banned_js_engines = []
410 self.use_all_engines = EMTEST_ALL_ENGINES
411
412 if EMTEST_DETECT_TEMPFILE_LEAKS:
413 for root, dirnames, filenames in os.walk(self.temp_dir):
414 for dirname in dirnames:
415 self.temp_files_before_run.append(os.path.normpath(os.path.join(root, dirname)))
416 for filename in filenames:
417 self.temp_files_before_run.append(os.path.normpath(os.path.join(root, filename)))
418
419 if EMTEST_SAVE_DIR:
420 self.working_dir = os.path.join(self.temp_dir, 'emscripten_test')
421 if os.path.exists(self.working_dir):
422 if EMTEST_SAVE_DIR == 2:
423 print('Not clearing existing test directory')
424 else:
425 print('Clearing existing test directory')
426 # Even when EMTEST_SAVE_DIR we still try to start with an empty directoy as many tests
427 # expect this. EMTEST_SAVE_DIR=2 can be used to keep the old contents for the new test
428 # run. This can be useful when iterating on a given test with extra files you want to keep
429 # around in the output directory.
430 delete_contents(self.working_dir)
431 else:
432 print('Creating new test output directory')
433 ensure_dir(self.working_dir)
434 else:
435 self.working_dir = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=self.temp_dir)
436 os.chdir(self.working_dir)
437
438 if not EMTEST_SAVE_DIR:
439 self.has_prev_ll = False
440 for temp_file in os.listdir(TEMP_DIR):
441 if temp_file.endswith('.ll'):
442 self.has_prev_ll = True
443
444 def tearDown(self):
445 if not EMTEST_SAVE_DIR:
446 # rmtree() fails on Windows if the current working directory is inside the tree.
447 os.chdir(os.path.dirname(self.get_dir()))
448 try_delete(self.get_dir())
449
450 if EMTEST_DETECT_TEMPFILE_LEAKS and not DEBUG:
451 temp_files_after_run = []
452 for root, dirnames, filenames in os.walk(self.temp_dir):
453 for dirname in dirnames:
454 temp_files_after_run.append(os.path.normpath(os.path.join(root, dirname)))
455 for filename in filenames:
456 temp_files_after_run.append(os.path.normpath(os.path.join(root, filename)))
457
458 # Our leak detection will pick up *any* new temp files in the temp dir.
459 # They may not be due to us, but e.g. the browser when running browser
460 # tests. Until we figure out a proper solution, ignore some temp file
461 # names that we see on our CI infrastructure.
462 ignorable_file_prefixes = [
463 '/tmp/tmpaddon',
464 '/tmp/circleci-no-output-timeout',
465 '/tmp/wasmer'
466 ]
467
468 left_over_files = set(temp_files_after_run) - set(self.temp_files_before_run)
469 left_over_files = [f for f in left_over_files if not any([f.startswith(prefix) for prefix in ignorable_file_prefixes])]
470 if len(left_over_files):
471 print('ERROR: After running test, there are ' + str(len(left_over_files)) + ' new temporary files/directories left behind:', file=sys.stderr)
472 for f in left_over_files:
473 print('leaked file: ' + f, file=sys.stderr)
474 self.fail('Test leaked ' + str(len(left_over_files)) + ' temporary files!')
475
476 def get_setting(self, key, default=None):
477 return self.settings_mods.get(key, default)
478
479 def set_setting(self, key, value=1):
480 if value is None:
481 self.clear_setting(key)
482 self.settings_mods[key] = value
483
484 def has_changed_setting(self, key):
485 return key in self.settings_mods
486
487 def clear_setting(self, key):
488 self.settings_mods.pop(key, None)
489
490 def serialize_settings(self):
491 ret = []
492 for key, value in self.settings_mods.items():
493 if value == 1:
494 ret.append(f'-s{key}')
495 elif type(value) == list:
496 ret.append(f'-s{key}={",".join(value)}')
497 else:
498 ret.append(f'-s{key}={value}')
499 return ret
500
501 def get_dir(self):
502 return self.working_dir
503
504 def in_dir(self, *pathelems):
505 return os.path.join(self.get_dir(), *pathelems)
506
507 def add_pre_run(self, code):
508 create_file('prerun.js', 'Module.preRun = function() { %s }' % code)
509 self.emcc_args += ['--pre-js', 'prerun.js']
510
511 def add_post_run(self, code):
512 create_file('postrun.js', 'Module.postRun = function() { %s }' % code)
513 self.emcc_args += ['--pre-js', 'postrun.js']
514
515 def add_on_exit(self, code):
516 create_file('onexit.js', 'Module.onExit = function() { %s }' % code)
517 self.emcc_args += ['--pre-js', 'onexit.js']
518
519 # returns the full list of arguments to pass to emcc
520 # param @main_file whether this is the main file of the test. some arguments
521 # (like --pre-js) do not need to be passed when building
522 # libraries, for example
523 def get_emcc_args(self, main_file=False):
524 args = self.serialize_settings() + self.emcc_args
525 if not main_file:
526 for i, arg in enumerate(args):
527 if arg in ('--pre-js', '--post-js'):
528 args[i] = None
529 args[i + 1] = None
530 args = [arg for arg in args if arg is not None]
531 return args
532
533 def verify_es5(self, filename):
534 es_check = shared.get_npm_cmd('es-check')
535 # use --quiet once its available
536 # See: https://github.com/dollarshaveclub/es-check/pull/126/
537 es_check_env = os.environ.copy()
538 es_check_env['PATH'] = os.path.dirname(config.NODE_JS[0]) + os.pathsep + es_check_env['PATH']
539 try:
540 shared.run_process(es_check + ['es5', os.path.abspath(filename), '--quiet'], stderr=PIPE, env=es_check_env)
541 except subprocess.CalledProcessError as e:
542 print(e.stderr)
543 self.fail('es-check failed to verify ES5 output compliance')
544
545 # Build JavaScript code from source code
546 def build(self, filename, libraries=[], includes=[], force_c=False, js_outfile=True, emcc_args=[]):
547 suffix = '.js' if js_outfile else '.wasm'
548 compiler = [compiler_for(filename, force_c)]
549 if compiler[0] == EMCC:
550 # TODO(https://github.com/emscripten-core/emscripten/issues/11121)
551 # We link with C++ stdlibs, even when linking with emcc for historical reasons. We can remove
552 # this if this issues is fixed.
553 compiler.append('-nostdlib++')
554
555 if force_c:
556 compiler.append('-xc')
557
558 dirname, basename = os.path.split(filename)
559 output = shared.unsuffixed(basename) + suffix
560 cmd = compiler + [filename, '-o', output] + self.get_emcc_args(main_file=True) + emcc_args + libraries
561 if shared.suffix(filename) not in ('.i', '.ii'):
562 # Add the location of the test file to include path.
563 cmd += ['-I.']
564 cmd += ['-I' + str(include) for include in includes]
565
566 self.run_process(cmd, stderr=self.stderr_redirect if not DEBUG else None)
567 self.assertExists(output)
568 if js_outfile and not self.uses_es6:
569 self.verify_es5(output)
570
571 if js_outfile and self.uses_memory_init_file():
572 src = read_file(output)
573 # side memory init file, or an empty one in the js
574 assert ('/* memory initializer */' not in src) or ('/* memory initializer */ allocate([]' in src)
575
576 return output
577
578 def get_func(self, src, name):
579 start = src.index('function ' + name + '(')
580 t = start
581 n = 0
582 while True:
583 if src[t] == '{':
584 n += 1
585 elif src[t] == '}':
586 n -= 1
587 if n == 0:
588 return src[start:t + 1]
589 t += 1
590 assert t < len(src)
591
592 def count_funcs(self, javascript_file):
593 num_funcs = 0
594 start_tok = "// EMSCRIPTEN_START_FUNCS"
595 end_tok = "// EMSCRIPTEN_END_FUNCS"
596 start_off = 0
597 end_off = 0
598
599 js = read_file(javascript_file)
600 blob = "".join(js.splitlines())
601
602 start_off = blob.find(start_tok) + len(start_tok)
603 end_off = blob.find(end_tok)
604 asm_chunk = blob[start_off:end_off]
605 num_funcs = asm_chunk.count('function ')
606 return num_funcs
607
608 def count_wasm_contents(self, wasm_binary, what):
609 out = self.run_process([os.path.join(building.get_binaryen_bin(), 'wasm-opt'), wasm_binary, '--metrics'], stdout=PIPE).stdout
610 # output is something like
611 # [?] : 125
612 for line in out.splitlines():
613 if '[' + what + ']' in line:
614 ret = line.split(':')[1].strip()
615 return int(ret)
616 self.fail('Failed to find [%s] in wasm-opt output' % what)
617
618 def get_wasm_text(self, wasm_binary):
619 return self.run_process([os.path.join(building.get_binaryen_bin(), 'wasm-dis'), wasm_binary], stdout=PIPE).stdout
620
621 def is_exported_in_wasm(self, name, wasm):
622 wat = self.get_wasm_text(wasm)
623 return ('(export "%s"' % name) in wat
624
625 def run_js(self, filename, engine=None, args=[], output_nicerizer=None, assert_returncode=0):
626 # use files, as PIPE can get too full and hang us
627 stdout = self.in_dir('stdout')
628 stderr = self.in_dir('stderr')
629 error = None
630 if not engine:
631 engine = self.js_engines[0]
632 if engine == config.NODE_JS:
633 engine = engine + self.node_args
634 if engine == config.V8_ENGINE:
635 engine = engine + self.v8_args
636 if EMTEST_VERBOSE:
637 print(f"Running '{filename}' under '{shared.shlex_join(engine)}'")
638 try:
639 jsrun.run_js(filename, engine, args,
640 stdout=open(stdout, 'w'),
641 stderr=open(stderr, 'w'),
642 assert_returncode=assert_returncode)
643 except subprocess.CalledProcessError as e:
644 error = e
645
646 # Make sure that we produced proper line endings to the .js file we are about to run.
647 if not filename.endswith('.wasm'):
648 self.assertEqual(line_endings.check_line_endings(filename), 0)
649
650 out = read_file(stdout)
651 err = read_file(stderr)
652 if output_nicerizer:
653 ret = output_nicerizer(out, err)
654 else:
655 ret = out + err
656 if error or EMTEST_VERBOSE:
657 ret = limit_size(ret)
658 print('-- begin program output --')
659 print(ret, end='')
660 print('-- end program output --')
661 if error:
662 if assert_returncode == NON_ZERO:
663 self.fail('JS subprocess unexpectedly succeeded (%s): Output:\n%s' % (error.cmd, ret))
664 else:
665 self.fail('JS subprocess failed (%s): %s. Output:\n%s' % (error.cmd, error.returncode, ret))
666
667 # We should pass all strict mode checks
668 self.assertNotContained('strict warning:', ret)
669 return ret
670
671 def assertExists(self, filename, msg=None):
672 if not msg:
673 msg = 'Expected file not found: ' + filename
674 self.assertTrue(os.path.exists(filename), msg)
675
676 def assertNotExists(self, filename, msg=None):
677 if not msg:
678 msg = 'Unexpected file exists: ' + filename
679 self.assertFalse(os.path.exists(filename), msg)
680
681 # Tests that the given two paths are identical, modulo path delimiters. E.g. "C:/foo" is equal to "C:\foo".
682 def assertPathsIdentical(self, path1, path2):
683 path1 = path1.replace('\\', '/')
684 path2 = path2.replace('\\', '/')
685 return self.assertIdentical(path1, path2)
686
687 # Tests that the given two multiline text content are identical, modulo line
688 # ending differences (\r\n on Windows, \n on Unix).
689 def assertTextDataIdentical(self, text1, text2, msg=None,
690 fromfile='expected', tofile='actual'):
691 text1 = text1.replace('\r\n', '\n')
692 text2 = text2.replace('\r\n', '\n')
693 return self.assertIdentical(text1, text2, msg, fromfile, tofile)
694
695 def assertIdentical(self, values, y, msg=None,
696 fromfile='expected', tofile='actual'):
697 if type(values) not in (list, tuple):
698 values = [values]
699 for x in values:
700 if x == y:
701 return # success
702 diff_lines = difflib.unified_diff(x.splitlines(), y.splitlines(),
703 fromfile=fromfile, tofile=tofile)
704 diff = ''.join([a.rstrip() + '\n' for a in diff_lines])
705 if EMTEST_VERBOSE:
706 print("Expected to have '%s' == '%s'" % (limit_size(values[0]), limit_size(y)))
707 fail_message = 'Unexpected difference:\n' + limit_size(diff)
708 if not EMTEST_VERBOSE:
709 fail_message += '\nFor full output run with EMTEST_VERBOSE=1.'
710 if msg:
711 fail_message += '\n' + msg
712 self.fail(fail_message)
713
714 def assertTextDataContained(self, text1, text2):
715 text1 = text1.replace('\r\n', '\n')
716 text2 = text2.replace('\r\n', '\n')
717 return self.assertContained(text1, text2)
718
719 def assertContained(self, values, string, additional_info=''):
720 if type(values) not in [list, tuple]:
721 values = [values]
722 if callable(string):
723 string = string()
724
725 if not any(v in string for v in values):
726 diff = difflib.unified_diff(values[0].split('\n'), string.split('\n'), fromfile='expected', tofile='actual')
727 diff = ''.join(a.rstrip() + '\n' for a in diff)
728 self.fail("Expected to find '%s' in '%s', diff:\n\n%s\n%s" % (
729 limit_size(values[0]), limit_size(string), limit_size(diff),
730 additional_info
731 ))
732
733 def assertNotContained(self, value, string):
734 if callable(value):
735 value = value() # lazy loading
736 if callable(string):
737 string = string()
738 if value in string:
739 self.fail("Expected to NOT find '%s' in '%s', diff:\n\n%s" % (
740 limit_size(value), limit_size(string),
741 limit_size(''.join([a.rstrip() + '\n' for a in difflib.unified_diff(value.split('\n'), string.split('\n'), fromfile='expected', tofile='actual')]))
742 ))
743
744 def assertContainedIf(self, value, string, condition):
745 if condition:
746 self.assertContained(value, string)
747 else:
748 self.assertNotContained(value, string)
749
750 def assertBinaryEqual(self, file1, file2):
751 self.assertEqual(os.path.getsize(file1),
752 os.path.getsize(file2))
753 self.assertEqual(read_binary(file1),
754 read_binary(file2))
755
756 library_cache = {}
757
758 def get_build_dir(self):
759 ret = os.path.join(self.get_dir(), 'building')
760 ensure_dir(ret)
761 return ret
762
763 def get_library(self, name, generated_libs, configure=['sh', './configure'],
764 configure_args=[], make=['make'], make_args=None,
765 env_init=None, cache_name_extra='', native=False):
766 if env_init is None:
767 env_init = {}
768 if make_args is None:
769 make_args = ['-j', str(shared.get_num_cores())]
770
771 build_dir = self.get_build_dir()
772 output_dir = self.get_dir()
773
774 emcc_args = self.get_emcc_args()
775
776 hash_input = (str(emcc_args) + ' $ ' + str(env_init)).encode('utf-8')
777 cache_name = name + ','.join([opt for opt in emcc_args if len(opt) < 7]) + '_' + hashlib.md5(hash_input).hexdigest() + cache_name_extra
778
779 valid_chars = "_%s%s" % (string.ascii_letters, string.digits)
780 cache_name = ''.join([(c if c in valid_chars else '_') for c in cache_name])
781
782 if self.library_cache.get(cache_name):
783 print('<load %s from cache> ' % cache_name, file=sys.stderr)
784 generated_libs = []
785 for basename, contents in self.library_cache[cache_name]:
786 bc_file = os.path.join(build_dir, cache_name + '_' + basename)
787 with open(bc_file, 'wb') as f:
788 f.write(contents)
789 generated_libs.append(bc_file)
790 return generated_libs
791
792 print(f'<building and saving {cache_name} into cache>', file=sys.stderr)
793 if configure is not None:
794 # Avoid += so we don't mutate the default arg
795 configure = configure + configure_args
796
797 cflags = ' '.join(self.get_emcc_args())
798 env_init.setdefault('CFLAGS', cflags)
799 env_init.setdefault('CXXFLAGS', cflags)
800 return build_library(name, build_dir, output_dir, generated_libs, configure,
801 make, make_args, self.library_cache,
802 cache_name, env_init=env_init, native=native)
803
804 def clear(self):
805 delete_contents(self.get_dir())
806 if EMSCRIPTEN_TEMP_DIR:
807 delete_contents(EMSCRIPTEN_TEMP_DIR)
808
809 def run_process(self, cmd, check=True, **args):
810 # Wrapper around shared.run_process. This is desirable so that the tests
811 # can fail (in the unittest sense) rather than error'ing.
812 # In the long run it would nice to completely remove the dependency on
813 # core emscripten code (shared.py) here.
814 try:
815 return shared.run_process(cmd, check=check, **args)
816 except subprocess.CalledProcessError as e:
817 if check and e.returncode != 0:
818 self.fail('subprocess exited with non-zero return code(%d): `%s`' %
819 (e.returncode, shared.shlex_join(cmd)))
820
821 def emcc(self, filename, args=[], output_filename=None, **kwargs):
822 if output_filename is None:
823 output_filename = filename + '.o'
824 try_delete(output_filename)
825 self.run_process([compiler_for(filename), filename] + args + ['-o', output_filename], **kwargs)
826
827 # Shared test code between main suite and others
828
829 def expect_fail(self, cmd, **args):
830 """Run a subprocess and assert that it returns non-zero.
831
832 Return the stderr of the subprocess.
833 """
834 proc = self.run_process(cmd, check=False, stderr=PIPE, **args)
835 self.assertNotEqual(proc.returncode, 0, 'subprocess unexpectedly succeeded. stderr:\n' + proc.stderr)
836 # When we check for failure we expect a user-visible error, not a traceback.
837 # However, on windows a python traceback can happen randomly sometimes,
838 # due to "Access is denied" https://github.com/emscripten-core/emscripten/issues/718
839 if not WINDOWS or 'Access is denied' not in proc.stderr:
840 self.assertNotContained('Traceback', proc.stderr)
841 return proc.stderr
842
843 # excercise dynamic linker.
844 #
845 # test that linking to shared library B, which is linked to A, loads A as well.
846 # main is also linked to C, which is also linked to A. A is loaded/initialized only once.
847 #
848 # B
849 # main < > A
850 # C
851 #
852 # this test is used by both test_core and test_browser.
853 # when run under broswer it excercises how dynamic linker handles concurrency
854 # - because B and C are loaded in parallel.
855 def _test_dylink_dso_needed(self, do_run):
856 create_file('liba.cpp', r'''
857 #include <stdio.h>
858 #include <emscripten.h>
859
860 static const char *afunc_prev;
861
862 extern "C" {
863 EMSCRIPTEN_KEEPALIVE void afunc(const char *s);
864 }
865
866 void afunc(const char *s) {
867 printf("a: %s (prev: %s)\n", s, afunc_prev);
868 afunc_prev = s;
869 }
870
871 struct ainit {
872 ainit() {
873 puts("a: loaded");
874 }
875 };
876
877 static ainit _;
878 ''')
879
880 create_file('libb.c', r'''
881 #include <emscripten.h>
882
883 void afunc(const char *s);
884
885 EMSCRIPTEN_KEEPALIVE void bfunc() {
886 afunc("b");
887 }
888 ''')
889
890 create_file('libc.c', r'''
891 #include <emscripten.h>
892
893 void afunc(const char *s);
894
895 EMSCRIPTEN_KEEPALIVE void cfunc() {
896 afunc("c");
897 }
898 ''')
899
900 # _test_dylink_dso_needed can be potentially called several times by a test.
901 # reset dylink-related options first.
902 self.clear_setting('MAIN_MODULE')
903 self.clear_setting('SIDE_MODULE')
904
905 # XXX in wasm each lib load currently takes 5MB; default INITIAL_MEMORY=16MB is thus not enough
906 self.set_setting('INITIAL_MEMORY', '32mb')
907
908 so = '.wasm' if self.is_wasm() else '.js'
909
910 def ccshared(src, linkto=[]):
911 cmdv = [EMCC, src, '-o', shared.unsuffixed(src) + so, '-s', 'SIDE_MODULE'] + self.get_emcc_args()
912 cmdv += linkto
913 self.run_process(cmdv)
914
915 ccshared('liba.cpp')
916 ccshared('libb.c', ['liba' + so])
917 ccshared('libc.c', ['liba' + so])
918
919 self.set_setting('MAIN_MODULE')
920 extra_args = ['-L.', 'libb' + so, 'libc' + so]
921 do_run(r'''
922 #ifdef __cplusplus
923 extern "C" {
924 #endif
925 void bfunc();
926 void cfunc();
927 #ifdef __cplusplus
928 }
929 #endif
930
931 int test_main() {
932 bfunc();
933 cfunc();
934 return 0;
935 }
936 ''',
937 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n', emcc_args=extra_args)
938
939 for libname in ['liba', 'libb', 'libc']:
940 self.emcc_args += ['--embed-file', libname + so]
941 do_run(r'''
942 #include <assert.h>
943 #include <dlfcn.h>
944 #include <stddef.h>
945
946 int test_main() {
947 void *bdso, *cdso;
948 void (*bfunc_ptr)(), (*cfunc_ptr)();
949
950 // FIXME for RTLD_LOCAL binding symbols to loaded lib is not currently working
951 bdso = dlopen("libb%(so)s", RTLD_NOW|RTLD_GLOBAL);
952 assert(bdso != NULL);
953 cdso = dlopen("libc%(so)s", RTLD_NOW|RTLD_GLOBAL);
954 assert(cdso != NULL);
955
956 bfunc_ptr = (void (*)())dlsym(bdso, "bfunc");
957 assert(bfunc_ptr != NULL);
958 cfunc_ptr = (void (*)())dlsym(cdso, "cfunc");
959 assert(cfunc_ptr != NULL);
960
961 bfunc_ptr();
962 cfunc_ptr();
963 return 0;
964 }
965 ''' % locals(),
966 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n')
967
968 def filtered_js_engines(self, js_engines=None):
969 if js_engines is None:
970 js_engines = self.js_engines
971 for engine in js_engines:
972 assert engine in config.JS_ENGINES, "js engine does not exist in config.JS_ENGINES"
973 assert type(engine) == list
974 for engine in self.banned_js_engines:
975 assert type(engine) in (list, type(None))
976 banned = [b[0] for b in self.banned_js_engines if b]
977 return [engine for engine in js_engines if engine and engine[0] not in banned]
978
979 def do_run(self, src, expected_output, force_c=False, **kwargs):
980 if 'no_build' in kwargs:
981 filename = src
982 else:
983 if force_c:
984 filename = 'src.c'
985 else:
986 filename = 'src.cpp'
987 with open(filename, 'w') as f:
988 f.write(src)
989 self._build_and_run(filename, expected_output, **kwargs)
990
991 def do_runf(self, filename, expected_output=None, **kwargs):
992 self._build_and_run(filename, expected_output, **kwargs)
993
994 ## Just like `do_run` but with filename of expected output
995 def do_run_from_file(self, filename, expected_output_filename, **kwargs):
996 self._build_and_run(filename, read_file(expected_output_filename), **kwargs)
997
998 def do_run_in_out_file_test(self, *path, **kwargs):
999 srcfile = test_file(*path)
1000 out_suffix = kwargs.pop('out_suffix', '')
1001 outfile = shared.unsuffixed(srcfile) + out_suffix + '.out'
1002 expected = read_file(outfile)
1003 self._build_and_run(srcfile, expected, **kwargs)
1004
1005 ## Does a complete test - builds, runs, checks output, etc.
1006 def _build_and_run(self, filename, expected_output, args=[], output_nicerizer=None,
1007 no_build=False,
1008 js_engines=None, libraries=[],
1009 includes=[],
1010 assert_returncode=0, assert_identical=False, assert_all=False,
1011 check_for_error=True, force_c=False, emcc_args=[]):
1012 logger.debug(f'_build_and_run: {filename}')
1013
1014 if no_build:
1015 js_file = filename
1016 else:
1017 self.build(filename, libraries=libraries, includes=includes,
1018 force_c=force_c, emcc_args=emcc_args)
1019 js_file = shared.unsuffixed(os.path.basename(filename)) + '.js'
1020 self.assertExists(js_file)
1021
1022 engines = self.filtered_js_engines(js_engines)
1023 if len(engines) > 1 and not self.use_all_engines:
1024 engines = engines[:1]
1025 # In standalone mode, also add wasm vms as we should be able to run there too.
1026 if self.get_setting('STANDALONE_WASM'):
1027 # TODO once standalone wasm support is more stable, apply use_all_engines
1028 # like with js engines, but for now as we bring it up, test in all of them
1029 if not self.wasm_engines:
1030 logger.warning('no wasm engine was found to run the standalone part of this test')
1031 engines += self.wasm_engines
1032 if self.get_setting('WASM2C') and not EMTEST_LACKS_NATIVE_CLANG:
1033 # compile the c file to a native executable.
1034 c = shared.unsuffixed(js_file) + '.wasm.c'
1035 executable = shared.unsuffixed(js_file) + '.exe'
1036 cmd = [shared.CLANG_CC, c, '-o', executable] + clang_native.get_clang_native_args()
1037 self.run_process(cmd, env=clang_native.get_clang_native_env())
1038 # we can now run the executable directly, without an engine, which
1039 # we indicate with None as the engine
1040 engines += [[None]]
1041 if len(engines) == 0:
1042 self.skipTest('No JS engine present to run this test with. Check %s and the paths therein.' % config.EM_CONFIG)
1043 for engine in engines:
1044 js_output = self.run_js(js_file, engine, args, output_nicerizer=output_nicerizer, assert_returncode=assert_returncode)
1045 js_output = js_output.replace('\r\n', '\n')
1046 if expected_output:
1047 try:
1048 if assert_identical:
1049 self.assertIdentical(expected_output, js_output)
1050 elif assert_all:
1051 for o in expected_output:
1052 self.assertContained(o, js_output)
1053 else:
1054 self.assertContained(expected_output, js_output)
1055 if check_for_error:
1056 self.assertNotContained('ERROR', js_output)
1057 except Exception:
1058 print('(test did not pass in JS engine: %s)' % engine)
1059 raise
1060
1061 def get_freetype_library(self):
1062 if '-Werror' in self.emcc_args:
1063 self.emcc_args.remove('-Werror')
1064 return self.get_library(os.path.join('third_party', 'freetype'), os.path.join('objs', '.libs', 'libfreetype.a'), configure_args=['--disable-shared', '--without-zlib'])
1065
1066 def get_poppler_library(self, env_init=None):
1067 # The fontconfig symbols are all missing from the poppler build
1068 # e.g. FcConfigSubstitute
1069 self.set_setting('ERROR_ON_UNDEFINED_SYMBOLS', 0)
1070
1071 self.emcc_args += [
1072 '-I' + test_file('third_party/freetype/include'),
1073 '-I' + test_file('third_party/poppler/include')
1074 ]
1075
1076 freetype = self.get_freetype_library()
1077
1078 # Poppler has some pretty glaring warning. Suppress them to keep the
1079 # test output readable.
1080 if '-Werror' in self.emcc_args:
1081 self.emcc_args.remove('-Werror')
1082 self.emcc_args += [
1083 '-Wno-sentinel',
1084 '-Wno-logical-not-parentheses',
1085 '-Wno-unused-private-field',
1086 '-Wno-tautological-compare',
1087 '-Wno-unknown-pragmas',
1088 ]
1089 env_init = env_init.copy() if env_init else {}
1090 env_init['FONTCONFIG_CFLAGS'] = ' '
1091 env_init['FONTCONFIG_LIBS'] = ' '
1092
1093 poppler = self.get_library(
1094 os.path.join('third_party', 'poppler'),
1095 [os.path.join('utils', 'pdftoppm.o'), os.path.join('utils', 'parseargs.o'), os.path.join('poppler', '.libs', 'libpoppler.a')],
1096 env_init=env_init,
1097 configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--disable-shared'])
1098
1099 return poppler + freetype
1100
1101 def get_zlib_library(self):
1102 if WINDOWS:
1103 return self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'),
1104 configure=['cmake', '.'],
1105 make=['cmake', '--build', '.'],
1106 make_args=[])
1107 return self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'), make_args=['libz.a'])
1108
1109
1110 # Run a server and a web page. When a test runs, we tell the server about it,
1111 # which tells the web page, which then opens a window with the test. Doing
1112 # it this way then allows the page to close() itself when done.
1113 def harness_server_func(in_queue, out_queue, port):
1114 class TestServerHandler(SimpleHTTPRequestHandler):
1115 # Request header handler for default do_GET() path in
1116 # SimpleHTTPRequestHandler.do_GET(self) below.
1117 def send_head(self):
1118 if self.path.endswith('.js'):
1119 path = self.translate_path(self.path)
1120 try:
1121 f = open(path, 'rb')
1122 except IOError:
1123 self.send_error(404, "File not found: " + path)
1124 return None
1125 self.send_response(200)
1126 self.send_header('Content-type', 'application/javascript')
1127 self.send_header('Connection', 'close')
1128 self.end_headers()
1129 return f
1130 else:
1131 return SimpleHTTPRequestHandler.send_head(self)
1132
1133 # Add COOP, COEP, CORP, and no-caching headers
1134 def end_headers(self):
1135 self.send_header('Access-Control-Allow-Origin', '*')
1136 self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
1137 self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
1138 self.send_header('Cross-Origin-Resource-Policy', 'cross-origin')
1139 self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
1140 return SimpleHTTPRequestHandler.end_headers(self)
1141
1142 def do_GET(self):
1143 if self.path == '/run_harness':
1144 if DEBUG:
1145 print('[server startup]')
1146 self.send_response(200)
1147 self.send_header('Content-type', 'text/html')
1148 self.end_headers()
1149 self.wfile.write(read_binary(test_file('browser_harness.html')))
1150 elif 'report_' in self.path:
1151 # the test is reporting its result. first change dir away from the
1152 # test dir, as it will be deleted now that the test is finishing, and
1153 # if we got a ping at that time, we'd return an error
1154 os.chdir(path_from_root())
1155 # for debugging, tests may encode the result and their own url (window.location) as result|url
1156 if '|' in self.path:
1157 path, url = self.path.split('|', 1)
1158 else:
1159 path = self.path
1160 url = '?'
1161 if DEBUG:
1162 print('[server response:', path, url, ']')
1163 if out_queue.empty():
1164 out_queue.put(path)
1165 else:
1166 # a badly-behaving test may send multiple xhrs with reported results; we just care
1167 # about the first (if we queued the others, they might be read as responses for
1168 # later tests, or maybe the test sends more than one in a racy manner).
1169 # we place 'None' in the queue here so that the outside knows something went wrong
1170 # (none is not a valid value otherwise; and we need the outside to know because if we
1171 # raise an error in here, it is just swallowed in python's webserver code - we want
1172 # the test to actually fail, which a webserver response can't do).
1173 out_queue.put(None)
1174 raise Exception('browser harness error, excessive response to server - test must be fixed! "%s"' % self.path)
1175 self.send_response(200)
1176 self.send_header('Content-type', 'text/plain')
1177 self.send_header('Cache-Control', 'no-cache, must-revalidate')
1178 self.send_header('Connection', 'close')
1179 self.send_header('Expires', '-1')
1180 self.end_headers()
1181 self.wfile.write(b'OK')
1182
1183 elif 'stdout=' in self.path or 'stderr=' in self.path or 'exception=' in self.path:
1184 '''
1185 To get logging to the console from browser tests, add this to
1186 print/printErr/the exception handler in src/shell.html:
1187
1188 var xhr = new XMLHttpRequest();
1189 xhr.open('GET', encodeURI('http://localhost:8888?stdout=' + text));
1190 xhr.send();
1191 '''
1192 print('[client logging:', unquote_plus(self.path), ']')
1193 self.send_response(200)
1194 self.send_header('Content-type', 'text/html')
1195 self.end_headers()
1196 elif self.path == '/check':
1197 self.send_response(200)
1198 self.send_header('Content-type', 'text/html')
1199 self.end_headers()
1200 if not in_queue.empty():
1201 # there is a new test ready to be served
1202 url, dir = in_queue.get()
1203 if DEBUG:
1204 print('[queue command:', url, dir, ']')
1205 assert in_queue.empty(), 'should not be any blockage - one test runs at a time'
1206 assert out_queue.empty(), 'the single response from the last test was read'
1207 # tell the browser to load the test
1208 self.wfile.write(b'COMMAND:' + url.encode('utf-8'))
1209 # move us to the right place to serve the files for the new test
1210 os.chdir(dir)
1211 else:
1212 # the browser must keep polling
1213 self.wfile.write(b'(wait)')
1214 else:
1215 # Use SimpleHTTPServer default file serving operation for GET.
1216 if DEBUG:
1217 print('[simple HTTP serving:', unquote_plus(self.path), ']')
1218 SimpleHTTPRequestHandler.do_GET(self)
1219
1220 def log_request(code=0, size=0):
1221 # don't log; too noisy
1222 pass
1223
1224 # allows streaming compilation to work
1225 SimpleHTTPRequestHandler.extensions_map['.wasm'] = 'application/wasm'
1226
1227 httpd = HTTPServer(('localhost', port), TestServerHandler)
1228 httpd.serve_forever() # test runner will kill us
1229
1230
1231 class Reporting(Enum):
1232 """When running browser tests we normally automatically include support
1233 code for reporting results back to the browser. This enum allows tests
1234 to decide what type of support code they need/want.
1235 """
1236 NONE = 0
1237 # Include the JS helpers for reporting results
1238 JS_ONLY = 1
1239 # Include C/C++ reporting code (REPORT_RESULT mactros) as well as JS helpers
1240 FULL = 2
1241
1242
1243 class BrowserCore(RunnerCore):
1244 # note how many tests hang / do not send an output. if many of these
1245 # happen, likely something is broken and it is best to abort the test
1246 # suite early, as otherwise we will wait for the timeout on every
1247 # single test (hundreds of minutes)
1248 MAX_UNRESPONSIVE_TESTS = 10
1249
1250 unresponsive_tests = 0
1251
1252 def __init__(self, *args, **kwargs):
1253 super().__init__(*args, **kwargs)
1254
1255 @staticmethod
1256 def browser_open(url):
1257 if not EMTEST_BROWSER:
1258 logger.info('Using default system browser')
1259 webbrowser.open_new(url)
1260 return
1261
1262 browser_args = shlex.split(EMTEST_BROWSER)
1263 # If the given browser is a scalar, treat it like one of the possible types
1264 # from https://docs.python.org/2/library/webbrowser.html
1265 if len(browser_args) == 1:
1266 try:
1267 # This throws if the type of browser isn't available
1268 webbrowser.get(browser_args[0]).open_new(url)
1269 logger.info('Using Emscripten browser: %s', browser_args[0])
1270 return
1271 except webbrowser.Error:
1272 # Ignore the exception and fallback to the custom command logic
1273 pass
1274 # Else assume the given browser is a specific program with additional
1275 # parameters and delegate to that
1276 logger.info('Using Emscripten browser: %s', str(browser_args))
1277 subprocess.Popen(browser_args + [url])
1278
1279 @classmethod
1280 def setUpClass(cls):
1281 super().setUpClass()
1282 cls.also_asmjs = int(os.getenv('EMTEST_BROWSER_ALSO_ASMJS', '0')) == 1
1283 cls.port = int(os.getenv('EMTEST_BROWSER_PORT', '8888'))
1284 if not has_browser():
1285 return
1286 cls.browser_timeout = 60
1287 cls.harness_in_queue = multiprocessing.Queue()
1288 cls.harness_out_queue = multiprocessing.Queue()
1289 cls.harness_server = multiprocessing.Process(target=harness_server_func, args=(cls.harness_in_queue, cls.harness_out_queue, cls.port))
1290 cls.harness_server.start()
1291 print('[Browser harness server on process %d]' % cls.harness_server.pid)
1292 cls.browser_open('http://localhost:%s/run_harness' % cls.port)
1293
1294 @classmethod
1295 def tearDownClass(cls):
1296 super().tearDownClass()
1297 if not has_browser():
1298 return
1299 cls.harness_server.terminate()
1300 print('[Browser harness server terminated]')
1301 if WINDOWS:
1302 # On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit:
1303 # WindowsError: [Error 32] The process cannot access the file because it is being used by another process.
1304 time.sleep(0.1)
1305
1306 def assert_out_queue_empty(self, who):
1307 if not self.harness_out_queue.empty():
1308 while not self.harness_out_queue.empty():
1309 self.harness_out_queue.get()
1310 raise Exception('excessive responses from %s' % who)
1311
1312 # @param extra_tries: how many more times to try this test, if it fails. browser tests have
1313 # many more causes of flakiness (in particular, they do not run
1314 # synchronously, so we have a timeout, which can be hit if the VM
1315 # we run on stalls temporarily), so we let each test try more than
1316 # once by default
1317 def run_browser(self, html_file, message, expectedResult=None, timeout=None, extra_tries=1):
1318 if not has_browser():
1319 return
1320 if BrowserCore.unresponsive_tests >= BrowserCore.MAX_UNRESPONSIVE_TESTS:
1321 self.skipTest('too many unresponsive tests, skipping browser launch - check your setup!')
1322 self.assert_out_queue_empty('previous test')
1323 if DEBUG:
1324 print('[browser launch:', html_file, ']')
1325 if expectedResult is not None:
1326 try:
1327 self.harness_in_queue.put((
1328 'http://localhost:%s/%s' % (self.port, html_file),
1329 self.get_dir()
1330 ))
1331 received_output = False
1332 output = '[no http server activity]'
1333 start = time.time()
1334 if timeout is None:
1335 timeout = self.browser_timeout
1336 while time.time() - start < timeout:
1337 if not self.harness_out_queue.empty():
1338 output = self.harness_out_queue.get()
1339 received_output = True
1340 break
1341 time.sleep(0.1)
1342 if not received_output:
1343 BrowserCore.unresponsive_tests += 1
1344 print('[unresponsive tests: %d]' % BrowserCore.unresponsive_tests)
1345 if output is None:
1346 # the browser harness reported an error already, and sent a None to tell
1347 # us to also fail the test
1348 raise Exception('failing test due to browser harness error')
1349 if output.startswith('/report_result?skipped:'):
1350 self.skipTest(unquote(output[len('/report_result?skipped:'):]).strip())
1351 else:
1352 # verify the result, and try again if we should do so
1353 output = unquote(output)
1354 try:
1355 self.assertContained(expectedResult, output)
1356 except Exception as e:
1357 if extra_tries > 0:
1358 print('[test error (see below), automatically retrying]')
1359 print(e)
1360 return self.run_browser(html_file, message, expectedResult, timeout, extra_tries - 1)
1361 else:
1362 raise e
1363 finally:
1364 time.sleep(0.1) # see comment about Windows above
1365 self.assert_out_queue_empty('this test')
1366 else:
1367 webbrowser.open_new(os.path.abspath(html_file))
1368 print('A web browser window should have opened a page containing the results of a part of this test.')
1369 print('You need to manually look at the page to see that it works ok: ' + message)
1370 print('(sleeping for a bit to keep the directory alive for the web browser..)')
1371 time.sleep(5)
1372 print('(moving on..)')
1373
1374 # @manually_trigger If set, we do not assume we should run the reftest when main() is done.
1375 # Instead, call doReftest() in JS yourself at the right time.
1376 def reftest(self, expected, manually_trigger=False):
1377 # make sure the pngs used here have no color correction, using e.g.
1378 # pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile outfile
1379 basename = os.path.basename(expected)
1380 shutil.copyfile(expected, os.path.join(self.get_dir(), basename))
1381 reporting = read_file(test_file('browser_reporting.js'))
1382 with open('reftest.js', 'w') as out:
1383 out.write('''
1384 function doReftest() {
1385 if (doReftest.done) return;
1386 doReftest.done = true;
1387 var img = new Image();
1388 img.onload = function() {
1389 assert(img.width == Module.canvas.width, 'Invalid width: ' + Module.canvas.width + ', should be ' + img.width);
1390 assert(img.height == Module.canvas.height, 'Invalid height: ' + Module.canvas.height + ', should be ' + img.height);
1391
1392 var canvas = document.createElement('canvas');
1393 canvas.width = img.width;
1394 canvas.height = img.height;
1395 var ctx = canvas.getContext('2d');
1396 ctx.drawImage(img, 0, 0);
1397 var expected = ctx.getImageData(0, 0, img.width, img.height).data;
1398
1399 var actualUrl = Module.canvas.toDataURL();
1400 var actualImage = new Image();
1401 actualImage.onload = function() {
1402 /*
1403 document.body.appendChild(img); // for comparisons
1404 var div = document.createElement('div');
1405 div.innerHTML = '^=expected, v=actual';
1406 document.body.appendChild(div);
1407 document.body.appendChild(actualImage); // to grab it for creating the test reference
1408 */
1409
1410 var actualCanvas = document.createElement('canvas');
1411 actualCanvas.width = actualImage.width;
1412 actualCanvas.height = actualImage.height;
1413 var actualCtx = actualCanvas.getContext('2d');
1414 actualCtx.drawImage(actualImage, 0, 0);
1415 var actual = actualCtx.getImageData(0, 0, actualImage.width, actualImage.height).data;
1416
1417 var total = 0;
1418 var width = img.width;
1419 var height = img.height;
1420 for (var x = 0; x < width; x++) {
1421 for (var y = 0; y < height; y++) {
1422 total += Math.abs(expected[y*width*4 + x*4 + 0] - actual[y*width*4 + x*4 + 0]);
1423 total += Math.abs(expected[y*width*4 + x*4 + 1] - actual[y*width*4 + x*4 + 1]);
1424 total += Math.abs(expected[y*width*4 + x*4 + 2] - actual[y*width*4 + x*4 + 2]);
1425 }
1426 }
1427 var wrong = Math.floor(total / (img.width*img.height*3)); // floor, to allow some margin of error for antialiasing
1428 // If the main JS file is in a worker, or modularize, then we need to supply our own reporting logic.
1429 if (typeof reportResultToServer === 'undefined') {
1430 (function() {
1431 %s
1432 reportResultToServer(wrong);
1433 })();
1434 } else {
1435 reportResultToServer(wrong);
1436 }
1437 };
1438 actualImage.src = actualUrl;
1439 }
1440 img.src = '%s';
1441 };
1442
1443 // Automatically trigger the reftest?
1444 if (!%s) {
1445 // Yes, automatically
1446
1447 Module['postRun'] = doReftest;
1448
1449 if (typeof WebGLClient !== 'undefined') {
1450 // trigger reftest from RAF as well, needed for workers where there is no pre|postRun on the main thread
1451 var realRAF = window.requestAnimationFrame;
1452 window.requestAnimationFrame = /** @suppress{checkTypes} */ (function(func) {
1453 realRAF(function() {
1454 func();
1455 realRAF(doReftest);
1456 });
1457 });
1458
1459 // trigger reftest from canvas render too, for workers not doing GL
1460 var realWOM = worker.onmessage;
1461 worker.onmessage = function(event) {
1462 realWOM(event);
1463 if (event.data.target === 'canvas' && event.data.op === 'render') {
1464 realRAF(doReftest);
1465 }
1466 };
1467 }
1468
1469 } else {
1470 // Manually trigger the reftest.
1471
1472 // The user will call it.
1473 // Add an event loop iteration to ensure rendering, so users don't need to bother.
1474 var realDoReftest = doReftest;
1475 doReftest = function() {
1476 setTimeout(realDoReftest, 1);
1477 };
1478 }
1479 ''' % (reporting, basename, int(manually_trigger)))
1480
1481 def compile_btest(self, args, reporting=Reporting.FULL):
1482 # Inject support code for reporting results. This adds an include a header so testcases can
1483 # use REPORT_RESULT, and also adds a cpp file to be compiled alongside the testcase, which
1484 # contains the implementation of REPORT_RESULT (we can't just include that implementation in
1485 # the header as there may be multiple files being compiled here).
1486 args += ['-s', 'IN_TEST_HARNESS']
1487 if reporting != Reporting.NONE:
1488 # For basic reporting we inject JS helper funtions to report result back to server.
1489 args += ['-DEMTEST_PORT_NUMBER=%d' % self.port,
1490 '--pre-js', test_file('browser_reporting.js')]
1491 if reporting == Reporting.FULL:
1492 # If C reporting (i.e. REPORT_RESULT macro) is required
1493 # also compile in report_result.cpp and forice-include report_result.h
1494 args += ['-I' + TEST_ROOT,
1495 '-include', test_file('report_result.h'),
1496 test_file('report_result.cpp')]
1497 self.run_process([EMCC] + self.get_emcc_args() + args)
1498
1499 def btest_exit(self, filename, assert_returncode=0, *args, **kwargs):
1500 """Special case of btest that reports its result solely via exiting
1501 with a give result code.
1502
1503 In this case we set EXIT_RUNTIME and we don't need to provide the
1504 REPORT_RESULT macro to the C code.
1505 """
1506 self.set_setting('EXIT_RUNTIME')
1507 kwargs['reporting'] = Reporting.JS_ONLY
1508 kwargs['expected'] = 'exit:%d' % assert_returncode
1509 return self.btest(filename, *args, **kwargs)
1510
1511 def btest(self, filename, expected=None, reference=None,
1512 reference_slack=0, manual_reference=False, post_build=None,
1513 args=None, message='.', also_proxied=False,
1514 url_suffix='', timeout=None, also_asmjs=False,
1515 manually_trigger_reftest=False, extra_tries=1,
1516 reporting=Reporting.FULL):
1517 assert expected or reference, 'a btest must either expect an output, or have a reference image'
1518 if args is None:
1519 args = []
1520 original_args = args.copy()
1521 if not os.path.exists(filename):
1522 filename = test_file(filename)
1523 if reference:
1524 self.reference = reference
1525 expected = [str(i) for i in range(0, reference_slack + 1)]
1526 self.reftest(test_file(reference), manually_trigger=manually_trigger_reftest)
1527 if not manual_reference:
1528 args += ['--pre-js', 'reftest.js', '-s', 'GL_TESTING']
1529 outfile = 'test.html'
1530 args += [filename, '-o', outfile]
1531 # print('all args:', args)
1532 try_delete(outfile)
1533 self.compile_btest(args, reporting=reporting)
1534 self.assertExists(outfile)
1535 if post_build:
1536 post_build()
1537 if not isinstance(expected, list):
1538 expected = [expected]
1539 self.run_browser(outfile + url_suffix, message, ['/report_result?' + e for e in expected], timeout=timeout, extra_tries=extra_tries)
1540
1541 # Tests can opt into being run under asmjs as well
1542 if 'WASM=0' not in original_args and (also_asmjs or self.also_asmjs):
1543 print('WASM=0')
1544 self.btest(filename, expected, reference, reference_slack, manual_reference, post_build,
1545 original_args + ['-s', 'WASM=0'], message, also_proxied=False, timeout=timeout)
1546
1547 if also_proxied:
1548 print('proxied...')
1549 if reference:
1550 assert not manual_reference
1551 manual_reference = True
1552 assert not post_build
1553 post_build = self.post_manual_reftest
1554 # run proxied
1555 self.btest(filename, expected, reference, reference_slack, manual_reference, post_build,
1556 original_args + ['--proxy-to-worker', '-s', 'GL_TESTING'], message, timeout=timeout)
1557
1558
1559 ###################################################################################################
1560
1561
1562 def build_library(name,
1563 build_dir,
1564 output_dir,
1565 generated_libs,
1566 configure=['sh', './configure'],
1567 make=['make'],
1568 make_args=[],
1569 cache=None,
1570 cache_name=None,
1571 env_init={},
1572 native=False):
1573 """Build a library and cache the result. We build the library file
1574 once and cache it for all our tests. (We cache in memory since the test
1575 directory is destroyed and recreated for each test. Note that we cache
1576 separately for different compilers). This cache is just during the test
1577 runner. There is a different concept of caching as well, see |Cache|.
1578 """
1579
1580 if type(generated_libs) is not list:
1581 generated_libs = [generated_libs]
1582 source_dir = test_file(name.replace('_native', ''))
1583
1584 project_dir = Path(build_dir, name)
1585 if os.path.exists(project_dir):
1586 shutil.rmtree(project_dir)
1587 # Useful in debugging sometimes to comment this out, and two lines above
1588 shutil.copytree(source_dir, project_dir)
1589
1590 generated_libs = [os.path.join(project_dir, lib) for lib in generated_libs]
1591
1592 if native:
1593 env = clang_native.get_clang_native_env()
1594 else:
1595 env = os.environ.copy()
1596 env.update(env_init)
1597
1598 if configure:
1599 if configure[0] == 'cmake':
1600 configure = [EMCMAKE] + configure
1601 else:
1602 configure = [EMCONFIGURE] + configure
1603 try:
1604 with open(os.path.join(project_dir, 'configure_out'), 'w') as out:
1605 with open(os.path.join(project_dir, 'configure_err'), 'w') as err:
1606 stdout = out if EM_BUILD_VERBOSE < 2 else None
1607 stderr = err if EM_BUILD_VERBOSE < 1 else None
1608 shared.run_process(configure, env=env, stdout=stdout, stderr=stderr,
1609 cwd=project_dir)
1610 except subprocess.CalledProcessError:
1611 print('-- configure stdout --')
1612 print(read_file(Path(project_dir, 'configure_out')))
1613 print('-- end configure stdout --')
1614 print('-- configure stderr --')
1615 print(read_file(Path(project_dir, 'configure_err')))
1616 print('-- end configure stderr --')
1617 raise
1618 # if we run configure or cmake we don't then need any kind
1619 # of special env when we run make below
1620 env = None
1621
1622 def open_make_out(mode='r'):
1623 return open(os.path.join(project_dir, 'make.out'), mode)
1624
1625 def open_make_err(mode='r'):
1626 return open(os.path.join(project_dir, 'make.err'), mode)
1627
1628 if EM_BUILD_VERBOSE >= 3:
1629 make_args += ['VERBOSE=1']
1630
1631 try:
1632 with open_make_out('w') as make_out:
1633 with open_make_err('w') as make_err:
1634 stdout = make_out if EM_BUILD_VERBOSE < 2 else None
1635 stderr = make_err if EM_BUILD_VERBOSE < 1 else None
1636 shared.run_process(make + make_args, stdout=stdout, stderr=stderr, env=env,
1637 cwd=project_dir)
1638 except subprocess.CalledProcessError:
1639 with open_make_out() as f:
1640 print('-- make stdout --')
1641 print(f.read())
1642 print('-- end make stdout --')
1643 with open_make_err() as f:
1644 print('-- make stderr --')
1645 print(f.read())
1646 print('-- end stderr --')
1647 raise
1648
1649 if cache is not None:
1650 cache[cache_name] = []
1651 for f in generated_libs:
1652 basename = os.path.basename(f)
1653 cache[cache_name].append((basename, read_binary(f)))
1654
1655 return generated_libs
0 #include <assert.h>
1 #include <stdbool.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <emscripten/emscripten.h>
5
6 bool doneCallback = false;
7
8 void myatexit() {
9 printf("myatexit\n");
10 assert(doneCallback);
11 }
12
13 void callback(void *arg) {
14 printf("callback\n");
15 doneCallback = true;
16 assert((int)arg == 42);
17 // Runtime should exit after this callback returns
18 }
19
20 int main() {
21 atexit(myatexit);
22 // The runtime should stay alive long enough for the callbackl
23 // to run.
24 emscripten_async_call(callback, (void*)42, 500);
25 printf("returning from main\n");
26 return 0;
27 }
0 returning from main
1 callback
2 myatexit
6363 atexit(cleanup);
6464 setup();
6565 test();
66
67 #ifdef REPORT_RESULT
68 REPORT_RESULT(0);
69 #endif
70 return EXIT_SUCCESS;
66 return 0;
7167 }
0 // Copyright 2012 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <math.h>
8 #include <stdlib.h>
9 #include <SDL.h>
10 #include <emscripten.h>
11 #include <assert.h>
12
13 bool exit_ok = false;
14 int last = 0;
15
16 bool pre1ed = false;
17 bool pre2ed = false;
18 void pre1(void *arg) {
19 assert(!pre1ed);
20 assert(!pre2ed);
21 assert((int)arg == 123);
22 pre1ed = true;
23 }
24 void pre2(void *arg) {
25 assert(pre1ed);
26 assert(!pre2ed);
27 assert((int)arg == 98);
28 pre2ed = true;
29 }
30
31 bool fived = false;
32 void five(void *arg) {
33 assert((int)arg == 55);
34 fived = true;
35 emscripten_resume_main_loop();
36 }
37
38 void argey(void* arg) {
39 static int counter = 0;
40 assert((int)arg == 17);
41 counter++;
42 printf("argey: %d\n", counter);
43 if (counter == 5) {
44 emscripten_cancel_main_loop();
45 // The main loop is now done so its ok to run atexit handlers.
46 exit_ok = true;
47 exit(0);
48 }
49 }
50
51 void mainey() {
52 static int counter = 0;
53 printf("mainey: %d\n", counter++);
54 if (counter == 20) {
55 emscripten_pause_main_loop();
56 emscripten_async_call(five, (void*)55, 1000);
57 } else if (counter == 22) { // very soon after 20, so without pausing we fail
58 assert(fived);
59 emscripten_push_main_loop_blocker(pre1, (void*)123);
60 emscripten_push_main_loop_blocker(pre2, (void*)98);
61 } else if (counter == 23) {
62 assert(pre1ed);
63 assert(pre2ed);
64 printf("Good!\n");
65 emscripten_cancel_main_loop();
66 emscripten_set_main_loop_arg(argey, (void*)17, 0, 0);
67 }
68 }
69
70 void four(void *arg) {
71 assert((int)arg == 43);
72 printf("four!\n");
73 emscripten_set_main_loop(mainey, 0, 0);
74 }
75
76 void __attribute__((used)) third() {
77 int now = SDL_GetTicks();
78 printf("thard! %d\n", now);
79 assert(abs(now - last - 1000) < 500);
80 emscripten_async_call(four, (void*)43, -1); // triggers requestAnimationFrame
81 }
82
83 void second(void *arg) {
84 int now = SDL_GetTicks();
85 printf("sacond! %d\n", now);
86 assert(abs(now - last - 500) < 250);
87 last = now;
88 emscripten_async_run_script("Module._third()", 1000);
89 }
90
91 // Should not be called when main return but only once the
92 // main loops is stopped and the runtime shuts down.
93 void check_exit_ok() {
94 assert(exit_ok == true);
95 }
96
97 int main() {
98 SDL_Init(0);
99 last = SDL_GetTicks();
100 printf("frist! %d\n", last);
101
102 double ratio = emscripten_get_device_pixel_ratio();
103 double ratio2 = EM_ASM_DOUBLE({
104 return window.devicePixelRatio || 1.0;
105 });
106
107 assert(ratio == ratio2);
108
109 atexit(check_exit_ok);
110
111 emscripten_async_call(second, (void*)0, 500);
112
113 return 1;
114 }
115
+0
-114
tests/emscripten_api_browser.cpp less more
0 // Copyright 2012 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <math.h>
7 #include <stdlib.h>
8 #include <SDL.h>
9 #include <emscripten.h>
10 #include <assert.h>
11
12 int last = 0;
13
14 extern "C" {
15
16 bool pre1ed = false;
17 bool pre2ed = false;
18 void pre1(void *arg) {
19 assert(!pre1ed);
20 assert(!pre2ed);
21 assert((int)arg == 123);
22 pre1ed = true;
23 }
24 void pre2(void *arg) {
25 assert(pre1ed);
26 assert(!pre2ed);
27 assert((int)arg == 98);
28 pre2ed = true;
29 }
30
31 bool fived = false;
32 void five(void *arg) {
33 assert((int)arg == 55);
34 fived = true;
35 emscripten_resume_main_loop();
36 }
37
38 void argey(void* arg) {
39 static int counter = 0;
40 assert((int)arg == 17);
41 counter++;
42 printf("argey: %d\n", counter);
43 if (counter == 5) {
44 emscripten_cancel_main_loop();
45 REPORT_RESULT(1);
46 }
47 }
48
49 void mainey() {
50 static int counter = 0;
51 printf("mainey: %d\n", counter++);
52 if (counter == 20) {
53 emscripten_pause_main_loop();
54 emscripten_async_call(five, (void*)55, 1000);
55 } else if (counter == 22) { // very soon after 20, so without pausing we fail
56 assert(fived);
57 emscripten_push_main_loop_blocker(pre1, (void*)123);
58 emscripten_push_main_loop_blocker(pre2, (void*)98);
59 } else if (counter == 23) {
60 assert(pre1ed);
61 assert(pre2ed);
62 printf("Good!\n");
63 emscripten_cancel_main_loop();
64 emscripten_set_main_loop_arg(argey, (void*)17, 0, 0);
65 }
66 }
67
68 void four(void *arg) {
69 assert((int)arg == 43);
70 printf("four!\n");
71 emscripten_set_main_loop(mainey, 0, 0);
72 }
73
74 void __attribute__((used)) third() {
75 int now = SDL_GetTicks();
76 printf("thard! %d\n", now);
77 assert(fabs(now - last - 1000) < 500);
78 emscripten_async_call(four, (void*)43, -1); // triggers requestAnimationFrame
79 }
80
81 void second(void *arg) {
82 int now = SDL_GetTicks();
83 printf("sacond! %d\n", now);
84 assert(fabs(now - last - 500) < 250);
85 last = now;
86 emscripten_async_run_script("Module._third()", 1000);
87 }
88
89 }
90
91 void never() {
92 REPORT_RESULT(0);
93 }
94
95 int main() {
96 SDL_Init(0);
97 last = SDL_GetTicks();
98 printf("frist! %d\n", last);
99
100 double ratio = emscripten_get_device_pixel_ratio();
101 double ratio2 = EM_ASM_DOUBLE({
102 return window.devicePixelRatio || 1.0;
103 });
104
105 assert(ratio == ratio2);
106
107 atexit(never); // should never be called - it is wrong to exit the runtime orderly if we have async calls!
108
109 emscripten_async_call(second, (void*)0, 500);
110
111 return 1;
112 }
113
0 // Copyright 2013 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9
10 #include <emscripten.h>
11
12 int value = 0;
13
14 void set(int x) {
15 printf("set! %d\n", x);
16 value = x;
17 }
18
19 void load2() {
20 printf("load2\n");
21
22 char buffer[10];
23 memset(buffer, 0, 10);
24 FILE *f = fopen("file1.txt", "r");
25 fread(buffer, 1, 5, f);
26 fclose(f);
27 assert(strcmp(buffer, "first") == 0);
28
29 memset(buffer, 0, 10);
30 f = fopen("file2.txt", "r");
31 fread(buffer, 1, 6, f);
32 fclose(f);
33 assert(strcmp(buffer, "second") == 0);
34
35 exit(0);
36 }
37
38 void error2() {
39 printf("fail2\n");
40 }
41
42 void load1() {
43 printf("load1\n");
44 assert(value == 456);
45 emscripten_async_load_script("script2.js", load2, error2);
46 }
47
48 void error1() {
49 printf("fail1\n");
50 }
51
52 int main() {
53 emscripten_async_load_script("script1.js", load1, error1);
54 return 99;
55 }
+0
-57
tests/emscripten_api_browser2.cpp less more
0 // Copyright 2013 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <assert.h>
8
9 #include <emscripten.h>
10
11 int value = 0;
12
13 extern "C" {
14 void set(int x) {
15 printf("set! %d\n", x);
16 value = x;
17 }
18 }
19
20 void load2() {
21 printf("load2\n");
22
23 char buffer[10];
24 memset(buffer, 0, 10);
25 FILE *f = fopen("file1.txt", "r");
26 fread(buffer, 1, 5, f);
27 fclose(f);
28 assert(strcmp(buffer, "first") == 0);
29
30 memset(buffer, 0, 10);
31 f = fopen("file2.txt", "r");
32 fread(buffer, 1, 6, f);
33 fclose(f);
34 assert(strcmp(buffer, "second") == 0);
35
36 REPORT_RESULT(1);
37 }
38 void error2() {
39 printf("fail2\n");
40 }
41
42 void load1() {
43 printf("load1\n");
44 assert(value == 456);
45 emscripten_async_load_script("script2.js", load2, error2);
46 }
47 void error1() {
48 printf("fail1\n");
49 }
50
51 int main() {
52 emscripten_async_load_script("script1.js", load1, error1);
53
54 return 1;
55 }
56
33 // found in the LICENSE file.
44
55 #include <stdio.h>
6 #include <stdlib.h>
67 #include <string.h>
78 #include <emscripten.h>
89
1819 printf("waka %d\n", x++);
1920
2021 if (x == 7 || x < 0) {
21 REPORT_RESULT(x);
2222 emscripten_cancel_main_loop();
23 exit(x);
2324 }
2425 }
2526
0 #include <assert.h>
01 #include <stdio.h>
12 #include <emscripten/emscripten.h>
23
3 int main()
4 {
5 double devicePixelRatio = emscripten_get_device_pixel_ratio();
6 printf("window.devicePixelRatio = %f.\n", devicePixelRatio);
7 int result = (devicePixelRatio > 0) ? 1 : 0;
8 if (result) {
9 printf("Test succeeded!\n");
10 }
11 #ifdef REPORT_RESULT
12 REPORT_RESULT(result);
13 #endif
4 int main() {
5 double devicePixelRatio = emscripten_get_device_pixel_ratio();
6 printf("window.devicePixelRatio = %f.\n", devicePixelRatio);
7 assert(devicePixelRatio > 0);
8 return 0;
149 }
1212
1313 void final(void*) {
1414 assert(frame == 110);
15 #ifdef REPORT_RESULT
1615 printf("Test passed.\n");
17 REPORT_RESULT(0);
18 #endif
16 exit(0);
1917 }
2018
2119 void looper() {
2826 timesTooSoon++;
2927 if (timesTooSoon >= 10) {
3028 printf("Abort: main loop tick was called too quickly after the previous frame, too many times!\n");
31 #ifdef REPORT_RESULT
32 REPORT_RESULT(1);
33 #endif
3429 emscripten_cancel_main_loop();
35 exit(0);
30 exit(1);
3631 }
3732 }
3833 prevTime = curTime;
4136 timesTooSoon++;
4237 if (timesTooSoon >= 2) {
4338 printf("Abort: With swap interval of 4, we should be running at most 15fps! (or 30fps on 120Hz displays) but seems like swap control is not working and we are running at 60fps!\n");
44 #ifdef REPORT_RESULT
45 REPORT_RESULT(2);
46 #endif
4739 emscripten_cancel_main_loop();
48 exit(0);
40 exit(2);
4941 }
5042 }
5143 if (frame > 0 && frame < 90 && frame % 10 == 0) {
7870
7971 int main() {
8072 emscripten_set_main_loop(looper, 5, 1);
73 return 99;
8174 }
1313
1414 void final(void*) {
1515 assert(frame == 20);
16 #ifdef REPORT_RESULT
17 REPORT_RESULT(0);
18 #else
1916 exit(0);
20 #endif
2117 }
2218
2319 void looper() {
2420 if (blockerExecuted == false) {
25 #ifdef REPORT_RESULT
26 REPORT_RESULT(1);
27 #else
2821 exit(1);
29 #endif
3022 }
3123
3224 frame++;
22 // University of Illinois/NCSA Open Source License. Both these licenses can be
33 // found in the LICENSE file.
44
5 #include <stdbool.h>
56 #include <stdlib.h>
67 #include <stdio.h>
78 #include <assert.h>
2021 double now = emscripten_get_now();
2122 double msecsPerFrame = (now - frame0) / (numFrames-1); // Sub one to account for intervals vs endpoints
2223 printf("Avg. msecs/frame: %f\n", msecsPerFrame);
23 #ifdef REPORT_RESULT
24 int result = (msecsPerFrame < 5); // Expecting to run extremely fast unthrottled, and certainly not bounded by vsync, so less than common 16.667 msecs per frame (this is assuming 60hz display)
25 REPORT_RESULT(result);
26 #endif
2724 emscripten_cancel_main_loop();
25 // Expecting to run extremely fast unthrottled, and certainly not bounded by
26 // vsync, so less than common 16.667 msecs per frame (this is assuming 60hz
27 // display)
28 exit((msecsPerFrame < 5) ? 0 : 1);
2829 }
2930 }
3031
3132 int main() {
3233 emscripten_set_main_loop(looper, 1, 0);
3334 emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0);
35 return 99;
3436 }
1818 printf("Frame %d\n", numFrames);
1919 if (numFrames == 10) {
2020 double now = emscripten_get_now();
21 double msecsPerFrame = (now - frame0) / (numFrames-1); // Sub one to account for intervals vs endpoints
21 // Sub one to account for intervals vs endpoints
22 double msecsPerFrame = (now - frame0) / (numFrames-1);
2223 printf("Avg. msecs/frame: %f\n", msecsPerFrame);
23 #ifdef REPORT_RESULT
24 int result = (msecsPerFrame > 350 && msecsPerFrame < 650); // Expecting 500msecs/frame, but allow a lot of leeway. Bad value would be 900msecs/frame (400msecs of processing below and 500msecs of delay)
25 REPORT_RESULT(result);
26 #endif
2724 emscripten_cancel_main_loop();
25 // Expecting 500msecs/frame, but allow a lot of leeway. Bad value would be
26 // 900msecs/frame (400msecs of processing below and 500msecs of delay)
27 exit((msecsPerFrame > 350 && msecsPerFrame < 650) ? 0 : 1);
2828 }
2929
3030 // Busy wait 400 msecs.
3737 int main() {
3838 // Want to run at 2 fps, or 500msecs/frame.
3939 emscripten_set_main_loop(looper, 2, 0);
40 return 99;
4041 }
4848 assert(h == 202);
4949 w = h = 0;
5050
51 #ifdef REPORT_RESULT
52 REPORT_RESULT(1);
53 #endif
51 return 0;
5452 }
2121 assert(fetch->data != 0);
2222 printf("Finished downloading %llu bytes\n", fetch->numBytes);
2323 emscripten_fetch_close(fetch);
24
25 #ifdef REPORT_RESULT
26 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
27 MAYBE_REPORT_RESULT(1);
28 #endif
29
24 exit(0);
3025 };
3126 attr.onprogress = [](emscripten_fetch_t *fetch) {
3227 if (fetch->totalBytes > 0) {
6560 emscripten_fetch_t *fetch = emscripten_fetch(&attr, "gears.png");
6661 assert(fetch != 0);
6762 memset(&attr, 0, sizeof(attr)); // emscripten_fetch() must be able to operate without referencing to this structure after the call.
63 return 99;
6864 }
22 // University of Illinois/NCSA Open Source License. Both these licenses can be
33 // found in the LICENSE file.
44
5 #include <assert.h>
56 #include <string.h>
67 #include <stdio.h>
78 #include <math.h>
1516 attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_SYNCHRONOUS;
1617 emscripten_fetch_t *fetch = emscripten_fetch(&attr, "gears.png");
1718 printf("Fetch finished with status %d\n", fetch->status);
18 #ifdef REPORT_RESULT
19 REPORT_RESULT(fetch->status);
20 #endif
19 assert(fetch->status == 200);
20 return 0;
2121 }
88 #include <assert.h>
99 #include <emscripten/fetch.h>
1010
11 int result = 0;
11 int result = 1;
1212
1313 int main()
1414 {
4646 assert( checksum == 0x08 );
4747 emscripten_fetch_close( fetch );
4848
49 if ( result == 0 ) result = 1;
50 #ifdef REPORT_RESULT
51 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
52 MAYBE_REPORT_RESULT(result);
53 #endif
49 if ( result == 1 ) result = 0;
5450 };
5551
5652 attr.onprogress = [] ( emscripten_fetch_t *fetch )
7369 };
7470
7571 emscripten_fetch_t *fetch = emscripten_fetch( &attr, "gears.png" );
76 if ( result == 0 )
72 if ( result != 0 )
7773 {
7874 result = 2;
7975 printf( "emscripten_fetch() failed to run synchronously!\n" );
8076 }
81 #ifdef REPORT_RESULT
82 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
83 MAYBE_REPORT_RESULT(result);
84 #endif
77 return result;
8578 }
1010
1111 // Compute rudimentary checksum of data
1212 uint32_t checksum = 0;
13
14 int result = 0;
1513
1614 int main()
1715 {
2725 assert(checksum == 0xA7F8E858U);
2826 emscripten_fetch_close(fetch);
2927
30 #ifdef REPORT_RESULT
31 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
32 MAYBE_REPORT_RESULT(1);
33 #endif
28 exit(0);
3429 };
3530 attr.onprogress = [](emscripten_fetch_t *fetch) {
3631 printf("Downloading.. %.2f%s complete. Received chunk [%llu, %llu[\n",
4843 };
4944 attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_APPEND | EMSCRIPTEN_FETCH_STREAM_DATA;
5045 emscripten_fetch_t *fetch = emscripten_fetch(&attr, "largefile.txt");
46 return 99;
5147 }
5454 if (result == -1) {
5555 printf("emscripten_fetch() failed to run synchronously!\n");
5656 }
57 #ifndef __EMSCRIPTEN_PTHREADS__
58 // For proxy-to-worker mode (the only case where we can do sync xhr in main())
59 // Just use REPORT_RESULT
60 REPORT_RESULT(result);
61 #endif
62 // Otherwise test that the exit status gets returned correctly.
57 assert(result == 0);
6358 return result;
6459 }
2525 assert((uintptr_t)fetch->userData == 0x12345678);
2626 assert(fetch->totalBytes == 6407);
2727 emscripten_fetch_close(fetch);
28
29 #ifdef REPORT_RESULT
30 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
31 MAYBE_REPORT_RESULT(1);
32 #endif
28 exit(0);
3329 };
3430
3531 attr.onprogress = [](emscripten_fetch_t *fetch) {
4945 emscripten_fetch_t *fetch = emscripten_fetch(&attr, "gears.png");
5046 assert(fetch != 0);
5147 memset(&attr, 0, sizeof(attr)); // emscripten_fetch() must be able to operate without referencing to this structure after the call.
48 return 99;
5249 }
88 #include <assert.h>
99 #include <emscripten/fetch.h>
1010
11 int result = 0;
11 int result = 1;
1212
1313 // This test is run in two modes: if FILE_DOES_NOT_EXIST defined,
1414 // then testing an XHR of a missing file.
4343 assert(checksum == 0x08);
4444 emscripten_fetch_close(fetch);
4545
46 #ifdef REPORT_RESULT
4746 #ifndef FILE_DOES_NOT_EXIST
48 result = 1;
47 result = 0;
4948 #endif
50 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
51 MAYBE_REPORT_RESULT(result);
52 #endif
49 exit(result);
5350 };
5451
5552 attr.onprogress = [](emscripten_fetch_t *fetch) {
6259 printf("Downloading.. %lld bytes complete.\n", fetch->dataOffset + fetch->numBytes);
6360 }
6461 #ifdef FILE_DOES_NOT_EXIST
65 assert(false && "onprogress handler called, but the file should not exist"); // We should not receive progress reports if the file doesn't exist.
62 // We should not receive progress reports if the file doesn't exist.
63 assert(false && "onprogress handler called, but the file should not exist");
6664 #endif
6765 // We must receive a call to the onprogress handler with 100% completion.
6866 if (fetch->dataOffset + fetch->numBytes == fetch->totalBytes) ++result;
7674 attr.onerror = [](emscripten_fetch_t *fetch) {
7775 printf("Download failed!\n");
7876 #ifndef FILE_DOES_NOT_EXIST
79 assert(false && "onerror handler called, but the transfer should have succeeded!"); // The file exists, shouldn't reach here.
77 // The file exists, shouldn't reach here.
78 assert(false && "onerror handler called, but the transfer should have succeeded!");
8079 #endif
8180 assert(fetch);
8281 assert(fetch->id != 0);
8382 assert(!strcmp(fetch->url, "gears.png"));
8483 assert((uintptr_t)fetch->userData == 0x12345678);
8584
86 #ifdef REPORT_RESULT
8785 #ifdef FILE_DOES_NOT_EXIST
88 result = 1;
86 result = 0;
8987 #endif
90 // Fetch API appears to sometimes call the handlers more than once, see https://github.com/emscripten-core/emscripten/pull/8191
91 MAYBE_REPORT_RESULT(result);
92 #endif
88 exit(result);
9389 };
9490
9591 emscripten_fetch_t *fetch = emscripten_fetch(&attr, "gears.png");
9692 assert(fetch != 0);
97 memset(&attr, 0, sizeof(attr)); // emscripten_fetch() must be able to operate without referencing to this structure after the call.
93 // emscripten_fetch() must be able to operate without referencing to this
94 // structure after the call.
95 memset(&attr, 0, sizeof(attr));
96 return 99;
9897 }
00 #include <stdio.h>
11 #include <stdlib.h>
22
3 int _Zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(int i1)
4 {
5 if (i1 > 0)
6 return _Zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(--i1);
7 for(;;)
8 malloc(1);
9 return 1;
3 int _Zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(int i1) {
4 if (i1 > 0)
5 return _Zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(--i1);
6 for(;;)
7 malloc(1);
8 return 1;
109 }
1110
12 int main()
13 {
14 _Zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(100);
11 int main() {
12 _Zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(100);
1513 }
55 */
66
77 #include <errno.h>
8 #include <string.h>
89 #include <fcntl.h>
910 #include <stdlib.h>
1011 #include <stdio.h>
1516
1617 int line = 0;
1718
18 void main_loop()
19 {
19 void main_loop() {
2020 char str[10] = {0};
2121 int ret;
2222
3232 }
3333
3434 int err = ferror(stdin);
35 if (ferror(stdin) && errno != EAGAIN) {
36 printf("error %d\n", err);
35 if (err && errno != EAGAIN) {
36 printf("error %s\n", strerror(errno));
3737 exit(EXIT_FAILURE);
3838 }
3939
4646 }
4747 }
4848
49 int main(int argc, char const *argv[])
50 {
49 int main(int argc, char const *argv[]) {
5150 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
5251
5352 // SM shell doesn't implement an event loop and therefor doesn't support
+0
-22
tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports less more
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 H
8 I
9 J
10 K
11 L
12 M
13 N
14 s
15 t
16 u
17 v
18 w
19 x
20 y
21 z
+0
-40
tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs less more
0 $GetQueue
1 $__emscripten_pthread_data_constructor
2 $__errno_location
3 $__pthread_mutex_lock
4 $__pthread_mutex_trylock
5 $__pthread_mutex_unlock
6 $__pthread_self_internal
7 $__pthread_setcancelstate
8 $__pthread_tsd_run_dtors
9 $__wasm_call_ctors
10 $__wasm_init_memory
11 $_do_call
12 $_emscripten_call_on_thread
13 $_emscripten_do_dispatch_to_thread
14 $_emscripten_thread_init
15 $_main_thread
16 $a_cas
17 $add
18 $dispose_chunk
19 $dlfree
20 $dlmalloc
21 $dlmemalign
22 $em_queued_call_free
23 $em_queued_call_malloc
24 $emscripten_async_run_in_main_thread
25 $emscripten_current_thread_process_queued_calls
26 $emscripten_get_global_libc
27 $emscripten_main_thread_process_queued_calls
28 $emscripten_register_main_browser_thread_id
29 $emscripten_run_in_main_runtime_thread_js
30 $emscripten_stack_set_limits
31 $emscripten_sync_run_in_main_thread
32 $emscripten_sync_run_in_main_thread
33 $emscripten_tls_init
34 $free_tls
35 $init_mparams
36 $sbrk
37 $stackAlloc
38 $stackRestore
39 $stackSave
+0
-18
tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports less more
0 a.a
1 a.b
2 a.c
3 a.d
4 a.e
5 a.f
6 a.g
7 a.h
8 a.i
9 a.j
10 a.k
11 a.l
12 a.m
13 a.n
14 a.o
15 a.p
16 a.q
17 a.r
+0
-18
tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent less more
0 a
1 b
2 c
3 d
4 e
5 f
6 g
7 h
8 i
9 j
10 k
11 l
12 m
13 n
14 o
15 p
16 q
17 r
+0
-1
tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.size less more
0 15868
0 #include <emscripten.h>
1
2 EMSCRIPTEN_KEEPALIVE int add(int x, int y) {
3 return x + y;
4 }
5
6 EMSCRIPTEN_KEEPALIVE int global_val = 0;
7
8 int main() {
9 }
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 H
8 I
9 J
10 K
11 L
12 M
13 N
14 O
15 P
16 s
17 t
18 u
19 v
20 w
21 x
22 y
23 z
0 $GetQueue
1 $__emscripten_pthread_data_constructor
2 $__errno_location
3 $__pthread_mutex_lock
4 $__pthread_mutex_trylock
5 $__pthread_mutex_unlock
6 $__pthread_self_internal
7 $__pthread_setcancelstate
8 $__pthread_tsd_run_dtors
9 $__wasm_call_ctors
10 $__wasm_init_memory
11 $_do_call
12 $_emscripten_call_on_thread
13 $_emscripten_do_dispatch_to_thread
14 $_emscripten_thread_init
15 $_main_thread
16 $a_cas
17 $add
18 $dispose_chunk
19 $dlfree
20 $dlmalloc
21 $dlmemalign
22 $em_queued_call_free
23 $em_queued_call_malloc
24 $emscripten_async_run_in_main_thread
25 $emscripten_current_thread_process_queued_calls
26 $emscripten_get_global_libc
27 $emscripten_main_thread_process_queued_calls
28 $emscripten_proxy_main
29 $emscripten_register_main_browser_thread_id
30 $emscripten_run_in_main_runtime_thread_js
31 $emscripten_stack_set_limits
32 $emscripten_sync_run_in_main_thread
33 $emscripten_sync_run_in_main_thread
34 $emscripten_tls_init
35 $free_tls
36 $init_mparams
37 $main
38 $sbrk
39 $stackAlloc
40 $stackRestore
41 $stackSave
0 a.a
1 a.b
2 a.c
3 a.d
4 a.e
5 a.f
6 a.g
7 a.h
8 a.i
9 a.j
10 a.k
11 a.l
12 a.m
13 a.n
14 a.o
15 a.p
16 a.q
17 a.r
0 #include <assert.h>
1 #include <stdlib.h>
2 #include <dlfcn.h>
3 #include <stdio.h>
4
5 int main() {
6 void* handle = dlopen("libside.so", RTLD_NOW);
7 printf("handle: %p\n", handle);
8 if (!handle) {
9 printf("%s\n", dlerror());
10 return 1;
11 }
12 int* foo = (int*)dlsym(handle, "foo");
13 if (!foo) {
14 printf("%s\n", dlerror());
15 return 1;
16 }
17 printf("foo = %d\n", *foo);
18 assert(*foo == 42);
19 exit(0);
20 }
0 Module["loadSplitModule"] = function(deferred, imports, prop) {
1 console.log('Custom handler for loading split module.');
2 console.log('Called with placeholder ', prop);
3
4 return instantiateSync(deferred, imports);
5 }
189189 TEST_START();
190190 errno = 0;
191191
192 ASSERT(munmap(MAP_FAILED, file_len()) == -1 && errno == EINVAL,
192 ASSERT(munmap((void*)0xdeadbeef, file_len()) == -1 && errno == EINVAL,
193193 "Expected EINVAL, as munmap should fail for wrong addr argument");
194194 TEST_PASS();
195195 }
33 # found in the LICENSE file.
44
55 import multiprocessing
6 import os
76 import sys
87 import unittest
98 import tempfile
1110 import queue
1211
1312 from tools.tempfiles import try_delete
13
14 NUM_CORES = None
1415
1516
1617 def g_testing_thread(work_queue, result_queue, temp_dir):
3940 self.max_cores = max_cores
4041
4142 def run(self, result):
43 # The 'spawn' method is used on windows and it can be useful to set this on
44 # all platforms when debugging multiprocessing issues. Without this we
45 # default to 'fork' on unix which is better because global state is
46 # inherited by the child process, but can lead to hard-to-debug windows-only
47 # issues.
48 # multiprocessing.set_start_method('spawn')
4249 test_queue = self.create_test_queue()
4350 self.init_processes(test_queue)
4451 results = self.collect_results()
136143 print(test, '... ok (%.2fs)' % (time.perf_counter() - self.start_time), file=sys.stderr)
137144 self.buffered_result = BufferedTestSuccess(test)
138145
146 def addExpectedFailure(self, test, err):
147 if hasattr(time, 'perf_counter'):
148 print(test, '... expected failure (%.2fs)' % (time.perf_counter() - self.start_time), file=sys.stderr)
149 self.buffered_result = BufferedTestExpectedFailure(test, err)
150
151 def addUnexpectedSuccess(self, test):
152 if hasattr(time, 'perf_counter'):
153 print(test, '... unexpected success (%.2fs)' % (time.perf_counter() - self.start_time), file=sys.stderr)
154 self.buffered_result = BufferedTestUnexpectedSuccess(test)
155
139156 def addSkip(self, test, reason):
140157 print(test, "... skipped '%s'" % reason, file=sys.stderr)
141158 self.buffered_result = BufferedTestSkip(test, reason)
180197 result.addFailure(self.test, self.error)
181198
182199
200 class BufferedTestExpectedFailure(BufferedTestBase):
201 def updateResult(self, result):
202 result.addExpectedFailure(self.test, self.error)
203
204
183205 class BufferedTestError(BufferedTestBase):
184206 def updateResult(self, result):
185207 result.addError(self.test, self.error)
208
209
210 class BufferedTestUnexpectedSuccess(BufferedTestBase):
211 def updateResult(self, result):
212 result.addUnexpectedSuccess(self.test)
186213
187214
188215 class FakeTraceback():
217244
218245
219246 def num_cores():
220 emcc_cores = os.environ.get('PARALLEL_SUITE_EMCC_CORES') or os.environ.get('EMCC_CORES')
221 if emcc_cores:
222 return int(emcc_cores)
247 if NUM_CORES:
248 return int(NUM_CORES)
223249 return multiprocessing.cpu_count()
224250
225251
1515 // Stores/encodes the results of calling to cleanup handlers.
1616 int cleanupState = 1;
1717
18 static void cleanup_handler1(void *arg)
19 {
20 cleanupState <<= 2;
21 cleanupState *= (int)arg; // Perform non-commutative arithmetic to a global var that encodes the cleanup stack order ops.
22 EM_ASM(console.log('Called clean-up handler 1 with arg ' + $0), arg);
23 // printf("Called clean-up handler 1 with arg %d\n", (int)arg);
18 static void cleanup_handler1(void *arg) {
19 cleanupState <<= 2;
20 // Perform non-commutative arithmetic to a global var that encodes the cleanup stack order ops.
21 cleanupState *= (int)arg;
22 EM_ASM(console.log('Called clean-up handler 1 with arg ' + $0), arg);
23 //printf("Called clean-up handler 1 with arg %d\n", (int)arg);
2424 }
2525
26 static void cleanup_handler2(void *arg)
27 {
28 cleanupState <<= 3;
29 cleanupState *= (int)arg; // Perform non-commutative arithmetic to a global var that encodes the cleanup stack order ops.
30 EM_ASM(console.log('Called clean-up handler 2 with arg ' + $0), arg);
31 // printf("Called clean-up handler 2 with arg %d\n", (int)arg);
26 static void cleanup_handler2(void *arg) {
27 cleanupState <<= 3;
28 // Perform non-commutative arithmetic to a global var that encodes the cleanup stack order ops.
29 cleanupState *= (int)arg;
30 EM_ASM(console.log('Called clean-up handler 2 with arg ' + $0), arg);
31 //printf("Called clean-up handler 2 with arg %d\n", (int)arg);
3232 }
3333
34 static void *thread_start1(void *arg)
35 {
36 pthread_cleanup_push(cleanup_handler1, (void*)(42 + (int)arg*100));
37 pthread_cleanup_push(cleanup_handler2, (void*)(69 + (int)arg*100));
38 pthread_cleanup_pop((int)arg);
39 pthread_cleanup_pop((int)arg);
40 pthread_exit(0);
34 static void *thread_start1(void *arg) {
35 pthread_cleanup_push(cleanup_handler1, (void*)(42 + (int)arg*100));
36 pthread_cleanup_push(cleanup_handler2, (void*)(69 + (int)arg*100));
37 pthread_cleanup_pop((int)arg);
38 pthread_cleanup_pop((int)arg);
39 pthread_exit(0);
4140 }
4241
43 static void *thread_start2(void *arg)
44 {
45 pthread_cleanup_push(cleanup_handler1, (void*)52);
46 pthread_cleanup_push(cleanup_handler2, (void*)79);
47 if (arg)
48 pthread_exit(0);
49 pthread_cleanup_pop(0);
50 pthread_cleanup_pop(0);
51 return 0;
42 static void *thread_start2(void *arg) {
43 pthread_cleanup_push(cleanup_handler1, (void*)52);
44 pthread_cleanup_push(cleanup_handler2, (void*)79);
45 if (arg)
46 pthread_exit(0);
47 pthread_cleanup_pop(0);
48 pthread_cleanup_pop(0);
49 return 0;
5250 }
5351
54 static void *thread_start3(void *arg)
55 {
56 pthread_cleanup_push(cleanup_handler1, (void*)62);
57 pthread_cleanup_push(cleanup_handler2, (void*)89);
58 for(;;)
59 {
60 pthread_testcancel();
61 }
62 pthread_cleanup_pop(0);
63 pthread_cleanup_pop(0);
64 pthread_exit(0);
52 static void *thread_start3(void *arg) {
53 pthread_cleanup_push(cleanup_handler1, (void*)62);
54 pthread_cleanup_push(cleanup_handler2, (void*)89);
55 for (;;) {
56 pthread_testcancel();
57 }
58 pthread_cleanup_pop(0);
59 pthread_cleanup_pop(0);
60 pthread_exit(0);
6561 }
6662
6763 pthread_t thr[4];
6864
69 int main()
70 {
71 int result = 0;
65 int main() {
66 int result = 0;
7267
73 if (!emscripten_has_threading_support())
74 {
75 #ifdef REPORT_RESULT
76 REPORT_RESULT(907640832);
77 #endif
78 printf("Skipped: Threading is not supported.\n");
79 return 0;
80 }
68 if (!emscripten_has_threading_support()) {
69 printf("Skipped: Threading is not supported.\n");
70 return 0;
71 }
8172
82 pthread_cleanup_push(cleanup_handler1, (void*)9998);
83 pthread_cleanup_push(cleanup_handler1, (void*)9999);
73 pthread_cleanup_push(cleanup_handler1, (void*)9998);
74 pthread_cleanup_push(cleanup_handler1, (void*)9999);
8475
85 int s = pthread_create(&thr[0], NULL, thread_start1, (void*)0);
86 assert(s == 0);
87 pthread_join(thr[0], 0);
88 s = pthread_create(&thr[1], NULL, thread_start1, (void*)1);
89 assert(s == 0);
90 pthread_join(thr[1], 0);
91 s = pthread_create(&thr[2], NULL, thread_start2, (void*)1);
92 assert(s == 0);
93 pthread_join(thr[2], 0);
76 int s = pthread_create(&thr[0], NULL, thread_start1, (void*)0);
77 assert(s == 0);
78 pthread_join(thr[0], 0);
79 s = pthread_create(&thr[1], NULL, thread_start1, (void*)1);
80 assert(s == 0);
81 pthread_join(thr[1], 0);
82 s = pthread_create(&thr[2], NULL, thread_start2, (void*)1);
83 assert(s == 0);
84 pthread_join(thr[2], 0);
9485 // TODO
9586 // s = pthread_create(&thr[3], NULL, thread_start3, (void*)1);
9687 // assert(s == 0);
9788 // s = pthread_cancel(thr[3]);
9889 // assert(s == 0);
99 pthread_cleanup_pop(1);
100 EM_ASM(console.log('Cleanup state variable: ' + $0), cleanupState);
90 pthread_cleanup_pop(1);
91 printf("Cleanup state variable: %d", cleanupState);
92 assert(cleanupState == 907640832);
10193
102 #ifdef REPORT_RESULT
103 REPORT_RESULT(cleanupState);
104 #endif
105
106 exit(EXIT_SUCCESS);
94 pthread_cleanup_pop(1);
95 exit(EXIT_SUCCESS);
10796 }
10897
10998 /*
0 Cleanup state variable: 907640832
44 * found in the LICENSE file.
55 */
66
7 #include <assert.h>
78 #include <pthread.h>
89 #include <stdio.h>
910 #include <stdlib.h>
10 // #include <emscripten/emscripten.h>
1111 #include <emscripten/threading.h>
1212 #include "../../system/lib/libc/musl/src/internal/pthread_impl.h"
1313
2525 return loc;
2626 }
2727
28 void *thread_test(void *t)
29 {
28 void *thread_test(void *t) {
3029 puts("Doing test in child thread");
3130 pthread_exit((void*)do_test());
3231 }
3332
34 int main (int argc, char *argv[])
35 {
33 int main (int argc, char *argv[]) {
3634 puts("Doing test in main thread");
3735 locale_t main_loc = do_test();
3836 locale_t child_loc;
3937
40 if (!emscripten_has_threading_support())
41 {
38 if (!emscripten_has_threading_support()) {
4239 child_loc = main_loc;
43 }
44 else
45 {
40 } else {
4641 long id = 1;
4742 pthread_t thread;
4843
5146 pthread_join(thread, (void**)&child_loc);
5247 }
5348
54 #ifdef REPORT_RESULT
55 int result = (main_loc == child_loc);
56 REPORT_RESULT(result);
57 #endif
58
59 pthread_exit(NULL);
49 assert(main_loc == child_loc);
50 return 0;
6051 }
0 #include <assert.h>
01 #include <stdlib.h>
12 #include <stdio.h>
23 #include <assert.h>
45 #include <emscripten/emscripten.h>
56 #include <emscripten/threading.h>
67
7 extern "C"
8 {
9 void EMSCRIPTEN_KEEPALIVE FinishTest(int result)
8 extern "C" void EMSCRIPTEN_KEEPALIVE FinishTest(int result)
109 {
1110 printf("Test finished, result: %d\n", result);
12 #ifdef REPORT_RESULT
13 REPORT_RESULT(result);
14 #endif
15 }
11 assert(result == 1);
12 exit(0);
1613 }
1714
1815 void TestAsyncRunScript()
3936
4037 int main() {
4138
42 // 1. Test that emscripten_run_script() works in a pthread, and it gets executed in the web worker and not on the main thread.
39 // 1. Test that emscripten_run_script() works in a pthread, and it gets
40 // executed in the web worker and not on the main thread.
4341 #if __EMSCRIPTEN_PTHREADS__
4442 emscripten_run_script("Module['ranScript'] = ENVIRONMENT_IS_PTHREAD && (typeof ENVIRONMENT_IS_WORKER !== 'undefined' && ENVIRONMENT_IS_WORKER);");
4543 #else
4644 emscripten_run_script("Module['ranScript'] = true;");
4745 #endif
4846
49 // 2. Test that emscripten_run_script_int() works in a pthread and it gets executed in the web worker and not on the main thread.
47 // 2. Test that emscripten_run_script_int() works in a pthread and it gets
48 // executed in the web worker and not on the main thread.
5049 #if __EMSCRIPTEN_PTHREADS__
5150 int result = emscripten_run_script_int("Module['ranScript'] && ENVIRONMENT_IS_PTHREAD && (typeof ENVIRONMENT_IS_WORKER !== 'undefined' && ENVIRONMENT_IS_WORKER);");
5251 #else
6867
6968 // 4. Test emscripten_async_load_script() runs in a pthread.
7069 emscripten_async_load_script("foo.js", AsyncScriptLoaded, AsyncScriptFailed);
70
71 // Should never get here
72 return 99;
7173 }
0 // Copyright 2015 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <pthread.h>
8
9 void destructor(void* arg) {
10 printf("destructor: %d\n", (int)arg);
11 assert(arg == (void*)42);
12 }
13
14 int main() {
15 pthread_key_t key;
16 pthread_key_create(&key, destructor);
17 void *val = pthread_getspecific(key);
18 assert(val == 0);
19 pthread_setspecific(key, (void*)42);
20 val = pthread_getspecific(key);
21 assert(val == (void*)42);
22 return 0;
23 }
+0
-22
tests/pthread/test_pthread_setspecific_mainthread.cpp less more
0 // Copyright 2015 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <pthread.h>
7
8 int main()
9 {
10 pthread_key_t key;
11 pthread_key_create(&key, NULL);
12 void *val = pthread_getspecific(key);
13 assert(val == 0);
14 pthread_setspecific(key, (void*)1);
15 val = pthread_getspecific(key);
16 assert(val == (void*)1);
17
18 #ifdef REPORT_RESULT
19 REPORT_RESULT(0);
20 #endif
21 }
12211221 "module": 4,
12221222 "nextInChain": 0
12231223 },
1224 "__cxa_exception": {
1225 "__size__": 16,
1226 "caught": 12,
1227 "exceptionDestructor": 8,
1228 "exceptionType": 4,
1229 "referenceCount": 0,
1230 "rethrown": 13
1231 },
12241232 "__wasi_fdstat_t": {
12251233 "__size__": 24,
12261234 "fs_filetype": 0,
1616
1717 # XXX Use EMTEST_ALL_ENGINES=1 in the env to test all engines!
1818
19 from enum import Enum
20 from functools import wraps
21 from subprocess import PIPE, STDOUT
2219 import argparse
2320 import atexit
24 import contextlib
25 import difflib
2621 import fnmatch
2722 import glob
28 import hashlib
2923 import logging
3024 import math
31 import multiprocessing
3225 import operator
3326 import os
3427 import random
35 import shlex
36 import shutil
37 import string
38 import subprocess
39 import stat
4028 import sys
41 import tempfile
42 import time
4329 import unittest
44 import webbrowser
45 from pathlib import Path
46 from http.server import HTTPServer, SimpleHTTPRequestHandler
47 from urllib.parse import unquote, unquote_plus
4830
4931 # Setup
5032
5133 __rootpath__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5234 sys.path.append(__rootpath__)
5335
54 import clang_native
5536 import jsrun
5637 import parallel_testsuite
57 from jsrun import NON_ZERO
58 from tools.shared import TEMP_DIR, EMCC, EMXX, DEBUG, EMCONFIGURE, EMCMAKE
59 from tools.shared import EMSCRIPTEN_TEMP_DIR
60 from tools.shared import EM_BUILD_VERBOSE
61 from tools.shared import get_canonical_temp_dir, try_delete
62 from tools.utils import MACOS, WINDOWS
63 from tools import shared, line_endings, building, config
64
65
66 def path_from_root(*pathelems):
67 """Construct a path relative to the emscripten root directory."""
68 return str(Path(__rootpath__, *pathelems))
69
70
71 sys.path.append(path_from_root('third_party/websockify'))
38 import common
39 from tools import shared, config
40
41
42 sys.path.append(shared.path_from_root('third_party/websockify'))
7243
7344 logger = logging.getLogger("runner")
7445
75 # User can specify an environment variable EMTEST_BROWSER to force the browser
76 # test suite to run using another browser command line than the default system
77 # browser. Setting '0' as the browser disables running a browser (but we still
78 # see tests compile)
79 EMTEST_BROWSER = os.getenv('EMTEST_BROWSER')
80
81 EMTEST_DETECT_TEMPFILE_LEAKS = int(os.getenv('EMTEST_DETECT_TEMPFILE_LEAKS', '0'))
82
83 # TODO(sbc): Remove this check for the legacy name once its been around for a while.
84 assert 'EM_SAVE_DIR' not in os.environ, "Please use EMTEST_SAVE_DIR instead of EM_SAVE_DIR"
85
86 EMTEST_SAVE_DIR = int(os.getenv('EMTEST_SAVE_DIR', '0'))
87
88 # generally js engines are equivalent, testing 1 is enough. set this
89 # to force testing on all js engines, good to find js engine bugs
90 EMTEST_ALL_ENGINES = os.getenv('EMTEST_ALL_ENGINES')
91
92 EMTEST_SKIP_SLOW = os.getenv('EMTEST_SKIP_SLOW')
93
94 EMTEST_LACKS_NATIVE_CLANG = os.getenv('EMTEST_LACKS_NATIVE_CLANG')
95
96 EMTEST_VERBOSE = int(os.getenv('EMTEST_VERBOSE', '0')) or shared.DEBUG
97
98 TEST_ROOT = path_from_root('tests')
99
100 WEBIDL_BINDER = shared.bat_suffix(path_from_root('tools/webidl_binder'))
101
102 EMBUILDER = shared.bat_suffix(path_from_root('embuilder'))
103
104
105 if EMTEST_VERBOSE:
46
47 if common.EMTEST_VERBOSE:
10648 logging.root.setLevel(logging.DEBUG)
107
108
109 def delete_contents(pathname):
110 for entry in os.listdir(pathname):
111 try_delete(os.path.join(pathname, entry))
112
113
114 def test_file(*path_components):
115 """Construct a path relative to the emscripten "tests" directory."""
116 return str(Path(TEST_ROOT, *path_components))
117
118
119 def read_file(*path_components):
120 return Path(*path_components).read_text()
121
122
123 def read_binary(*path_components):
124 return Path(*path_components).read_bytes()
125
126
127 # checks if browser testing is enabled
128 def has_browser():
129 return EMTEST_BROWSER != '0'
130
131
132 def compiler_for(filename, force_c=False):
133 if shared.suffix(filename) in ('.cc', '.cxx', '.cpp') and not force_c:
134 return EMXX
135 else:
136 return EMCC
137
138
139 # Generic decorator that calls a function named 'condition' on the test class and
140 # skips the test if that function returns true
141 def skip_if(func, condition, explanation='', negate=False):
142 assert callable(func)
143 explanation_str = ' : %s' % explanation if explanation else ''
144
145 @wraps(func)
146 def decorated(self, *args, **kwargs):
147 choice = self.__getattribute__(condition)()
148 if negate:
149 choice = not choice
150 if choice:
151 self.skipTest(condition + explanation_str)
152 func(self, *args, **kwargs)
153
154 return decorated
155
156
157 def needs_dylink(func):
158 assert callable(func)
159
160 @wraps(func)
161 def decorated(self):
162 self.check_dylink()
163 return func(self)
164
165 return decorated
166
167
168 def is_slow_test(func):
169 assert callable(func)
170
171 @wraps(func)
172 def decorated(self, *args, **kwargs):
173 if EMTEST_SKIP_SLOW:
174 return self.skipTest('skipping slow tests')
175 return func(self, *args, **kwargs)
176
177 return decorated
178
179
180 def disabled(note=''):
181 assert not callable(note)
182 return unittest.skip(note)
183
184
185 def no_mac(note=''):
186 assert not callable(note)
187 if MACOS:
188 return unittest.skip(note)
189 return lambda f: f
190
191
192 def no_windows(note=''):
193 assert not callable(note)
194 if WINDOWS:
195 return unittest.skip(note)
196 return lambda f: f
197
198
199 def requires_native_clang(func):
200 assert callable(func)
201
202 def decorated(self, *args, **kwargs):
203 if EMTEST_LACKS_NATIVE_CLANG:
204 return self.skipTest('native clang tests are disabled')
205 return func(self, *args, **kwargs)
206
207 return decorated
208
209
210 def require_node(func):
211 assert callable(func)
212
213 def decorated(self, *args, **kwargs):
214 self.require_node()
215 return func(self, *args, **kwargs)
216
217 return decorated
218
219
220 def require_v8(func):
221 assert callable(func)
222
223 def decorated(self, *args, **kwargs):
224 self.require_v8()
225 return func(self, *args, **kwargs)
226
227 return decorated
228
229
230 def node_pthreads(f):
231 def decorated(self):
232 self.set_setting('USE_PTHREADS')
233 self.emcc_args += ['-Wno-pthreads-mem-growth']
234 if self.get_setting('MINIMAL_RUNTIME'):
235 self.skipTest('node pthreads not yet supported with MINIMAL_RUNTIME')
236 self.js_engines = [config.NODE_JS]
237 self.node_args += ['--experimental-wasm-threads', '--experimental-wasm-bulk-memory']
238 f(self)
239 return decorated
240
241
242 @contextlib.contextmanager
243 def env_modify(updates):
244 """A context manager that updates os.environ."""
245 # This could also be done with mock.patch.dict() but taking a dependency
246 # on the mock library is probably not worth the benefit.
247 old_env = os.environ.copy()
248 print("env_modify: " + str(updates))
249 # Seting a value to None means clear the environment variable
250 clears = [key for key, value in updates.items() if value is None]
251 updates = {key: value for key, value in updates.items() if value is not None}
252 os.environ.update(updates)
253 for key in clears:
254 if key in os.environ:
255 del os.environ[key]
256 try:
257 yield
258 finally:
259 os.environ.clear()
260 os.environ.update(old_env)
261
262
263 # Decorator version of env_modify
264 def with_env_modify(updates):
265 def decorated(f):
266 def modified(self):
267 with env_modify(updates):
268 return f(self)
269 return modified
270 return decorated
271
272
273 def ensure_dir(dirname):
274 dirname = Path(dirname)
275 dirname.mkdir(parents=True, exist_ok=True)
276
277
278 def limit_size(string, maxbytes=800000 * 20, maxlines=100000, max_line=5000):
279 lines = string.splitlines()
280 for i, line in enumerate(lines):
281 if len(line) > max_line:
282 lines[i] = line[:max_line] + '[..]'
283 if len(lines) > maxlines:
284 lines = lines[0:maxlines // 2] + ['[..]'] + lines[-maxlines // 2:]
285 string = '\n'.join(lines) + '\n'
286 if len(string) > maxbytes:
287 string = string[0:maxbytes // 2] + '\n[..]\n' + string[-maxbytes // 2:]
288 return string
289
290
291 def create_file(name, contents, binary=False):
292 name = Path(name)
293 assert not name.is_absolute()
294 if binary:
295 name.write_bytes(contents)
296 else:
297 name.write_text(contents)
298
299
300 def make_executable(name):
301 Path(name).chmod(stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
30249
30350
30451 # The core test modes
33784 ]
33885
33986
340 def parameterized(parameters):
341 """
342 Mark a test as parameterized.
343
344 Usage:
345 @parameterized({
346 'subtest1': (1, 2, 3),
347 'subtest2': (4, 5, 6),
348 })
349 def test_something(self, a, b, c):
350 ... # actual test body
351
352 This is equivalent to defining two tests:
353
354 def test_something_subtest1(self):
355 # runs test_something(1, 2, 3)
356
357 def test_something_subtest2(self):
358 # runs test_something(4, 5, 6)
359 """
360 def decorator(func):
361 func._parameterize = parameters
362 return func
363 return decorator
364
365
366 class RunnerMeta(type):
367 @classmethod
368 def make_test(mcs, name, func, suffix, args):
369 """
370 This is a helper function to create new test functions for each parameterized form.
371
372 :param name: the original name of the function
373 :param func: the original function that we are parameterizing
374 :param suffix: the suffix to append to the name of the function for this parameterization
375 :param args: the positional arguments to pass to the original function for this parameterization
376 :returns: a tuple of (new_function_name, new_function_object)
377 """
378
379 # Create the new test function. It calls the original function with the specified args.
380 # We use @functools.wraps to copy over all the function attributes.
381 @wraps(func)
382 def resulting_test(self):
383 return func(self, *args)
384
385 # Add suffix to the function name so that it displays correctly.
386 if suffix:
387 resulting_test.__name__ = f'{name}_{suffix}'
388 else:
389 resulting_test.__name__ = name
390
391 # On python 3, functions have __qualname__ as well. This is a full dot-separated path to the
392 # function. We add the suffix to it as well.
393 resulting_test.__qualname__ = f'{func.__qualname__}_{suffix}'
394
395 return resulting_test.__name__, resulting_test
396
397 def __new__(mcs, name, bases, attrs):
398 # This metaclass expands parameterized methods from `attrs` into separate ones in `new_attrs`.
399 new_attrs = {}
400
401 for attr_name, value in attrs.items():
402 # Check if a member of the new class has _parameterize, the tag inserted by @parameterized.
403 if hasattr(value, '_parameterize'):
404 # If it does, we extract the parameterization information, build new test functions.
405 for suffix, args in value._parameterize.items():
406 new_name, func = mcs.make_test(attr_name, value, suffix, args)
407 assert new_name not in new_attrs, 'Duplicate attribute name generated when parameterizing %s' % attr_name
408 new_attrs[new_name] = func
409 else:
410 # If not, we just copy it over to new_attrs verbatim.
411 assert attr_name not in new_attrs, '%s collided with an attribute from parameterization' % attr_name
412 new_attrs[attr_name] = value
413
414 # We invoke type, the default metaclass, to actually create the new class, with new_attrs.
415 return type.__new__(mcs, name, bases, new_attrs)
416
417
418 class RunnerCore(unittest.TestCase, metaclass=RunnerMeta):
419 # default temporary directory settings. set_temp_dir may be called later to
420 # override these
421 temp_dir = TEMP_DIR
422 canonical_temp_dir = get_canonical_temp_dir(TEMP_DIR)
423
424 # This avoids cluttering the test runner output, which is stderr too, with compiler warnings etc.
425 # Change this to None to get stderr reporting, for debugging purposes
426 stderr_redirect = STDOUT
427
428 def is_wasm(self):
429 return self.get_setting('WASM') != 0
430
431 def check_dylink(self):
432 if self.get_setting('ALLOW_MEMORY_GROWTH') == 1 and not self.is_wasm():
433 self.skipTest('no dynamic linking with memory growth (without wasm)')
434 if not self.is_wasm():
435 self.skipTest('no dynamic linking support in wasm2js yet')
436 if '-fsanitize=address' in self.emcc_args:
437 self.skipTest('no dynamic linking support in ASan yet')
438 if '-fsanitize=leak' in self.emcc_args:
439 self.skipTest('no dynamic linking support in LSan yet')
440
441 def require_v8(self):
442 if not config.V8_ENGINE or config.V8_ENGINE not in config.JS_ENGINES:
443 if 'EMTEST_SKIP_V8' in os.environ:
444 self.skipTest('test requires v8 and EMTEST_SKIP_V8 is set')
445 else:
446 self.fail('d8 required to run this test. Use EMTEST_SKIP_V8 to skip')
447 self.js_engines = [config.V8_ENGINE]
448
449 def require_node(self):
450 if not config.NODE_JS or config.NODE_JS not in config.JS_ENGINES:
451 if 'EMTEST_SKIP_NODE' in os.environ:
452 self.skipTest('test requires node and EMTEST_SKIP_NODE is set')
453 else:
454 self.fail('node required to run this test. Use EMTEST_SKIP_NODE to skip')
455 self.js_engines = [config.NODE_JS]
456
457 def uses_memory_init_file(self):
458 if self.get_setting('SIDE_MODULE') or (self.is_wasm() and not self.get_setting('WASM2JS')):
459 return False
460 elif '--memory-init-file' in self.emcc_args:
461 return int(self.emcc_args[self.emcc_args.index('--memory-init-file') + 1])
462 else:
463 # side modules handle memory differently; binaryen puts the memory in the wasm module
464 opt_supports = any(opt in self.emcc_args for opt in ('-O2', '-O3', '-Os', '-Oz'))
465 return opt_supports
466
467 def set_temp_dir(self, temp_dir):
468 self.temp_dir = temp_dir
469 self.canonical_temp_dir = get_canonical_temp_dir(self.temp_dir)
470 # Explicitly set dedicated temporary directory for parallel tests
471 os.environ['EMCC_TEMP_DIR'] = self.temp_dir
472
473 @classmethod
474 def setUpClass(cls):
475 super().setUpClass()
476 print('(checking sanity from test runner)') # do this after we set env stuff
477 shared.check_sanity(force=True)
478
479 def setUp(self):
480 super().setUp()
481 self.settings_mods = {}
482 self.emcc_args = ['-Werror']
483 self.node_args = []
484 self.v8_args = []
485 self.env = {}
486 self.temp_files_before_run = []
487 self.uses_es6 = False
488 self.js_engines = config.JS_ENGINES.copy()
489 self.wasm_engines = config.WASM_ENGINES.copy()
490 self.banned_js_engines = []
491 self.use_all_engines = EMTEST_ALL_ENGINES
492
493 if EMTEST_DETECT_TEMPFILE_LEAKS:
494 for root, dirnames, filenames in os.walk(self.temp_dir):
495 for dirname in dirnames:
496 self.temp_files_before_run.append(os.path.normpath(os.path.join(root, dirname)))
497 for filename in filenames:
498 self.temp_files_before_run.append(os.path.normpath(os.path.join(root, filename)))
499
500 if EMTEST_SAVE_DIR:
501 self.working_dir = os.path.join(self.temp_dir, 'emscripten_test')
502 if os.path.exists(self.working_dir):
503 if EMTEST_SAVE_DIR == 2:
504 print('Not clearing existing test directory')
505 else:
506 print('Clearing existing test directory')
507 # Even when EMTEST_SAVE_DIR we still try to start with an empty directoy as many tests
508 # expect this. EMTEST_SAVE_DIR=2 can be used to keep the old contents for the new test
509 # run. This can be useful when iterating on a given test with extra files you want to keep
510 # around in the output directory.
511 delete_contents(self.working_dir)
512 else:
513 print('Creating new test output directory')
514 ensure_dir(self.working_dir)
515 else:
516 self.working_dir = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=self.temp_dir)
517 os.chdir(self.working_dir)
518
519 if not EMTEST_SAVE_DIR:
520 self.has_prev_ll = False
521 for temp_file in os.listdir(TEMP_DIR):
522 if temp_file.endswith('.ll'):
523 self.has_prev_ll = True
524
525 def tearDown(self):
526 if not EMTEST_SAVE_DIR:
527 # rmtree() fails on Windows if the current working directory is inside the tree.
528 os.chdir(os.path.dirname(self.get_dir()))
529 try_delete(self.get_dir())
530
531 if EMTEST_DETECT_TEMPFILE_LEAKS and not DEBUG:
532 temp_files_after_run = []
533 for root, dirnames, filenames in os.walk(self.temp_dir):
534 for dirname in dirnames:
535 temp_files_after_run.append(os.path.normpath(os.path.join(root, dirname)))
536 for filename in filenames:
537 temp_files_after_run.append(os.path.normpath(os.path.join(root, filename)))
538
539 # Our leak detection will pick up *any* new temp files in the temp dir.
540 # They may not be due to us, but e.g. the browser when running browser
541 # tests. Until we figure out a proper solution, ignore some temp file
542 # names that we see on our CI infrastructure.
543 ignorable_file_prefixes = [
544 '/tmp/tmpaddon',
545 '/tmp/circleci-no-output-timeout',
546 '/tmp/wasmer'
547 ]
548
549 left_over_files = set(temp_files_after_run) - set(self.temp_files_before_run)
550 left_over_files = [f for f in left_over_files if not any([f.startswith(prefix) for prefix in ignorable_file_prefixes])]
551 if len(left_over_files):
552 print('ERROR: After running test, there are ' + str(len(left_over_files)) + ' new temporary files/directories left behind:', file=sys.stderr)
553 for f in left_over_files:
554 print('leaked file: ' + f, file=sys.stderr)
555 self.fail('Test leaked ' + str(len(left_over_files)) + ' temporary files!')
556
557 def get_setting(self, key, default=None):
558 return self.settings_mods.get(key, default)
559
560 def set_setting(self, key, value=1):
561 if value is None:
562 self.clear_setting(key)
563 self.settings_mods[key] = value
564
565 def has_changed_setting(self, key):
566 return key in self.settings_mods
567
568 def clear_setting(self, key):
569 self.settings_mods.pop(key, None)
570
571 def serialize_settings(self):
572 ret = []
573 for key, value in self.settings_mods.items():
574 if value == 1:
575 ret.append(f'-s{key}')
576 elif type(value) == list:
577 ret.append(f'-s{key}={",".join(value)}')
578 else:
579 ret.append(f'-s{key}={value}')
580 return ret
581
582 def get_dir(self):
583 return self.working_dir
584
585 def in_dir(self, *pathelems):
586 return os.path.join(self.get_dir(), *pathelems)
587
588 def add_pre_run(self, code):
589 create_file('prerun.js', 'Module.preRun = function() { %s }' % code)
590 self.emcc_args += ['--pre-js', 'prerun.js']
591
592 def add_post_run(self, code):
593 create_file('postrun.js', 'Module.postRun = function() { %s }' % code)
594 self.emcc_args += ['--pre-js', 'postrun.js']
595
596 def add_on_exit(self, code):
597 create_file('onexit.js', 'Module.onExit = function() { %s }' % code)
598 self.emcc_args += ['--pre-js', 'onexit.js']
599
600 # returns the full list of arguments to pass to emcc
601 # param @main_file whether this is the main file of the test. some arguments
602 # (like --pre-js) do not need to be passed when building
603 # libraries, for example
604 def get_emcc_args(self, main_file=False):
605 args = self.serialize_settings() + self.emcc_args
606 if not main_file:
607 for i, arg in enumerate(args):
608 if arg in ('--pre-js', '--post-js'):
609 args[i] = None
610 args[i + 1] = None
611 args = [arg for arg in args if arg is not None]
612 return args
613
614 def verify_es5(self, filename):
615 es_check = shared.get_npm_cmd('es-check')
616 # use --quiet once its available
617 # See: https://github.com/dollarshaveclub/es-check/pull/126/
618 es_check_env = os.environ.copy()
619 es_check_env['PATH'] = os.path.dirname(config.NODE_JS[0]) + os.pathsep + es_check_env['PATH']
620 try:
621 shared.run_process(es_check + ['es5', os.path.abspath(filename)], stderr=PIPE, env=es_check_env)
622 except subprocess.CalledProcessError as e:
623 print(e.stderr)
624 self.fail('es-check failed to verify ES5 output compliance')
625
626 # Build JavaScript code from source code
627 def build(self, filename, libraries=[], includes=[], force_c=False,
628 post_build=None, js_outfile=True, emcc_args=[]):
629 suffix = '.js' if js_outfile else '.wasm'
630 compiler = [compiler_for(filename, force_c)]
631 if compiler[0] == EMCC:
632 # TODO(https://github.com/emscripten-core/emscripten/issues/11121)
633 # We link with C++ stdlibs, even when linking with emcc for historical reasons. We can remove
634 # this if this issues is fixed.
635 compiler.append('-nostdlib++')
636
637 if force_c:
638 compiler.append('-xc')
639
640 dirname, basename = os.path.split(filename)
641 output = shared.unsuffixed(basename) + suffix
642 cmd = compiler + [filename, '-o', output] + self.get_emcc_args(main_file=True) + emcc_args + libraries
643 if shared.suffix(filename) not in ('.i', '.ii'):
644 # Add the location of the test file to include path.
645 cmd += ['-I.']
646 cmd += ['-I' + str(include) for include in includes]
647
648 self.run_process(cmd, stderr=self.stderr_redirect if not DEBUG else None)
649 self.assertExists(output)
650 if js_outfile and not self.uses_es6:
651 self.verify_es5(output)
652
653 if post_build:
654 post_build(output)
655
656 if js_outfile and self.uses_memory_init_file():
657 src = read_file(output)
658 # side memory init file, or an empty one in the js
659 assert ('/* memory initializer */' not in src) or ('/* memory initializer */ allocate([]' in src)
660
661 return output
662
663 def get_func(self, src, name):
664 start = src.index('function ' + name + '(')
665 t = start
666 n = 0
667 while True:
668 if src[t] == '{':
669 n += 1
670 elif src[t] == '}':
671 n -= 1
672 if n == 0:
673 return src[start:t + 1]
674 t += 1
675 assert t < len(src)
676
677 def count_funcs(self, javascript_file):
678 num_funcs = 0
679 start_tok = "// EMSCRIPTEN_START_FUNCS"
680 end_tok = "// EMSCRIPTEN_END_FUNCS"
681 start_off = 0
682 end_off = 0
683
684 js = read_file(javascript_file)
685 blob = "".join(js.splitlines())
686
687 start_off = blob.find(start_tok) + len(start_tok)
688 end_off = blob.find(end_tok)
689 asm_chunk = blob[start_off:end_off]
690 num_funcs = asm_chunk.count('function ')
691 return num_funcs
692
693 def count_wasm_contents(self, wasm_binary, what):
694 out = self.run_process([os.path.join(building.get_binaryen_bin(), 'wasm-opt'), wasm_binary, '--metrics'], stdout=PIPE).stdout
695 # output is something like
696 # [?] : 125
697 for line in out.splitlines():
698 if '[' + what + ']' in line:
699 ret = line.split(':')[1].strip()
700 return int(ret)
701 self.fail('Failed to find [%s] in wasm-opt output' % what)
702
703 def get_wasm_text(self, wasm_binary):
704 return self.run_process([os.path.join(building.get_binaryen_bin(), 'wasm-dis'), wasm_binary], stdout=PIPE).stdout
705
706 def is_exported_in_wasm(self, name, wasm):
707 wat = self.get_wasm_text(wasm)
708 return ('(export "%s"' % name) in wat
709
710 def run_js(self, filename, engine=None, args=[], output_nicerizer=None, assert_returncode=0):
711 # use files, as PIPE can get too full and hang us
712 stdout = self.in_dir('stdout')
713 stderr = self.in_dir('stderr')
714 error = None
715 if not engine:
716 engine = self.js_engines[0]
717 if engine == config.NODE_JS:
718 engine = engine + self.node_args
719 if engine == config.V8_ENGINE:
720 engine = engine + self.v8_args
721 if EMTEST_VERBOSE:
722 print(f"Running '{filename}' under '{shared.shlex_join(engine)}'")
723 try:
724 jsrun.run_js(filename, engine, args,
725 stdout=open(stdout, 'w'),
726 stderr=open(stderr, 'w'),
727 assert_returncode=assert_returncode)
728 except subprocess.CalledProcessError as e:
729 error = e
730
731 # Make sure that we produced proper line endings to the .js file we are about to run.
732 if not filename.endswith('.wasm'):
733 self.assertEqual(line_endings.check_line_endings(filename), 0)
734
735 out = read_file(stdout)
736 err = read_file(stderr)
737 if output_nicerizer:
738 ret = output_nicerizer(out, err)
739 else:
740 ret = out + err
741 if error or EMTEST_VERBOSE:
742 ret = limit_size(ret)
743 print('-- begin program output --')
744 print(ret, end='')
745 print('-- end program output --')
746 if error:
747 if assert_returncode == NON_ZERO:
748 self.fail('JS subprocess unexpectedly succeeded (%s): Output:\n%s' % (error.cmd, ret))
749 else:
750 self.fail('JS subprocess failed (%s): %s. Output:\n%s' % (error.cmd, error.returncode, ret))
751
752 # We should pass all strict mode checks
753 self.assertNotContained('strict warning:', ret)
754 return ret
755
756 def assertExists(self, filename, msg=None):
757 if not msg:
758 msg = 'Expected file not found: ' + filename
759 self.assertTrue(os.path.exists(filename), msg)
760
761 def assertNotExists(self, filename, msg=None):
762 if not msg:
763 msg = 'Unexpected file exists: ' + filename
764 self.assertFalse(os.path.exists(filename), msg)
765
766 # Tests that the given two paths are identical, modulo path delimiters. E.g. "C:/foo" is equal to "C:\foo".
767 def assertPathsIdentical(self, path1, path2):
768 path1 = path1.replace('\\', '/')
769 path2 = path2.replace('\\', '/')
770 return self.assertIdentical(path1, path2)
771
772 # Tests that the given two multiline text content are identical, modulo line
773 # ending differences (\r\n on Windows, \n on Unix).
774 def assertTextDataIdentical(self, text1, text2, msg=None,
775 fromfile='expected', tofile='actual'):
776 text1 = text1.replace('\r\n', '\n')
777 text2 = text2.replace('\r\n', '\n')
778 return self.assertIdentical(text1, text2, msg, fromfile, tofile)
779
780 def assertIdentical(self, values, y, msg=None,
781 fromfile='expected', tofile='actual'):
782 if type(values) not in (list, tuple):
783 values = [values]
784 for x in values:
785 if x == y:
786 return # success
787 diff_lines = difflib.unified_diff(x.splitlines(), y.splitlines(),
788 fromfile=fromfile, tofile=tofile)
789 diff = ''.join([a.rstrip() + '\n' for a in diff_lines])
790 if EMTEST_VERBOSE:
791 print("Expected to have '%s' == '%s'" % (limit_size(values[0]), limit_size(y)))
792 fail_message = 'Unexpected difference:\n' + limit_size(diff)
793 if not EMTEST_VERBOSE:
794 fail_message += '\nFor full output run with EMTEST_VERBOSE=1.'
795 if msg:
796 fail_message += '\n' + msg
797 self.fail(fail_message)
798
799 def assertTextDataContained(self, text1, text2):
800 text1 = text1.replace('\r\n', '\n')
801 text2 = text2.replace('\r\n', '\n')
802 return self.assertContained(text1, text2)
803
804 def assertContained(self, values, string, additional_info=''):
805 if type(values) not in [list, tuple]:
806 values = [values]
807 if callable(string):
808 string = string()
809
810 if not any(v in string for v in values):
811 diff = difflib.unified_diff(values[0].split('\n'), string.split('\n'), fromfile='expected', tofile='actual')
812 diff = ''.join(a.rstrip() + '\n' for a in diff)
813 self.fail("Expected to find '%s' in '%s', diff:\n\n%s\n%s" % (
814 limit_size(values[0]), limit_size(string), limit_size(diff),
815 additional_info
816 ))
817
818 def assertNotContained(self, value, string):
819 if callable(value):
820 value = value() # lazy loading
821 if callable(string):
822 string = string()
823 if value in string:
824 self.fail("Expected to NOT find '%s' in '%s', diff:\n\n%s" % (
825 limit_size(value), limit_size(string),
826 limit_size(''.join([a.rstrip() + '\n' for a in difflib.unified_diff(value.split('\n'), string.split('\n'), fromfile='expected', tofile='actual')]))
827 ))
828
829 def assertContainedIf(self, value, string, condition):
830 if condition:
831 self.assertContained(value, string)
832 else:
833 self.assertNotContained(value, string)
834
835 def assertBinaryEqual(self, file1, file2):
836 self.assertEqual(os.path.getsize(file1),
837 os.path.getsize(file2))
838 self.assertEqual(read_binary(file1),
839 read_binary(file2))
840
841 library_cache = {}
842
843 def get_build_dir(self):
844 ret = os.path.join(self.get_dir(), 'building')
845 ensure_dir(ret)
846 return ret
847
848 def get_library(self, name, generated_libs, configure=['sh', './configure'],
849 configure_args=[], make=['make'], make_args=None,
850 env_init={}, cache_name_extra='', native=False):
851 if make_args is None:
852 make_args = ['-j', str(shared.get_num_cores())]
853
854 build_dir = self.get_build_dir()
855 output_dir = self.get_dir()
856
857 emcc_args = self.get_emcc_args()
858
859 hash_input = (str(emcc_args) + ' $ ' + str(env_init)).encode('utf-8')
860 cache_name = name + ','.join([opt for opt in emcc_args if len(opt) < 7]) + '_' + hashlib.md5(hash_input).hexdigest() + cache_name_extra
861
862 valid_chars = "_%s%s" % (string.ascii_letters, string.digits)
863 cache_name = ''.join([(c if c in valid_chars else '_') for c in cache_name])
864
865 if self.library_cache.get(cache_name):
866 print('<load %s from cache> ' % cache_name, file=sys.stderr)
867 generated_libs = []
868 for basename, contents in self.library_cache[cache_name]:
869 bc_file = os.path.join(build_dir, cache_name + '_' + basename)
870 with open(bc_file, 'wb') as f:
871 f.write(contents)
872 generated_libs.append(bc_file)
873 return generated_libs
874
875 print(f'<building and saving {cache_name} into cache>', file=sys.stderr)
876 if configure is not None:
877 # Avoid += so we don't mutate the default arg
878 configure = configure + configure_args
879
880 return build_library(name, build_dir, output_dir, generated_libs, configure,
881 make, make_args, self.library_cache,
882 cache_name, env_init=env_init, native=native, cflags=self.get_emcc_args())
883
884 def clear(self):
885 delete_contents(self.get_dir())
886 if EMSCRIPTEN_TEMP_DIR:
887 delete_contents(EMSCRIPTEN_TEMP_DIR)
888
889 def run_process(self, cmd, check=True, **args):
890 # Wrapper around shared.run_process. This is desirable so that the tests
891 # can fail (in the unittest sense) rather than error'ing.
892 # In the long run it would nice to completely remove the dependency on
893 # core emscripten code (shared.py) here.
894 try:
895 return shared.run_process(cmd, check=check, **args)
896 except subprocess.CalledProcessError as e:
897 if check and e.returncode != 0:
898 self.fail('subprocess exited with non-zero return code(%d): `%s`' %
899 (e.returncode, shared.shlex_join(cmd)))
900
901 def emcc(self, filename, args=[], output_filename=None, **kwargs):
902 if output_filename is None:
903 output_filename = filename + '.o'
904 try_delete(output_filename)
905 self.run_process([compiler_for(filename), filename] + args + ['-o', output_filename], **kwargs)
906
907 # Shared test code between main suite and others
908
909 def expect_fail(self, cmd, **args):
910 """Run a subprocess and assert that it returns non-zero.
911
912 Return the stderr of the subprocess.
913 """
914 proc = self.run_process(cmd, check=False, stderr=PIPE, **args)
915 self.assertNotEqual(proc.returncode, 0, 'subprocess unexpectedly succeeded. stderr:\n' + proc.stderr)
916 # When we check for failure we expect a user-visible error, not a traceback.
917 # However, on windows a python traceback can happen randomly sometimes,
918 # due to "Access is denied" https://github.com/emscripten-core/emscripten/issues/718
919 if not WINDOWS or 'Access is denied' not in proc.stderr:
920 self.assertNotContained('Traceback', proc.stderr)
921 return proc.stderr
922
923 # excercise dynamic linker.
924 #
925 # test that linking to shared library B, which is linked to A, loads A as well.
926 # main is also linked to C, which is also linked to A. A is loaded/initialized only once.
927 #
928 # B
929 # main < > A
930 # C
931 #
932 # this test is used by both test_core and test_browser.
933 # when run under broswer it excercises how dynamic linker handles concurrency
934 # - because B and C are loaded in parallel.
935 def _test_dylink_dso_needed(self, do_run):
936 create_file('liba.cpp', r'''
937 #include <stdio.h>
938 #include <emscripten.h>
939
940 static const char *afunc_prev;
941
942 extern "C" {
943 EMSCRIPTEN_KEEPALIVE void afunc(const char *s);
944 }
945
946 void afunc(const char *s) {
947 printf("a: %s (prev: %s)\n", s, afunc_prev);
948 afunc_prev = s;
949 }
950
951 struct ainit {
952 ainit() {
953 puts("a: loaded");
954 }
955 };
956
957 static ainit _;
958 ''')
959
960 create_file('libb.c', r'''
961 #include <emscripten.h>
962
963 void afunc(const char *s);
964
965 EMSCRIPTEN_KEEPALIVE void bfunc() {
966 afunc("b");
967 }
968 ''')
969
970 create_file('libc.c', r'''
971 #include <emscripten.h>
972
973 void afunc(const char *s);
974
975 EMSCRIPTEN_KEEPALIVE void cfunc() {
976 afunc("c");
977 }
978 ''')
979
980 # _test_dylink_dso_needed can be potentially called several times by a test.
981 # reset dylink-related options first.
982 self.clear_setting('MAIN_MODULE')
983 self.clear_setting('SIDE_MODULE')
984
985 # XXX in wasm each lib load currently takes 5MB; default INITIAL_MEMORY=16MB is thus not enough
986 self.set_setting('INITIAL_MEMORY', '32mb')
987
988 so = '.wasm' if self.is_wasm() else '.js'
989
990 def ccshared(src, linkto=[]):
991 cmdv = [EMCC, src, '-o', shared.unsuffixed(src) + so, '-s', 'SIDE_MODULE'] + self.get_emcc_args()
992 cmdv += linkto
993 self.run_process(cmdv)
994
995 ccshared('liba.cpp')
996 ccshared('libb.c', ['liba' + so])
997 ccshared('libc.c', ['liba' + so])
998
999 self.set_setting('MAIN_MODULE')
1000 extra_args = ['-L.', 'libb' + so, 'libc' + so]
1001 do_run(r'''
1002 #ifdef __cplusplus
1003 extern "C" {
1004 #endif
1005 void bfunc();
1006 void cfunc();
1007 #ifdef __cplusplus
1008 }
1009 #endif
1010
1011 int test_main() {
1012 bfunc();
1013 cfunc();
1014 return 0;
1015 }
1016 ''',
1017 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n', emcc_args=extra_args)
1018
1019 for libname in ['liba', 'libb', 'libc']:
1020 self.emcc_args += ['--embed-file', libname + so]
1021 do_run(r'''
1022 #include <assert.h>
1023 #include <dlfcn.h>
1024 #include <stddef.h>
1025
1026 int test_main() {
1027 void *bdso, *cdso;
1028 void (*bfunc_ptr)(), (*cfunc_ptr)();
1029
1030 // FIXME for RTLD_LOCAL binding symbols to loaded lib is not currently working
1031 bdso = dlopen("libb%(so)s", RTLD_NOW|RTLD_GLOBAL);
1032 assert(bdso != NULL);
1033 cdso = dlopen("libc%(so)s", RTLD_NOW|RTLD_GLOBAL);
1034 assert(cdso != NULL);
1035
1036 bfunc_ptr = (void (*)())dlsym(bdso, "bfunc");
1037 assert(bfunc_ptr != NULL);
1038 cfunc_ptr = (void (*)())dlsym(cdso, "cfunc");
1039 assert(cfunc_ptr != NULL);
1040
1041 bfunc_ptr();
1042 cfunc_ptr();
1043 return 0;
1044 }
1045 ''' % locals(),
1046 'a: loaded\na: b (prev: (null))\na: c (prev: b)\n')
1047
1048 def filtered_js_engines(self, js_engines=None):
1049 if js_engines is None:
1050 js_engines = self.js_engines
1051 for engine in js_engines:
1052 assert engine in config.JS_ENGINES, "js engine does not exist in config.JS_ENGINES"
1053 assert type(engine) == list
1054 for engine in self.banned_js_engines:
1055 assert type(engine) in (list, type(None))
1056 banned = [b[0] for b in self.banned_js_engines if b]
1057 return [engine for engine in js_engines if engine and engine[0] not in banned]
1058
1059 def do_run(self, src, expected_output, force_c=False, **kwargs):
1060 if 'no_build' in kwargs:
1061 filename = src
1062 else:
1063 if force_c:
1064 filename = 'src.c'
1065 else:
1066 filename = 'src.cpp'
1067 with open(filename, 'w') as f:
1068 f.write(src)
1069 self._build_and_run(filename, expected_output, **kwargs)
1070
1071 def do_runf(self, filename, expected_output=None, **kwargs):
1072 self._build_and_run(filename, expected_output, **kwargs)
1073
1074 ## Just like `do_run` but with filename of expected output
1075 def do_run_from_file(self, filename, expected_output_filename, **kwargs):
1076 self._build_and_run(filename, read_file(expected_output_filename), **kwargs)
1077
1078 def do_run_in_out_file_test(self, *path, **kwargs):
1079 srcfile = test_file(*path)
1080 out_suffix = kwargs.pop('out_suffix', '')
1081 outfile = shared.unsuffixed(srcfile) + out_suffix + '.out'
1082 expected = read_file(outfile)
1083 self._build_and_run(srcfile, expected, **kwargs)
1084
1085 ## Does a complete test - builds, runs, checks output, etc.
1086 def _build_and_run(self, filename, expected_output, args=[], output_nicerizer=None,
1087 no_build=False,
1088 js_engines=None, post_build=None, libraries=[],
1089 includes=[],
1090 assert_returncode=0, assert_identical=False, assert_all=False,
1091 check_for_error=True, force_c=False, emcc_args=[]):
1092 logger.debug(f'_build_and_run: {filename}')
1093
1094 if no_build:
1095 js_file = filename
1096 else:
1097 self.build(filename, libraries=libraries, includes=includes, post_build=post_build,
1098 force_c=force_c, emcc_args=emcc_args)
1099 js_file = shared.unsuffixed(os.path.basename(filename)) + '.js'
1100 self.assertExists(js_file)
1101
1102 engines = self.filtered_js_engines(js_engines)
1103 if len(engines) > 1 and not self.use_all_engines:
1104 engines = engines[:1]
1105 # In standalone mode, also add wasm vms as we should be able to run there too.
1106 if self.get_setting('STANDALONE_WASM'):
1107 # TODO once standalone wasm support is more stable, apply use_all_engines
1108 # like with js engines, but for now as we bring it up, test in all of them
1109 if not self.wasm_engines:
1110 logger.warning('no wasm engine was found to run the standalone part of this test')
1111 engines += self.wasm_engines
1112 if self.get_setting('WASM2C') and not EMTEST_LACKS_NATIVE_CLANG:
1113 # compile the c file to a native executable.
1114 c = shared.unsuffixed(js_file) + '.wasm.c'
1115 executable = shared.unsuffixed(js_file) + '.exe'
1116 cmd = [shared.CLANG_CC, c, '-o', executable] + clang_native.get_clang_native_args()
1117 self.run_process(cmd, env=clang_native.get_clang_native_env())
1118 # we can now run the executable directly, without an engine, which
1119 # we indicate with None as the engine
1120 engines += [[None]]
1121 if len(engines) == 0:
1122 self.skipTest('No JS engine present to run this test with. Check %s and the paths therein.' % config.EM_CONFIG)
1123 for engine in engines:
1124 js_output = self.run_js(js_file, engine, args, output_nicerizer=output_nicerizer, assert_returncode=assert_returncode)
1125 js_output = js_output.replace('\r\n', '\n')
1126 if expected_output:
1127 try:
1128 if assert_identical:
1129 self.assertIdentical(expected_output, js_output)
1130 elif assert_all:
1131 for o in expected_output:
1132 self.assertContained(o, js_output)
1133 else:
1134 self.assertContained(expected_output, js_output)
1135 if check_for_error:
1136 self.assertNotContained('ERROR', js_output)
1137 except Exception:
1138 print('(test did not pass in JS engine: %s)' % engine)
1139 raise
1140
1141 def get_freetype_library(self):
1142 if '-Werror' in self.emcc_args:
1143 self.emcc_args.remove('-Werror')
1144 return self.get_library(os.path.join('third_party', 'freetype'), os.path.join('objs', '.libs', 'libfreetype.a'), configure_args=['--disable-shared', '--without-zlib'])
1145
1146 def get_poppler_library(self, env_init=None):
1147 # The fontconfig symbols are all missing from the poppler build
1148 # e.g. FcConfigSubstitute
1149 self.set_setting('ERROR_ON_UNDEFINED_SYMBOLS', 0)
1150
1151 self.emcc_args += [
1152 '-I' + test_file('third_party/freetype/include'),
1153 '-I' + test_file('third_party/poppler/include')
1154 ]
1155
1156 freetype = self.get_freetype_library()
1157
1158 # Poppler has some pretty glaring warning. Suppress them to keep the
1159 # test output readable.
1160 if '-Werror' in self.emcc_args:
1161 self.emcc_args.remove('-Werror')
1162 self.emcc_args += [
1163 '-Wno-sentinel',
1164 '-Wno-logical-not-parentheses',
1165 '-Wno-unused-private-field',
1166 '-Wno-tautological-compare',
1167 '-Wno-unknown-pragmas',
1168 ]
1169 env_init = env_init.copy() if env_init else {}
1170 env_init['FONTCONFIG_CFLAGS'] = ' '
1171 env_init['FONTCONFIG_LIBS'] = ' '
1172
1173 poppler = self.get_library(
1174 os.path.join('third_party', 'poppler'),
1175 [os.path.join('utils', 'pdftoppm.o'), os.path.join('utils', 'parseargs.o'), os.path.join('poppler', '.libs', 'libpoppler.a')],
1176 env_init=env_init,
1177 configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--disable-shared'])
1178
1179 return poppler + freetype
1180
1181 def get_zlib_library(self):
1182 if WINDOWS:
1183 return self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'),
1184 configure=['cmake', '.'],
1185 make=['cmake', '--build', '.'],
1186 make_args=[])
1187 return self.get_library(os.path.join('third_party', 'zlib'), os.path.join('libz.a'), make_args=['libz.a'])
1188
1189
1190 # Run a server and a web page. When a test runs, we tell the server about it,
1191 # which tells the web page, which then opens a window with the test. Doing
1192 # it this way then allows the page to close() itself when done.
1193 def harness_server_func(in_queue, out_queue, port):
1194 class TestServerHandler(SimpleHTTPRequestHandler):
1195 # Request header handler for default do_GET() path in
1196 # SimpleHTTPRequestHandler.do_GET(self) below.
1197 def send_head(self):
1198 if self.path.endswith('.js'):
1199 path = self.translate_path(self.path)
1200 try:
1201 f = open(path, 'rb')
1202 except IOError:
1203 self.send_error(404, "File not found: " + path)
1204 return None
1205 self.send_response(200)
1206 self.send_header('Content-type', 'application/javascript')
1207 self.send_header('Connection', 'close')
1208 self.end_headers()
1209 return f
1210 else:
1211 return SimpleHTTPRequestHandler.send_head(self)
1212
1213 # Add COOP, COEP, CORP, and no-caching headers
1214 def end_headers(self):
1215 self.send_header('Access-Control-Allow-Origin', '*')
1216 self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
1217 self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
1218 self.send_header('Cross-Origin-Resource-Policy', 'cross-origin')
1219 self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
1220 return SimpleHTTPRequestHandler.end_headers(self)
1221
1222 def do_GET(self):
1223 if self.path == '/run_harness':
1224 if DEBUG:
1225 print('[server startup]')
1226 self.send_response(200)
1227 self.send_header('Content-type', 'text/html')
1228 self.end_headers()
1229 self.wfile.write(read_binary(test_file('browser_harness.html')))
1230 elif 'report_' in self.path:
1231 # the test is reporting its result. first change dir away from the
1232 # test dir, as it will be deleted now that the test is finishing, and
1233 # if we got a ping at that time, we'd return an error
1234 os.chdir(path_from_root())
1235 # for debugging, tests may encode the result and their own url (window.location) as result|url
1236 if '|' in self.path:
1237 path, url = self.path.split('|', 1)
1238 else:
1239 path = self.path
1240 url = '?'
1241 if DEBUG:
1242 print('[server response:', path, url, ']')
1243 if out_queue.empty():
1244 out_queue.put(path)
1245 else:
1246 # a badly-behaving test may send multiple xhrs with reported results; we just care
1247 # about the first (if we queued the others, they might be read as responses for
1248 # later tests, or maybe the test sends more than one in a racy manner).
1249 # we place 'None' in the queue here so that the outside knows something went wrong
1250 # (none is not a valid value otherwise; and we need the outside to know because if we
1251 # raise an error in here, it is just swallowed in python's webserver code - we want
1252 # the test to actually fail, which a webserver response can't do).
1253 out_queue.put(None)
1254 raise Exception('browser harness error, excessive response to server - test must be fixed! "%s"' % self.path)
1255 self.send_response(200)
1256 self.send_header('Content-type', 'text/plain')
1257 self.send_header('Cache-Control', 'no-cache, must-revalidate')
1258 self.send_header('Connection', 'close')
1259 self.send_header('Expires', '-1')
1260 self.end_headers()
1261 self.wfile.write(b'OK')
1262
1263 elif 'stdout=' in self.path or 'stderr=' in self.path or 'exception=' in self.path:
1264 '''
1265 To get logging to the console from browser tests, add this to
1266 print/printErr/the exception handler in src/shell.html:
1267
1268 var xhr = new XMLHttpRequest();
1269 xhr.open('GET', encodeURI('http://localhost:8888?stdout=' + text));
1270 xhr.send();
1271 '''
1272 print('[client logging:', unquote_plus(self.path), ']')
1273 self.send_response(200)
1274 self.send_header('Content-type', 'text/html')
1275 self.end_headers()
1276 elif self.path == '/check':
1277 self.send_response(200)
1278 self.send_header('Content-type', 'text/html')
1279 self.end_headers()
1280 if not in_queue.empty():
1281 # there is a new test ready to be served
1282 url, dir = in_queue.get()
1283 if DEBUG:
1284 print('[queue command:', url, dir, ']')
1285 assert in_queue.empty(), 'should not be any blockage - one test runs at a time'
1286 assert out_queue.empty(), 'the single response from the last test was read'
1287 # tell the browser to load the test
1288 self.wfile.write(b'COMMAND:' + url.encode('utf-8'))
1289 # move us to the right place to serve the files for the new test
1290 os.chdir(dir)
1291 else:
1292 # the browser must keep polling
1293 self.wfile.write(b'(wait)')
1294 else:
1295 # Use SimpleHTTPServer default file serving operation for GET.
1296 if DEBUG:
1297 print('[simple HTTP serving:', unquote_plus(self.path), ']')
1298 SimpleHTTPRequestHandler.do_GET(self)
1299
1300 def log_request(code=0, size=0):
1301 # don't log; too noisy
1302 pass
1303
1304 # allows streaming compilation to work
1305 SimpleHTTPRequestHandler.extensions_map['.wasm'] = 'application/wasm'
1306
1307 httpd = HTTPServer(('localhost', port), TestServerHandler)
1308 httpd.serve_forever() # test runner will kill us
1309
1310
1311 class Reporting(Enum):
1312 """When running browser tests we normally automatically include support
1313 code for reporting results back to the browser. This enum allows tests
1314 to decide what type of support code they need/want.
1315 """
1316 NONE = 0
1317 # Include the JS helpers for reporting results
1318 JS_ONLY = 1
1319 # Include C/C++ reporting code (REPORT_RESULT mactros) as well as JS helpers
1320 FULL = 2
1321
1322
1323 class BrowserCore(RunnerCore):
1324 # note how many tests hang / do not send an output. if many of these
1325 # happen, likely something is broken and it is best to abort the test
1326 # suite early, as otherwise we will wait for the timeout on every
1327 # single test (hundreds of minutes)
1328 MAX_UNRESPONSIVE_TESTS = 10
1329
1330 unresponsive_tests = 0
1331
1332 def __init__(self, *args, **kwargs):
1333 super().__init__(*args, **kwargs)
1334
1335 @staticmethod
1336 def browser_open(url):
1337 if not EMTEST_BROWSER:
1338 logger.info('Using default system browser')
1339 webbrowser.open_new(url)
1340 return
1341
1342 browser_args = shlex.split(EMTEST_BROWSER)
1343 # If the given browser is a scalar, treat it like one of the possible types
1344 # from https://docs.python.org/2/library/webbrowser.html
1345 if len(browser_args) == 1:
1346 try:
1347 # This throws if the type of browser isn't available
1348 webbrowser.get(browser_args[0]).open_new(url)
1349 logger.info('Using Emscripten browser: %s', browser_args[0])
1350 return
1351 except webbrowser.Error:
1352 # Ignore the exception and fallback to the custom command logic
1353 pass
1354 # Else assume the given browser is a specific program with additional
1355 # parameters and delegate to that
1356 logger.info('Using Emscripten browser: %s', str(browser_args))
1357 subprocess.Popen(browser_args + [url])
1358
1359 @classmethod
1360 def setUpClass(cls):
1361 super().setUpClass()
1362 cls.also_asmjs = int(os.getenv('EMTEST_BROWSER_ALSO_ASMJS', '0')) == 1
1363 cls.port = int(os.getenv('EMTEST_BROWSER_PORT', '8888'))
1364 if not has_browser():
1365 return
1366 cls.browser_timeout = 60
1367 cls.harness_in_queue = multiprocessing.Queue()
1368 cls.harness_out_queue = multiprocessing.Queue()
1369 cls.harness_server = multiprocessing.Process(target=harness_server_func, args=(cls.harness_in_queue, cls.harness_out_queue, cls.port))
1370 cls.harness_server.start()
1371 print('[Browser harness server on process %d]' % cls.harness_server.pid)
1372 cls.browser_open('http://localhost:%s/run_harness' % cls.port)
1373
1374 @classmethod
1375 def tearDownClass(cls):
1376 super().tearDownClass()
1377 if not has_browser():
1378 return
1379 cls.harness_server.terminate()
1380 print('[Browser harness server terminated]')
1381 if WINDOWS:
1382 # On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit:
1383 # WindowsError: [Error 32] The process cannot access the file because it is being used by another process.
1384 time.sleep(0.1)
1385
1386 def assert_out_queue_empty(self, who):
1387 if not self.harness_out_queue.empty():
1388 while not self.harness_out_queue.empty():
1389 self.harness_out_queue.get()
1390 raise Exception('excessive responses from %s' % who)
1391
1392 # @param extra_tries: how many more times to try this test, if it fails. browser tests have
1393 # many more causes of flakiness (in particular, they do not run
1394 # synchronously, so we have a timeout, which can be hit if the VM
1395 # we run on stalls temporarily), so we let each test try more than
1396 # once by default
1397 def run_browser(self, html_file, message, expectedResult=None, timeout=None, extra_tries=1):
1398 if not has_browser():
1399 return
1400 if BrowserCore.unresponsive_tests >= BrowserCore.MAX_UNRESPONSIVE_TESTS:
1401 self.skipTest('too many unresponsive tests, skipping browser launch - check your setup!')
1402 self.assert_out_queue_empty('previous test')
1403 if DEBUG:
1404 print('[browser launch:', html_file, ']')
1405 if expectedResult is not None:
1406 try:
1407 self.harness_in_queue.put((
1408 'http://localhost:%s/%s' % (self.port, html_file),
1409 self.get_dir()
1410 ))
1411 received_output = False
1412 output = '[no http server activity]'
1413 start = time.time()
1414 if timeout is None:
1415 timeout = self.browser_timeout
1416 while time.time() - start < timeout:
1417 if not self.harness_out_queue.empty():
1418 output = self.harness_out_queue.get()
1419 received_output = True
1420 break
1421 time.sleep(0.1)
1422 if not received_output:
1423 BrowserCore.unresponsive_tests += 1
1424 print('[unresponsive tests: %d]' % BrowserCore.unresponsive_tests)
1425 if output is None:
1426 # the browser harness reported an error already, and sent a None to tell
1427 # us to also fail the test
1428 raise Exception('failing test due to browser harness error')
1429 if output.startswith('/report_result?skipped:'):
1430 self.skipTest(unquote(output[len('/report_result?skipped:'):]).strip())
1431 else:
1432 # verify the result, and try again if we should do so
1433 output = unquote(output)
1434 try:
1435 self.assertContained(expectedResult, output)
1436 except Exception as e:
1437 if extra_tries > 0:
1438 print('[test error (see below), automatically retrying]')
1439 print(e)
1440 return self.run_browser(html_file, message, expectedResult, timeout, extra_tries - 1)
1441 else:
1442 raise e
1443 finally:
1444 time.sleep(0.1) # see comment about Windows above
1445 self.assert_out_queue_empty('this test')
1446 else:
1447 webbrowser.open_new(os.path.abspath(html_file))
1448 print('A web browser window should have opened a page containing the results of a part of this test.')
1449 print('You need to manually look at the page to see that it works ok: ' + message)
1450 print('(sleeping for a bit to keep the directory alive for the web browser..)')
1451 time.sleep(5)
1452 print('(moving on..)')
1453
1454 # @manually_trigger If set, we do not assume we should run the reftest when main() is done.
1455 # Instead, call doReftest() in JS yourself at the right time.
1456 def reftest(self, expected, manually_trigger=False):
1457 # make sure the pngs used here have no color correction, using e.g.
1458 # pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile outfile
1459 basename = os.path.basename(expected)
1460 shutil.copyfile(expected, os.path.join(self.get_dir(), basename))
1461 reporting = read_file(test_file('browser_reporting.js'))
1462 with open('reftest.js', 'w') as out:
1463 out.write('''
1464 function doReftest() {
1465 if (doReftest.done) return;
1466 doReftest.done = true;
1467 var img = new Image();
1468 img.onload = function() {
1469 assert(img.width == Module.canvas.width, 'Invalid width: ' + Module.canvas.width + ', should be ' + img.width);
1470 assert(img.height == Module.canvas.height, 'Invalid height: ' + Module.canvas.height + ', should be ' + img.height);
1471
1472 var canvas = document.createElement('canvas');
1473 canvas.width = img.width;
1474 canvas.height = img.height;
1475 var ctx = canvas.getContext('2d');
1476 ctx.drawImage(img, 0, 0);
1477 var expected = ctx.getImageData(0, 0, img.width, img.height).data;
1478
1479 var actualUrl = Module.canvas.toDataURL();
1480 var actualImage = new Image();
1481 actualImage.onload = function() {
1482 /*
1483 document.body.appendChild(img); // for comparisons
1484 var div = document.createElement('div');
1485 div.innerHTML = '^=expected, v=actual';
1486 document.body.appendChild(div);
1487 document.body.appendChild(actualImage); // to grab it for creating the test reference
1488 */
1489
1490 var actualCanvas = document.createElement('canvas');
1491 actualCanvas.width = actualImage.width;
1492 actualCanvas.height = actualImage.height;
1493 var actualCtx = actualCanvas.getContext('2d');
1494 actualCtx.drawImage(actualImage, 0, 0);
1495 var actual = actualCtx.getImageData(0, 0, actualImage.width, actualImage.height).data;
1496
1497 var total = 0;
1498 var width = img.width;
1499 var height = img.height;
1500 for (var x = 0; x < width; x++) {
1501 for (var y = 0; y < height; y++) {
1502 total += Math.abs(expected[y*width*4 + x*4 + 0] - actual[y*width*4 + x*4 + 0]);
1503 total += Math.abs(expected[y*width*4 + x*4 + 1] - actual[y*width*4 + x*4 + 1]);
1504 total += Math.abs(expected[y*width*4 + x*4 + 2] - actual[y*width*4 + x*4 + 2]);
1505 }
1506 }
1507 var wrong = Math.floor(total / (img.width*img.height*3)); // floor, to allow some margin of error for antialiasing
1508 // If the main JS file is in a worker, or modularize, then we need to supply our own reporting logic.
1509 if (typeof reportResultToServer === 'undefined') {
1510 (function() {
1511 %s
1512 reportResultToServer(wrong);
1513 })();
1514 } else {
1515 reportResultToServer(wrong);
1516 }
1517 };
1518 actualImage.src = actualUrl;
1519 }
1520 img.src = '%s';
1521 };
1522
1523 // Automatically trigger the reftest?
1524 if (!%s) {
1525 // Yes, automatically
1526
1527 Module['postRun'] = doReftest;
1528
1529 if (typeof WebGLClient !== 'undefined') {
1530 // trigger reftest from RAF as well, needed for workers where there is no pre|postRun on the main thread
1531 var realRAF = window.requestAnimationFrame;
1532 window.requestAnimationFrame = /** @suppress{checkTypes} */ (function(func) {
1533 realRAF(function() {
1534 func();
1535 realRAF(doReftest);
1536 });
1537 });
1538
1539 // trigger reftest from canvas render too, for workers not doing GL
1540 var realWOM = worker.onmessage;
1541 worker.onmessage = function(event) {
1542 realWOM(event);
1543 if (event.data.target === 'canvas' && event.data.op === 'render') {
1544 realRAF(doReftest);
1545 }
1546 };
1547 }
1548
1549 } else {
1550 // Manually trigger the reftest.
1551
1552 // The user will call it.
1553 // Add an event loop iteration to ensure rendering, so users don't need to bother.
1554 var realDoReftest = doReftest;
1555 doReftest = function() {
1556 setTimeout(realDoReftest, 1);
1557 };
1558 }
1559 ''' % (reporting, basename, int(manually_trigger)))
1560
1561 def compile_btest(self, args, reporting=Reporting.FULL):
1562 # Inject support code for reporting results. This adds an include a header so testcases can
1563 # use REPORT_RESULT, and also adds a cpp file to be compiled alongside the testcase, which
1564 # contains the implementation of REPORT_RESULT (we can't just include that implementation in
1565 # the header as there may be multiple files being compiled here).
1566 args += ['-s', 'IN_TEST_HARNESS']
1567 if reporting != Reporting.NONE:
1568 # For basic reporting we inject JS helper funtions to report result back to server.
1569 args += ['-DEMTEST_PORT_NUMBER=%d' % self.port,
1570 '--pre-js', test_file('browser_reporting.js')]
1571 if reporting == Reporting.FULL:
1572 # If C reporting (i.e. REPORT_RESULT macro) is required
1573 # also compile in report_result.cpp and forice-include report_result.h
1574 args += ['-I' + TEST_ROOT,
1575 '-include', test_file('report_result.h'),
1576 test_file('report_result.cpp')]
1577 self.run_process([EMCC] + self.get_emcc_args() + args)
1578
1579 def btest_exit(self, filename, assert_returncode=0, *args, **kwargs):
1580 """Special case of btest that reports its result solely via exiting
1581 with a give result code.
1582
1583 In this case we set EXIT_RUNTIME and we don't need to provide the
1584 REPORT_RESULT macro to the C code.
1585 """
1586 self.set_setting('EXIT_RUNTIME')
1587 kwargs['reporting'] = Reporting.JS_ONLY
1588 kwargs['expected'] = 'exit:%d' % assert_returncode
1589 return self.btest(filename, *args, **kwargs)
1590
1591 def btest(self, filename, expected=None, reference=None,
1592 reference_slack=0, manual_reference=False, post_build=None,
1593 args=None, message='.', also_proxied=False,
1594 url_suffix='', timeout=None, also_asmjs=False,
1595 manually_trigger_reftest=False, extra_tries=1,
1596 reporting=Reporting.FULL):
1597 assert expected or reference, 'a btest must either expect an output, or have a reference image'
1598 if args is None:
1599 args = []
1600 original_args = args.copy()
1601 if not os.path.exists(filename):
1602 filename = test_file(filename)
1603 if reference:
1604 self.reference = reference
1605 expected = [str(i) for i in range(0, reference_slack + 1)]
1606 self.reftest(test_file(reference), manually_trigger=manually_trigger_reftest)
1607 if not manual_reference:
1608 args += ['--pre-js', 'reftest.js', '-s', 'GL_TESTING']
1609 outfile = 'test.html'
1610 args += [filename, '-o', outfile]
1611 # print('all args:', args)
1612 try_delete(outfile)
1613 self.compile_btest(args, reporting=reporting)
1614 self.assertExists(outfile)
1615 if post_build:
1616 post_build()
1617 if not isinstance(expected, list):
1618 expected = [expected]
1619 self.run_browser(outfile + url_suffix, message, ['/report_result?' + e for e in expected], timeout=timeout, extra_tries=extra_tries)
1620
1621 # Tests can opt into being run under asmjs as well
1622 if 'WASM=0' not in original_args and (also_asmjs or self.also_asmjs):
1623 print('WASM=0')
1624 self.btest(filename, expected, reference, reference_slack, manual_reference, post_build,
1625 original_args + ['-s', 'WASM=0'], message, also_proxied=False, timeout=timeout)
1626
1627 if also_proxied:
1628 print('proxied...')
1629 if reference:
1630 assert not manual_reference
1631 manual_reference = True
1632 assert not post_build
1633 post_build = self.post_manual_reftest
1634 # run proxied
1635 self.btest(filename, expected, reference, reference_slack, manual_reference, post_build,
1636 original_args + ['--proxy-to-worker', '-s', 'GL_TESTING'], message, timeout=timeout)
1637
1638
1639 ###################################################################################################
1640
1641
1642 def build_library(name,
1643 build_dir,
1644 output_dir,
1645 generated_libs,
1646 configure=['sh', './configure'],
1647 make=['make'],
1648 make_args=[],
1649 cache=None,
1650 cache_name=None,
1651 env_init={},
1652 native=False,
1653 cflags=[]):
1654 """Build a library and cache the result. We build the library file
1655 once and cache it for all our tests. (We cache in memory since the test
1656 directory is destroyed and recreated for each test. Note that we cache
1657 separately for different compilers). This cache is just during the test
1658 runner. There is a different concept of caching as well, see |Cache|.
1659 """
1660
1661 if type(generated_libs) is not list:
1662 generated_libs = [generated_libs]
1663 source_dir = test_file(name.replace('_native', ''))
1664
1665 project_dir = Path(build_dir, name)
1666 if os.path.exists(project_dir):
1667 shutil.rmtree(project_dir)
1668 # Useful in debugging sometimes to comment this out, and two lines above
1669 shutil.copytree(source_dir, project_dir)
1670
1671 generated_libs = [os.path.join(project_dir, lib) for lib in generated_libs]
1672 if native:
1673 env = clang_native.get_clang_native_env()
1674 else:
1675 env = building.get_building_env(cflags=cflags)
1676 for k, v in env_init.items():
1677 env[k] = v
1678 if configure:
1679 if configure[0] == 'cmake':
1680 configure = [EMCMAKE] + configure
1681 else:
1682 configure = [EMCONFIGURE] + configure
1683 try:
1684 with open(os.path.join(project_dir, 'configure_out'), 'w') as out:
1685 with open(os.path.join(project_dir, 'configure_err'), 'w') as err:
1686 stdout = out if EM_BUILD_VERBOSE < 2 else None
1687 stderr = err if EM_BUILD_VERBOSE < 1 else None
1688 shared.run_process(configure, env=env, stdout=stdout, stderr=stderr,
1689 cwd=project_dir)
1690 except subprocess.CalledProcessError:
1691 print('-- configure stdout --')
1692 print(read_file(Path(project_dir, 'configure_out')))
1693 print('-- end configure stdout --')
1694 print('-- configure stderr --')
1695 print(read_file(Path(project_dir, 'configure_err')))
1696 print('-- end configure stderr --')
1697 raise
1698
1699 def open_make_out(mode='r'):
1700 return open(os.path.join(project_dir, 'make.out'), mode)
1701
1702 def open_make_err(mode='r'):
1703 return open(os.path.join(project_dir, 'make.err'), mode)
1704
1705 if EM_BUILD_VERBOSE >= 3:
1706 make_args += ['VERBOSE=1']
1707
1708 try:
1709 with open_make_out('w') as make_out:
1710 with open_make_err('w') as make_err:
1711 stdout = make_out if EM_BUILD_VERBOSE < 2 else None
1712 stderr = make_err if EM_BUILD_VERBOSE < 1 else None
1713 shared.run_process(make + make_args, stdout=stdout, stderr=stderr, env=env,
1714 cwd=project_dir)
1715 except subprocess.CalledProcessError:
1716 with open_make_out() as f:
1717 print('-- make stdout --')
1718 print(f.read())
1719 print('-- end make stdout --')
1720 with open_make_err() as f:
1721 print('-- make stderr --')
1722 print(f.read())
1723 print('-- end stderr --')
1724 raise
1725
1726 if cache is not None:
1727 cache[cache_name] = []
1728 for f in generated_libs:
1729 basename = os.path.basename(f)
1730 cache[cache_name].append((basename, read_binary(f)))
1731
1732 return generated_libs
1733
1734
173587 def check_js_engines():
173688 working_engines = [e for e in config.JS_ENGINES if jsrun.check_engine(e)]
173789 if len(working_engines) < len(config.JS_ENGINES):
173890 print('Not all the JS engines in JS_ENGINES appears to work.')
173991 exit(1)
174092
1741 if EMTEST_ALL_ENGINES:
93 if common.EMTEST_ALL_ENGINES:
174294 print('(using ALL js engines)')
174395 else:
174496 logger.warning('use EMTEST_ALL_ENGINES=1 in the env to run against all JS '
1910262
1911263 def suite_for_module(module, tests):
1912264 suite_supported = module.__name__ in ('test_core', 'test_other', 'test_posixtest')
1913 if not EMTEST_SAVE_DIR and not DEBUG:
265 if not common.EMTEST_SAVE_DIR and not shared.DEBUG:
1914266 has_multiple_tests = len(tests) > 1
1915267 has_multiple_cores = parallel_testsuite.num_cores() > 1
1916268 if suite_supported and has_multiple_tests and has_multiple_cores:
1931283 res = testRunner.run(suite)
1932284 msg = ('%s: %s run, %s errors, %s failures, %s skipped' %
1933285 (mod_name, res.testsRun, len(res.errors), len(res.failures), len(res.skipped)))
1934 num_failures += len(res.errors) + len(res.failures)
286 num_failures += len(res.errors) + len(res.failures) + len(res.unexpectedSuccesses)
1935287 resultMessages.append(msg)
1936288
1937289 if len(resultMessages) > 1:
1941293 for msg in resultMessages:
1942294 print(' ' + msg)
1943295
1944 # Return the number of failures as the process exit code for automating success/failure reporting.
1945 return min(num_failures, 255)
296 return num_failures
1946297
1947298
1948299 def parse_args(args):
1949300 parser = argparse.ArgumentParser(prog='runner.py', description=__doc__)
301 parser.add_argument('--save-dir', action='store_true', default='EMTEST_SAVE_DIR' in os.environ,
302 help='Save the temporary directory used during for each '
303 'test. Implies --cores=1.')
304 parser.add_argument('--no-clean', action='store_true',
305 help='Do not clean the temporary directory before each test run')
306 parser.add_argument('--verbose', action='store_true')
307 parser.add_argument('--all-engines', action='store_true')
308 parser.add_argument('--detect-leaks', action='store_true')
309 parser.add_argument('--skip-slow', action='store_true', help='Skip tests marked as slow')
310 parser.add_argument('--cores',
311 help='Set the number tests to run in parallel. Defaults '
312 'to the number of CPU cores.')
313 parser.add_argument('--rebaseline', action='store_true',
314 help='Automatically update test expectations for tests that support it.')
315 parser.add_argument('--browser',
316 help='Command to launch web browser in which to run browser tests.')
1950317 parser.add_argument('tests', nargs='*')
1951318 return parser.parse_args()
1952319
1953320
321 def configure():
322 common.EMTEST_BROWSER = os.getenv('EMTEST_BROWSER')
323 common.EMTEST_DETECT_TEMPFILE_LEAKS = int(os.getenv('EMTEST_DETECT_TEMPFILE_LEAKS', '0'))
324 common.EMTEST_SAVE_DIR = int(os.getenv('EMTEST_SAVE_DIR', '0'))
325 common.EMTEST_ALL_ENGINES = int(os.getenv('EMTEST_ALL_ENGINES', '0'))
326 common.EMTEST_SKIP_SLOW = int(os.getenv('EMTEST_SKIP_SLOW', '0'))
327 common.EMTEST_LACKS_NATIVE_CLANG = int(os.getenv('EMTEST_LACKS_NATIVE_CLANG', '0'))
328 common.EMTEST_REBASELINE = int(os.getenv('EMTEST_REBASELINE', '0'))
329 common.EMTEST_VERBOSE = int(os.getenv('EMTEST_VERBOSE', '0')) or shared.DEBUG
330
331 assert 'PARALLEL_SUITE_EMCC_CORES' not in os.environ, 'use EMTEST_CORES rather than PARALLEL_SUITE_EMCC_CORES'
332 parallel_testsuite.NUM_CORES = os.environ.get('EMTEST_CORES') or os.environ.get('EMCC_CORES')
333
334
1954335 def main(args):
1955336 options = parse_args(args)
337
338 # We set the environments variables here and then call configure,
339 # to apply them. This means the python's multiprocessing child
340 # process will see the same configuration even though they don't
341 # parse the command line.
342 def set_env(name, option_value):
343 if option_value is None:
344 return
345 if option_value is False:
346 value = '0'
347 elif option_value is True:
348 value = '1'
349 else:
350 value = str(option_value)
351 os.environ[name] = value
352
353 set_env('EMTEST_BROWSER', options.browser)
354 set_env('EMTEST_DETECT_TEMPFILE_LEAKS', options.detect_leaks)
355 set_env('EMTEST_SAVE_DIR', options.save_dir)
356 if options.no_clean:
357 set_env('EMTEST_SAVE_DIR', 2)
358 else:
359 set_env('EMTEST_SAVE_DIR', options.save_dir)
360 set_env('EMTEST_SKIP_SLOW', options.skip_slow)
361 set_env('EMTEST_ALL_ENGINES', options.all_engines)
362 set_env('EMTEST_REBASELINE', options.rebaseline)
363 set_env('EMTEST_VERBOSE', options.verbose)
364 set_env('EMTEST_CORES', options.cores)
365
366 configure()
367
1956368 check_js_engines()
1957369
1958370 def prepend_default(arg):
1972384 print('ERROR: could not find the following tests: ' + ' '.join(unmatched_tests))
1973385 return 1
1974386
1975 return run_tests(options, suites)
1976
387 num_failures = run_tests(options, suites)
388 # Return the number of failures as the process exit code
389 # for automating success/failure reporting. Return codes
390 # over 125 are not well supported on UNIX.
391 return min(num_failures, 125)
392
393
394 configure()
1977395
1978396 if __name__ == '__main__':
1979397 try:
+0
-32
tests/sigalrm.cpp less more
0 // Copyright 2015 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <unistd.h>
9 #include <pthread.h>
10
11 void alarm_handler(int dummy)
12 {
13 printf("Received alarm!\n");
14 #ifdef REPORT_RESULT
15 REPORT_RESULT(0);
16 #endif
17 exit(0);
18 }
19
20 int main()
21 {
22 if (signal(SIGALRM, alarm_handler) == SIG_ERR)
23 {
24 printf("Error in signal()!\n");
25 #ifdef REPORT_RESULT
26 REPORT_RESULT(1);
27 #endif
28 exit(1);
29 }
30 alarm(5);
31 }
2727 assert(errno == ENOSYS);
2828 assert(system("true") == -1);
2929 assert(errno == ENOSYS);
30 #ifdef REPORT_RESULT
31 REPORT_RESULT(0);
32 #endif
3330 #endif
3431 return 0;
3532 }
1717
1818 import clang_native
1919 import jsrun
20 import runner
21 from runner import TEST_ROOT, test_file, read_file, read_binary
20 import common
21 from common import TEST_ROOT, test_file, read_file, read_binary
2222 from tools.shared import run_process, PIPE, try_delete, EMCC, config
2323 from tools import building
2424
388388 ]
389389
390390
391 class benchmark(runner.RunnerCore):
391 class benchmark(common.RunnerCore):
392392 save_dir = True
393393
394394 @classmethod
404404 except Exception:
405405 pass
406406 try:
407 with runner.chdir(os.path.expanduser('~/Dev/mozilla-central')):
407 with common.chdir(os.path.expanduser('~/Dev/mozilla-central')):
408408 fingerprint.append('sm: ' + [line for line in run_process(['hg', 'tip'], stdout=PIPE).stdout.splitlines() if 'changeset' in line][0])
409409 except Exception:
410410 pass
1919 from pathlib import Path
2020 from urllib.request import urlopen
2121
22 from runner import BrowserCore, RunnerCore, path_from_root, has_browser, EMTEST_BROWSER, Reporting
23 from runner import create_file, parameterized, ensure_dir, disabled, test_file, WEBIDL_BINDER
24 from runner import read_file
22 from common import BrowserCore, RunnerCore, path_from_root, has_browser, EMTEST_BROWSER, Reporting
23 from common import create_file, parameterized, ensure_dir, disabled, test_file, WEBIDL_BINDER, EMMAKE
24 from common import read_file, require_v8
2525 from tools import shared
2626 from tools import system_libs
2727 from tools.shared import EMCC, WINDOWS, FILE_PACKAGER, PIPE
28 from tools.shared import try_delete, config
28 from tools.shared import try_delete
2929
3030
3131 def test_chunked_synchronous_xhr_server(support_byte_ranges, chunkSize, data, checksum, port):
425425 self.compile_btest([cpp, '--pre-js', data_js_file, '-o', abs_page_file, '-s', 'FORCE_FILESYSTEM'])
426426 self.run_browser(page_file, '|load me right before|.', '/report_result?0')
427427
428 def test_preload_caching(self):
428 @parameterized({
429 '0': (0,),
430 '1mb': (1 * 1024 * 1024,),
431 '100mb': (100 * 1024 * 1024,),
432 '150mb': (150 * 1024 * 1024,),
433 })
434 def test_preload_caching(self, extra_size):
429435 create_file('main.cpp', r'''
430436 #include <stdio.h>
431437 #include <string.h>
472478 # chrome's limit on IndexedDB item sizes, see
473479 # https://cs.chromium.org/chromium/src/content/renderer/indexed_db/webidbdatabase_impl.cc?type=cs&q=%22The+serialized+value+is+too+large%22&sq=package:chromium&g=0&l=177
474480 # https://cs.chromium.org/chromium/src/out/Debug/gen/third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h?type=cs&sq=package:chromium&g=0&l=60
475 for extra_size in (0, 1 * 1024 * 1024, 100 * 1024 * 1024, 150 * 1024 * 1024):
476 if is_chrome() and extra_size >= 100 * 1024 * 1024:
477 continue
478 create_file('somefile.txt', '''load me right before running the code please''' + ('_' * extra_size))
479 print('size:', os.path.getsize('somefile.txt'))
480 self.compile_btest(['main.cpp', '--use-preload-cache', '--js-library', 'test.js', '--preload-file', 'somefile.txt', '-o', 'page.html', '-s', 'ALLOW_MEMORY_GROWTH'])
481 self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
482 self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?2')
481 if is_chrome() and extra_size >= 100 * 1024 * 1024:
482 self.skipTest('chrome bug')
483 create_file('somefile.txt', '''load me right before running the code please''' + ('_' * extra_size))
484 print('size:', os.path.getsize('somefile.txt'))
485 self.compile_btest(['main.cpp', '--use-preload-cache', '--js-library', 'test.js', '--preload-file', 'somefile.txt', '-o', 'page.html', '-s', 'ALLOW_MEMORY_GROWTH'])
486 self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
487 self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?2')
483488
484489 def test_preload_caching_indexeddb_name(self):
485490 create_file('somefile.txt', '''load me right before running the code please''')
718723 shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.not')
719724 self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not', '-lSDL', '-lGL'], also_proxied=True, manually_trigger_reftest=True)
720725
721 def test_sdl_image_prepare_data(self):
726 @parameterized({
727 '': ([],),
728 # add testing for closure on preloaded files + ENVIRONMENT=web (we must not
729 # emit any node.js code here, see
730 # https://github.com/emscripten-core/emscripten/issues/14486
731 'closure_webonly': (['--closure', '1', '-s', 'ENVIRONMENT=web'],)
732 })
733 def test_sdl_image_prepare_data(self, args):
722734 # load an image file, get pixel data.
723735 shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.not')
724 self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not', '-lSDL', '-lGL'], manually_trigger_reftest=True)
736 self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not', '-lSDL', '-lGL'] + args, manually_trigger_reftest=True)
725737
726738 def test_sdl_image_must_prepare(self):
727739 # load an image file, get pixel data.
17461758 Path('Chapter_9/TextureWrap', 'CH09_TextureWrap.o'),
17471759 Path('Chapter_10/MultiTexture', 'CH10_MultiTexture.o'),
17481760 Path('Chapter_13/ParticleSystem', 'CH13_ParticleSystem.o'),
1749 ], configure=None)
1761 ], configure=None, make=[EMMAKE, 'make'])
17501762
17511763 def book_path(*pathelems):
17521764 return test_file('glbook', *pathelems)
18041816 self.btest('clientside_vertex_arrays_es3.c', reference='gl_triangle.png', args=['-s', 'FULL_ES3=1', '-s', 'USE_GLFW=3', '-lglfw', '-lGLESv2'])
18051817
18061818 def test_emscripten_api(self):
1807 self.btest('emscripten_api_browser.cpp', '1', args=['-s', 'EXPORTED_FUNCTIONS=_main,_third', '-lSDL'])
1819 self.btest_exit('emscripten_api_browser.c', args=['-s', 'EXPORTED_FUNCTIONS=_main,_third', '-lSDL'])
18081820
18091821 def test_emscripten_api2(self):
18101822 def setup():
18161828
18171829 setup()
18181830 self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt'], stdout=open('script2.js', 'w'))
1819 self.btest('emscripten_api_browser2.cpp', '1', args=['-s', 'EXPORTED_FUNCTIONS=_main,_set', '-s', 'FORCE_FILESYSTEM'])
1831 self.btest_exit('emscripten_api_browser2.c', args=['-s', 'EXPORTED_FUNCTIONS=_main,_set', '-s', 'FORCE_FILESYSTEM'])
18201832
18211833 # check using file packager to another dir
18221834 self.clear()
18241836 ensure_dir('sub')
18251837 self.run_process([FILE_PACKAGER, 'sub/test.data', '--preload', 'file1.txt', 'file2.txt'], stdout=open('script2.js', 'w'))
18261838 shutil.copyfile(Path('sub/test.data'), 'test.data')
1827 self.btest('emscripten_api_browser2.cpp', '1', args=['-s', 'EXPORTED_FUNCTIONS=_main,_set', '-s', 'FORCE_FILESYSTEM'])
1839 self.btest_exit('emscripten_api_browser2.c', args=['-s', 'EXPORTED_FUNCTIONS=_main,_set', '-s', 'FORCE_FILESYSTEM'])
18281840
18291841 def test_emscripten_api_infloop(self):
1830 self.btest('emscripten_api_browser_infloop.cpp', '7')
1842 self.btest_exit('emscripten_api_browser_infloop.cpp', assert_returncode=7)
18311843
18321844 def test_emscripten_fs_api(self):
18331845 shutil.copyfile(test_file('screenshot.png'), 'screenshot.png') # preloaded *after* run
18401852 @requires_threads
18411853 def test_emscripten_main_loop(self):
18421854 for args in [[], ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD', '-s', 'EXIT_RUNTIME']]:
1843 self.btest('emscripten_main_loop.cpp', '0', args=args)
1855 self.btest_exit('emscripten_main_loop.cpp', args=args)
18441856
18451857 @requires_threads
18461858 def test_emscripten_main_loop_settimeout(self):
18471859 for args in [
18481860 [],
18491861 # test pthreads + AUTO_JS_LIBRARIES mode as well
1850 ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD', '-s', 'AUTO_JS_LIBRARIES=0']
1862 ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD', '-s', 'AUTO_JS_LIBRARIES=0'],
18511863 ]:
1852 self.btest('emscripten_main_loop_settimeout.cpp', '1', args=args)
1864 self.btest_exit('emscripten_main_loop_settimeout.cpp', args=args)
18531865
18541866 @requires_threads
18551867 def test_emscripten_main_loop_and_blocker(self):
18561868 for args in [[], ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD']]:
1857 self.btest('emscripten_main_loop_and_blocker.cpp', '0', args=args)
1869 self.btest_exit('emscripten_main_loop_and_blocker.cpp', args=args)
18581870
18591871 @requires_threads
18601872 def test_emscripten_main_loop_and_blocker_exit(self):
18611873 # Same as above but tests that EXIT_RUNTIME works with emscripten_main_loop. The
18621874 # app should still stay alive until the loop ends
1863 self.btest_exit('emscripten_main_loop_and_blocker.cpp', 0)
1875 self.btest_exit('emscripten_main_loop_and_blocker.cpp')
18641876
18651877 @requires_threads
18661878 def test_emscripten_main_loop_setimmediate(self):
18671879 for args in [[], ['--proxy-to-worker'], ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD']]:
1868 self.btest('emscripten_main_loop_setimmediate.cpp', '1', args=args)
1880 self.btest_exit('emscripten_main_loop_setimmediate.cpp', args=args)
18691881
18701882 def test_fs_after_main(self):
18711883 for args in [[], ['-O1']]:
22202232
22212233 def test_runtimelink(self):
22222234 create_file('header.h', r'''
2223 struct point
2224 {
2235 struct point {
22252236 int x, y;
22262237 };
22272238 ''')
22282239
2229 create_file('supp.cpp', r'''
2240 create_file('supp.c', r'''
22302241 #include <stdio.h>
22312242 #include "header.h"
22322243
22332244 extern void mainFunc(int x);
22342245 extern int mainInt;
22352246
2236 void suppFunc(struct point &p) {
2237 printf("supp: %d,%d\n", p.x, p.y);
2238 mainFunc(p.x + p.y);
2247 void suppFunc(struct point *p) {
2248 printf("supp: %d,%d\n", p->x, p->y);
2249 mainFunc(p->x + p->y);
22392250 printf("supp see: %d\n", mainInt);
22402251 }
22412252
22422253 int suppInt = 76;
22432254 ''')
22442255
2245 create_file('main.cpp', r'''
2256 create_file('main.c', r'''
22462257 #include <stdio.h>
2258 #include <assert.h>
22472259 #include "header.h"
22482260
2249 extern void suppFunc(struct point &p);
2261 extern void suppFunc(struct point *p);
22502262 extern int suppInt;
22512263
22522264 void mainFunc(int x) {
22532265 printf("main: %d\n", x);
2266 assert(x == 56);
22542267 }
22552268
22562269 int mainInt = 543;
22572270
22582271 int main( int argc, const char *argv[] ) {
22592272 struct point p = { 54, 2 };
2260 suppFunc(p);
2273 suppFunc(&p);
22612274 printf("main see: %d\nok.\n", suppInt);
2262 return suppInt;
2275 assert(suppInt == 76);
2276 return 0;
22632277 }
22642278 ''')
2265 self.run_process([EMCC, 'supp.cpp', '-o', 'supp.wasm', '-s', 'SIDE_MODULE', '-O2', '-s', 'EXPORT_ALL'])
2266 self.btest_exit('main.cpp', args=['-DBROWSER=1', '-s', 'MAIN_MODULE', '-O2', 'supp.wasm', '-s', 'EXPORT_ALL'], assert_returncode=76)
2279 self.run_process([EMCC, 'supp.c', '-o', 'supp.wasm', '-s', 'SIDE_MODULE', '-O2'])
2280 self.btest_exit('main.c', args=['-s', 'MAIN_MODULE=2', '-O2', 'supp.wasm'])
22672281
22682282 def test_pre_run_deps(self):
22692283 # Adding a dependency in preRun will delay run
24572471 time.sleep(10)
24582472
24592473 def test_emscripten_async_wget_side_module(self):
2460 self.run_process([EMCC, test_file('browser_module.cpp'), '-o', 'lib.wasm', '-O2', '-s', 'SIDE_MODULE', '-s', 'EXPORTED_FUNCTIONS=_one,_two'])
2461 self.btest_exit('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE'], assert_returncode=8)
2474 self.run_process([EMCC, test_file('browser_module.c'), '-o', 'lib.wasm', '-O2', '-s', 'SIDE_MODULE'])
2475 self.btest_exit('browser_main.c', args=['-O2', '-s', 'MAIN_MODULE=2'])
24622476
24632477 @parameterized({
24642478 'non-lz4': ([],),
24712485 return 42;
24722486 }
24732487 ''')
2474 self.run_process([EMCC, 'library.c', '-s', 'SIDE_MODULE', '-O2', '-o', 'library.so', '-s', 'EXPORT_ALL'])
2488 self.run_process([EMCC, 'library.c', '-s', 'SIDE_MODULE', '-O2', '-o', 'library.so'])
24752489 create_file('main.c', r'''
24762490 #include <dlfcn.h>
24772491 #include <stdio.h>
24972511 ''')
24982512 self.btest_exit(
24992513 'main.c',
2500 args=['-s', 'MAIN_MODULE', '--preload-file', '.@/', '-O2', '--use-preload-plugins', '-s', 'EXPORT_ALL'] + args)
2514 args=['-s', 'MAIN_MODULE=2', '--preload-file', '.@/', '-O2', '--use-preload-plugins'] + args)
25012515
25022516 def test_mmap_file(self):
25032517 create_file('data.dat', 'data from the file ' + ('.' * 9000))
26072621 self.btest(test_file('webgl_color_buffer_readpixels.cpp'), args=['-lGL'], expected='0')
26082622
26092623 # Test for PR#5373 (https://github.com/emscripten-core/emscripten/pull/5373)
2624 @requires_graphics_hardware
26102625 def test_webgl_shader_source_length(self):
26112626 for opts in [[], ['-s', 'FULL_ES2=1']]:
26122627 print(opts)
26132628 self.btest(test_file('webgl_shader_source_length.cpp'), args=opts + ['-lGL'], expected='0')
26142629
26152630 # Tests calling glGetString(GL_UNMASKED_VENDOR_WEBGL).
2631 @requires_graphics_hardware
26162632 def test_webgl_unmasked_vendor_webgl(self):
26172633 self.btest(test_file('webgl_unmasked_vendor_webgl.c'), args=['-lGL'], expected='0')
26182634
2635 @requires_graphics_hardware
26192636 def test_webgl2(self):
26202637 for opts in [
26212638 ['-s', 'MIN_CHROME_VERSION=0'],
26372654 # (the testcase doesn't even use threads, but is compiled with thread support).
26382655 self.btest(test_file('webgl2.cpp'), args=['-s', 'MAX_WEBGL_VERSION=2', '-lGL', '-s', 'USE_PTHREADS'], expected='0')
26392656
2657 @requires_graphics_hardware
26402658 def test_webgl2_objects(self):
26412659 self.btest(test_file('webgl2_objects.cpp'), args=['-s', 'MAX_WEBGL_VERSION=2', '-lGL'], expected='0')
26422660
2661 @requires_graphics_hardware
26432662 def test_html5_webgl_api(self):
26442663 for mode in [['-s', 'OFFSCREENCANVAS_SUPPORT', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'],
26452664 ['-s', 'OFFSCREEN_FRAMEBUFFER', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'],
26482667 continue
26492668 self.btest(test_file('html5_webgl.c'), args=['-s', 'MAX_WEBGL_VERSION=2', '-lGL'] + mode, expected='0')
26502669
2670 @requires_graphics_hardware
26512671 def test_webgl2_ubos(self):
26522672 self.btest(test_file('webgl2_ubos.cpp'), args=['-s', 'MAX_WEBGL_VERSION=2', '-lGL'], expected='0')
26532673
27182738
27192739 def test_wget(self):
27202740 create_file('test.txt', 'emscripten')
2721 self.btest(test_file('test_wget.c'), expected='1', args=['-s', 'ASYNCIFY'])
2741 self.btest_exit(test_file('test_wget.c'), args=['-s', 'ASYNCIFY'])
27222742
27232743 def test_wget_data(self):
27242744 create_file('test.txt', 'emscripten')
2725 self.btest(test_file('test_wget_data.c'), expected='1', args=['-O2', '-g2', '-s', 'ASYNCIFY'])
2745 self.btest_exit(test_file('test_wget_data.c'), args=['-O2', '-g2', '-s', 'ASYNCIFY'])
27262746
27272747 @parameterized({
27282748 '': ([],),
32083228 def test_sdl2_misc(self):
32093229 self.btest_exit('sdl2_misc.c', args=['-s', 'USE_SDL=2'])
32103230
3211 @disabled('https://github.com/emscripten-core/emscripten/issues/13101')
32123231 def test_sdl2_misc_main_module(self):
32133232 self.btest_exit('sdl2_misc.c', args=['-s', 'USE_SDL=2', '-s', 'MAIN_MODULE'])
32143233
34723491
34733492 @requires_sync_compilation
34743493 def test_dynamic_link(self):
3475 create_file('main.cpp', r'''
3494 create_file('main.c', r'''
34763495 #include <stdio.h>
34773496 #include <stdlib.h>
34783497 #include <string.h>
34923511 });
34933512 puts(ret);
34943513 EM_ASM({ assert(Module.printed === 'hello through side', ['expected', Module.printed]); });
3495 REPORT_RESULT(2);
34963514 return 0;
34973515 }
34983516 ''')
3499 create_file('side.cpp', r'''
3517 create_file('side.c', r'''
35003518 #include <stdlib.h>
35013519 #include <string.h>
35023520 char *side(const char *data);
35063524 return ret;
35073525 }
35083526 ''')
3509 self.run_process([EMCC, 'side.cpp', '-s', 'SIDE_MODULE', '-O2', '-o', 'side.wasm', '-s', 'EXPORT_ALL'])
3510 self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE', '-O2', '-s', 'EXPORT_ALL', 'side.wasm'])
3527 self.run_process([EMCC, 'side.c', '-s', 'SIDE_MODULE', '-O2', '-o', 'side.wasm'])
3528 self.btest_exit(self.in_dir('main.c'), args=['-s', 'MAIN_MODULE=2', '-O2', 'side.wasm'])
35113529
35123530 print('wasm in worker (we can read binary data synchronously there)')
35133531
3514 self.run_process([EMCC, 'side.cpp', '-s', 'SIDE_MODULE', '-O2', '-o', 'side.wasm', '-s', 'EXPORT_ALL'])
3515 self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE', '-O2', '--proxy-to-worker', '-s', 'EXPORT_ALL', 'side.wasm'])
3532 self.run_process([EMCC, 'side.c', '-s', 'SIDE_MODULE', '-O2', '-o', 'side.wasm'])
3533 self.btest_exit(self.in_dir('main.c'), args=['-s', 'MAIN_MODULE=2', '-O2', '--proxy-to-worker', 'side.wasm'])
35163534
35173535 print('wasm (will auto-preload since no sync binary reading)')
35183536
35193537 # same wasm side module works
3520 self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE', '-O2', '-s', 'EXPORT_ALL', 'side.wasm'])
3538 self.btest_exit(self.in_dir('main.c'), args=['-s', 'MAIN_MODULE=2', '-O2', '-s', 'EXPORT_ALL', 'side.wasm'])
3539
3540 def test_dlopen_blocking(self):
3541 create_file('side.c', 'int foo = 42;\n')
3542 self.run_process([EMCC, 'side.c', '-o', 'libside.so', '-s', 'SIDE_MODULE', '-s', 'USE_PTHREADS', '-Wno-experimental'])
3543 # Attempt to use dlopen without preloading the side module should fail on the main thread
3544 # since the syncronous `readBinary` function does not exist.
3545 self.btest_exit(test_file('other/test_dlopen_blocking.c'), assert_returncode=1, args=['-s', 'MAIN_MODULE=2'])
3546 # But with PROXY_TO_PTHEAD it does work, since we can do blocking and sync XHR in a worker.
3547 self.btest_exit(test_file('other/test_dlopen_blocking.c'), args=['-s', 'MAIN_MODULE=2', '-s', 'PROXY_TO_PTHREAD', '-s', 'USE_PTHREADS', '-Wno-experimental'])
35213548
35223549 # verify that dynamic linking works in all kinds of in-browser environments.
35233550 # don't mix different kinds in a single test.
35663593 @requires_graphics_hardware
35673594 @requires_sync_compilation
35683595 def test_dynamic_link_glemu(self):
3569 create_file('main.cpp', r'''
3596 create_file('main.c', r'''
35703597 #include <stdio.h>
35713598 #include <string.h>
35723599 #include <assert.h>
35793606 return 0;
35803607 }
35813608 ''')
3582 create_file('side.cpp', r'''
3609 create_file('side.c', r'''
35833610 #include "SDL/SDL.h"
35843611 #include "SDL/SDL_opengl.h"
35853612 const char *side() {
35883615 return (const char *)glGetString(GL_EXTENSIONS);
35893616 }
35903617 ''')
3591 self.run_process([EMCC, 'side.cpp', '-s', 'SIDE_MODULE', '-O2', '-o', 'side.wasm', '-lSDL', '-s', 'EXPORT_ALL'])
3592
3593 self.btest(self.in_dir('main.cpp'), '1', args=['-s', 'MAIN_MODULE', '-O2', '-s', 'LEGACY_GL_EMULATION', '-lSDL', '-lGL', '-s', 'EXPORT_ALL', 'side.wasm'])
3618 self.run_process([EMCC, 'side.c', '-s', 'SIDE_MODULE', '-O2', '-o', 'side.wasm', '-lSDL'])
3619
3620 self.btest(self.in_dir('main.c'), '1', args=['-s', 'MAIN_MODULE=2', '-O2', '-s', 'LEGACY_GL_EMULATION', '-lSDL', '-lGL', 'side.wasm'])
35943621
35953622 def test_dynamic_link_many(self):
35963623 # test asynchronously loading two side modules during startup
35973624 create_file('main.c', r'''
3625 #include <assert.h>
35983626 int side1();
35993627 int side2();
36003628 int main() {
3601 return side1() + side2();
3629 assert(side1() == 1);
3630 assert(side2() == 2);
3631 return 0;
36023632 }
36033633 ''')
36043634 create_file('side1.c', r'''
36093639 ''')
36103640 self.run_process([EMCC, 'side1.c', '-s', 'SIDE_MODULE', '-o', 'side1.wasm'])
36113641 self.run_process([EMCC, 'side2.c', '-s', 'SIDE_MODULE', '-o', 'side2.wasm'])
3612 self.btest_exit(self.in_dir('main.c'), assert_returncode=3,
3613 args=['-s', 'MAIN_MODULE', 'side1.wasm', 'side2.wasm'])
3642 self.btest_exit(self.in_dir('main.c'), args=['-s', 'MAIN_MODULE=2', 'side1.wasm', 'side2.wasm'])
36143643
36153644 def test_dynamic_link_pthread_many(self):
36163645 # Test asynchronously loading two side modules during startup
36543683 self.run_process([EMCC, 'side1.cpp', '-Wno-experimental', '-pthread', '-s', 'SIDE_MODULE', '-o', 'side1.wasm'])
36553684 self.run_process([EMCC, 'side2.cpp', '-Wno-experimental', '-pthread', '-s', 'SIDE_MODULE', '-o', 'side2.wasm'])
36563685 self.btest(self.in_dir('main.cpp'), '1',
3657 args=['-Wno-experimental', '-pthread', '-s', 'MAIN_MODULE', 'side1.wasm', 'side2.wasm'])
3686 args=['-Wno-experimental', '-pthread', '-s', 'MAIN_MODULE=2', 'side1.wasm', 'side2.wasm'])
36583687
36593688 def test_memory_growth_during_startup(self):
36603689 create_file('data.dat', 'X' * (30 * 1024 * 1024))
38503879 # Test that pthread cleanup stack (pthread_cleanup_push/_pop) works.
38513880 @requires_threads
38523881 def test_pthread_cleanup(self):
3853 self.btest(test_file('pthread/test_pthread_cleanup.cpp'), expected='907640832', args=['-O3', '-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE=8'])
3882 self.btest_exit(test_file('pthread/test_pthread_cleanup.cpp'), args=['-O3', '-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE=8'])
38543883
38553884 # Tests the pthread mutex api.
38563885 @requires_threads
39263955 # Test that the main thread is able to use pthread_set/getspecific.
39273956 @requires_threads
39283957 def test_pthread_setspecific_mainthread(self):
3929 self.btest(test_file('pthread/test_pthread_setspecific_mainthread.cpp'), expected='0', args=['-s', 'INITIAL_MEMORY=64MB', '-O3', '-s', 'USE_PTHREADS'], also_asmjs=True)
3958 self.btest_exit(test_file('pthread/test_pthread_setspecific_mainthread.c'), args=['-s', 'INITIAL_MEMORY=64MB', '-O3', '-s', 'USE_PTHREADS'], also_asmjs=True)
39303959
39313960 # Test that pthreads have access to filesystem.
39323961 @requires_threads
41514180
41524181 # Test that it is possible to send a signal via calling alarm(timeout), which in turn calls to the signal handler set by signal(SIGALRM, func);
41534182 def test_sigalrm(self):
4154 self.btest(test_file('sigalrm.cpp'), expected='0', args=['-O3'])
4183 self.btest_exit(test_file('test_sigalrm.c'), args=['-O3'])
41554184
41564185 def test_canvas_style_proxy(self):
41574186 self.btest('canvas_style_proxy.c', expected='1', args=['--proxy-to-worker', '--shell-file', test_file('canvas_style_proxy_shell.html'), '--pre-js', test_file('canvas_style_proxy_pre.js')])
42764305 size = os.path.getsize('test.js')
42774306 print('size:', size)
42784307 # Note that this size includes test harness additions (for reporting the result, etc.).
4279 self.assertLess(abs(size - 5453), 100)
4308 self.assertLess(abs(size - 5368), 100)
42804309
42814310 # Tests that it is possible to initialize and render WebGL content in a pthread by using OffscreenCanvas.
42824311 # -DTEST_CHAINED_WEBGL_CONTEXT_PASSING: Tests that it is possible to transfer WebGL canvas in a chain from main thread -> thread 1 -> thread 2 and then init and render WebGL content there.
42834312 @no_chrome('see https://crbug.com/961765')
42844313 @requires_threads
42854314 @requires_offscreen_canvas
4315 @requires_graphics_hardware
42864316 def test_webgl_offscreen_canvas_in_pthread(self):
42874317 for args in [[], ['-DTEST_CHAINED_WEBGL_CONTEXT_PASSING']]:
42884318 self.btest('gl_in_pthread.cpp', expected='1', args=args + ['-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT', '-lGL'])
42914321 # -DTEST_MAIN_THREAD_EXPLICIT_COMMIT: Test the same (WebGL on main thread after pthread), but by using explicit .commit() to swap on the main thread instead of implicit "swap when rAF ends" logic
42924322 @requires_threads
42934323 @requires_offscreen_canvas
4324 @requires_graphics_hardware
42944325 @disabled('This test is disabled because current OffscreenCanvas does not allow transfering it after a rendering context has been created for it.')
42954326 def test_webgl_offscreen_canvas_in_mainthread_after_pthread(self):
42964327 for args in [[], ['-DTEST_MAIN_THREAD_EXPLICIT_COMMIT']]:
42984329
42994330 @requires_threads
43004331 @requires_offscreen_canvas
4332 @requires_graphics_hardware
43014333 def test_webgl_offscreen_canvas_only_in_pthread(self):
4302 self.btest('gl_only_in_pthread.cpp', expected='0', args=['-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE', '-s', 'OFFSCREENCANVAS_SUPPORT', '-lGL', '-s', 'OFFSCREEN_FRAMEBUFFER'])
4334 self.btest_exit('gl_only_in_pthread.cpp', args=['-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE', '-s', 'OFFSCREENCANVAS_SUPPORT', '-lGL', '-s', 'OFFSCREEN_FRAMEBUFFER'])
43034335
43044336 # Tests that rendering from client side memory without default-enabling extensions works.
43054337 @requires_graphics_hardware
43064338 def test_webgl_from_client_side_memory_without_default_enabled_extensions(self):
4307 self.btest('webgl_draw_triangle.c', '0', args=['-lGL', '-s', 'OFFSCREEN_FRAMEBUFFER', '-DEXPLICIT_SWAP=1', '-DDRAW_FROM_CLIENT_MEMORY=1', '-s', 'FULL_ES2=1'])
4339 self.btest_exit('webgl_draw_triangle.c', args=['-lGL', '-s', 'OFFSCREEN_FRAMEBUFFER', '-DEXPLICIT_SWAP=1', '-DDRAW_FROM_CLIENT_MEMORY=1', '-s', 'FULL_ES2=1'])
43084340
43094341 # Tests for WEBGL_multi_draw extension
43104342 # For testing WebGL draft extensions like this, if using chrome as the browser,
43414373 @requires_graphics_hardware
43424374 def test_webgl_sample_query(self):
43434375 cmd = ['-s', 'MAX_WEBGL_VERSION=2', '-lGL']
4344 self.btest('webgl_sample_query.cpp', expected='0', args=cmd)
4376 self.btest_exit('webgl_sample_query.cpp', args=cmd)
43454377
43464378 @requires_graphics_hardware
43474379 def test_webgl_timer_query(self):
43544386 ['-s', 'MAX_WEBGL_VERSION=2'],
43554387 ]:
43564388 cmd = args + ['-lGL']
4357 self.btest('webgl_timer_query.cpp', expected='0', args=cmd)
4389 self.btest_exit('webgl_timer_query.cpp', args=cmd)
43584390
43594391 # Tests that -s OFFSCREEN_FRAMEBUFFER=1 rendering works.
43604392 @requires_graphics_hardware
43644396 for version in [[], ['-s', 'FULL_ES3'], ['-s', 'FULL_ES3']]:
43654397 args = ['-lGL', '-s', 'OFFSCREEN_FRAMEBUFFER', '-DEXPLICIT_SWAP=1'] + threads + version
43664398 print('with args: %s' % str(args))
4367 self.btest('webgl_draw_triangle.c', '0', args=args)
4399 self.btest_exit('webgl_draw_triangle.c', args=args)
43684400
43694401 # Tests that VAOs can be used even if WebGL enableExtensionsByDefault is set to 0.
43704402 @requires_graphics_hardware
43714403 def test_webgl_vao_without_automatic_extensions(self):
4372 self.btest('test_webgl_no_auto_init_extensions.c', '0', args=['-lGL', '-s', 'GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=0'])
4404 self.btest_exit('test_webgl_no_auto_init_extensions.c', args=['-lGL', '-s', 'GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=0'])
43734405
43744406 # Tests that offscreen framebuffer state restoration works
43754407 @requires_graphics_hardware
43884420 ['-s', 'MAX_WEBGL_VERSION=2', '-DTEST_WEBGL2=1', '-DTEST_ANTIALIAS=0'],
43894421 ]:
43904422 cmd = args + ['-lGL', '-s', 'OFFSCREEN_FRAMEBUFFER', '-DEXPLICIT_SWAP=1']
4391 self.btest('webgl_offscreen_framebuffer_swap_with_bad_state.c', '0', args=cmd)
4423 self.btest_exit('webgl_offscreen_framebuffer_swap_with_bad_state.c', args=cmd)
43924424
43934425 # Tests that -s WORKAROUND_OLD_WEBGL_UNIFORM_UPLOAD_IGNORED_OFFSET_BUG=1 rendering works.
43944426 @requires_graphics_hardware
43954427 def test_webgl_workaround_webgl_uniform_upload_bug(self):
4396 self.btest('webgl_draw_triangle_with_uniform_color.c', '0', args=['-lGL', '-s', 'WORKAROUND_OLD_WEBGL_UNIFORM_UPLOAD_IGNORED_OFFSET_BUG'])
4428 self.btest_exit('webgl_draw_triangle_with_uniform_color.c', args=['-lGL', '-s', 'WORKAROUND_OLD_WEBGL_UNIFORM_UPLOAD_IGNORED_OFFSET_BUG'])
43974429
43984430 # Tests that using an array of structs in GL uniforms works.
43994431 @requires_graphics_hardware
44054437 # -DTEST_OFFSCREEN_CANVAS=2: Tests that if a WebGL context is created on a pthread that has the canvas transferred to it via automatic transferring of Module.canvas when EMSCRIPTEN_PTHREAD_TRANSFERRED_CANVASES is not defined, then OffscreenCanvas is also used
44064438 @requires_threads
44074439 @requires_offscreen_canvas
4440 @requires_graphics_hardware
44084441 def test_webgl_offscreen_canvas_in_proxied_pthread(self):
44094442 for asyncify in [0, 1]:
44104443 cmd = ['-s', 'USE_PTHREADS', '-s', 'OFFSCREENCANVAS_SUPPORT', '-lGL', '-s', 'GL_DEBUG', '-s', 'PROXY_TO_PTHREAD']
44354468 '-s', 'MAX_WEBGL_VERSION=2',
44364469 '-s', 'GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=' + str(simple_enable_extensions),
44374470 '-s', 'GL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=' + str(simple_enable_extensions)]
4438 self.btest('webgl2_simple_enable_extensions.c', expected='0', args=cmd)
4471 self.btest_exit('webgl2_simple_enable_extensions.c', args=cmd)
44394472
44404473 # Tests the feature that shell html page can preallocate the typed array and place it
44414474 # to Module.buffer before loading the script page.
44474480 # Tests emscripten_fetch() usage to XHR data directly to memory without persisting results to IndexedDB.
44484481 def test_fetch_to_memory(self):
44494482 # Test error reporting in the negative case when the file URL doesn't exist. (http 404)
4450 self.btest('fetch/to_memory.cpp',
4451 expected='1',
4452 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '-DFILE_DOES_NOT_EXIST'],
4453 also_asmjs=True)
4483 self.btest_exit('fetch/to_memory.cpp',
4484 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '-DFILE_DOES_NOT_EXIST'],
4485 also_asmjs=True)
44544486
44554487 # Test the positive case when the file URL exists. (http 200)
44564488 shutil.copyfile(test_file('gears.png'), 'gears.png')
44574489 for arg in [[], ['-s', 'FETCH_SUPPORT_INDEXEDDB=0']]:
4458 self.btest('fetch/to_memory.cpp',
4459 expected='1',
4460 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH'] + arg,
4461 also_asmjs=True)
4490 self.btest_exit('fetch/to_memory.cpp',
4491 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH'] + arg,
4492 also_asmjs=True)
44624493
44634494 @parameterized({
44644495 '': ([],),
44744505
44754506 def test_fetch_to_indexdb(self):
44764507 shutil.copyfile(test_file('gears.png'), 'gears.png')
4477 self.btest('fetch/to_indexeddb.cpp',
4478 expected='1',
4479 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH'],
4480 also_asmjs=True)
4508 self.btest_exit('fetch/to_indexeddb.cpp',
4509 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH'],
4510 also_asmjs=True)
44814511
44824512 # Tests emscripten_fetch() usage to persist an XHR into IndexedDB and subsequently load up from there.
44834513 def test_fetch_cached_xhr(self):
44844514 shutil.copyfile(test_file('gears.png'), 'gears.png')
4485 self.btest('fetch/cached_xhr.cpp',
4486 expected='1',
4487 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH'],
4488 also_asmjs=True)
4515 self.btest_exit('fetch/cached_xhr.cpp',
4516 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH'],
4517 also_asmjs=True)
44894518
44904519 # Tests that response headers get set on emscripten_fetch_t values.
44914520 @requires_threads
44924521 def test_fetch_response_headers(self):
44934522 shutil.copyfile(test_file('gears.png'), 'gears.png')
4494 self.btest('fetch/response_headers.cpp', expected='1', args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'], also_asmjs=True)
4523 self.btest_exit('fetch/response_headers.cpp', args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'], also_asmjs=True)
44954524
44964525 # Test emscripten_fetch() usage to stream a XHR in to memory without storing the full file in memory
44974526 def test_fetch_stream_file(self):
45044533 with open('largefile.txt', 'w') as f:
45054534 for i in range(1024):
45064535 f.write(s)
4507 self.btest('fetch/stream_file.cpp',
4508 expected='1',
4509 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '-s', 'INITIAL_MEMORY=536870912'],
4510 also_asmjs=True)
4536 self.btest_exit('fetch/stream_file.cpp',
4537 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '-s', 'INITIAL_MEMORY=536870912'],
4538 also_asmjs=True)
45114539
45124540 # Tests emscripten_fetch() usage in synchronous mode when used from the main
45134541 # thread proxied to a Worker with -s PROXY_TO_PTHREAD=1 option.
45214549 @requires_threads
45224550 def test_fetch_implicit_append(self):
45234551 shutil.copyfile(test_file('gears.png'), 'gears.png')
4524 self.btest('fetch/example_synchronous_fetch.cpp', expected='200', args=['-s', 'FETCH', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'])
4552 self.btest_exit('fetch/example_synchronous_fetch.cpp', args=['-s', 'FETCH', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'])
45254553
45264554 # Tests synchronous emscripten_fetch() usage from wasm pthread in fastcomp.
45274555 @requires_threads
45284556 def test_fetch_sync_xhr_in_wasm(self):
45294557 shutil.copyfile(test_file('gears.png'), 'gears.png')
4530 self.btest('fetch/example_synchronous_fetch.cpp', expected='200', args=['-s', 'FETCH', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'])
4558 self.btest_exit('fetch/example_synchronous_fetch.cpp', args=['-s', 'FETCH', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'])
45314559
45324560 # Tests that the Fetch API works for synchronous XHRs when used with --proxy-to-worker.
45334561 @requires_threads
45344562 def test_fetch_sync_xhr_in_proxy_to_worker(self):
45354563 shutil.copyfile(test_file('gears.png'), 'gears.png')
4536 self.btest('fetch/sync_xhr.cpp',
4537 expected='0',
4538 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '--proxy-to-worker'],
4539 also_asmjs=True)
4564 self.btest_exit('fetch/sync_xhr.cpp',
4565 args=['-s', 'FETCH_DEBUG', '-s', 'FETCH', '--proxy-to-worker'],
4566 also_asmjs=True)
45404567
45414568 # Tests waiting on EMSCRIPTEN_FETCH_WAITABLE request from a worker thread
45424569 @no_wasm_backend("emscripten_fetch_wait uses an asm.js based web worker")
45784605 @requires_asmfs
45794606 @requires_threads
45804607 def test_asmfs_mkdir_create_unlink_rmdir(self):
4581 self.btest('cstdio/test_remove.cpp', expected='0', args=['-s', 'ASMFS', '-s', 'WASM=0', '-s', 'USE_PTHREADS', '-s', 'FETCH_DEBUG'])
4608 self.btest_exit('cstdio/test_remove.cpp', args=['-s', 'ASMFS', '-s', 'WASM=0', '-s', 'USE_PTHREADS', '-s', 'FETCH_DEBUG'])
45824609
45834610 @requires_asmfs
45844611 @requires_threads
46234650 ['-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE=2'],
46244651 ]:
46254652 print("Testing with: ", args)
4626 self.btest('pthread/test_pthread_locale.c', expected='1', args=args)
4627
4628 # Tests the Emscripten HTML5 API emscripten_set_canvas_element_size() and emscripten_get_canvas_element_size() functionality in singlethreaded programs.
4653 self.btest_exit('pthread/test_pthread_locale.c', args=args)
4654
4655 # Tests the Emscripten HTML5 API emscripten_set_canvas_element_size() and
4656 # emscripten_get_canvas_element_size() functionality in singlethreaded programs.
46294657 def test_emscripten_set_canvas_element_size(self):
4630 self.btest('emscripten_set_canvas_element_size.c', expected='1')
4631
4632 # Test that emscripten_get_device_pixel_ratio() is callable from pthreads (and proxies to main thread to obtain the proper window.devicePixelRatio value).
4658 self.btest_exit('emscripten_set_canvas_element_size.c')
4659
4660 # Test that emscripten_get_device_pixel_ratio() is callable from pthreads (and proxies to main
4661 # thread to obtain the proper window.devicePixelRatio value).
46334662 @requires_threads
46344663 def test_emscripten_get_device_pixel_ratio(self):
46354664 for args in [[], ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD']]:
4636 self.btest('emscripten_get_device_pixel_ratio.c', expected='1', args=args)
4665 self.btest_exit('emscripten_get_device_pixel_ratio.c', args=args)
46374666
46384667 # Tests that emscripten_run_script() variants of functions work in pthreads.
46394668 @requires_threads
46404669 def test_pthread_run_script(self):
46414670 for args in [[], ['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD']]:
4642 self.btest(test_file('pthread/test_pthread_run_script.cpp'), expected='1', args=['-O3'] + args)
4671 self.btest_exit(test_file('pthread/test_pthread_run_script.cpp'), args=['-O3'] + args)
46434672
46444673 # Tests emscripten_set_canvas_element_size() and OffscreenCanvas functionality in different build configurations.
46454674 @requires_threads
46554684 ]:
46564685 cmd = ['-lGL', '-O3', '-g2', '--shell-file', test_file('canvas_animate_resize_shell.html'), '-s', 'GL_DEBUG', '--threadprofiler'] + args
46574686 print(' '.join(cmd))
4658 self.btest('canvas_animate_resize.cpp', expected='1', args=cmd)
4687 self.btest_exit('canvas_animate_resize.cpp', args=cmd)
46594688
46604689 # Tests the absolute minimum pthread-enabled application.
46614690 @requires_threads
49584987 # Tests that Closure run in combination with -s ENVIRONMENT=web mode works with a small WebGL application
49594988 @requires_graphics_hardware
49604989 def test_closure_in_web_only_target_environment_webgl(self):
4961 self.btest('webgl_draw_triangle.c', '0', args=['-lGL', '-s', 'ENVIRONMENT=web', '-O3', '--closure=1'])
4990 self.btest_exit('webgl_draw_triangle.c', args=['-lGL', '-s', 'ENVIRONMENT=web', '-O3', '--closure=1'])
49624991
49634992 def test_no_declare_asm_module_exports_asmjs(self):
49644993 for minimal_runtime in [[], ['-s', 'MINIMAL_RUNTIME']]:
49865015
49875016 # Tests emscripten_unwind_to_js_event_loop() behavior
49885017 def test_emscripten_unwind_to_js_event_loop(self, *args):
4989 self.btest(test_file('browser/test_emscripten_unwind_to_js_event_loop.c'), '1', args=['-s', 'NO_EXIT_RUNTIME'])
5018 self.btest_exit(test_file('browser/test_emscripten_unwind_to_js_event_loop.c'))
49905019
49915020 def test_wasm2js_fallback(self):
49925021 for args in [[], ['-s', 'MINIMAL_RUNTIME']]:
50195048 self.run_browser('test.html', 'hello!', '/report_result?0')
50205049
50215050 def test_system(self):
5022 self.btest(test_file('system.c'), '0')
5051 self.btest_exit(test_file('system.c'))
50235052
50245053 # Tests that it is possible to hook into/override a symbol defined in a system library.
50255054 @requires_graphics_hardware
50285057
50295058 # When WebGL is implicitly linked in, the implicit linking should happen before any user --js-libraries, so that they can adjust
50305059 # the behavior afterwards.
5031 self.btest(test_file('test_override_system_js_lib_symbol.c'),
5032 expected='5121',
5033 args=['--js-library', test_file('test_override_system_js_lib_symbol.js')])
5060 self.btest_exit(test_file('test_override_system_js_lib_symbol.c'),
5061 args=['--js-library', test_file('test_override_system_js_lib_symbol.js')])
50345062
50355063 # When WebGL is explicitly linked to in strict mode, the linking order on command line should enable overriding.
5036 self.btest(test_file('test_override_system_js_lib_symbol.c'),
5037 expected='5121',
5038 args=['-s', 'AUTO_JS_LIBRARIES=0', '-lwebgl.js', '--js-library', test_file('test_override_system_js_lib_symbol.js')])
5064 self.btest_exit(test_file('test_override_system_js_lib_symbol.c'),
5065 args=['-s', 'AUTO_JS_LIBRARIES=0', '-lwebgl.js', '--js-library', test_file('test_override_system_js_lib_symbol.js')])
50395066
50405067 @no_firefox('no 4GB support yet')
5068 @require_v8
50415069 def test_zzz_zzz_4gb(self):
50425070 # TODO Convert to an actual browser test when it reaches stable.
50435071 # For now, keep this in browser as this suite runs serially, which
50485076 # test that we can allocate in the 2-4GB range, if we enable growth and
50495077 # set the max appropriately
50505078 self.emcc_args += ['-O2', '-s', 'ALLOW_MEMORY_GROWTH', '-s', 'MAXIMUM_MEMORY=4GB']
5051 self.do_run_in_out_file_test('browser', 'test_4GB.cpp', js_engines=[config.V8_ENGINE])
5079 self.do_run_in_out_file_test('browser', 'test_4GB.cpp')
50525080
50535081 # Tests that emmalloc supports up to 4GB Wasm heaps.
50545082 @no_firefox('no 4GB support yet')
50765104 self.btest(test_file('browser/emmalloc_memgrowth.cpp'), expected='0', args=['-s', 'MALLOC=emmalloc', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'ABORTING_MALLOC=0', '-s', 'ASSERTIONS=2', '-s', 'MINIMAL_RUNTIME=1', '-s', 'MAXIMUM_MEMORY=4GB'])
50775105
50785106 @no_firefox('no 4GB support yet')
5107 @require_v8
50795108 def test_zzz_zzz_2gb_fail(self):
50805109 # TODO Convert to an actual browser test when it reaches stable.
50815110 # For now, keep this in browser as this suite runs serially, which
50865115 # test that growth doesn't go beyond 2GB without the max being set for that,
50875116 # and that we can catch an allocation failure exception for that
50885117 self.emcc_args += ['-O2', '-s', 'ALLOW_MEMORY_GROWTH', '-s', 'MAXIMUM_MEMORY=2GB']
5089 self.do_run_in_out_file_test('browser', 'test_2GB_fail.cpp', js_engines=[config.V8_ENGINE])
5118 self.do_run_in_out_file_test('browser', 'test_2GB_fail.cpp')
50905119
50915120 @no_firefox('no 4GB support yet')
5121 @require_v8
50925122 def test_zzz_zzz_4gb_fail(self):
50935123 # TODO Convert to an actual browser test when it reaches stable.
50945124 # For now, keep this in browser as this suite runs serially, which
50995129 # test that we properly report an allocation error that would overflow over
51005130 # 4GB.
51015131 self.emcc_args += ['-O2', '-s', 'ALLOW_MEMORY_GROWTH', '-s', 'MAXIMUM_MEMORY=4GB', '-s', 'ABORTING_MALLOC=0']
5102 self.do_run_in_out_file_test('browser', 'test_4GB_fail.cpp', js_engines=[config.V8_ENGINE])
5132 self.do_run_in_out_file_test('browser', 'test_4GB_fail.cpp')
51035133
51045134 @disabled("only run this manually, to test for race conditions")
51055135 @parameterized({
2323 from tools.shared import PYTHON, EMCC, EMAR
2424 from tools.utils import WINDOWS, MACOS
2525 from tools import shared, building, config, webassembly
26 from runner import RunnerCore, path_from_root, requires_native_clang, test_file
27 from runner import skip_if, needs_dylink, no_windows, is_slow_test, create_file, parameterized
28 from runner import env_modify, with_env_modify, disabled, node_pthreads
29 from runner import read_file, read_binary
30 from runner import NON_ZERO, WEBIDL_BINDER, EMBUILDER
26 from common import RunnerCore, path_from_root, requires_native_clang, test_file
27 from common import skip_if, needs_dylink, no_windows, is_slow_test, create_file, parameterized
28 from common import env_modify, with_env_modify, disabled, node_pthreads
29 from common import read_file, read_binary, require_node, require_v8
30 from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, EMMAKE
3131 import clang_native
3232
3333 # decorators for limiting which modes a test can run in
7676 def decorated(self):
7777 old = self.use_all_engines
7878 self.use_all_engines = True
79 self.set_setting('ENVIRONMENT', 'web,node,shell')
7980 try:
8081 f(self)
8182 finally:
462463 def test_cube2hash(self):
463464 # A good test of i64 math
464465 self.do_run('// empty file', 'Usage: hashstring <seed>',
465 libraries=self.get_library('third_party/cube2hash', ['libcube2hash.a'], configure=None),
466 libraries=self.get_library('third_party/cube2hash', ['libcube2hash.a'], configure=None, make=[EMMAKE, 'make']),
466467 includes=[test_file('third_party/cube2hash')], assert_returncode=NON_ZERO)
467468
468469 for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
23352336 self.set_setting('INITIAL_MEMORY', '300mb')
23362337 self.do_run_in_out_file_test('pthread/test_pthread_thread_local_storage.cpp')
23372338
2339 @node_pthreads
2340 def test_pthread_cleanup(self):
2341 self.set_setting('EXIT_RUNTIME')
2342 self.set_setting('PTHREAD_POOL_SIZE', 4)
2343 self.do_run_in_out_file_test('pthread/test_pthread_cleanup.cpp')
2344
2345 @node_pthreads
2346 def test_pthread_setspecific_mainthread(self):
2347 self.set_setting('EXIT_RUNTIME')
2348 self.do_run_in_out_file_test('pthread/test_pthread_setspecific_mainthread.c')
2349
23382350 def test_tcgetattr(self):
23392351 self.do_runf(test_file('termios/test_tcgetattr.c'), 'success')
23402352
25462558 return 0;
25472559 }
25482560 '''
2549 self.do_run(src, 'error: Could not load dynamic lib: libfoo.so\nError: No such file or directory')
2550 print('without assertions, the error is less clear')
2551 self.set_setting('ASSERTIONS', 0)
2552 self.do_run(src, 'error: Could not load dynamic lib: libfoo.so\nError: FS error')
2561 self.do_run(src, "error: Could not load dynamic lib: libfoo.so\nError: ENOENT: no such file or directory, open 'libfoo.so'")
25532562
25542563 @needs_dylink
25552564 def test_dlfcn_basic(self):
52845293 self.do_runf(test_file('fs/test_64bit.c'), 'success')
52855294
52865295 def test_sigalrm(self):
5287 self.do_runf(test_file('sigalrm.cpp'), '')
5296 self.do_runf(test_file('test_sigalrm.c'), 'Received alarm!')
52885297
52895298 @no_windows('https://github.com/emscripten-core/emscripten/issues/8882')
52905299 def test_unistd_access(self):
56825691 def test_whets(self):
56835692 self.do_runf(test_file('whets.cpp'), 'Single Precision C Whetstone Benchmark')
56845693
5694 # node is slower, and fail on 64-bit
5695 @require_v8
56855696 @no_asan('depends on the specifics of memory size, which for asan we are forced to increase')
56865697 def test_dlmalloc_inline(self):
5687 self.banned_js_engines = [config.NODE_JS] # slower, and fail on 64-bit
56885698 # needed with typed arrays
56895699 self.set_setting('INITIAL_MEMORY', '128mb')
56905700
56925702 self.do_run(src, '*1,0*', args=['200', '1'], force_c=True)
56935703 self.do_run('src.js', '*400,0*', args=['400', '400'], force_c=True, no_build=True)
56945704
5705 # node is slower, and fail on 64-bit
5706 @require_v8
56955707 @no_asan('depends on the specifics of memory size, which for asan we are forced to increase')
56965708 def test_dlmalloc(self):
5697 self.banned_js_engines = [config.NODE_JS] # slower, and fail on 64-bit
56985709 # needed with typed arrays
56995710 self.set_setting('INITIAL_MEMORY', '128mb')
57005711
59475958 def test_lua(self):
59485959 self.emcc_args.remove('-Werror')
59495960
5961 libs = self.get_library('third_party/lua', [Path('src/lua.o'), Path('src/liblua.a')], make=[EMMAKE, 'make', 'generic'], configure=None)
59505962 self.do_run('',
59515963 'hello lua world!\n17\n1\n2\n3\n4\n7',
59525964 args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
5953 libraries=self.get_library('third_party/lua', [Path('src/lua.o'), Path('src/liblua.a')], make=['make', 'generic'], configure=None),
5965 libraries=libs,
59545966 includes=[test_file('lua')],
59555967 output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n'))
59565968
69446956 })
69456957 @sync
69466958 def test_webidl(self, mode, allow_memory_growth):
6959 self.uses_es6 = True
69476960 if self.maybe_closure():
69486961 # avoid closure minified names competing with our test code in the global name space
69496962 self.set_setting('MODULARIZE')
69546967 self.assertExists('glue.cpp')
69556968 self.assertExists('glue.js')
69566969
6970 post_js = '\n\n'
6971 if self.get_setting('MODULARIZE'):
6972 post_js += 'var TheModule = Module();\n'
6973 else:
6974 post_js += 'var TheModule = Module;\n'
6975 post_js += '\n\n'
6976 if allow_memory_growth:
6977 post_js += "var isMemoryGrowthAllowed = true;\n"
6978 else:
6979 post_js += "var isMemoryGrowthAllowed = false;\n"
6980 post_js += read_file(test_file('webidl/post.js'))
6981 post_js += '\n\n'
6982 create_file('extern-post.js', post_js)
6983
69576984 # Export things on "TheModule". This matches the typical use pattern of the bound library
69586985 # being used as Box2D.* or Ammo.*, and we cannot rely on "Module" being always present (closure may remove it).
6959 self.emcc_args += ['-s', 'EXPORTED_FUNCTIONS=_malloc,_free', '--post-js', 'glue.js']
6986 self.emcc_args += ['-s', 'EXPORTED_FUNCTIONS=_malloc,_free', '--post-js=glue.js', '--extern-post-js=extern-post.js']
69606987 if allow_memory_growth:
69616988 self.set_setting('ALLOW_MEMORY_GROWTH')
69626989
6963 def post(filename):
6964 with open(filename, 'a') as f:
6965 f.write('\n\n')
6966 if self.get_setting('MODULARIZE'):
6967 f.write('var TheModule = Module();\n')
6968 else:
6969 f.write('var TheModule = Module;\n')
6970 f.write('\n\n')
6971 if allow_memory_growth:
6972 f.write("var isMemoryGrowthAllowed = true;")
6973 else:
6974 f.write("var isMemoryGrowthAllowed = false;")
6975 f.write(read_file(test_file('webidl/post.js')))
6976 f.write('\n\n')
6977
69786990 output = test_file('webidl/output_%s.txt' % mode)
6979 self.do_run_from_file(test_file('webidl/test.cpp'), output, post_build=post)
6991 self.do_run_from_file(test_file('webidl/test.cpp'), output)
69806992
69816993 ### Tests for tools
69826994
72147226 def test_modularize_closure_pre(self):
72157227 # test that the combination of modularize + closure + pre-js works. in that mode,
72167228 # closure should not minify the Module object in a way that the pre-js cannot use it.
7229 create_file('post.js', 'var TheModule = Module();\n')
72177230 self.emcc_args += [
72187231 '--pre-js', test_file('core/modularize_closure_pre.js'),
7232 '--extern-post-js=post.js',
72197233 '--closure=1',
72207234 '-g1',
72217235 '-s',
72227236 'MODULARIZE=1',
72237237 ]
7224
7225 def post(filename):
7226 with open(filename, 'a') as f:
7227 f.write('\n\n')
7228 f.write('var TheModule = Module();\n')
7229
7230 self.do_core_test('modularize_closure_pre.c', post_build=post)
7238 self.do_core_test('modularize_closure_pre.c')
72317239
72327240 @no_wasm2js('symbol names look different wasm2js backtraces')
72337241 def test_emscripten_log(self):
73127320 def test_vswprintf_utf8(self):
73137321 self.do_run_in_out_file_test('vswprintf_utf8.c')
73147322
7323 # needs setTimeout which only node has
7324 @require_node
73157325 @no_asan('asan is not compatible with asyncify stack operations; may also need to not instrument asan_c_load_4, TODO')
7316 def test_async(self):
7326 def test_async_hello(self):
73177327 # needs to flush stdio streams
73187328 self.set_setting('EXIT_RUNTIME')
73197329 self.set_setting('ASYNCIFY')
7320 self.banned_js_engines = [config.SPIDERMONKEY_ENGINE, config.V8_ENGINE] # needs setTimeout which only node has
7321
7322 src = r'''
7330
7331 create_file('main.c', r'''
73237332 #include <stdio.h>
73247333 #include <emscripten.h>
73257334 void f(void *p) {
73347343 emscripten_sleep(100);
73357344 printf("%d\n", i);
73367345 }
7337 '''
7338
7339 self.do_run(src, 'HelloWorld!99')
7340
7341 print('check bad ccall use')
7342 src = r'''
7346 ''')
7347
7348 self.do_runf('main.c', 'HelloWorld!99')
7349
7350 @require_node
7351 @no_asan('asyncify stack operations confuse asan')
7352 def test_async_ccall_bad(self):
7353 # check bad ccall use
7354 # needs to flush stdio streams
7355 self.set_setting('EXIT_RUNTIME')
7356 self.set_setting('ASYNCIFY')
7357 self.set_setting('ASSERTIONS')
7358 self.set_setting('INVOKE_RUN', 0)
7359 create_file('main.c', r'''
73437360 #include <stdio.h>
73447361 #include <emscripten.h>
73457362 int main() {
73477364 emscripten_sleep(100);
73487365 printf("World\n");
73497366 }
7350 '''
7351 self.set_setting('ASSERTIONS')
7352 self.set_setting('INVOKE_RUN', 0)
7367 ''')
73537368 create_file('pre.js', '''
73547369 Module['onRuntimeInitialized'] = function() {
73557370 try {
73627377 };
73637378 ''')
73647379 self.emcc_args += ['--pre-js', 'pre.js']
7365 self.do_run(src, 'The call to main is running asynchronously.')
7366
7367 print('check reasonable ccall use')
7368 src = r'''
7380 self.do_runf('main.c', 'The call to main is running asynchronously.')
7381
7382 @require_node
7383 @no_asan('asyncify stack operations confuse asan')
7384 def test_async_ccall_good(self):
7385 # check reasonable ccall use
7386 # needs to flush stdio streams
7387 self.set_setting('EXIT_RUNTIME')
7388 self.set_setting('ASYNCIFY')
7389 self.set_setting('ASSERTIONS')
7390 self.set_setting('INVOKE_RUN', 0)
7391 create_file('main.c', r'''
73697392 #include <stdio.h>
73707393 #include <emscripten.h>
73717394 int main() {
73737396 emscripten_sleep(100);
73747397 printf("World\n");
73757398 }
7376 '''
7399 ''')
73777400 create_file('pre.js', '''
73787401 Module['onRuntimeInitialized'] = function() {
73797402 ccall('main', null, ['number', 'string'], [2, 'waka'], { async: true });
73807403 };
73817404 ''')
7382 self.do_run(src, 'HelloWorld')
7383
7405 self.emcc_args += ['--pre-js', 'pre.js']
7406 self.do_runf('main.c', 'HelloWorld')
7407
7408 @no_asan('asyncify stack operations confuse asan')
7409 def test_async_ccall_promise(self):
73847410 print('check ccall promise')
7411 self.set_setting('ASYNCIFY')
7412 self.set_setting('ASSERTIONS')
7413 self.set_setting('INVOKE_RUN', 0)
73857414 self.set_setting('EXPORTED_FUNCTIONS', ['_stringf', '_floatf'])
7386 src = r'''
7415 create_file('main.c', r'''
73877416 #include <stdio.h>
73887417 #include <emscripten.h>
7389 extern "C" {
7390 const char* stringf(char* param) {
7391 emscripten_sleep(20);
7392 printf("%s", param);
7393 return "second";
7394 }
7395 double floatf() {
7396 emscripten_sleep(20);
7397 emscripten_sleep(20);
7398 return 6.4;
7399 }
7418 const char* stringf(char* param) {
7419 emscripten_sleep(20);
7420 printf("%s", param);
7421 return "second";
74007422 }
7401 '''
7423 double floatf() {
7424 emscripten_sleep(20);
7425 emscripten_sleep(20);
7426 return 6.4;
7427 }
7428 ''')
74027429 create_file('pre.js', r'''
74037430 Module['onRuntimeInitialized'] = function() {
74047431 ccall('stringf', 'string', ['string'], ['first\n'], { async: true })
74087435 });
74097436 };
74107437 ''')
7411 self.do_run(src, 'first\nsecond\n6.4')
7438 self.emcc_args += ['--pre-js', 'pre.js']
7439 self.do_runf('main.c', 'first\nsecond\n6.4')
74127440
74137441 @no_asan('asyncify stack operations confuse asan')
74147442 def test_fibers_asyncify(self):
74397467 self.set_setting('ASYNCIFY_ONLY', '@response.file')
74407468 self.set_setting('ASYNCIFY')
74417469 self.emcc_args += args
7442 try:
7470
7471 if should_pass:
74437472 self.do_core_test('test_asyncify_lists.cpp', assert_identical=True)
7444 if not should_pass:
7445 should_pass = True
7446 raise Exception('should not have passed')
7447 except Exception:
7448 if should_pass:
7449 raise
7473 else:
7474 self.do_runf(test_file('core/test_asyncify_lists.cpp'), 'exception thrown', assert_returncode=NON_ZERO)
74507475
74517476 # use of ASYNCIFY_* options may require intermediate debug info. that should
74527477 # not end up emitted in the final binary
74537478 if self.is_wasm():
7454 with open('test_asyncify_lists.wasm', 'rb') as f:
7455 binary = f.read()
7479 binary = read_binary('test_asyncify_lists.wasm')
74567480 # there should be no name section
74577481 self.assertFalse(b'name' in binary)
74587482 # in a fully-optimized build, imports and exports are minified too and we
74957519 self.set_setting('ASYNCIFY')
74967520 self.set_setting('ASSERTIONS')
74977521 self.set_setting('EXIT_RUNTIME', 1)
7498 self.do_core_test('test_asyncify_during_exit.cpp', assert_returncode=1)
7522 self.do_core_test('test_asyncify_during_exit.cpp', assert_returncode=NON_ZERO)
74997523 print('NO_ASYNC')
75007524 self.do_core_test('test_asyncify_during_exit.cpp', emcc_args=['-DNO_ASYNC'], out_suffix='_no_async')
75017525
80038027 })
80048028 @no_wasm2js('TODO: sanitizers in wasm2js')
80058029 def test_ubsan_full_stack_trace(self, g_flag, expected_output):
8006 self.emcc_args += ['-fsanitize=null', g_flag]
8007 self.set_setting('ALLOW_MEMORY_GROWTH')
8008
80098030 if g_flag == '-gsource-map':
80108031 if not self.is_wasm():
80118032 self.skipTest('wasm2js has no source map support')
80128033 elif '-Oz' in self.emcc_args:
80138034 self.skipTest('-Oz breaks stack traces')
80148035
8015 def modify_env(filename):
8016 contents = read_file(filename)
8017 contents = 'Module = {UBSAN_OPTIONS: "print_stacktrace=1"};' + contents
8018 with open(filename, 'w') as f:
8019 f.write(contents)
8020
8036 create_file('pre.js', 'Module = {UBSAN_OPTIONS: "print_stacktrace=1"};')
8037 self.emcc_args += ['-fsanitize=null', g_flag, '--pre-js=pre.js']
8038 self.set_setting('ALLOW_MEMORY_GROWTH')
80218039 self.do_runf(test_file('core/test_ubsan_full_null_ref.cpp'),
8022 post_build=modify_env, assert_all=True, expected_output=expected_output)
8040 assert_all=True, expected_output=expected_output)
80238041
80248042 @no_wasm2js('TODO: sanitizers in wasm2js')
80258043 def test_ubsan_typeinfo_eq(self):
81448162 @no_safe_heap('asan does not work with SAFE_HEAP')
81458163 @no_wasm2js('TODO: ASAN in wasm2js')
81468164 def test_asan_modularized_with_closure(self):
8147 self.emcc_args.append('-fsanitize=address')
8165 # the bug is that createModule() returns undefined, instead of the
8166 # proper Promise object.
8167 create_file('post.js', 'if (!(createModule() instanceof Promise)) throw "Promise was not returned :(";\n')
8168 self.emcc_args += ['-fsanitize=address', '--extern-post-js=post.js']
81488169 self.set_setting('MODULARIZE')
81498170 self.set_setting('EXPORT_NAME', 'createModule')
81508171 self.set_setting('USE_CLOSURE_COMPILER')
81518172 self.set_setting('ALLOW_MEMORY_GROWTH')
81528173 self.set_setting('INITIAL_MEMORY', '300mb')
8153
8154 def post(filename):
8155 with open(filename, 'a') as f:
8156 f.write('\n\n')
8157 # the bug is that createModule() returns undefined, instead of the
8158 # proper Promise object.
8159 f.write('if (!(createModule() instanceof Promise)) throw "Promise was not returned :(";\n')
8160
8161 self.do_runf(test_file('hello_world.c'),
8162 post_build=post,
8163 expected_output='hello, world!')
8174 self.do_runf(test_file('hello_world.c'), expected_output='hello, world!')
81648175
81658176 @no_asan('SAFE_HEAP cannot be used with ASan')
81668177 def test_safe_heap_user_js(self):
82418252 def test_pthread_create_pool(self):
82428253 # with a pool, we can synchronously depend on workers being available
82438254 self.set_setting('PTHREAD_POOL_SIZE', '2')
8255 self.set_setting('EXIT_RUNTIME')
82448256 self.emcc_args += ['-DALLOW_SYNC']
82458257 self.do_run_in_out_file_test('core/pthread/create.cpp')
82468258
82488260 def test_pthread_create_proxy(self):
82498261 # with PROXY_TO_PTHREAD, we can synchronously depend on workers being available
82508262 self.set_setting('PROXY_TO_PTHREAD')
8263 self.set_setting('EXIT_RUNTIME')
82518264 self.emcc_args += ['-DALLOW_SYNC']
82528265 self.do_run_in_out_file_test('core/pthread/create.cpp')
82538266
82558268 def test_pthread_create_embind_stack_check(self):
82568269 # embind should work with stack overflow checks (see #12356)
82578270 self.set_setting('STACK_OVERFLOW_CHECK', 2)
8271 self.set_setting('EXIT_RUNTIME')
82588272 self.emcc_args += ['--bind']
82598273 self.do_run_in_out_file_test('core/pthread/create.cpp')
82608274
82618275 @node_pthreads
82628276 def test_pthread_exceptions(self):
82638277 self.set_setting('PTHREAD_POOL_SIZE', '2')
8278 self.set_setting('EXIT_RUNTIME')
82648279 self.emcc_args += ['-fexceptions']
82658280 self.do_run_in_out_file_test('core/pthread/exceptions.cpp')
82668281
85038518 err = self.expect_fail([EMCC, 'connect.c', '-sREVERSE_DEPS=none'])
85048519 self.assertContained('undefined symbol: ntohs', err)
85058520
8521 def test_emscripten_async_call(self):
8522 self.set_setting('EXIT_RUNTIME')
8523 self.do_run_in_out_file_test(test_file('core/test_emscripten_async_call.c'))
8524
85068525
85078526 # Generate tests for everything
85088527 def make_run(name, emcc_args, settings=None, env=None):
99 if __name__ == '__main__':
1010 raise Exception('do not run this file directly; do something like: tests/runner.py interactive')
1111
12 from runner import parameterized
13 from runner import BrowserCore, test_file
12 from common import parameterized
13 from common import BrowserCore, test_file
1414 from tools.shared import WINDOWS
1515 from tools.utils import which
1616
3131 from tools.shared import try_delete, config
3232 from tools.shared import EMCC, EMXX, EMAR, EMRANLIB, PYTHON, FILE_PACKAGER, WINDOWS, EM_BUILD_VERBOSE
3333 from tools.shared import CLANG_CC, CLANG_CXX, LLVM_AR, LLVM_DWARFDUMP, EMCMAKE, EMCONFIGURE
34 from runner import RunnerCore, path_from_root, is_slow_test, ensure_dir, disabled, make_executable
35 from runner import env_modify, no_mac, no_windows, requires_native_clang, with_env_modify
36 from runner import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file
37 from runner import compiler_for, read_file, read_binary, EMBUILDER, require_v8, require_node
34 from common import RunnerCore, path_from_root, is_slow_test, ensure_dir, disabled, make_executable
35 from common import env_modify, no_mac, no_windows, requires_native_clang, with_env_modify
36 from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file
37 from common import compiler_for, read_file, read_binary, EMBUILDER, require_v8, require_node
3838 from tools import shared, building, utils, deps_info
39 import common
3940 import jsrun
4041 import clang_native
4142 from tools import line_endings
4748 emsize = shared.bat_suffix(path_from_root('emsize'))
4849 wasm_dis = Path(building.get_binaryen_bin(), 'wasm-dis')
4950 wasm_opt = Path(building.get_binaryen_bin(), 'wasm-opt')
50
51 EMTEST_REBASELINE = int(os.getenv('EMTEST_REBASELINE', '0'))
5251
5352
5453 class temp_directory():
511510 self.clear()
512511 wasm = '=0' not in str(mode)
513512 print(' mode', mode, 'wasm?', wasm)
514 self.run_process([EMCC, test_file('hello_world.c')] + opts + mode)
513 self.run_process([EMCC, test_file('hello_world.c'), '-sENVIRONMENT=node,shell'] + opts + mode)
515514 self.assertExists('a.out.js')
516515 if wasm:
517516 self.assertExists('a.out.wasm')
26012600 def test_demangle_malloc_infinite_loop_crash(self):
26022601 self.run_process([EMXX, test_file('malloc_demangle_infinite_loop.cpp'), '-g', '-s', 'ABORTING_MALLOC', '-s', 'DEMANGLE_SUPPORT'])
26032602 output = self.run_js('a.out.js', assert_returncode=NON_ZERO)
2604 if output.count('Cannot enlarge memory arrays') > 4:
2603 if output.count('Cannot enlarge memory arrays') > 5:
26052604 print(output)
2606 self.assertLess(output.count('Cannot enlarge memory arrays'), 5)
2605 self.assertLess(output.count('Cannot enlarge memory arrays'), 6)
26072606
26082607 @require_node
26092608 def test_module_exports_with_closure(self):
27552754 return 0;
27562755 }
27572756 ''')
2758 self.run_process([EMXX, 'src.cpp', '--embed-file', 'src.cpp'])
2757 self.run_process([EMXX, 'src.cpp', '--embed-file', 'src.cpp', '-sENVIRONMENT=node,shell'])
27592758 for engine in config.JS_ENGINES:
27602759 out = self.run_js('a.out.js', engine=engine)
27612760 self.assertContained('File size: 724', out)
38793878 self.run_process([EMXX, 'code.cpp'])
38803879 self.assertContained('I am ' + os.path.realpath(self.get_dir()).replace('\\', '/') + '/a.out.js', self.run_js('a.out.js').replace('\\', '/'))
38813880
3882 def test_returncode(self):
3881 @parameterized({
3882 'no_exit_runtime': [True],
3883 '': [False],
3884 })
3885 def test_returncode(self, no_exit):
38833886 create_file('src.cpp', r'''
38843887 #include <stdio.h>
38853888 #include <stdlib.h>
38923895 }
38933896 ''')
38943897 for code in [0, 123]:
3895 for no_exit in [0, 1]:
3896 for call_exit in [0, 1]:
3897 for async_compile in [0, 1]:
3898 self.run_process([EMXX, 'src.cpp', '-DCODE=%d' % code, '-s', 'EXIT_RUNTIME=%d' % (1 - no_exit), '-DCALL_EXIT=%d' % call_exit, '-s', 'WASM_ASYNC_COMPILATION=%d' % async_compile])
3899 for engine in config.JS_ENGINES:
3900 # async compilation can't return a code in d8
3901 if async_compile and engine == config.V8_ENGINE:
3902 continue
3903 print(code, no_exit, call_exit, async_compile, engine)
3904 proc = self.run_process(engine + ['a.out.js'], stderr=PIPE, check=False)
3905 # we always emit the right exit code, whether we exit the runtime or not
3906 self.assertEqual(proc.returncode, code)
3907 msg = 'but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'
3908 if no_exit and call_exit:
3909 self.assertContained(msg, proc.stderr)
3910 else:
3911 self.assertNotContained(msg, proc.stderr)
3898 for call_exit in [0, 1]:
3899 for async_compile in [0, 1]:
3900 self.run_process([EMXX, 'src.cpp', '-sENVIRONMENT=node,shell', '-DCODE=%d' % code, '-s', 'EXIT_RUNTIME=%d' % (1 - no_exit), '-DCALL_EXIT=%d' % call_exit, '-s', 'WASM_ASYNC_COMPILATION=%d' % async_compile])
3901 for engine in config.JS_ENGINES:
3902 # async compilation can't return a code in d8
3903 if async_compile and engine == config.V8_ENGINE:
3904 continue
3905 print(code, call_exit, async_compile, engine)
3906 proc = self.run_process(engine + ['a.out.js'], stderr=PIPE, check=False)
3907 msg = 'but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'
3908 if no_exit and call_exit:
3909 self.assertContained(msg, proc.stderr)
3910 else:
3911 self.assertNotContained(msg, proc.stderr)
3912 # we always emit the right exit code, whether we exit the runtime or not
3913 self.assertEqual(proc.returncode, code)
39123914
39133915 def test_emscripten_force_exit_NO_EXIT_RUNTIME(self):
39143916 create_file('src.cpp', r'''
42254227 # a program which includes a non-trivial syscall, but disables the filesystem.
42264228 create_file('src.c', r'''
42274229 #include <sys/time.h>
4228 #include <stddef.h>
4229 extern int __sys_openat(int);
4230 #include <fcntl.h>
42304231 int main() {
4231 return __sys_openat(0);
4232 return openat(0, "foo", 0);
42324233 }''')
42334234 self.run_process([EMCC, 'src.c', '-s', 'NO_FILESYSTEM'])
42344235
57225723 self.assertContained('hello1_val by hello1:3', out)
57235724 self.assertContained('hello1_val by hello2:3', out)
57245725
5726 def test_dlopen_blocking(self):
5727 create_file('side.c', 'int foo = 42;\n')
5728 self.run_process([EMCC, 'side.c', '-o', 'libside.so', '-s', 'SIDE_MODULE'])
5729 self.set_setting('MAIN_MODULE', 2)
5730 self.set_setting('EXIT_RUNTIME')
5731 # Under node this should should always works because we can do synchronous readBinary
5732 self.do_other_test('test_dlopen_blocking.c')
5733
57255734 def test_dlsym_rtld_default(self):
57265735 create_file('main.c', r'''
57275736 #include <stdio.h>
69626971 def assertFileContents(self, filename, contents):
69636972 contents = contents.replace('\r', '')
69646973
6965 if EMTEST_REBASELINE:
6974 if common.EMTEST_REBASELINE:
69666975 with open(filename, 'w') as f:
69676976 f.write(contents)
69686977 return
70277036 # measure the wasm size without the name section
70287037 self.run_process([wasm_opt, 'a.out.wasm', '--strip-debug', '--all-features', '-o', 'a.out.nodebug.wasm'])
70297038 wasm_size = os.path.getsize('a.out.nodebug.wasm')
7030 if EMTEST_REBASELINE:
7039 if common.EMTEST_REBASELINE:
70317040 with open(size_file, 'w') as f:
70327041 f.write(f'{wasm_size}\n')
70337042
70907099
70917100 @node_pthreads
70927101 def test_metadce_minimal_pthreads(self):
7093 self.run_metadce_test('minimal.c', ['-Oz', '-sUSE_PTHREADS', '-sPROXY_TO_PTHREAD'], [], [])
7102 self.run_metadce_test('minimal_main.c', ['-Oz', '-sUSE_PTHREADS', '-sPROXY_TO_PTHREAD'], [], [])
70947103
70957104 @parameterized({
70967105 'noexcept': (['-O2'], [], ['waka']), # noqa
82818290 proc = self.run_process([EMCC, test_file('hello_world.c'), '-s', 'ASYNCIFY', '-s', "ASYNCIFY_ONLY=[DOS_ReadFile(unsigned short, unsigned char*, unsigned short*, bool)]"], stdout=PIPE, stderr=PIPE)
82828291 self.assertContained('emcc: ASYNCIFY list contains an item without balanced parentheses', proc.stderr)
82838292 self.assertContained(' DOS_ReadFile(unsigned short', proc.stderr)
8284 self.assertContained('Try to quote the entire argument', proc.stderr)
8293 self.assertContained('Try using a response file', proc.stderr)
82858294
82868295 def test_asyncify_response_file(self):
82878296 create_file('a.txt', r'''[
87818790 try:
87828791 expected_results = json.loads(read_file(results_file))
87838792 except Exception:
8784 if not EMTEST_REBASELINE:
8793 if not common.EMTEST_REBASELINE:
87858794 raise
87868795
87878796 args = [EMCC, '-o', 'a.html'] + args + sources
88508859 # happens in wasm2js, so it may be platform-nondeterminism in closure
88518860 # compiler).
88528861 # TODO: identify what is causing this. meanwhile allow some amount of slop
8853 if not EMTEST_REBASELINE:
8862 if not common.EMTEST_REBASELINE:
88548863 if js:
88558864 slop = 30
88568865 else:
88718880 print('Total output size=' + str(total_output_size) + ' bytes, expected total size=' + str(total_expected_size) + ', delta=' + str(total_output_size - total_expected_size) + print_percent(total_output_size, total_expected_size))
88728881 print('Total output size gzipped=' + str(total_output_size_gz) + ' bytes, expected total size gzipped=' + str(total_expected_size_gz) + ', delta=' + str(total_output_size_gz - total_expected_size_gz) + print_percent(total_output_size_gz, total_expected_size_gz))
88738882
8874 if EMTEST_REBASELINE:
8883 if common.EMTEST_REBASELINE:
88758884 open(results_file, 'w').write(json.dumps(obtained_results, indent=2) + '\n')
88768885 else:
88778886 if total_output_size > total_expected_size:
91729181 # DEFAULT_PTHREAD_STACK_SIZE.
91739182 self.do_smart_test(test_file('other/test_proxy_to_pthread_stack.c'),
91749183 ['success'],
9175 emcc_args=['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD', '-s', 'DEFAULT_PTHREAD_STACK_SIZE=64kb', '-s', 'TOTAL_STACK=128kb'])
9184 emcc_args=['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD', '-s', 'DEFAULT_PTHREAD_STACK_SIZE=64kb', '-s', 'TOTAL_STACK=128kb', '-s', 'EXIT_RUNTIME'])
91769185
91779186 @parameterized({
91789187 'async': ['-s', 'WASM_ASYNC_COMPILATION'],
92379246
92389247 def test_INCOMING_MODULE_JS_API(self):
92399248 def test(args):
9240 self.run_process([EMCC, test_file('hello_world.c'), '-O3', '--closure=1'] + args)
9249 self.run_process([EMCC, test_file('hello_world.c'), '-O3', '--closure=1', '-sENVIRONMENT=node,shell'] + args)
92419250 for engine in config.JS_ENGINES:
92429251 self.assertContained('hello, world!', self.run_js('a.out.js', engine=engine))
92439252 # ignore \r which on windows can increase the size
92489257 # Changing this option to [] should decrease code size.
92499258 self.assertLess(changed, normal)
92509259 # Check an absolute code size as well, with some slack.
9251 self.assertLess(abs(changed - 5872), 150)
9260 self.assertLess(abs(changed - 5001), 150)
92529261
92539262 def test_llvm_includes(self):
92549263 create_file('atomics.c', '#include <stdatomic.h>')
95819590
95829591 def test_non_wasm_without_wasm_in_vm(self):
95839592 # Test that our non-wasm output does not depend on wasm support in the vm.
9584 self.run_process([EMXX, test_file('hello_world.cpp'), '-s', 'WASM=0'])
9593 self.run_process([EMXX, test_file('hello_world.cpp'), '-s', 'WASM=0', '-sENVIRONMENT=node,shell'])
95859594 js = read_file('a.out.js')
95869595 with open('a.out.js', 'w') as f:
95879596 f.write('var WebAssembly = null;\n' + js)
1030610315 def test_syslog(self):
1030710316 self.do_other_test('test_syslog.c')
1030810317
10309 def test_split_module(self):
10318 @parameterized({
10319 '': (False,),
10320 'custom': (True,),
10321 })
10322 def test_split_module(self, customLoader):
1031010323 self.set_setting('SPLIT_MODULE')
1031110324 self.emcc_args += ['-g', '-Wno-experimental']
1031210325 self.emcc_args += ['--post-js', test_file('other/test_split_module.post.js')]
10326 if customLoader:
10327 self.emcc_args += ['--pre-js', test_file('other/test_load_split_module.pre.js')]
1031310328 self.emcc_args += ['-sEXPORTED_FUNCTIONS=_malloc,_free']
1031410329 self.do_other_test('test_split_module.c')
1031510330 self.assertExists('test_split_module.wasm')
1032410339 os.rename('secondary.wasm', 'test_split_module.deferred.wasm')
1032510340 result = self.run_js('test_split_module.js')
1032610341 self.assertNotIn('profile', result)
10342 self.assertContainedIf('Custom handler for loading split module.', result, condition=customLoader)
1032710343 self.assertIn('Hello! answer: 42', result)
1032810344
1032910345 def test_split_main_module(self):
1036910385 def test_gen_struct_info(self):
1037010386 # This tests is fragile and will need updating any time any of the refereced
1037110387 # structs or defines change. However its easy to rebaseline with
10372 # EMTEST_REBASELINE and it prrevents regressions or unintended changes
10388 # EMTEST_REBASELINE and it prevents regressions or unintended changes
1037310389 # to the output json.
1037410390 self.run_process([PYTHON, path_from_root('tools/gen_struct_info.py'), '-o', 'out.json'])
1037510391 self.assertFileContents(test_file('reference_struct_info.json'), read_file('out.json'))
1043310449 cmd.append('-sUSE_OFFSET_CONVERTER')
1043410450 if 'embind' in function:
1043510451 cmd.append('--bind')
10436 if 'fetch' in function:
10437 cmd.append('-sFETCH')
1043810452 if 'websocket' in function:
1043910453 cmd += ['-sPROXY_POSIX_SOCKETS', '-lwebsocket.js']
1044010454 if function == 'Mix_LoadWAV_RW':
1048310497 def test_shell_Oz(self):
1048410498 # regression test for -Oz working on non-web, non-node environments that
1048510499 # lack TextDecoder
10486 self.run_process([EMCC, test_file('hello_world.c'), '-Oz'])
10487 self.assertContained('hello, world!', self.run_js('a.out.js'))
10500 self.emcc_args += ['-Oz']
10501 self.do_runf(test_file('hello_world.c'), 'hello, world!')
1048810502
1048910503 def test_runtime_keepalive(self):
1049010504 self.uses_es6 = True
1065610670 # Here we use NO_AUTO_NATIVE_LIBRARIES to disable the implictly linking that normally
1065710671 # includes the native GL library.
1065810672 self.run_process([EMCC, test_file('other/test_explict_gl_linking.c'), '-sNO_AUTO_NATIVE_LIBRARIES', '-lGL'])
10673
10674 def test_no_main_with_PROXY_TO_PTHREAD(self):
10675 create_file('lib.cpp', r'''
10676 #include <emscripten.h>
10677 EMSCRIPTEN_KEEPALIVE
10678 void foo() {}
10679 ''')
10680 err = self.expect_fail([EMCC, 'lib.cpp', '-pthread', '-sPROXY_TO_PTHREAD'])
10681 self.assertContained('emcc: error: PROXY_TO_PTHREAD proxies main() for you, but no main exists', err)
10682
10683 def test_archive_bad_extension(self):
10684 # Regression test for https://github.com/emscripten-core/emscripten/issues/14012
10685 # where llvm_nm_multiple would be confused by archives names like object files.
10686 create_file('main.c', '''
10687 #include <sys/socket.h>
10688 int main() {
10689 return (int)&accept;
10690 }
10691 ''')
10692
10693 self.run_process([EMCC, '-c', 'main.c'])
10694 self.run_process([EMAR, 'crs', 'libtest.bc', 'main.o'])
10695 self.run_process([EMCC, 'libtest.bc', 'libtest.bc'])
10696
10697 def test_split_dwarf_implicit_compile(self):
10698 # Verify that the dwo file is generated in the current working directory, even when implicitly
10699 # compiling (compile+link).
10700 self.run_process([EMCC, test_file('hello_world.c'), '-g', '-gsplit-dwarf'])
10701 self.assertExists('hello_world.dwo')
10702
10703 @parameterized({
10704 '': [[]],
10705 'strict': [['-sSTRICT']],
10706 'no_allow': [['-sALLOW_UNIMPLEMENTED_SYSCALLS=0']],
10707 })
10708 def test_unimplemented_syscalls(self, args):
10709 create_file('main.c', '''
10710 #include <assert.h>
10711 #include <errno.h>
10712 #include <sys/mman.h>
10713
10714 int main() {
10715 assert(mincore(0, 0, 0) == -1);
10716 assert(errno == ENOSYS);
10717 return 0;
10718 }
10719 ''')
10720 cmd = [EMCC, 'main.c', '-sASSERTIONS'] + args
10721 if args:
10722 err = self.expect_fail(cmd)
10723 self.assertContained('error: attempt to link unsupport syscall: __sys_mincore (use -s ALLOW_UNIMPLEMENTED_SYSCALLS (the default) to allow linking with a stub version', err)
10724 else:
10725 self.run_process(cmd)
10726 err = self.run_js('a.out.js')
10727 self.assertContained('warning: unsupported syscall: __sys_mincore', err)
10728
10729 @require_v8
10730 def test_missing_shell_support(self):
10731 # By default shell support is not included
10732 self.run_process([EMCC, test_file('hello_world.c')])
10733 err = self.run_js('a.out.js', assert_returncode=NON_ZERO)
10734 self.assertContained('shell environment detected but not enabled at build time.', err)
55
66 GLuint what_got_created(void);
77
8 int main()
9 {
8 int main() {
109 EmscriptenWebGLContextAttributes attr;
1110 emscripten_webgl_init_context_attributes(&attr);
1211 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context("#canvas", &attr);
2120 GLuint whatGotCreated = what_got_created();
2221 printf("Created texture of type 0x%x\n", whatGotCreated);
2322 assert(createType == whatGotCreated);
24 #ifdef REPORT_RESULT
25 REPORT_RESULT(whatGotCreated);
26 #endif
23 return 0;
2724 }
1010
1111 import glob
1212 import os
13 import unittest
1314
14 from runner import RunnerCore, path_from_root
15 from tools import config
16 from tools.shared import EMCC
15 from common import RunnerCore, path_from_root, node_pthreads
1716 import test_posixtest_browser
1817
1918 testsuite_root = path_from_root('tests/third_party/posixtestsuite')
3029 def filter_tests(all_tests):
3130 pthread_tests = [t for t in all_tests if t.startswith('pthread_')]
3231 # filter out some tests we don't support
33 pthread_tests = [t for t in pthread_tests if not t.startswith('pthread_atfork')]
3432 pthread_tests = [t for t in pthread_tests if not t.startswith('pthread_sigmask')]
3533 return pthread_tests
3634
4745 return pthread_tests
4846
4947
50 engine = config.NODE_JS + ['--experimental-wasm-threads', '--experimental-wasm-bulk-memory']
51
5248 # Mark certain tests as unsupported
5349 # TODO: Investigate failing semaphores tests.
54 unsupported = {
50 unsupported_noreturn = {
5551 'test_pthread_atfork_1_1': 'fork() and multiple processes are not supported',
5652 'test_pthread_atfork_1_2': 'fork() and multiple processes are not supported',
5753 'test_pthread_atfork_2_1': 'fork() and multiple processes are not supported',
5854 'test_pthread_atfork_2_2': 'fork() and multiple processes are not supported',
5955 'test_pthread_atfork_3_2': 'fork() and multiple processes are not supported',
6056 'test_pthread_atfork_4_1': 'fork() and multiple processes are not supported',
57 'test_pthread_kill_1_1': 'signals are not supported',
58 'test_pthread_create_1_5': 'semaphores are not supported',
59 'test_pthread_exit_6_1': 'lacking necessary mmap() support',
60 'test_pthread_spin_lock_1_1': 'signals are not supported',
61 'test_pthread_mutex_lock_5_1': 'signals are not supported',
62 'test_pthread_mutexattr_settype_2_1': 'interrupting pthread_mutex_lock wait via SIGALRM is not supported',
63 'test_pthread_spin_lock_3_1': 'signals are not supported',
64 'test_pthread_mutex_lock_3_1': 'signals are not supported',
65 'test_pthread_create_14_1': 'signals are not supported',
66 'test_pthread_detach_4_3': 'signals are not supported',
67 'test_pthread_join_6_3': 'signals are not supported',
68 'test_pthread_cond_init_4_2': 'signals are not supported',
69 'test_pthread_barrier_wait_3_2': 'signals are not supported',
70 }
71
72 unsupported = {
6173 'test_pthread_attr_setinheritsched_2_3': 'scheduling policy/parameters are not supported',
6274 'test_pthread_attr_setinheritsched_2_4': 'scheduling policy/parameters are not supported',
6375 'test_pthread_attr_setschedparam_1_3': 'scheduling policy/parameters are not supported',
6577 'test_pthread_attr_setschedpolicy_4_1': 'scheduling policy/parameters are not supported',
6678 'test_pthread_barrierattr_getpshared_2_1': 'shm_open and shm_unlink are not supported',
6779 'test_pthread_barrier_wait_3_1': 'signals are not supported',
68 'test_pthread_barrier_wait_3_2': 'signals are not supported',
69 'test_pthread_cancel_5_2': 'signals are not supported',
7080 'test_pthread_cond_broadcast_1_2': 'lacking necessary mmap() support',
7181 'test_pthread_cond_broadcast_2_3': 'lacking necessary mmap() support',
72 'test_pthread_cond_broadcast_4_2': 'signals are not supported',
7382 'test_pthread_cond_destroy_2_1': 'lacking necessary mmap() support',
7483 'test_pthread_cond_init_1_2': 'clock_settime() is not supported',
7584 'test_pthread_cond_init_1_3': 'lacking necessary mmap() support',
7685 'test_pthread_cond_init_2_2': 'clock_settime() is not supported',
7786 'test_pthread_cond_init_4_1': 'fork() and multiple processes are not supported',
78 'test_pthread_cond_init_4_2': 'signals are not supported',
7987 'test_pthread_cond_signal_1_2': 'lacking necessary mmap() support',
80 'test_pthread_cond_signal_4_2': 'signals are not supported',
8188 'test_pthread_cond_timedwait_2_4': 'lacking necessary mmap() support',
8289 'test_pthread_cond_timedwait_2_7': 'lacking necessary mmap() support',
8390 'test_pthread_cond_timedwait_4_2': 'lacking necessary mmap() support',
8491 'test_pthread_cond_wait_2_2': 'lacking necessary mmap() support',
85 'test_pthread_cond_wait_4_1': 'fork() and multiple processes are not supported',
86 'test_pthread_create_1_5': 'semaphores are not supported',
87 'test_pthread_create_1_6': 'semaphores are not supported',
8892 'test_pthread_create_8_1': 'signals are not supported',
8993 'test_pthread_create_8_2': 'signals are not supported',
9094 'test_pthread_create_10_1': 'signals are not supported',
91 'test_pthread_create_14_1': 'signals are not supported',
92 'test_pthread_create_15_1': 'signals are not supported',
93 'test_pthread_detach_4_3': 'signals are not supported',
94 'test_pthread_equal_2_1': 'signals are not supported',
95 'test_pthread_exit_6_1': 'lacking necessary mmap() support',
96 'test_pthread_exit_6_2': 'semaphores are not supported',
9795 'test_pthread_getschedparam_1_3': 'scheduling policy/parameters are not supported',
98 'test_pthread_getschedparam_4_1': 'signals are not supported',
99 'test_pthread_join_6_3': 'signals are not supported',
100 'test_pthread_kill_1_1': 'signals are not supported',
10196 'test_pthread_kill_1_2': 'signals are not supported',
102 'test_pthread_kill_8_1': 'signals are not supported',
10397 'test_pthread_mutexattr_getprioceiling_1_2': 'pthread_mutexattr_setprioceiling is not supported',
10498 'test_pthread_mutexattr_getprotocol_1_2': 'pthread_mutexattr_setprotocol is not supported',
10599 'test_pthread_mutexattr_setprioceiling_1_1': 'pthread_mutexattr_setprioceiling is not supported',
106100 'test_pthread_mutexattr_setprioceiling_3_1': 'pthread_mutexattr_setprioceiling is not supported',
107101 'test_pthread_mutexattr_setprioceiling_3_2': 'pthread_mutexattr_setprioceiling is not supported',
108102 'test_pthread_mutexattr_setprotocol_1_1': 'setting pthread_mutexattr_setprotocol to a nonzero value is not supported',
109 'test_pthread_mutexattr_settype_2_1': 'interrupting pthread_mutex_lock wait via SIGALRM is not supported',
110103 'test_pthread_mutex_getprioceiling_1_1': 'pthread_mutex_getprioceiling is not supported',
111 'test_pthread_mutex_init_1_2': 'signals are not supported',
112104 'test_pthread_mutex_init_5_1': 'fork() and multiple processes are not supported',
113 'test_pthread_mutex_lock_3_1': 'signals are not supported',
114 'test_pthread_mutex_lock_5_1': 'signals are not supported',
115105 'test_pthread_mutex_trylock_1_2': 'lacking necessary mmap() support',
116106 'test_pthread_mutex_trylock_2_1': 'lacking necessary mmap() support',
117107 'test_pthread_mutex_trylock_4_2': 'lacking necessary mmap() support',
118 'test_pthread_mutex_trylock_4_3': 'signals are not supported',
119 'test_pthread_once_6_1': 'signals are not supported',
120108 'test_pthread_rwlockattr_getpshared_2_1': 'shm_open and shm_unlink are not supported',
121109 'test_pthread_rwlock_rdlock_2_1': 'thread priorities not supported, cannot test rwlocking in priority order',
122110 'test_pthread_rwlock_rdlock_2_2': 'thread priorities not supported, cannot test rwlocking in priority order',
125113 'test_pthread_rwlock_timedrdlock_6_2': 'signals are not supported',
126114 'test_pthread_rwlock_timedwrlock_6_1': 'signals are not supported',
127115 'test_pthread_rwlock_timedwrlock_6_2': 'signals are not supported',
128 'test_pthread_rwlock_unlock_3_1': 'thread priorities not supported, cannot test rwlocking in priority order',
129116 'test_pthread_rwlock_wrlock_2_1': 'signals are not supported',
130 'test_pthread_setschedparam_5_1': 'signals are not supported',
131117 'test_pthread_spin_init_2_1': 'shm_open and shm_unlink are not supported',
132118 'test_pthread_spin_init_2_2': 'shm_open and shm_unlink are not supported',
133 'test_pthread_spin_lock_1_1': 'signals are not supported',
134 'test_pthread_spin_lock_3_1': 'signals are not supported',
135119 }
136120
137121 # Mark certain tests as flaky, which may sometimes fail.
138 # TODO invesigate these tests.
122 # TODO investigate these tests.
139123 flaky = {
140124 'test_pthread_cond_signal_1_1': 'flaky: https://github.com/emscripten-core/emscripten/issues/13283',
125 'test_pthread_barrier_wait_2_1': 'flaky: https://github.com/emscripten-core/emscripten/issues/14508',
126 'test_pthread_rwlock_unlock_3_1': 'Test fail: writer did not get write lock, when main release the lock',
141127 }
142128
143 # Mark certain tests as not passing
129 # Mark certain tests as disabled. These are tests that are either flaky or never return.
144130 disabled = {
131 **flaky,
132 **unsupported_noreturn,
133 }
134
135 # These tests are known to fail reliably. We run them anyway so that we can
136 # detect fixes overtime.
137 expect_fail = {
145138 **unsupported,
146 **flaky,
147 'test_pthread_create_11_1': 'never returns',
148 'test_pthread_barrier_wait_2_1': 'never returns',
149139 'test_pthread_attr_setscope_5_1': 'internally skipped (PTS_UNTESTED)',
150 'test_pthread_create_5_1': 'never returns',
151 'test_pthread_exit_1_2': 'never returns',
152 'test_pthread_exit_2_2': 'never returns',
153 'test_pthread_exit_3_2': 'never returns',
154 'test_pthread_exit_4_1': 'never returns',
155 'test_pthread_getcpuclockid_1_1': 'never returns',
156 'test_pthread_key_create_1_2': 'never returns',
157 'test_pthread_rwlock_rdlock_1_1': 'fails with "main: Unexpected thread state"',
158 'test_pthread_rwlock_timedrdlock_1_1': 'fails with "main: Unexpected thread state"',
159 'test_pthread_rwlock_timedrdlock_3_1': 'fails with "main: Unexpected thread state"',
160 'test_pthread_rwlock_timedrdlock_5_1': 'fails with "main: Unexpected thread state"',
161 'test_pthread_rwlock_timedwrlock_1_1': 'fails with "main: Unexpected thread state"',
162 'test_pthread_rwlock_timedwrlock_3_1': 'fails with "main: Unexpected thread state"',
163 'test_pthread_rwlock_timedwrlock_5_1': 'fails with "main: Unexpected thread state"',
164 'test_pthread_rwlock_wrlock_1_1': 'fails with "main: Unexpected thread state"',
165 'test_pthread_rwlock_trywrlock_1_1': 'fails with "main: Unexpected thread state"',
166 'test_pthread_spin_destroy_3_1': 'never returns',
167 'test_pthread_spin_init_4_1': 'never returns',
168140 }
169141
170142
171143 def make_test(name, testfile, browser):
172144
145 @node_pthreads
173146 def f(self):
174147 if name in disabled:
175148 self.skipTest(disabled[name])
179152 '-Wno-int-conversion',
180153 '-sUSE_PTHREADS',
181154 '-sEXIT_RUNTIME',
182 '-sTOTAL_MEMORY=268435456',
155 '-sTOTAL_MEMORY=256mb',
183156 '-sPTHREAD_POOL_SIZE=40']
184157 if browser:
185 # Only are only needed for browser tests of the was btest
186 # injects headers using `-include` flag.
187 args += ['-Wno-macro-redefined', '-D_GNU_SOURCE']
188 self.btest(testfile, args=args, expected='exit:0')
158 self.btest_exit(testfile, args=args)
189159 else:
190 self.run_process([EMCC, testfile, '-o', 'test.js'] + args)
191 self.run_js('test.js', engine=engine)
160 self.do_runf(testfile, emcc_args=args)
161
162 if name in expect_fail:
163 f = unittest.expectedFailure(f)
192164
193165 return f
194166
66 parallel.
77 """
88
9 from runner import BrowserCore
9 from common import BrowserCore
1010
1111
1212 class posixtest_browser(BrowserCore):
1111 from pathlib import Path
1212 from subprocess import PIPE, STDOUT
1313
14 from runner import RunnerCore, path_from_root, env_modify, test_file
15 from runner import create_file, ensure_dir, make_executable, with_env_modify
16 from runner import parameterized, EMBUILDER
14 from common import RunnerCore, path_from_root, env_modify, test_file
15 from common import create_file, ensure_dir, make_executable, with_env_modify
16 from common import parameterized, EMBUILDER
1717 from tools.config import EM_CONFIG
1818 from tools.shared import EMCC
1919 from tools.shared import CANONICAL_TEMP_DIR
0 // Copyright 2015 The Emscripten Authors. All rights reserved.
1 // Emscripten is available under two separate licenses, the MIT license and the
2 // University of Illinois/NCSA Open Source License. Both these licenses can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <unistd.h>
9 #include <pthread.h>
10
11 void alarm_handler(int dummy) {
12 printf("Received alarm!\n");
13 exit(0);
14 }
15
16 int main() {
17 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
18 printf("Error in signal()!\n");
19 exit(1);
20 }
21 alarm(1);
22 }
2222 # which is the same behavior as before.
2323 pass
2424 import clang_native
25 from runner import BrowserCore, no_windows, create_file, test_file, read_file
25 from common import BrowserCore, no_windows, create_file, test_file, read_file
2626 from tools import shared, config, utils
2727 from tools.shared import PYTHON, EMCC, path_from_root, WINDOWS, run_process, CLANG_CC
2828
2121 glGenVertexArraysOES(1, &vao);
2222 assert(vao != 0);
2323 }
24 #ifdef REPORT_RESULT
25 REPORT_RESULT(0);
26 #endif
24
25 return 0;
2726 }
44 * found in the LICENSE file.
55 */
66
7 #include <assert.h>
78 #include <stdio.h>
9 #include <stdlib.h>
810 #include <ctype.h>
911 #include <string.h>
1012 #include <emscripten.h>
1113
12 int main()
13 {
14 const char * file = "/test.txt";
15 emscripten_wget(file , file);
16 FILE * f = fopen(file, "r");
17 int result = 0;
18 if(f) {
1914 #define BUFSIZE 1024
20 char buf[BUFSIZE];
21 fgets(buf, BUFSIZE, f);
22 buf[BUFSIZE-1] = 0;
23 for(int i = 0; i < BUFSIZE; ++i)
24 buf[i] = tolower(buf[i]);
25 if(strstr(buf, "emscripten"))
26 result = 1;
27 fclose(f);
28 }
29 REPORT_RESULT(result);
30 return 0;
15
16 int main() {
17 const char * file = "/test.txt";
18 printf("calling wget\n");
19 emscripten_wget(file , file);
20 printf("back from wget\n");
21
22 FILE * f = fopen(file, "r");
23 assert(f);
24
25 char buf[BUFSIZE];
26 fgets(buf, BUFSIZE, f);
27 buf[BUFSIZE-1] = 0;
28 for(int i = 0; i < BUFSIZE; ++i) {
29 buf[i] = tolower(buf[i]);
30 }
31 assert(strstr(buf, "emscripten"));
32 fclose(f);
33
34 printf("exiting main\n");
35 // Implicit return from main with ASYNCIFY + EXIT_RUNTIME
36 // currently doesn't work so we need to explictly exit.
37 // https://github.com/emscripten-core/emscripten/issues/14417
38 exit(0);
3139 }
55 */
66
77 #include <stdio.h>
8 #include <stdlib.h>
89 #include <ctype.h>
910 #include <string.h>
1011 #include <assert.h>
1112
1213 #include <emscripten.h>
1314
14 int main()
15 {
16 const char * file = "/test.txt";
17 void* buffer;
18 int num, error;
15 int main() {
16 const char * file = "/test.txt";
17 void* buffer;
18 int num, error;
1919
20 printf("load %s\n", file);
21 emscripten_wget_data(file, &buffer, &num, &error);
22 assert(!error);
23 printf("buffer: %s\n", (char*)buffer);
24 assert(strstr(buffer, "emscripten") == buffer);
20 printf("load %s\n", file);
21 emscripten_wget_data(file, &buffer, &num, &error);
22 assert(!error);
23 printf("buffer: %s\n", (char*)buffer);
24 assert(strstr(buffer, "emscripten") == buffer);
2525
26 printf("load non-existing\n");
27 emscripten_wget_data("doesnotexist", &buffer, &num, &error);
28 assert(error);
26 printf("load non-existing\n");
27 emscripten_wget_data("doesnotexist", &buffer, &num, &error);
28 assert(error);
2929
30 printf("ok!\n");
31 REPORT_RESULT(1);
32 return 0;
30 printf("ok!\n");
31 // Implicit return from main with ASYNCIFY + EXIT_RUNTIME
32 // currently doesn't work so we need to explictly exit.
33 // https://github.com/emscripten-core/emscripten/issues/14417
34 exit(0);
3335 }
6969 assert(hasext(exts, "WEBGL_multi_draw_instanced_base_vertex_base_instance") == emscripten_webgl_enable_extension(context, "WEBGL_multi_draw_instanced_base_vertex_base_instance"));
7070 #endif
7171
72 #ifdef REPORT_RESULT
73 REPORT_RESULT(0);
74 #endif
72 return 0;
7573 }
116116 glClearColor(0.3f,0.3f,0.3f,1);
117117 glClear(GL_COLOR_BUFFER_BIT);
118118 glDrawArrays(GL_TRIANGLES, 0, 3);
119 return 0;
119120 }
108108 emscripten_webgl_commit_frame();
109109 #endif
110110
111 #ifdef REPORT_RESULT
112 REPORT_RESULT(0);
113 #endif
111 return 0;
114112 }
111111 emscripten_webgl_commit_frame();
112112 #endif
113113
114 #ifdef REPORT_RESULT
115 REPORT_RESULT(0);
116 #endif
114 return 0;
117115 }
1313 #include <emscripten/html5.h>
1414 #include <GLES2/gl2.h>
1515
16 #ifdef REPORT_RESULT
17 #define DIE() do { REPORT_RESULT(1); exit(1); } while (0)
18 #else
19 #define DIE() do { exit(1); } while (0)
20 #endif
21
22 int main()
23 {
16 int main() {
2417 EmscriptenWebGLContextAttributes attr;
2518 emscripten_webgl_init_context_attributes(&attr);
2619 attr.explicitSwapControl = 1;
3730 #if !TEST_WEBGL2 && TEST_VAO
3831 // This test cannot run without browser support for OES_vertex_array_object.
3932 if (!emscripten_webgl_enable_extension(ctx, "OES_vertex_array_object")) {
40 DIE();
33 return 1;
4134 }
4235 #endif
4336
4841 emscripten_webgl_commit_frame();
4942
5043 if (glGetError() != GL_NO_ERROR) {
51 DIE();
44 return 1;
5245 }
5346
5447 // C doesn't have access to the "frontbuffer" (canvas contents).
6053 return pixels[0] == 0 && pixels[1] == 255 && pixels[2] == 0 && pixels[3] == 255;
6154 });
6255 if (!canvas_is_green) {
63 DIE();
56 return 1;
6457 }
6558
66 #ifdef REPORT_RESULT
67 REPORT_RESULT(0);
68 #endif
59 return 0;
6960 }
22 // University of Illinois/NCSA Open Source License. Both these licenses can be
33 // found in the LICENSE file.
44
5 #include <stdlib.h>
56 #include <cassert>
67 #include <cstdio>
78 #include <emscripten.h>
2930 GLuint any;
3031 GL_CALL(glGetQueryObjectuiv(sampleQuery, GL_QUERY_RESULT, &any));
3132
32 if(!any) return;
33 if (!any) return;
3334
3435 printf("queried any samples passed: %u\n", any);
3536 emscripten_cancel_main_loop();
3637
3738 GL_CALL(glDeleteQueries(1, &sampleQuery));
3839
39 #ifdef REPORT_RESULT
40 REPORT_RESULT(result);
41 #endif
40 // result == 0 signals success
41 exit(result);
4242 }
4343
4444 GLuint compile_shader(GLenum shaderType, const char *src)
6363 return program;
6464 }
6565
66 int main()
67 {
66 int main() {
6867 EmscriptenWebGLContextAttributes attrs;
6968 emscripten_webgl_init_context_attributes(&attrs);
7069
7372 attrs.minorVersion = 0;
7473
7574 /* Skip WebGL 2 tests if not supported */
76 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context( "#canvas", &attrs );
77 if (!context)
78 {
75 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context("#canvas", &attrs);
76 if (!context) {
7977 printf("Skipped: WebGL 2 is not supported.\n");
80 #ifdef REPORT_RESULT
81 REPORT_RESULT(result);
82 #endif
8378 return 0;
8479 }
8580 emscripten_webgl_make_context_current(context);
139134 /* Run the main loop to get the result */
140135 emscripten_set_main_loop(getQueryResult, 0, 0);
141136
142 return 0;
137 return 99;
143138 }
33 // found in the LICENSE file.
44
55 #include <cassert>
6 #include <cstdlib>
67 #include <cstdio>
78 #include <cstring>
89 #include <emscripten.h>
5152 GL_CALL(glDeleteQueriesEXT(1, &timerQuery));
5253 #endif
5354
54 #ifdef REPORT_RESULT
55 REPORT_RESULT(result);
56 #endif
55 exit(result);
5756 }
5857
5958 int main()
374374 */
375375 nodeBuffer.SlowBuffer.prototype.toString = function() {};
376376
377 /**
378 * @param {number} size
379 * @param {(string|!Buffer|number)=} fill
380 * @param {string=} encoding
381 * @return {!Buffer}
382 */
383 nodeBuffer.Buffer.alloc;
384
385 /**
386 * @param {Array} aray
387 * @return {!Buffer}
388 */
389 nodeBuffer.Buffer.from;
390
377391 //
378392 // Legacy
379393 //
112112 for a in archive_contents:
113113 missing_contents = [x for x in a['o_files'] if not os.path.exists(x)]
114114 if missing_contents:
115 exit_with_error('llvm-ar failed to extract file(s) ' + str(missing_contents) + ' from archive file ' + f + '!')
115 exit_with_error(f'llvm-ar failed to extract file(s) {missing_contents} from archive file {f}!')
116116
117117 return archive_contents
118118
155155 return arg
156156
157157
158 def get_building_env(cflags=[]):
158 def get_building_env():
159159 env = os.environ.copy()
160160 # point CC etc. to the em* tools.
161161 env['CC'] = EMCC
166166 env['LDSHARED'] = EMCC
167167 env['RANLIB'] = EMRANLIB
168168 env['EMSCRIPTEN_TOOLS'] = path_from_root('tools')
169 if cflags:
170 env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(cflags)
171169 env['HOST_CC'] = CLANG_CC
172170 env['HOST_CXX'] = CLANG_CXX
173171 env['HOST_CFLAGS'] = '-W' # if set to nothing, CFLAGS is used, which we don't want
202200
203201 # Runs llvm-nm for the given list of files.
204202 # The results are populated in nm_cache
203 @ToolchainProfiler.profile_block('llvm_nm_multiple')
205204 def llvm_nm_multiple(files):
206 with ToolchainProfiler.profile_block('llvm_nm_multiple'):
207 if len(files) == 0:
208 return []
209 # Run llvm-nm on files that we haven't cached yet
210 llvm_nm_files = [f for f in files if f not in nm_cache]
211
212 # We can issue multiple files in a single llvm-nm calls, but only if those
213 # files are all .o or .bc files. Because of llvm-nm output format, we cannot
214 # llvm-nm multiple .a files in one call, but those must be individually checked.
215
216 o_files = [f for f in llvm_nm_files if os.path.splitext(f)[1].lower() in ['.o', '.obj', '.bc']]
217 a_files = [f for f in llvm_nm_files if f not in o_files]
218
219 # Issue parallel calls for .a files
220 if len(a_files) > 0:
221 results = shared.run_multiple_processes([[LLVM_NM, a] for a in a_files], pipe_stdout=True, check=False)
222 for i in range(len(results)):
223 nm_cache[a_files[i]] = parse_symbols(results[i])
224
225 # Issue a single batch call for multiple .o files
226 if len(o_files) > 0:
227 cmd = [LLVM_NM] + o_files
228 cmd = get_command_with_possible_response_file(cmd)
229 results = run_process(cmd, stdout=PIPE, stderr=PIPE, check=False)
230
231 # If one or more of the input files cannot be processed, llvm-nm will return a non-zero error code, but it will still process and print
232 # out all the other files in order. So even if process return code is non zero, we should always look at what we got to stdout.
233 if results.returncode != 0:
234 logger.debug('Subcommand ' + ' '.join(cmd) + ' failed with return code ' + str(results.returncode) + '! (An input file was corrupt?)')
235
236 results = results.stdout
237
238 # llvm-nm produces a single listing of form
239 # file1.o:
240 # 00000001 T __original_main
241 # U __stack_pointer
242 #
243 # file2.o:
244 # 0000005d T main
245 # U printf
246 #
247 # ...
248 # so loop over the report to extract the results
249 # for each individual file.
250
251 filename = o_files[0]
252
253 # When we dispatched more than one file, we must manually parse
254 # the file result delimiters (like shown structured above)
255 if len(o_files) > 1:
256 file_start = 0
257 i = 0
258
259 while True:
260 nl = results.find('\n', i)
261 if nl < 0:
262 break
263 colon = results.rfind(':', i, nl)
264 if colon >= 0 and results[colon + 1] == '\n': # New file start?
265 nm_cache[filename] = parse_symbols(results[file_start:i - 1])
266 filename = results[i:colon].strip()
267 file_start = colon + 2
268 i = nl + 1
269
270 nm_cache[filename] = parse_symbols(results[file_start:])
271 else:
272 # We only dispatched a single file, so can parse all of the result directly
273 # to that file.
274 nm_cache[filename] = parse_symbols(results)
205 if len(files) == 0:
206 return []
207 # Run llvm-nm on files that we haven't cached yet
208 llvm_nm_files = [f for f in files if f not in nm_cache]
209
210 # We can issue multiple files in a single llvm-nm calls, but only if those
211 # files are all .o or .bc files. Because of llvm-nm output format, we cannot
212 # llvm-nm multiple .a files in one call, but those must be individually checked.
213
214 a_files = [f for f in llvm_nm_files if is_ar(f)]
215 o_files = [f for f in llvm_nm_files if f not in a_files]
216
217 # Issue parallel calls for .a files
218 if len(a_files) > 0:
219 results = shared.run_multiple_processes([[LLVM_NM, a] for a in a_files], pipe_stdout=True, check=False)
220 for i in range(len(results)):
221 nm_cache[a_files[i]] = parse_symbols(results[i])
222
223 # Issue a single batch call for multiple .o files
224 if len(o_files) > 0:
225 cmd = [LLVM_NM] + o_files
226 cmd = get_command_with_possible_response_file(cmd)
227 results = run_process(cmd, stdout=PIPE, stderr=PIPE, check=False)
228
229 # If one or more of the input files cannot be processed, llvm-nm will return a non-zero error code, but it will still process and print
230 # out all the other files in order. So even if process return code is non zero, we should always look at what we got to stdout.
231 if results.returncode != 0:
232 logger.debug(f'Subcommand {" ".join(cmd)} failed with return code {results.returncode}! (An input file was corrupt?)')
233
234 results = results.stdout
235
236 # llvm-nm produces a single listing of form
237 # file1.o:
238 # 00000001 T __original_main
239 # U __stack_pointer
240 #
241 # file2.o:
242 # 0000005d T main
243 # U printf
244 #
245 # ...
246 # so loop over the report to extract the results
247 # for each individual file.
248
249 filename = o_files[0]
250
251 # When we dispatched more than one file, we must manually parse
252 # the file result delimiters (like shown structured above)
253 if len(o_files) > 1:
254 file_start = 0
255 i = 0
256
257 while True:
258 nl = results.find('\n', i)
259 if nl < 0:
260 break
261 colon = results.rfind(':', i, nl)
262 if colon >= 0 and results[colon + 1] == '\n': # New file start?
263 nm_cache[filename] = parse_symbols(results[file_start:i - 1])
264 filename = results[i:colon].strip()
265 file_start = colon + 2
266 i = nl + 1
267
268 nm_cache[filename] = parse_symbols(results[file_start:])
269 else:
270 # We only dispatched a single file, so can parse all of the result directly
271 # to that file.
272 nm_cache[filename] = parse_symbols(results)
275273
276274 return [nm_cache[f] if f in nm_cache else ObjectFileInfo(1, '') for f in files]
277275
280278 return llvm_nm_multiple([file])[0]
281279
282280
281 @ToolchainProfiler.profile_block('read_link_inputs')
283282 def read_link_inputs(files):
284 with ToolchainProfiler.profile_block('read_link_inputs'):
285 # Before performing the link, we need to look at each input file to determine which symbols
286 # each of them provides. Do this in multiple parallel processes.
287 archive_names = [] # .a files passed in to the command line to the link
288 object_names = [] # .o/.bc files passed in to the command line to the link
289 for f in files:
290 absolute_path_f = make_paths_absolute(f)
291
292 if absolute_path_f not in ar_contents and is_ar(absolute_path_f):
293 archive_names.append(absolute_path_f)
294 elif absolute_path_f not in nm_cache and is_bitcode(absolute_path_f):
295 object_names.append(absolute_path_f)
296
297 # Archives contain objects, so process all archives first in parallel to obtain the object files in them.
298 archive_contents = extract_archive_contents(archive_names)
299
300 for a in archive_contents:
301 ar_contents[os.path.abspath(a['archive_name'])] = a['o_files']
302 for o in a['o_files']:
303 if o not in nm_cache:
304 object_names.append(o)
305
306 # Next, extract symbols from all object files (either standalone or inside archives we just extracted)
307 # The results are not used here directly, but populated to llvm-nm cache structure.
308 llvm_nm_multiple(object_names)
283 # Before performing the link, we need to look at each input file to determine which symbols
284 # each of them provides. Do this in multiple parallel processes.
285 archive_names = [] # .a files passed in to the command line to the link
286 object_names = [] # .o/.bc files passed in to the command line to the link
287 for f in files:
288 absolute_path_f = make_paths_absolute(f)
289
290 if absolute_path_f not in ar_contents and is_ar(absolute_path_f):
291 archive_names.append(absolute_path_f)
292 elif absolute_path_f not in nm_cache and is_bitcode(absolute_path_f):
293 object_names.append(absolute_path_f)
294
295 # Archives contain objects, so process all archives first in parallel to obtain the object files in them.
296 archive_contents = extract_archive_contents(archive_names)
297
298 for a in archive_contents:
299 ar_contents[os.path.abspath(a['archive_name'])] = a['o_files']
300 for o in a['o_files']:
301 if o not in nm_cache:
302 object_names.append(o)
303
304 # Next, extract symbols from all object files (either standalone or inside archives we just extracted)
305 # The results are not used here directly, but populated to llvm-nm cache structure.
306 llvm_nm_multiple(object_names)
309307
310308
311309 def llvm_backend_args():
334332 return args
335333
336334
335 @ToolchainProfiler.profile_block('linking to object file')
337336 def link_to_object(args, target):
338337 # link using lld unless LTO is requested (lld can't output LTO/bitcode object files).
339338 if not settings.LTO:
673672 elif shrink_level >= 2:
674673 return '-Oz'
675674 else:
676 return '-O' + str(min(opt_level, 3))
675 return f'-O{min(opt_level, 3)}'
677676
678677
679678 def js_optimizer(filename, passes):
756755 return True
757756
758757
758 @ToolchainProfiler.profile_block('closure_compiler')
759759 def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None):
760 with ToolchainProfiler.profile_block('closure_compiler'):
761 env = shared.env_with_node_in_path()
762 user_args = []
763 env_args = os.environ.get('EMCC_CLOSURE_ARGS')
764 if env_args:
765 user_args += shlex.split(env_args)
766 if extra_closure_args:
767 user_args += extra_closure_args
768
769 # Closure compiler expects JAVA_HOME to be set *and* java.exe to be in the PATH in order
770 # to enable use the java backend. Without this it will only try the native and JavaScript
771 # versions of the compiler.
772 java_bin = os.path.dirname(config.JAVA)
773 if java_bin:
774 def add_to_path(dirname):
775 env['PATH'] = env['PATH'] + os.pathsep + dirname
776 add_to_path(java_bin)
777 java_home = os.path.dirname(java_bin)
778 env.setdefault('JAVA_HOME', java_home)
779
780 closure_cmd = get_closure_compiler()
781
782 native_closure_compiler_works = check_closure_compiler(closure_cmd, user_args, env, allowed_to_fail=True)
783 if not native_closure_compiler_works and not any(a.startswith('--platform') for a in user_args):
784 # Run with Java Closure compiler as a fallback if the native version does not work
785 user_args.append('--platform=java')
786 check_closure_compiler(closure_cmd, user_args, env, allowed_to_fail=False)
787
788 # Closure externs file contains known symbols to be extern to the minification, Closure
789 # should not minify these symbol names.
790 CLOSURE_EXTERNS = [path_from_root('src', 'closure-externs', 'closure-externs.js')]
791
792 # Closure compiler needs to know about all exports that come from the wasm module, because to optimize for small code size,
793 # the exported symbols are added to global scope via a foreach loop in a way that evades Closure's static analysis. With an explicit
794 # externs file for the exports, Closure is able to reason about the exports.
795 if settings.WASM_FUNCTION_EXPORTS and not settings.DECLARE_ASM_MODULE_EXPORTS:
796 # Generate an exports file that records all the exported symbols from the wasm module.
797 module_exports_suppressions = '\n'.join(['/**\n * @suppress {duplicate, undefinedVars}\n */\nvar %s;\n' % asmjs_mangle(i) for i in settings.WASM_FUNCTION_EXPORTS])
798 exports_file = configuration.get_temp_files().get('_module_exports.js')
799 exports_file.write(module_exports_suppressions.encode())
800 exports_file.close()
801
802 CLOSURE_EXTERNS += [exports_file.name]
803
804 # Node.js specific externs
805 if shared.target_environment_may_be('node'):
806 NODE_EXTERNS_BASE = path_from_root('third_party', 'closure-compiler', 'node-externs')
807 NODE_EXTERNS = os.listdir(NODE_EXTERNS_BASE)
808 NODE_EXTERNS = [os.path.join(NODE_EXTERNS_BASE, name) for name in NODE_EXTERNS
809 if name.endswith('.js')]
810 CLOSURE_EXTERNS += [path_from_root('src', 'closure-externs', 'node-externs.js')] + NODE_EXTERNS
811
812 # V8/SpiderMonkey shell specific externs
813 if shared.target_environment_may_be('shell'):
814 V8_EXTERNS = [path_from_root('src', 'closure-externs', 'v8-externs.js')]
815 SPIDERMONKEY_EXTERNS = [path_from_root('src', 'closure-externs', 'spidermonkey-externs.js')]
816 CLOSURE_EXTERNS += V8_EXTERNS + SPIDERMONKEY_EXTERNS
817
818 # Web environment specific externs
819 if shared.target_environment_may_be('web') or shared.target_environment_may_be('worker'):
820 BROWSER_EXTERNS_BASE = path_from_root('src', 'closure-externs', 'browser-externs')
821 if os.path.isdir(BROWSER_EXTERNS_BASE):
822 BROWSER_EXTERNS = os.listdir(BROWSER_EXTERNS_BASE)
823 BROWSER_EXTERNS = [os.path.join(BROWSER_EXTERNS_BASE, name) for name in BROWSER_EXTERNS
824 if name.endswith('.js')]
825 CLOSURE_EXTERNS += BROWSER_EXTERNS
826
827 if settings.MINIMAL_RUNTIME and settings.USE_PTHREADS and not settings.MODULARIZE:
828 CLOSURE_EXTERNS += [path_from_root('src', 'minimal_runtime_worker_externs.js')]
829
830 args = ['--compilation_level', 'ADVANCED_OPTIMIZATIONS' if advanced else 'SIMPLE_OPTIMIZATIONS']
831 # Keep in sync with ecmaVersion in tools/acorn-optimizer.js
832 args += ['--language_in', 'ECMASCRIPT_2020']
833 # Tell closure not to do any transpiling or inject any polyfills.
834 # At some point we may want to look into using this as way to convert to ES5 but
835 # babel is perhaps a better tool for that.
836 args += ['--language_out', 'NO_TRANSPILE']
837 # Tell closure never to inject the 'use strict' directive.
838 args += ['--emit_use_strict=false']
839
840 # Closure compiler is unable to deal with path names that are not 7-bit ASCII:
841 # https://github.com/google/closure-compiler/issues/3784
842 tempfiles = configuration.get_temp_files()
843 outfile = tempfiles.get('.cc.js').name # Safe 7-bit filename
844
845 def move_to_safe_7bit_ascii_filename(filename):
846 safe_filename = tempfiles.get('.js').name # Safe 7-bit filename
847 shutil.copyfile(filename, safe_filename)
848 return os.path.relpath(safe_filename, tempfiles.tmpdir)
849
850 for e in CLOSURE_EXTERNS:
851 args += ['--externs', move_to_safe_7bit_ascii_filename(e)]
852
853 for i in range(len(user_args)):
854 if user_args[i] == '--externs':
855 user_args[i + 1] = move_to_safe_7bit_ascii_filename(user_args[i + 1])
856
857 # Specify output file relative to the temp directory to avoid specifying non-7-bit-ASCII path names.
858 args += ['--js_output_file', os.path.relpath(outfile, tempfiles.tmpdir)]
859
860 if settings.IGNORE_CLOSURE_COMPILER_ERRORS:
861 args.append('--jscomp_off=*')
862 if pretty:
863 args += ['--formatting', 'PRETTY_PRINT']
864 # Specify input file relative to the temp directory to avoid specifying non-7-bit-ASCII path names.
865 args += ['--js', move_to_safe_7bit_ascii_filename(filename)]
866 cmd = closure_cmd + args + user_args
867 logger.debug('closure compiler: ' + ' '.join(cmd))
868
869 # Closure compiler does not work if any of the input files contain characters outside the
870 # 7-bit ASCII range. Therefore make sure the command line we pass does not contain any such
871 # input files by passing all input filenames relative to the cwd. (user temp directory might
872 # be in user's home directory, and user's profile name might contain unicode characters)
873 proc = run_process(cmd, stderr=PIPE, check=False, env=env, cwd=tempfiles.tmpdir)
874
875 # XXX Closure bug: if Closure is invoked with --create_source_map, Closure should create a
876 # outfile.map source map file (https://github.com/google/closure-compiler/wiki/Source-Maps)
877 # But it looks like it creates such files on Linux(?) even without setting that command line
878 # flag (and currently we don't), so delete the produced source map file to not leak files in
879 # temp directory.
880 try_delete(outfile + '.map')
881
882 # Print Closure diagnostics result up front.
883 if proc.returncode != 0:
884 logger.error('Closure compiler run failed:\n')
885 elif len(proc.stderr.strip()) > 0:
886 if settings.CLOSURE_WARNINGS == 'error':
887 logger.error('Closure compiler completed with warnings and -s CLOSURE_WARNINGS=error enabled, aborting!\n')
888 elif settings.CLOSURE_WARNINGS == 'warn':
889 logger.warn('Closure compiler completed with warnings:\n')
890
891 # Print input file (long wall of text!)
892 if DEBUG == 2 and (proc.returncode != 0 or (len(proc.stderr.strip()) > 0 and settings.CLOSURE_WARNINGS != 'quiet')):
893 input_file = open(filename, 'r').read().splitlines()
894 for i in range(len(input_file)):
895 sys.stderr.write(str(i + 1) + ': ' + input_file[i] + '\n')
896
897 if proc.returncode != 0:
898 logger.error(proc.stderr) # print list of errors (possibly long wall of text if input was minified)
899
900 # Exit and print final hint to get clearer output
901 msg = 'closure compiler failed (rc: %d): %s' % (proc.returncode, shared.shlex_join(cmd))
902 if not pretty:
903 msg += ' the error message may be clearer with -g1 and EMCC_DEBUG=2 set'
904 exit_with_error(msg)
905
906 if len(proc.stderr.strip()) > 0 and settings.CLOSURE_WARNINGS != 'quiet':
907 # print list of warnings (possibly long wall of text if input was minified)
908 if settings.CLOSURE_WARNINGS == 'error':
909 logger.error(proc.stderr)
910 else:
911 logger.warn(proc.stderr)
912
913 # Exit and/or print final hint to get clearer output
914 if not pretty:
915 logger.warn('(rerun with -g1 linker flag for an unminified output)')
916 elif DEBUG != 2:
917 logger.warn('(rerun with EMCC_DEBUG=2 enabled to dump Closure input file)')
918
919 if settings.CLOSURE_WARNINGS == 'error':
920 exit_with_error('closure compiler produced warnings and -s CLOSURE_WARNINGS=error enabled')
921
922 return outfile
760 env = shared.env_with_node_in_path()
761 user_args = []
762 env_args = os.environ.get('EMCC_CLOSURE_ARGS')
763 if env_args:
764 user_args += shlex.split(env_args)
765 if extra_closure_args:
766 user_args += extra_closure_args
767
768 # Closure compiler expects JAVA_HOME to be set *and* java.exe to be in the PATH in order
769 # to enable use the java backend. Without this it will only try the native and JavaScript
770 # versions of the compiler.
771 java_bin = os.path.dirname(config.JAVA)
772 if java_bin:
773 def add_to_path(dirname):
774 env['PATH'] = env['PATH'] + os.pathsep + dirname
775 add_to_path(java_bin)
776 java_home = os.path.dirname(java_bin)
777 env.setdefault('JAVA_HOME', java_home)
778
779 closure_cmd = get_closure_compiler()
780
781 native_closure_compiler_works = check_closure_compiler(closure_cmd, user_args, env, allowed_to_fail=True)
782 if not native_closure_compiler_works and not any(a.startswith('--platform') for a in user_args):
783 # Run with Java Closure compiler as a fallback if the native version does not work
784 user_args.append('--platform=java')
785 check_closure_compiler(closure_cmd, user_args, env, allowed_to_fail=False)
786
787 # Closure externs file contains known symbols to be extern to the minification, Closure
788 # should not minify these symbol names.
789 CLOSURE_EXTERNS = [path_from_root('src', 'closure-externs', 'closure-externs.js')]
790
791 # Closure compiler needs to know about all exports that come from the wasm module, because to optimize for small code size,
792 # the exported symbols are added to global scope via a foreach loop in a way that evades Closure's static analysis. With an explicit
793 # externs file for the exports, Closure is able to reason about the exports.
794 if settings.WASM_FUNCTION_EXPORTS and not settings.DECLARE_ASM_MODULE_EXPORTS:
795 # Generate an exports file that records all the exported symbols from the wasm module.
796 module_exports_suppressions = '\n'.join(['/**\n * @suppress {duplicate, undefinedVars}\n */\nvar %s;\n' % asmjs_mangle(i) for i in settings.WASM_FUNCTION_EXPORTS])
797 exports_file = configuration.get_temp_files().get('_module_exports.js')
798 exports_file.write(module_exports_suppressions.encode())
799 exports_file.close()
800
801 CLOSURE_EXTERNS += [exports_file.name]
802
803 # Node.js specific externs
804 if shared.target_environment_may_be('node'):
805 NODE_EXTERNS_BASE = path_from_root('third_party', 'closure-compiler', 'node-externs')
806 NODE_EXTERNS = os.listdir(NODE_EXTERNS_BASE)
807 NODE_EXTERNS = [os.path.join(NODE_EXTERNS_BASE, name) for name in NODE_EXTERNS
808 if name.endswith('.js')]
809 CLOSURE_EXTERNS += [path_from_root('src', 'closure-externs', 'node-externs.js')] + NODE_EXTERNS
810
811 # V8/SpiderMonkey shell specific externs
812 if shared.target_environment_may_be('shell'):
813 V8_EXTERNS = [path_from_root('src', 'closure-externs', 'v8-externs.js')]
814 SPIDERMONKEY_EXTERNS = [path_from_root('src', 'closure-externs', 'spidermonkey-externs.js')]
815 CLOSURE_EXTERNS += V8_EXTERNS + SPIDERMONKEY_EXTERNS
816
817 # Web environment specific externs
818 if shared.target_environment_may_be('web') or shared.target_environment_may_be('worker'):
819 BROWSER_EXTERNS_BASE = path_from_root('src', 'closure-externs', 'browser-externs')
820 if os.path.isdir(BROWSER_EXTERNS_BASE):
821 BROWSER_EXTERNS = os.listdir(BROWSER_EXTERNS_BASE)
822 BROWSER_EXTERNS = [os.path.join(BROWSER_EXTERNS_BASE, name) for name in BROWSER_EXTERNS
823 if name.endswith('.js')]
824 CLOSURE_EXTERNS += BROWSER_EXTERNS
825
826 if settings.MINIMAL_RUNTIME and settings.USE_PTHREADS and not settings.MODULARIZE:
827 CLOSURE_EXTERNS += [path_from_root('src', 'minimal_runtime_worker_externs.js')]
828
829 args = ['--compilation_level', 'ADVANCED_OPTIMIZATIONS' if advanced else 'SIMPLE_OPTIMIZATIONS']
830 # Keep in sync with ecmaVersion in tools/acorn-optimizer.js
831 args += ['--language_in', 'ECMASCRIPT_2020']
832 # Tell closure not to do any transpiling or inject any polyfills.
833 # At some point we may want to look into using this as way to convert to ES5 but
834 # babel is perhaps a better tool for that.
835 args += ['--language_out', 'NO_TRANSPILE']
836 # Tell closure never to inject the 'use strict' directive.
837 args += ['--emit_use_strict=false']
838
839 # Closure compiler is unable to deal with path names that are not 7-bit ASCII:
840 # https://github.com/google/closure-compiler/issues/3784
841 tempfiles = configuration.get_temp_files()
842 outfile = tempfiles.get('.cc.js').name # Safe 7-bit filename
843
844 def move_to_safe_7bit_ascii_filename(filename):
845 safe_filename = tempfiles.get('.js').name # Safe 7-bit filename
846 shutil.copyfile(filename, safe_filename)
847 return os.path.relpath(safe_filename, tempfiles.tmpdir)
848
849 for e in CLOSURE_EXTERNS:
850 args += ['--externs', move_to_safe_7bit_ascii_filename(e)]
851
852 for i in range(len(user_args)):
853 if user_args[i] == '--externs':
854 user_args[i + 1] = move_to_safe_7bit_ascii_filename(user_args[i + 1])
855
856 # Specify output file relative to the temp directory to avoid specifying non-7-bit-ASCII path names.
857 args += ['--js_output_file', os.path.relpath(outfile, tempfiles.tmpdir)]
858
859 if settings.IGNORE_CLOSURE_COMPILER_ERRORS:
860 args.append('--jscomp_off=*')
861 if pretty:
862 args += ['--formatting', 'PRETTY_PRINT']
863 # Specify input file relative to the temp directory to avoid specifying non-7-bit-ASCII path names.
864 args += ['--js', move_to_safe_7bit_ascii_filename(filename)]
865 cmd = closure_cmd + args + user_args
866 logger.debug('closure compiler: ' + ' '.join(cmd))
867
868 # Closure compiler does not work if any of the input files contain characters outside the
869 # 7-bit ASCII range. Therefore make sure the command line we pass does not contain any such
870 # input files by passing all input filenames relative to the cwd. (user temp directory might
871 # be in user's home directory, and user's profile name might contain unicode characters)
872 proc = run_process(cmd, stderr=PIPE, check=False, env=env, cwd=tempfiles.tmpdir)
873
874 # XXX Closure bug: if Closure is invoked with --create_source_map, Closure should create a
875 # outfile.map source map file (https://github.com/google/closure-compiler/wiki/Source-Maps)
876 # But it looks like it creates such files on Linux(?) even without setting that command line
877 # flag (and currently we don't), so delete the produced source map file to not leak files in
878 # temp directory.
879 try_delete(outfile + '.map')
880
881 # Print Closure diagnostics result up front.
882 if proc.returncode != 0:
883 logger.error('Closure compiler run failed:\n')
884 elif len(proc.stderr.strip()) > 0:
885 if settings.CLOSURE_WARNINGS == 'error':
886 logger.error('Closure compiler completed with warnings and -s CLOSURE_WARNINGS=error enabled, aborting!\n')
887 elif settings.CLOSURE_WARNINGS == 'warn':
888 logger.warn('Closure compiler completed with warnings:\n')
889
890 # Print input file (long wall of text!)
891 if DEBUG == 2 and (proc.returncode != 0 or (len(proc.stderr.strip()) > 0 and settings.CLOSURE_WARNINGS != 'quiet')):
892 input_file = open(filename, 'r').read().splitlines()
893 for i in range(len(input_file)):
894 sys.stderr.write(f'{i + 1}: {input_file[i]}\n')
895
896 if proc.returncode != 0:
897 logger.error(proc.stderr) # print list of errors (possibly long wall of text if input was minified)
898
899 # Exit and print final hint to get clearer output
900 msg = 'closure compiler failed (rc: %d): %s' % (proc.returncode, shared.shlex_join(cmd))
901 if not pretty:
902 msg += ' the error message may be clearer with -g1 and EMCC_DEBUG=2 set'
903 exit_with_error(msg)
904
905 if len(proc.stderr.strip()) > 0 and settings.CLOSURE_WARNINGS != 'quiet':
906 # print list of warnings (possibly long wall of text if input was minified)
907 if settings.CLOSURE_WARNINGS == 'error':
908 logger.error(proc.stderr)
909 else:
910 logger.warn(proc.stderr)
911
912 # Exit and/or print final hint to get clearer output
913 if not pretty:
914 logger.warn('(rerun with -g1 linker flag for an unminified output)')
915 elif DEBUG != 2:
916 logger.warn('(rerun with EMCC_DEBUG=2 enabled to dump Closure input file)')
917
918 if settings.CLOSURE_WARNINGS == 'error':
919 exit_with_error('closure compiler produced warnings and -s CLOSURE_WARNINGS=error enabled')
920
921 return outfile
923922
924923
925924 # minify the final wasm+JS combination. this is done after all the JS
11441143 passes += ['last']
11451144 if passes:
11461145 # hackish fixups to work around wasm2js style and the js optimizer FIXME
1147 wasm2js_js = '// EMSCRIPTEN_START_ASM\n' + wasm2js_js + '// EMSCRIPTEN_END_ASM\n'
1146 wasm2js_js = f'// EMSCRIPTEN_START_ASM\n{wasm2js_js}// EMSCRIPTEN_END_ASM\n'
11481147 wasm2js_js = wasm2js_js.replace('// EMSCRIPTEN_START_FUNCS;\n', '// EMSCRIPTEN_START_FUNCS\n')
11491148 wasm2js_js = wasm2js_js.replace('// EMSCRIPTEN_END_FUNCS;\n', '// EMSCRIPTEN_END_FUNCS\n')
11501149 wasm2js_js = wasm2js_js.replace('\n function $', '\nfunction $')
11821181 finds = re.findall(r'''[\w\d_$]+\.__wasm2jsInstantiate__''', all_js)
11831182 assert len(finds) == 1
11841183 marker = finds[0]
1185 all_js = all_js.replace(marker, '(\n' + wasm2js_js + '\n)')
1184 all_js = all_js.replace(marker, f'(\n{wasm2js_js}\n)')
11861185 # replace the placeholder with the actual code
11871186 js_file = js_file + '.wasm2js.js'
11881187 with open(js_file, 'w') as f:
13781377 logger.debug('Mapping library `%s` to JS libraries: %s' % (library_name, libs))
13791378 return (libs, native_library_map.get(library_name))
13801379
1381 if library_name.endswith('.js') and os.path.isfile(path_from_root('src', 'library_' + library_name)):
1382 return (['library_' + library_name], None)
1380 if library_name.endswith('.js') and os.path.isfile(path_from_root('src', f'library_{library_name}')):
1381 return ([f'library_{library_name}'], None)
13831382
13841383 return (None, None)
13851384
14931492 extra += '\nnote: to disable int64 legalization (which requires changes after link) use -s WASM_BIGINT'
14941493 if settings.OPT_LEVEL > 0:
14951494 extra += '\nnote: -O2+ optimizations always require changes, build with -O0 or -O1 instead'
1496 exit_with_error('changes to the wasm are required after link, but disallowed by ERROR_ON_WASM_CHANGES_AFTER_LINK: ' + str(cmd) + extra)
1495 exit_with_error(f'changes to the wasm are required after link, but disallowed by ERROR_ON_WASM_CHANGES_AFTER_LINK: {cmd}{extra}')
14971496 if debug:
14981497 cmd += ['-g'] # preserve the debug info
14991498 # if the features are not already handled, handle them
15011500 # if we are emitting a source map, every time we load and save the wasm
15021501 # we must tell binaryen to update it
15031502 if settings.GENERATE_SOURCE_MAP and outfile:
1504 cmd += ['--input-source-map=' + infile + '.map']
1505 cmd += ['--output-source-map=' + outfile + '.map']
1503 cmd += [f'--input-source-map={infile}.map']
1504 cmd += [f'--output-source-map={outfile}.map']
15061505 ret = check_call(cmd, stdout=stdout).stdout
15071506 if outfile:
15081507 save_intermediate(outfile, '%s.wasm' % tool)
4242 raise Exception('Attempt to lock the cache but FROZEN_CACHE is set')
4343
4444 if not self.EM_EXCLUSIVE_CACHE_ACCESS and self.acquired_count == 0:
45 logger.debug('PID %s acquiring multiprocess file lock to Emscripten cache at %s' % (str(os.getpid()), self.dirname))
45 logger.debug(f'PID {os.getpid()} acquiring multiprocess file lock to Emscripten cache at {self.dirname}')
4646 try:
4747 self.filelock.acquire(60)
4848 except filelock.Timeout:
4949 # The multiprocess cache locking can be disabled altogether by setting EM_EXCLUSIVE_CACHE_ACCESS=1 environment
5050 # variable before building. (in that case, use "embuilder.py build ALL" to prepopulate the cache)
51 logger.warning('Accessing the Emscripten cache at "' + self.dirname + '" is taking a long time, another process should be writing to it. If there are none and you suspect this process has deadlocked, try deleting the lock file "' + self.filelock_name + '" and try again. If this occurs deterministically, consider filing a bug.')
51 logger.warning(f'Accessing the Emscripten cache at "{self.dirname}" is taking a long time, another process should be writing to it. If there are none and you suspect this process has deadlocked, try deleting the lock file "{self.filelock_name}" and try again. If this occurs deterministically, consider filing a bug.')
5252 self.filelock.acquire()
5353
5454 self.prev_EM_EXCLUSIVE_CACHE_ACCESS = os.environ.get('EM_EXCLUSIVE_CACHE_ACCESS')
6565 else:
6666 del os.environ['EM_EXCLUSIVE_CACHE_ACCESS']
6767 self.filelock.release()
68 logger.debug('PID %s released multiprocess file lock to Emscripten cache at %s' % (str(os.getpid()), self.dirname))
68 logger.debug(f'PID {os.getpid()} released multiprocess file lock to Emscripten cache at {self.dirname}')
6969
7070 @contextlib.contextmanager
7171 def lock(self):
125125 with self.lock():
126126 name = os.path.join(self.dirname, shortname)
127127 if os.path.exists(name):
128 logger.info('deleting cached file: %s', name)
128 logger.info(f'deleting cached file: {name}')
129129 tempfiles.try_delete(name)
130130
131131 def get_lib(self, libname, *args, **kwargs):
145145 if config.FROZEN_CACHE:
146146 # Raise an exception here rather than exit_with_error since in practice this
147147 # should never happen
148 raise Exception('FROZEN_CACHE is set, but cache file is missing: "%s" (in cache root path "%s")' % (shortname, self.dirname))
148 raise Exception(f'FROZEN_CACHE is set, but cache file is missing: "{shortname}" (in cache root path "{self.dirname}")')
149149
150150 with self.lock():
151151 if os.path.exists(cachename) and not force:
155155 what = 'system library'
156156 else:
157157 what = 'system asset'
158 message = 'generating ' + what + ': ' + shortname + '... (this will be cached in "' + cachename + '" for subsequent builds)'
158 message = f'generating {what}: {shortname}... (this will be cached in "{cachename}" for subsequent builds)'
159159 logger.info(message)
160160 utils.safe_ensure_dirs(os.path.dirname(cachename))
161161 creator(cachename)
88 import os
99 import re
1010 import sys
11 from pathlib import Path
1112
1213 __rootpath__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
1314
2021 return '0x' + ('0' * (len(x) - 6)) + x[2:].upper()
2122
2223
23 repdata = open(path_from_root('system', 'include', 'GL', 'gl.h')).readlines() + ['\n'] + \
24 open(path_from_root('system', 'include', 'GL', 'glext.h')).readlines()
24 repdata = (
25 Path(path_from_root('system', 'include', 'GL', 'gl.h')).read_text().splitline(keepends=True) +
26 ['\n'] +
27 Path(path_from_root('system', 'include', 'GL', 'glext.h')).read_text().splitlines(keepends=True)
28 )
2529 reps = {}
2630 for rep in repdata:
2731 rep = rep.replace('\t', ' ').replace('\n', '')
55 import os
66 import sys
77 import logging
8
9 from . import utils
810 from .utils import path_from_root, exit_with_error, __rootpath__, which
911
1012 logger = logging.getLogger('shared')
105107 Also check EM_<KEY> environment variables to override specific config keys.
106108 """
107109 config = {}
108 config_text = open(EM_CONFIG, 'r').read()
110 config_text = utils.read_file(EM_CONFIG)
109111 try:
110112 exec(config_text, config)
111113 except Exception as e:
170172 def generate_config(path, first_time=False):
171173 # Note: repr is used to ensure the paths are escaped correctly on Windows.
172174 # The full string is replaced so that the template stays valid Python.
173 config_data = open(path_from_root('tools', 'settings_template.py')).read().splitlines()
174 config_data = config_data[3:] # remove the initial comment
175
176 config_data = utils.read_file(path_from_root('tools', 'settings_template.py'))
177 config_data = config_data.splitlines()[3:] # remove the initial comment
175178 config_data = '\n'.join(config_data)
176179 # autodetect some default paths
177180 config_data = config_data.replace('\'{{{ EMSCRIPTEN_ROOT }}}\'', repr(__rootpath__))
183186
184187 abspath = os.path.abspath(os.path.expanduser(path))
185188 # write
186 with open(abspath, 'w') as f:
187 f.write(config_data)
189
190 utils.write_file(abspath, config_data)
188191
189192 if first_time:
190193 print('''
1616
1717 sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
1818
19 from tools import shared
19 from tools import shared, utils
2020
2121
2222 js_file = sys.argv[1]
9292
9393 # main
9494 def main():
95 js = open(js_file).read()
95 js = utils.read_file(js_file)
9696 ctors_start, ctors_end = find_ctors(js)
9797 if ctors_start < 0:
9898 logger.debug('ctor_evaller: no ctors')
113113 logger.debug('ctor_evaller: not successful')
114114 sys.exit(0)
115115 logger.debug('ctor_evaller: we managed to remove %d ctors' % num_successful)
116 open(js_file, 'w').write(new_js)
116 utils.write_file(js_file, new_js)
117117
118118
119119 if __name__ == '__main__':
1111 from __future__ import print_function
1212 import os, sys
1313
14 from pathlib import Path
15
1416
1517 def process_line(line):
1618 #AD:2041,0.900000
1921 num, val = line.split(',')
2022 return [int(num), float(val)]
2123
22 a = open(sys.argv[1], 'r').readlines()
23 b = open(sys.argv[2], 'r').readlines()
24 a = Path(sys.argv[1]).read_text().splitlines(keepends=True)
25 b = Path(sys.argv[2]).read_text().splitlines(keepends=True)
2426 MIN = 0.0001 if len(sys.argv) < 4 else sys.argv[3]
2527
2628 ai = 0
1010
1111 from __future__ import print_function
1212 import os, sys, shutil
13 from pathlib import Path
1314 from subprocess import Popen, PIPE, STDOUT
1415
1516 __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
17
18
1619 def path_from_root(*pathelems):
1720 return os.path.join(__rootpath__, *pathelems)
18 exec(open(path_from_root('tools', 'shared.py'), 'r').read())
21
22 exec(Path(path_from_root('tools', 'shared.py').read_text()))
1923
20 file1 = open(sys.argv[1]).read()
21 file2 = open(sys.argv[2]).read()
24 shutil.copyfile(sys.argv[1], 'left')
25 shutil.copyfile(sys.argv[2], 'right')
2226
23 leftf = open('left', 'w')
24 leftf.write(file1)
25 leftf.close()
26
27 rightf = open('right', 'w')
28 rightf.write(file2)
29 rightf.close()
3027
3128 def run_code(name):
3229 ret = run_js(name, stderr=PIPE, full_output=True, assert_returncode=None, engine=SPIDERMONKEY_ENGINE)
1212
1313 from __future__ import print_function
1414 import os, sys, shutil
15 from pathlib import Path
1516 from subprocess import Popen, PIPE, STDOUT
1617
1718 __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
1819 def path_from_root(*pathelems):
1920 return os.path.join(__rootpath__, *pathelems)
20 exec(open(path_from_root('tools', 'shared.py'), 'r').read())
21
22 exec(Path(path_from_root('tools', 'shared.py').read())
2123
22 file1 = open(sys.argv[1]).read()
23 file2 = open(sys.argv[2]).read()
24 shutil.copyfile(sys.argv[1], 'left')
25 shutil.copyfile(sys.argv[2], 'right')
2426
25 leftf = open('left', 'w')
26 leftf.write(file1)
27 leftf.close()
28
29 rightf = open('right', 'w')
30 rightf.write(file2)
31 rightf.close()
3227
3328 def run_code(name):
3429 ret = run_js(name, stderr=PIPE, full_output=True)
5247 while True:
5348 mid = int((low + high)/2)
5449 print(low, high, ' current: %d' % mid, end=' ')
55 open('middle', 'w').write('\n'.join(left_lines[:mid] + right_lines[mid:]))
50 Path('middle').write_text('\n'.join(left_lines[:mid] + right_lines[mid:]))
5651 shutil.copyfile('middle', 'middle' + str(mid))
5752 result = run_code('middle')
5853 print(result == left_result, result == right_result)#, 'XXX', left_result, 'YYY', result, 'ZZZ', right_result
1010
1111 from __future__ import print_function
1212 import os, sys, shutil
13 from pathlib import Path
1314 from subprocess import Popen, PIPE, STDOUT
1415
1516 __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
17
1618 def path_from_root(*pathelems):
1719 return os.path.join(__rootpath__, *pathelems)
18 exec(open(path_from_root('tools', 'shared.py'), 'r').read())
1920
20 file1 = open(sys.argv[1]).read()
21 file2 = open(sys.argv[2]).read()
21 exec(Path(path_from_root('tools', 'shared.py')).read_text())
2222
23 leftf = open('left', 'w')
24 leftf.write(file1)
25 leftf.close()
26
27 rightf = open('right', 'w')
28 rightf.write(file2)
29 rightf.close()
23 shutil.copyfile(sys.argv[1], 'left')
24 shutil.copyfile(sys.argv[2], 'right')
3025
3126 def run_code(name):
3227 shutil.copyfile(name, 'src.cpp.o.wat')
88 '''
99 from __future__ import print_function
1010 import os, sys
11 from pathlib import Path
1112
12 f1 = open(sys.argv[1], 'r').readlines()
13 f2 = open(sys.argv[2], 'r').readlines()
13
14 f1 = Path(sys.argv[1]).read_text().splitlines(keepends=True)
15 f2 = Path(sys.argv[2]).read_text().splitlines(keepends=True)
1416
1517 for i in range(len(f1)):
1618 if f1[i] == f2[i]: continue
88
99 from __future__ import print_function
1010 import os, sys, re
11 from pathlib import Path
1112
1213 filename = sys.argv[1]
13 data = open(filename).read()
14 data = Path(filename).read_text()
1415 iss = re.findall(r' i\d+ [^=]', data)
1516 set_iss = set(iss)
1617 bigs = []
88 from __future__ import print_function
99 import os, sys
1010
11 from pathlib import Path
12
1113 kill = False
1214
1315 valids = sys.argv[2].split(',')
1416
15 for line in open(sys.argv[1]).readlines():
17 for line in Path(sys.argv[1]).read_text().splitlines(keepends=True):
1618 line = line.replace('\n', '')
1719 if line.startswith('define ') and line.endswith('{'):
1820 ok = False
5353 'Mix_LoadWAV_RW': ['fileno'],
5454 'SDL_CreateRGBSurface': ['malloc', 'free'],
5555 'SDL_GL_GetProcAddress': ['malloc'],
56 'SDL_Init': ['malloc', 'free', 'memset', 'memcpy'],
56 'SDL_Init': ['malloc', 'free', 'memcpy'],
5757 'SDL_LockSurface': ['malloc', 'free'],
5858 'SDL_OpenAudio': ['malloc', 'free'],
5959 'SDL_PushEvent': ['malloc', 'free'],
8383 'emscripten_async_wget2_data': ['malloc', 'free'],
8484 'emscripten_async_wget_data': ['malloc', 'free'],
8585 'emscripten_create_worker': ['malloc', 'free'],
86 'emscripten_fetch': ['emscripten_is_main_browser_thread'],
8786 'emscripten_get_compiler_setting': ['malloc'],
8887 'emscripten_get_preloaded_image_data': ['malloc'],
8988 'emscripten_get_preloaded_image_data_from_FILE': ['fileno'],
138137 'emscripten_set_touchstart_callback_on_thread': ['malloc', 'free'],
139138 'emscripten_set_visibilitychange_callback_on_thread': ['malloc', 'free'],
140139 'emscripten_set_wheel_callback_on_thread': ['malloc', 'free'],
141 'emscripten_start_fetch': ['emscripten_is_main_browser_thread'],
142140 'emscripten_webgl_create_context': ['malloc'],
143141 'emscripten_webgl_destroy_context': ['emscripten_webgl_make_context_current', 'emscripten_webgl_get_current_context'],
144142 'emscripten_webgl_get_parameter_utf8': ['malloc'],
159157 'getnameinfo': ['htons', 'ntohs'],
160158 'getpeername': ['htons'],
161159 'getsockname': ['htons'],
162 'getrusage': ['memset'],
163160 'glGetString': ['malloc'],
164161 'glGetStringi': ['malloc'],
165162 'glMapBufferRange': ['malloc'],
172169 'localtime': ['_get_tzname', '_get_daylight', '_get_timezone', 'malloc'],
173170 'localtime_r': ['_get_tzname', '_get_daylight', '_get_timezone', 'malloc'],
174171 'mktime': ['_get_tzname', '_get_daylight', '_get_timezone', 'malloc'],
175 'mmap': ['memalign', 'memset', 'malloc'],
176 'munmap': ['malloc', 'free'],
172 'mmap': ['memalign'],
173 'munmap': ['free'],
177174 'pthread_create': ['malloc', 'free', 'emscripten_main_thread_process_queued_calls'],
178 'readdir': ['malloc'],
179 'realpath': ['malloc'],
180175 'recv': ['htons'],
181176 'accept': ['htons'],
182177 'recvfrom': ['htons'],
192187 'setgroups': ['sysconf'],
193188 'syslog': ['malloc', 'ntohs'],
194189 'timegm': ['_get_tzname', '_get_daylight', '_get_timezone', 'malloc'],
195 'times': ['memset'],
196 'tmpnam': ['malloc'],
197 'ttyname': ['malloc'],
198190 'tzset': ['_get_tzname', '_get_daylight', '_get_timezone', 'malloc'],
199 'uuid_clear': ['memset'],
200191 'uuid_compare': ['memcmp'],
201192 'uuid_copy': ['memcpy'],
202193 'wgpuBufferGetMappedRange': ['malloc', 'free'],
99 import random
1010 import subprocess
1111 import time
12 from pathlib import Path
1213
1314
1415 def run():
1516 subprocess.check_call(['emcc', 'src.cpp', '-O2'])
1617 ret = {}
1718 for relevant_file in os.listdir('.'):
18 ret[relevant_file] = open(relevant_file).read()
19 ret[relevant_file] = Path(relevant_file).read_text()
1920 return ret
2021
2122
2324 if not os.path.exists(subdir):
2425 os.mkdir(subdir)
2526 for relevant_file in data.keys():
26 open(os.path.join(subdir, relevant_file), 'w').write(data[relevant_file])
27 Path(os.path.join(subdir, relevant_file)).write_text(data[relevant_file])
2728
2829
2930 os.chdir('/tmp/emscripten_temp')
3031 assert len(os.listdir('.')) == 0, 'temp dir should start out empty, after that, everything there looks important to us'
31 open('src.cpp', 'w').write('''
32 Path('src.cpp').write_text('''
3233 #include <iostream>
3334
3435 int main()
1313 import re
1414 import subprocess
1515 import sys
16 from pathlib import Path
17
1618
1719 # If true, we are printing delta information between two data sets. If false, we are just printing symbol info for a single data set
1820 diffing_two_data_sets = False
371373
372374
373375 def analyze_javascript_file(filename, total_source_set_size, symbol_map=None):
374 file_contents = open(filename).read()
376 file_contents = Path(filename).read_text()
375377 print('Analyzing JS file ' + filename + ', ' + str(len(file_contents)) + ' bytes...')
376378 return analyze_javascript_file_contents(filename, file_contents, total_source_set_size, symbol_map)
377379
378380
379381 def analyze_html_file(filename, total_source_set_size, symbol_map=None):
380 file_contents = open(filename).read()
382 file_contents = Path(filename).read_text()
381383 print('Analyzing HTML file ' + filename + ', ' + str(len(file_contents)) + ' bytes...')
382384 data = {}
383385 parse_pos = 0
99 import sys
1010 import tempfile
1111 import time
12 from pathlib import Path
13
1214
1315 profiler_logs_path = os.path.join(tempfile.gettempdir(), 'emscripten_toolchain_profiler_logs')
1416
5254 print('Processing ' + str(len(log_files)) + ' profile log files in "' + profiler_logs_path + '"...')
5355 for f in log_files:
5456 try:
55 json_data = open(f, 'r').read()
57 json_data = Path(f).read_text()
5658 if len(json_data.strip()) == 0:
5759 continue
5860 lines = json_data.split('\n')
7476 emprofile_json_data = json.dumps(all_results, indent=2)
7577
7678 html_file = OUTFILE + '.html'
77 html_contents = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'toolchain_profiler.results_template.html'), 'r').read().replace('{{{ emprofile_json_data }}}', emprofile_json_data)
78 open(html_file, 'w').write(html_contents)
79 html_contents = Path(os.path.dirname(os.path.realpath(__file__)), 'toolchain_profiler.results_template.html').read_text().replace('{{{ emprofile_json_data }}}', emprofile_json_data)
80 Path(html_file).write_text(html_contents)
7981 print('Wrote "' + html_file + '"')
8082
8183
112112 import re
113113 import sys
114114 import shutil
115 from pathlib import Path
115116
116117 assert len(sys.argv) >= 4, 'Usage: reproduceriter.py IN_DIR OUT_DIR FIRST_JS [WINDOW_LOCATION]'
117118
146147 if filename.endswith('.js'):
147148 fullname = os.path.join(parent, filename)
148149 print(' ', fullname)
149 js = open(fullname).read()
150 with open(fullname) as fh:
151 js = fh.read()
150152 js = re.sub(r'document\.on(\w+) ?= ?([\w.$]+)', lambda m: 'Recorder.onEvent("' + m.group(1) + '", ' + m.group(2) + ')', js)
151153 js = re.sub(r'''([\w.'"\[\]]+)\.addEventListener\(([\w,. $]+)\)''', lambda m: 'Recorder.addListener(' + m.group(1) + ', ' + m.group(2) + ')', js)
152 open(fullname, 'w').write(js)
154 Path(fullname).write_text(js)
153155
154156 # Add our boilerplate
155157
156158 print('add boilerplate...')
157159
158 open(os.path.join(out_dir, first_js), 'w').write(
159 (open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src', 'headless.js')).read() % (
160 window_location, window_location.split('?')[-1], on_idle or 'null', dirs_to_drop
161 ) if shell else '') +
162 open(os.path.join(os.path.dirname(__file__), 'reproduceriter.js')).read() +
163 open(os.path.join(in_dir, first_js)).read() + ('\nwindow.runEventLoop();\n' if shell else '')
164 )
160 with open(os.path.join(out_dir, first_js), 'w') as fh1:
161 fh1.write(
162 (Path(os.path.dirname(os.path.dirname(__file__)), 'src', 'headless.js').read_text() % (
163 window_location, window_location.split('?')[-1], on_idle or 'null', dirs_to_drop
164 ) if shell else '') +
165 Path(os.path.dirname(__file__), 'reproduceriter.js').read_text() +
166 Path(in_dir, first_js).read_text() + ('\nwindow.runEventLoop();\n' if shell else '')
167 )
165168
166169 print('done!')
2020
2121 Usage:
2222
23 file_packager TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--indexedDB-name=EM_PRELOAD_CACHE] [--separate-metadata] [--lz4] [--use-preload-plugins]
23 file_packager TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--indexedDB-name=EM_PRELOAD_CACHE] [--separate-metadata] [--lz4] [--use-preload-plugins] [--no-node]
2424
2525 --preload ,
2626 --embed See emcc --help for more details on those options.
4747
4848 --use-preload-plugins Tells the file packager to run preload plugins on the files as they are loaded. This performs tasks like decoding images
4949 and audio using the browser's codecs.
50
51 --no-node Whether to support Node.js. By default we do, which emits some extra code.
5052
5153 Notes:
5254
5456 subdir\file, in JS it will be subdir/file. For simplicity we treat the web platform as a *NIX.
5557 """
5658
59 import base64
5760 import os
5861 import sys
5962 import shutil
6467 sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
6568
6669 import posixpath
67 from tools import shared
70 from tools import shared, utils
6871 from subprocess import PIPE
6972 import fnmatch
7073 import json
9093
9194 excluded_patterns = []
9295 new_data_files = []
96
97
98 def base64_encode(b):
99 b64 = base64.b64encode(b)
100 return b64.decode('ascii')
93101
94102
95103 def has_hidden_attribute(filepath):
173181 separate_metadata = False
174182 lz4 = False
175183 use_preload_plugins = False
184 support_node = True
176185
177186 for arg in sys.argv[2:]:
178187 if arg == '--preload':
202211 leading = ''
203212 elif arg == '--use-preload-plugins':
204213 use_preload_plugins = True
214 leading = ''
215 elif arg == '--no-node':
216 support_node = False
205217 leading = ''
206218 elif arg.startswith('--js-output'):
207219 jsoutput = arg.split('=', 1)[1] if '=' in arg else None
457469 basename = os.path.basename(filename)
458470 if file_['mode'] == 'embed':
459471 # Embed
460 data = list(bytearray(open(file_['srcpath'], 'rb').read()))
461 code += '''var fileData%d = [];\n''' % counter
462 if data:
463 parts = []
464 chunk_size = 10240
465 start = 0
466 while start < len(data):
467 parts.append('''fileData%d.push.apply(fileData%d, %s);\n'''
468 % (counter, counter, str(data[start:start + chunk_size])))
469 start += chunk_size
470 code += ''.join(parts)
471 code += ('''Module['FS_createDataFile']('%s', '%s', fileData%d, true, true, false);\n'''
472 data = base64_encode(utils.read_binary(file_['srcpath']))
473 code += '''var fileData%d = '%s';\n''' % (counter, data)
474 code += ('''Module['FS_createDataFile']('%s', '%s', decodeBase64(fileData%d), true, true, false);\n'''
472475 % (dirname, basename, counter))
473476 counter += 1
474477 elif file_['mode'] == 'preload':
707710 }
708711 '''
709712
710 ret += r'''
711 function fetchRemotePackage(packageName, packageSize, callback, errback) {
713 # add Node.js support code, if necessary
714 node_support_code = ''
715 if support_node:
716 node_support_code = r'''
712717 if (typeof process === 'object') {
713718 require('fs').readFile(packageName, function(err, contents) {
714719 if (err) {
719724 });
720725 return;
721726 }
727 '''
728 ret += r'''
729 function fetchRemotePackage(packageName, packageSize, callback, errback) {
730 %(node_support_code)s
722731 var xhr = new XMLHttpRequest();
723732 xhr.open('GET', packageName, true);
724733 xhr.responseType = 'arraybuffer';
769778 function handleError(error) {
770779 console.error('package error:', error);
771780 };
772 '''
781 ''' % {'node_support_code': node_support_code}
773782
774783 code += r'''
775784 function processPackageData(arrayBuffer) {
140140
141141 for line in lines:
142142 arg = line[1:].strip()
143 if '::' in arg:
144 arg = arg.split('::', 1)[1]
143145 if line[0] == 'K':
144146 # This is a key
145147 key = arg
251253 show('Compiling generated code...')
252254
253255 # -Oz optimizes enough to avoid warnings on code size/num locals
254 cmd = [shared.EMCC] + cflags + ['-o', js_file[1], src_file[1],
256 cmd = [shared.EMXX] + cflags + ['-o', js_file[1], src_file[1],
255257 '-O0',
256258 '-Werror',
257259 '-Wno-format',
407409
408410 internal_cflags = [
409411 '-I' + shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal'),
412 '-I' + shared.path_from_root('system', 'lib', 'libcxxabi', 'src'),
413 '-D__USING_EMSCRIPTEN_EXCEPTIONS__',
410414 ]
411415
412416 # Look for structs in all passed headers.
55 sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
66
77 from tools import building
8 from tools.utils import read_file, write_file
89
9 f = open(sys.argv[1], 'r').read()
10 f = read_file(sys.argv[1])
1011 orig_size = len(f)
1112
1213 f = f.strip()
5051 f = re.sub(r'([;{}=,\*/\(\)\[\]])[\s]', r'\1', f)
5152
5253 # Finally, rerun minifier because the above changes may have left redundant whitespaces
53 open(sys.argv[1], 'w').write(f)
54 write_file(sys.argv[1], f)
5455 minified = building.acorn_optimizer(sys.argv[1], ['minifyWhitespace'], return_output=True)
55 open(sys.argv[1], 'w').write(minified)
56 write_file(sys.argv[1], minified)
5657
5758 # optimized_size = len(f)
5859 # print('Further optimized ' + str(optimized_size - orig_size) + ' bytes (' + str(orig_size) + ' -> ' + str(optimized_size) + ' bytes, {0:.2f}'.format((optimized_size-orig_size)*100.0/orig_size) + '%)')
59 open(sys.argv[1], 'w').write(f)
60 write_file(sys.argv[1], f)
1414 sys.path.insert(1, __rootpath__)
1515
1616 from tools.toolchain_profiler import ToolchainProfiler
17 from tools import building, config, shared
17 from tools import building, config, shared, utils
1818
1919 configuration = shared.configuration
2020 temp_files = configuration.get_temp_files()
150150 if not isinstance(passes, list):
151151 passes = [passes]
152152
153 js = open(filename).read()
153 js = utils.read_file(filename)
154154 if os.linesep != '\n':
155155 js = js.replace(os.linesep, '\n') # we assume \n in the splitting code
156156
332332 acorn_passes.append('minifyWhitespace')
333333 cld = building.acorn_optimizer(cld, acorn_passes)
334334 temp_files.note(cld)
335 coutput = open(cld).read()
335 coutput = utils.read_file(cld)
336336
337337 coutput = coutput.replace('wakaUnknownBefore();', start_asm)
338338 after = 'wakaUnknownAfter'
363363 # sort functions by size, to make diffing easier and to improve aot times
364364 funcses = []
365365 for out_file in filenames:
366 funcses.append(split_funcs(open(out_file).read(), False))
366 funcses.append(split_funcs(utils.read_file(out_file), False))
367367 funcs = [item for sublist in funcses for item in sublist]
368368 funcses = None
369369 if not os.environ.get('EMCC_NO_OPT_SORT'):
380380 else:
381381 # just concat the outputs
382382 for out_file in filenames:
383 f.write(open(out_file).read())
383 f.write(utils.read_file(out_file))
384384
385385 with ToolchainProfiler.profile_block('write_post'):
386386 f.write('\n')
149149
150150 var start = Date.now();
151151 var compressedData = MiniLZ4.compressPackage(data);
152 nodeFS['writeFileSync'](output, Buffer(compressedData['data']));
152 nodeFS['writeFileSync'](output, Buffer.from(compressedData['data']));
153153 compressedData['data'] = null;
154154 printErr('compressed in ' + (Date.now() - start) + ' ms');
155155 print(JSON.stringify(compressedData));
66
77 from tools import shared
88 from tools import line_endings
9 from tools import utils
910 from tools.settings import settings
1011
1112 logger = logging.getLogger('minimal_runtime_shell')
156157
157158 def generate_minimal_runtime_html(target, options, js_target, target_basename):
158159 logger.debug('generating HTML for minimal runtime')
159 shell = open(options.shell_path, 'r').read()
160 shell = utils.read_file(options.shell_path)
160161 if settings.SINGLE_FILE:
161162 # No extra files needed to download in a SINGLE_FILE build.
162163 shell = shell.replace('{{{ DOWNLOAD_JS_AND_WASM_FILES }}}', '')
165166
166167 temp_files = shared.configuration.get_temp_files()
167168 with temp_files.get_file(suffix='.js') as shell_temp:
168 open(shell_temp, 'w').write(shell)
169 utils.write_file(shell_temp, shell)
169170 shell = shared.read_and_preprocess(shell_temp)
170171
171172 if re.search(r'{{{\s*SCRIPT\s*}}}', shell):
177178
178179 # In SINGLE_FILE build, embed the main .js file into the .html output
179180 if settings.SINGLE_FILE:
180 js_contents = open(js_target).read()
181 js_contents = utils.read_file(js_target)
181182 shared.try_delete(js_target)
182183 else:
183184 js_contents = ''
44
55 import os
66 import shutil
7 from pathlib import Path
78
89 TAG = 'version_1'
910 HASH = '0d0b1280ba0501ad0a23cf1daa1f86821c722218b59432734d3087a89acd22aabd5c3e5e1269700dcd41e87073046e906060f167c032eb91a3ac8c5808a02783'
2526 os.makedirs(dest_path)
2627 shutil.rmtree(dest_path, ignore_errors=True)
2728 shutil.copytree(source_path, dest_path)
28 open(os.path.join(dest_path, 'include/ftconfig.h'), 'w').write(ftconf_h)
29 Path(dest_path, 'include/ftconfig.h').write_text(ftconf_h)
2930
3031 # build
3132 srcs = ['src/autofit/autofit.c',
33 # found in the LICENSE file.
44
55 import os
6 import shutil
76 import logging
87
9 from tools import system_libs
10
11 TAG = '1.7.5'
12 HASH = 'c2c13fc97bb74f0f13092b07804f7087e948bce49793f48b62c2c24a5792523acc0002840bebf21829172bb2e7c3df9f9625250aec6c786a55489667dd04d6a0'
8 TAG = '2.8.1'
9 HASH = 'c969ec1677f2f023c05698a226c96b23a815db732f1561d486b25b07c3663ea8192e49ee1253b7b623b43d713b9230df3265a47da6fd65378256ecada90c6ae4'
1310
1411 deps = ['freetype']
12
13 srcs = '''
14 hb-aat-layout.cc
15 hb-aat-map.cc
16 hb-blob.cc
17 hb-buffer-serialize.cc
18 hb-buffer.cc
19 hb-common.cc
20 hb-draw.cc
21 hb-face.cc
22 hb-fallback-shape.cc
23 hb-font.cc
24 hb-map.cc
25 hb-number.cc
26 hb-ot-cff1-table.cc
27 hb-ot-cff2-table.cc
28 hb-ot-color.cc
29 hb-ot-face.cc
30 hb-ot-font.cc
31 hb-ot-layout.cc
32 hb-ot-map.cc
33 hb-ot-math.cc
34 hb-ot-meta.cc
35 hb-ot-metrics.cc
36 hb-ot-name.cc
37 hb-ot-shape-complex-arabic.cc
38 hb-ot-shape-complex-default.cc
39 hb-ot-shape-complex-hangul.cc
40 hb-ot-shape-complex-hebrew.cc
41 hb-ot-shape-complex-indic-table.cc
42 hb-ot-shape-complex-indic.cc
43 hb-ot-shape-complex-khmer.cc
44 hb-ot-shape-complex-myanmar.cc
45 hb-ot-shape-complex-syllabic.cc
46 hb-ot-shape-complex-thai.cc
47 hb-ot-shape-complex-use.cc
48 hb-ot-shape-complex-vowel-constraints.cc
49 hb-ot-shape-fallback.cc
50 hb-ot-shape-normalize.cc
51 hb-ot-shape.cc
52 hb-ot-tag.cc
53 hb-ot-var.cc
54 hb-set.cc
55 hb-shape-plan.cc
56 hb-shape.cc
57 hb-shaper.cc
58 hb-static.cc
59 hb-style.cc
60 hb-ucd.cc
61 hb-unicode.cc
62 hb-glib.cc
63 hb-ft.cc
64 hb-graphite2.cc
65 hb-uniscribe.cc
66 hb-gdi.cc
67 hb-directwrite.cc
68 hb-coretext.cc
69 '''.split()
1570
1671
1772 def needed(settings):
2479
2580 def get(ports, settings, shared):
2681 ports.fetch_project('harfbuzz', 'https://github.com/harfbuzz/harfbuzz/releases/download/' +
27 TAG + '/harfbuzz-' + TAG + '.tar.bz2', 'harfbuzz-' + TAG, sha512hash=HASH)
82 TAG + '/harfbuzz-' + TAG + '.tar.xz', 'harfbuzz-' + TAG, sha512hash=HASH)
2883
2984 def create(final):
3085 logging.info('building port: harfbuzz')
3287
3388 source_path = os.path.join(ports.get_dir(), 'harfbuzz', 'harfbuzz-' + TAG)
3489 build_path = os.path.join(ports.get_build_dir(), 'harfbuzz')
90 freetype_include = os.path.join(ports.get_include_dir(), 'freetype2', 'freetype')
91 ports.install_headers(os.path.join(source_path, 'src'), target='harfbuzz')
3592
36 freetype_lib = shared.Cache.get_path(shared.Cache.get_lib_name('libfreetype.a'))
37 freetype_include = os.path.join(ports.get_include_dir(), 'freetype2', 'freetype')
38 freetype_include_dirs = freetype_include + ';' + os.path.join(freetype_include, 'config')
93 # TODO(sbc): Look into HB_TINY, HB_LEAN, HB_MINI options. Remove
94 # HAVE_MMAP/HAVE_MPROTECT/HAVE_SYSCONF since we don't really support those?
3995
40 cmake_cmd = [
41 shared.EMCMAKE,
42 'cmake',
43 '-B' + build_path,
44 '-H' + source_path,
45 '-DCMAKE_BUILD_TYPE=Release',
46 '-DCMAKE_INSTALL_PREFIX=' + build_path,
47 '-DFREETYPE_INCLUDE_DIRS=' + freetype_include_dirs,
48 '-DFREETYPE_LIBRARY=' + freetype_lib,
49 '-DHB_HAVE_FREETYPE=ON'
50 ]
96 # These cflags are the ones that the cmake build selects when running emcmake
97 # with harfbuzz
98 cflags = '''
99 -DHAVE_FREETYPE
100 -DHAVE_ATEXIT
101 -DHAVE_FALLBACK
102 -DHAVE_FT_SET_VAR_BLEND_COORDINATES
103 -DHAVE_INTEL_ATOMIC_PRIMITIVES
104 -DHAVE_MMAP
105 -DHAVE_MPROTECT
106 -DHAVE_OT
107 -DHAVE_STRTOD_L
108 -DHAVE_SYSCONF
109 -DHAVE_UCDN
110 -DHAVE_UNIST_H
111 -DHAVE_XLOCALE_H
112 -DHAVE_SYS_MMAN_H
113 -DHAVE_UNISTD_H
114 -fno-rtti
115 -fno-exceptions
116 -O3
117 -DNDEBUG
118 '''.split()
51119
52 extra_cflags = []
120 cflags += ['-I' + freetype_include, '-I' + os.path.join(freetype_include, 'config')]
53121
54122 if settings.RELOCATABLE:
55 extra_cflags.append('-fPIC')
123 cflags.append('-fPIC')
56124
57125 if settings.USE_PTHREADS:
58 extra_cflags.append('-pthread')
126 cflags.append('-pthread')
127 cflags.append('-DHAVE_PTHREAD')
128 else:
129 cflags.append('-DHB_NO_MT')
59130
60 if len(extra_cflags):
61 cmake_cmd += ['-DCMAKE_CXX_FLAGS="{}"'.format(' '.join(extra_cflags))]
62 cmake_cmd += ['-DCMAKE_C_FLAGS="{}"'.format(' '.join(extra_cflags))]
63
64 shared.run_process(cmake_cmd, env=system_libs.clean_env())
65 shared.run_process(['cmake', '--build', build_path, '--target', 'install'])
66
67 ports.install_header_dir(os.path.join(build_path, 'include', 'harfbuzz'))
68
69 shutil.copyfile(os.path.join(build_path, 'libharfbuzz.a'), final)
131 commands = []
132 o_s = []
133 for src in srcs:
134 o = os.path.join(build_path, src + '.o')
135 shared.safe_ensure_dirs(os.path.dirname(o))
136 commands.append([shared.EMCC, '-c', os.path.join(source_path, 'src', src), '-o', o] + cflags)
137 o_s.append(o)
138 ports.run_commands(commands)
139 ports.create_lib(final, o_s)
70140
71141 return [shared.Cache.get_lib(get_lib_name(settings), create, what='port')]
72142
80150
81151
82152 def process_args(ports):
83 return ['-I' + os.path.join(ports.get_build_dir(), 'harfbuzz', 'include', 'harfbuzz')]
153 return ['-I' + os.path.join(ports.get_include_dir(), 'harfbuzz')]
84154
85155
86156 def show():
55 import os
66 import shutil
77 import logging
8 from pathlib import Path
89
910 VERSION = '9c'
1011 HASH = 'b2affe9a1688bd49fc033f4682c4a242d4ee612f1affaef532f5adcb4602efc4433c4a52a4b3d69e7440ff1f6413b1b041b419bc90efd6d697999961a9a6afb7'
2930 shutil.rmtree(dest_path, ignore_errors=True)
3031 shutil.copytree(source_path, dest_path)
3132
32 open(os.path.join(dest_path, 'jconfig.h'), 'w').write(jconfig_h)
33 Path(dest_path, 'jconfig.h').write_text(jconfig_h)
3334 ports.install_headers(dest_path)
3435
3536 ports.build_port(
55 import os
66 import shutil
77 import logging
8 from pathlib import Path
89
910 TAG = '11022021'
1011 HASH = 'f770031ad6c2152cbed8c8eab8edf2be1d27f9e74bc255a9930c17019944ee5fdda5308ea992c66a78af9fe1d8dca090f6c956910ce323f8728247c10e44036b'
2930
3031 shutil.rmtree(dest_path, ignore_errors=True)
3132 shutil.copytree(source_path, dest_path)
32 open(os.path.join(sauce_path, 'config.h'), 'w').write(config_h)
33 Path(sauce_path, 'config.h').write_text(config_h)
3334
3435 flags = [
3536 '-DOPT_GENERIC',
55 import os
66 import shutil
77 import logging
8 from pathlib import Path
89
910 TAG = '1.6.37'
1011 HASH = '2ce2b855af307ca92a6e053f521f5d262c36eb836b4810cb53c809aa3ea2dcc08f834aee0ffd66137768a54397e28e92804534a74abb6fc9f6f3127f14c9c338'
2930 shutil.rmtree(dest_path, ignore_errors=True)
3031 shutil.copytree(source_path, dest_path)
3132
32 open(os.path.join(dest_path, 'pnglibconf.h'), 'w').write(pnglibconf_h)
33 Path(dest_path, 'pnglibconf.h').write_text(pnglibconf_h)
3334 ports.install_headers(dest_path)
3435
3536 ports.build_port(dest_path, final, flags=['-s', 'USE_ZLIB=1'], exclude_files=['pngtest'], exclude_dirs=['scripts', 'contrib'])
55 import os
66 import shutil
77 import logging
8 from pathlib import Path
89
910 TAG = '1.26.2'
1011 HASH = 'aa63fcb08b243a1e09f7701b3d84a19d7412a87253d54d49f014fdb9e75bbc81d152a41ed750fccde901453929b2a001585a7645351b41845ad205c17a73dcc9'
2930
3031 shutil.rmtree(dest_path, ignore_errors=True)
3132 shutil.copytree(source_path, dest_path)
32 open(os.path.join(sauce_path, 'config.h'), 'w').write(config_h)
33 open(os.path.join(libmpg123_path, 'mpg123.h'), 'w').write(mpg123_h)
33 Path(sauce_path, 'config.h').write_text(config_h)
34 Path(libmpg123_path, 'mpg123.h').write_text(mpg123_h)
3435
3536 flags = [
3637 '-DOPT_GENERIC',
55 import logging
66 import os
77 import shutil
8 from pathlib import Path
89
910 TAG = 'version_1'
1011 HASH = '929e8d6003c06ae09593021b83323c8f1f54532b67b8ba189f4aedce52c25dc182bac474de5392c46ad5b0dea5a24928e4ede1492d52f4dd5cd58eea9be4dba7'
2728 shutil.rmtree(dest_path, ignore_errors=True)
2829 shutil.copytree(source_path, dest_path)
2930
30 open(os.path.join(dest_path, 'include', 'ogg', 'config_types.h'), 'w').write(config_types_h)
31 Path(dest_path, 'include', 'ogg', 'config_types.h').write_text(config_types_h)
3132
3233 header_dir = os.path.join(ports.get_include_dir(), 'ogg')
3334 shutil.rmtree(header_dir, ignore_errors=True)
44
55 import os
66 import shutil
7 from pathlib import Path
78
89 TAG = '1.2.11'
910 HASH = 'a42b8359e76cf7b3ae70bf31f0f8a8caa407ac80e8fe08b838076cd5e45ac2e685dae45eb59db2d25543fb3b5bd13b843a02bb8373cda704d7238be50d5e9c68'
2526 os.makedirs(dest_path)
2627 shutil.rmtree(dest_path, ignore_errors=True)
2728 shutil.copytree(source_path, dest_path)
28 open(os.path.join(dest_path, 'zconf.h'), 'w').write(zconf_h)
29 Path(dest_path, 'zconf.h').write_text(zconf_h)
2930 ports.install_headers(dest_path)
3031
3132 # build
3334 commands = []
3435 o_s = []
3536 for src in srcs:
36 o = os.path.join(ports.get_build_dir(), 'zlib', src + '.o')
37 o = os.path.join(dest_path, src + '.o')
3738 shared.safe_ensure_dirs(os.path.dirname(o))
3839 commands.append([shared.EMCC, os.path.join(dest_path, src), '-O2', '-o', o, '-I' + dest_path, '-w', '-c'])
3940 o_s.append(o)
9595 self.allowed_settings.clear()
9696
9797 # Load the JS defaults into python.
98 settings = open(path_from_root('src', 'settings.js')).read().replace('//', '#')
98 with open(path_from_root('src', 'settings.js')) as fh:
99 settings = fh.read().replace('//', '#')
99100 settings = re.sub(r'var ([\w\d]+)', r'attrs["\1"]', settings)
100101 # Variable TARGET_NOT_SUPPORTED is referenced by value settings.js (also beyond declaring it),
101102 # so must pass it there explicitly.
102103 exec(settings, {'attrs': self.attrs})
103104
104 settings = open(path_from_root('src', 'settings_internal.js')).read().replace('//', '#')
105 with open(path_from_root('src', 'settings_internal.js')) as fh:
106 settings = fh.read().replace('//', '#')
105107 settings = re.sub(r'var ([\w\d]+)', r'attrs["\1"]', settings)
106108 internal_attrs = {}
107109 exec(settings, {'attrs': internal_attrs})
3030 from . import diagnostics
3131 from . import config
3232 from . import filelock
33 from . import utils
3334 from .settings import settings
3435
3536
242243 if check and proc.returncode != 0:
243244 raise subprocess.CalledProcessError(proc.returncode, '', stdout, stderr)
244245 if TRACK_PROCESS_SPAWNS:
245 logging.info('Process ' + str(proc.pid) + ' finished after ' + str(time.time() - start) + ' seconds. Exit code: ' + str(proc.returncode))
246 logging.info(f'Process {proc.pid} finished after {time.time() - start} seconds. Exit code: {proc.returncode}')
246247 return '\n'.join(out) if full_output else out[0]
247248
248249
252253 else:
253254 cmd = config.NODE_JS + [path_from_root('node_modules', '.bin', name)]
254255 if not os.path.exists(cmd[-1]):
255 exit_with_error('%s was not found! Please run "npm install" in Emscripten root directory to set up npm dependencies' % name)
256 exit_with_error(f'{name} was not found! Please run "npm install" in Emscripten root directory to set up npm dependencies')
256257 return cmd
257258
258259
321322 return False
322323
323324 if version < EXPECTED_NODE_VERSION:
324 diagnostics.warning('version-check', 'node version appears too old (seeing "%s", expected "%s")', actual, 'v' + ('.'.join(map(str, EXPECTED_NODE_VERSION))))
325 expected = '.'.join(str(v) for v in EXPECTED_NODE_VERSION)
326 diagnostics.warning('version-check', f'node version appears too old (seeing "{actual}", expected "v{expected}")')
325327 return False
326328
327329 return True
337339
338340
339341 def generate_sanity():
340 sanity_file_content = EMSCRIPTEN_VERSION + '|' + config.LLVM_ROOT + '|' + get_clang_version()
341 config_data = open(config.EM_CONFIG).read()
342 sanity_file_content = f'{EMSCRIPTEN_VERSION}|{config.LLVM_ROOT}|{get_clang_version()}'
343 config_data = utils.read_file(config.EM_CONFIG)
342344 checksum = binascii.crc32(config_data.encode())
343345 sanity_file_content += '|%#x\n' % checksum
344346 return sanity_file_content
406408 sanity_file = Cache.get_path('sanity.txt')
407409 with Cache.lock():
408410 if os.path.exists(sanity_file):
409 sanity_data = open(sanity_file).read()
411 sanity_data = utils.read_file(sanity_file)
410412 if sanity_data != expected:
411413 logger.debug('old sanity: %s' % sanity_data)
412414 logger.debug('new sanity: %s' % expected)
500502
501503 self.TEMP_DIR = os.environ.get("EMCC_TEMP_DIR", tempfile.gettempdir())
502504 if not os.path.isdir(self.TEMP_DIR):
503 exit_with_error("The temporary directory `" + self.TEMP_DIR + "` does not exist! Please make sure that the path is correct.")
505 exit_with_error(f'The temporary directory `{self.TEMP_DIR}` does not exist! Please make sure that the path is correct.')
504506
505507 self.CANONICAL_TEMP_DIR = get_canonical_temp_dir(self.TEMP_DIR)
506508
509511 try:
510512 safe_ensure_dirs(self.EMSCRIPTEN_TEMP_DIR)
511513 except Exception as e:
512 exit_with_error(str(e) + 'Could not create canonical temp dir. Check definition of TEMP_DIR in ' + config.EM_CONFIG)
514 exit_with_error(str(e) + f'Could not create canonical temp dir. Check definition of TEMP_DIR in {config.EM_CONFIG}')
513515
514516 # Since the canonical temp directory is, by definition, the same
515517 # between all processes that run in DEBUG mode we need to use a multi
545547
546548
547549 def target_environment_may_be(environment):
548 return settings.ENVIRONMENT == '' or environment in settings.ENVIRONMENT.split(',')
550 return not settings.ENVIRONMENT or environment in settings.ENVIRONMENT.split(',')
549551
550552
551553 def print_compiler_stage(cmd):
787789 args += ['--expandMacros']
788790
789791 run_js_tool(path_from_root('tools/preprocessor.js'), args, True, stdout=open(stdout, 'w'), cwd=dirname)
790 out = open(stdout, 'r').read()
792 out = utils.read_file(stdout)
791793
792794 return out
793795
9797 shutil.copyfile(inputs[0], libname)
9898 else:
9999 building.link_to_object(inputs, libname)
100 elif suffix == '.a':
100 else:
101 assert suffix == '.a'
101102 building.emar('cr', libname, inputs)
102 else:
103 raise Exception('unknown suffix ' + libname)
104103
105104
106105 def get_wasm_libc_rt_files():
150149 return math_files + other_files + iprintf_files
151150
152151
152 def is_case_insensitive(path):
153 """Returns True if the filesystem at `path` is case insensitive."""
154 utils.write_file(os.path.join(path, 'test_file'), '')
155 case_insensitive = os.path.exists(os.path.join(path, 'TEST_FILE'))
156 os.remove(os.path.join(path, 'test_file'))
157 return case_insensitive
158
159
153160 class Library:
154161 """
155162 `Library` is the base class of all system libraries.
342349 objects = []
343350 cflags = self.get_cflags()
344351 base_flags = get_base_cflags()
352 case_insensitive = is_case_insensitive(build_dir)
345353 for src in self.get_files():
346 o = os.path.join(build_dir, shared.unsuffixed_basename(src) + '.o')
354 object_basename = shared.unsuffixed_basename(src)
355 # Resolve duplicates by appending unique.
356 # This is needed on case insensitve filesystem to handle,
357 # for example, _exit.o and _Exit.o.
358 if case_insensitive:
359 object_basename = object_basename.lower()
360 o = os.path.join(build_dir, object_basename + '.o')
361 object_uuid = 0
362 # Find a unique basename
363 while o in objects:
364 object_uuid += 1
365 o = os.path.join(build_dir, f'{object_basename}__{object_uuid}.o')
347366 ext = shared.suffix(src)
348367 if ext in ('.s', '.S', '.c'):
349368 cmd = [shared.EMCC]
692711
693712 # musl modules
694713 ignore = [
695 'ipc', 'passwd', 'signal', 'sched', 'ipc', 'time', 'linux',
714 'ipc', 'passwd', 'signal', 'sched', 'time', 'linux',
696715 'aio', 'exit', 'legacy', 'mq', 'setjmp', 'env',
697716 'ldso'
698717 ]
703722 'res_query.c', 'res_querydomain.c', 'gai_strerror.c',
704723 'proto.c', 'gethostbyaddr.c', 'gethostbyaddr_r.c', 'gethostbyname.c',
705724 'gethostbyname2_r.c', 'gethostbyname_r.c', 'gethostbyname2.c',
706 'alarm.c', 'syscall.c', '_exit.c', 'popen.c',
725 'alarm.c', 'syscall.c', 'popen.c',
707726 'getgrouplist.c', 'initgroups.c', 'wordexp.c', 'timer_create.c',
708727 'faccessat.c',
709728 # 'process' exclusion
730749 if self.is_mt:
731750 ignore += [
732751 'clone.c', '__lock.c',
733 'pthread_cleanup_push.c', 'pthread_create.c',
752 'pthread_create.c',
734753 'pthread_kill.c', 'pthread_sigmask.c',
735754 '__set_thread_area.c', 'synccall.c',
736755 '__syscall_cp.c', '__tls_get_addr.c',
760779 path_components=['system', 'lib', 'libc', 'musl', 'src', 'thread'],
761780 filenames=[
762781 'pthread_self.c',
782 'pthread_cleanup_push.c',
763783 # C11 thread library functions
764784 'call_once.c',
765785 'tss_create.c',
825845 filenames=['sched_yield.c'])
826846
827847 libc_files += files_in_path(
848 path_components=['system', 'lib', 'libc', 'musl', 'src', 'exit'],
849 filenames=['_Exit.c'])
850
851 libc_files += files_in_path(
852 path_components=['system', 'lib', 'libc', 'musl', 'src', 'signal'],
853 filenames=[
854 'getitimer.c',
855 'killpg.c',
856 'setitimer.c',
857 'sigaddset.c',
858 'sigdelset.c',
859 'sigemptyset.c',
860 'sigfillset.c',
861 'sigismember.c',
862 'signal.c',
863 'sigprocmask.c',
864 'sigrtmax.c',
865 'sigrtmin.c',
866 'sigwait.c',
867 ])
868
869 libc_files += files_in_path(
828870 path_components=['system', 'lib', 'libc'],
829871 filenames=[
830872 'extras.c',
931973 cflags.append('-D_LIBCXXABI_NO_EXCEPTIONS')
932974 elif self.eh_mode == Exceptions.EMSCRIPTEN:
933975 cflags.append('-D__USING_EMSCRIPTEN_EXCEPTIONS__')
976 # The code used to interpret exceptions during terminate
977 # is not compatible with emscripten exceptions.
978 cflags.append('-DLIBCXXABI_SILENT_TERMINATE')
934979 elif self.eh_mode == Exceptions.WASM:
935980 cflags.append('-D__USING_WASM_EXCEPTIONS__')
936981 return cflags
941986 'cxa_aux_runtime.cpp',
942987 'cxa_default_handlers.cpp',
943988 'cxa_demangle.cpp',
944 'cxa_exception_storage.cpp',
945989 'cxa_guard.cpp',
946990 'cxa_handlers.cpp',
947991 'cxa_virtual.cpp',
9561000 filenames += ['cxa_noexception.cpp']
9571001 elif self.eh_mode == Exceptions.WASM:
9581002 filenames += [
1003 'cxa_exception_storage.cpp',
9591004 'cxa_exception.cpp',
9601005 'cxa_personality.cpp'
9611006 ]
13861431 # including fprintf etc.
13871432 exit_files = files_in_path(
13881433 path_components=['system', 'lib', 'libc', 'musl', 'src', 'exit'],
1389 filenames=['assert.c', 'atexit.c', 'exit.c']) + files_in_path(
1390 path_components=['system', 'lib', 'libc', 'musl', 'src', 'unistd'],
1391 filenames=['_exit.c'])
1434 filenames=['assert.c', 'atexit.c', 'exit.c'])
13921435 return base_files + time_files + exit_files
13931436
13941437
14901533 force = ','.join(name for name, lib in system_libs_map.items() if not lib.never_force)
14911534 force_include = set((force.split(',') if force else []) + forced)
14921535 if force_include:
1493 logger.debug('forcing stdlibs: ' + str(force_include))
1536 logger.debug(f'forcing stdlibs: {force_include}')
14941537
14951538 def add_library(libname):
14961539 lib = system_libs_map[libname]
16301673 target = os.path.basename(src_dir)
16311674 dest = os.path.join(Ports.get_include_dir(), target)
16321675 shared.try_delete(dest)
1633 logger.debug('installing headers: ' + dest)
1676 logger.debug(f'installing headers: {dest}')
16341677 shutil.copytree(src_dir, dest)
16351678
16361679 @staticmethod
1637 def install_headers(src_dir, pattern="*.h", target=None):
1638 logger.debug("install_headers")
1680 def install_headers(src_dir, pattern='*.h', target=None):
1681 logger.debug('install_headers')
16391682 dest = Ports.get_include_dir()
16401683 if target:
16411684 dest = os.path.join(dest, target)
16421685 shared.safe_ensure_dirs(dest)
16431686 matches = glob.glob(os.path.join(src_dir, pattern))
1644 assert matches, "no headers found to install in %s" % src_dir
1687 assert matches, f'no headers found to install in {src_dir}'
16451688 for f in matches:
16461689 logger.debug('installing: ' + os.path.join(dest, os.path.basename(f)))
16471690 shutil.copyfile(f, os.path.join(dest, os.path.basename(f)))
17351778 shared.exit_with_error('%s is not a known port' % name)
17361779 port = ports.ports_by_name[name]
17371780 if not hasattr(port, 'SUBDIR'):
1738 logger.error('port %s lacks .SUBDIR attribute, which we need in order to override it locally, please update it' % name)
1781 logger.error(f'port {name} lacks .SUBDIR attribute, which we need in order to override it locally, please update it')
17391782 sys.exit(1)
17401783 subdir = port.SUBDIR
17411784 target = os.path.join(fullname, subdir)
17421785 if os.path.exists(target) and not dir_is_newer(path, target):
1743 logger.warning('not grabbing local port: ' + name + ' from ' + path + ' to ' + fullname + ' (subdir: ' + subdir + ') as the destination ' + target + ' is newer (run emcc --clear-ports if that is incorrect)')
1786 logger.warning(f'not grabbing local port: {name} from {path} to {fullname} (subdir: {subdir}) as the destination {target} is newer (run emcc --clear-ports if that is incorrect)')
17441787 else:
1745 logger.warning('grabbing local port: ' + name + ' from ' + path + ' to ' + fullname + ' (subdir: ' + subdir + ')')
1788 logger.warning(f'grabbing local port: {name} from {path} to {fullname} (subdir: {subdir})')
17461789 shared.try_delete(fullname)
17471790 shutil.copytree(path, target)
17481791 Ports.clear_project_build(name)
17491792 return
17501793
1751 if url.endswith('.tar.bz2'):
1752 fullpath = fullname + '.tar.bz2'
1753 elif url.endswith('.tar.gz'):
1754 fullpath = fullname + '.tar.gz'
1755 else:
1756 fullpath = fullname + '.zip'
1794 url_filename = url.rsplit('/')[-1]
1795 ext = url_filename.split('.', 1)[1]
1796 fullpath = fullname + '.' + ext
17571797
17581798 if name not in Ports.name_cache: # only mention each port once in log
1759 logger.debug('including port: ' + name)
1760 logger.debug(' (at ' + fullname + ')')
1799 logger.debug(f'including port: {name}')
1800 logger.debug(f' (at {fullname})')
17611801 Ports.name_cache.add(name)
17621802
17631803 def retrieve():
17641804 # retrieve from remote server
1765 logger.info('retrieving port: ' + name + ' from ' + url)
1805 logger.info(f'retrieving port: {name} from {url}')
17661806 try:
17671807 import requests
17681808 response = requests.get(url)
17751815 if sha512hash:
17761816 actual_hash = hashlib.sha512(data).hexdigest()
17771817 if actual_hash != sha512hash:
1778 shared.exit_with_error('Unexpected hash: ' + actual_hash + '\n'
1818 shared.exit_with_error(f'Unexpected hash: {actual_hash}\n'
17791819 'If you are updating the port, please update the hash in the port module.')
17801820 with open(fullpath, 'wb') as f:
17811821 f.write(data)
17831823 marker = os.path.join(fullname, '.emscripten_url')
17841824
17851825 def unpack():
1786 logger.info('unpacking port: ' + name)
1826 logger.info(f'unpacking port: {name}')
17871827 shared.safe_ensure_dirs(fullname)
17881828 shutil.unpack_archive(filename=fullpath, extract_dir=fullname)
17891829 with open(marker, 'w') as f:
77 '''
88
99 import os
10 from pathlib import Path
1011
1112
1213 def all_children(subdir):
1920 if not (x.endswith('.py') or x.endswith('.c') or x.endswith('.cpp') or x.endswith('.h') or x.endswith('.js') or x.endswith('.ll')):
2021 continue
2122 print(x)
22 orig = open(x).read()
23 orig = Path(x).read_text()
2324 fixed = orig.copy()
2425 fixed = fixed.replace('Module["print"](', 'out(')
2526 fixed = fixed.replace('Module[\'print\'](', 'out(')
4445 fixed = fixed.replace('Module.printErr = ', 'err = ')
4546
4647 if fixed != orig:
47 open(x, 'w').write(fixed)
48 Path(x).write_text(fixed)
6767 return exe_file + suffix
6868
6969 return None
70
71
72 def read_file(file_path):
73 """Read from a file opened in text mode"""
74 with open(file_path) as fh:
75 return fh.read()
76
77
78 def read_binary(file_path):
79 """Read from a file opened in binary mode"""
80 with open(file_path, 'rb') as fh:
81 return fh.read()
82
83
84 def write_file(file_path, text):
85 """Write to a file opened in text mode"""
86 with open(file_path, 'w') as fh:
87 fh.write(text)
1717 import os
1818 import re
1919 from subprocess import Popen, PIPE
20 from pathlib import Path
2021 import sys
2122
2223 sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
24
2325
2426 logger = logging.getLogger('wasm-sourcemap')
2527
175177
176178 def read_dwarf_entries(wasm, options):
177179 if options.dwarfdump_output:
178 output = open(options.dwarfdump_output, 'rb').read()
180 output = Path(options.dwarfdump_output).read_bytes()
179181 elif options.dwarfdump:
180182 logger.debug('Reading DWARF information from %s' % wasm)
181183 if not os.path.exists(options.dwarfdump):
1212 import sys
1313
1414 from . import shared
15 from . import utils
1516 from .settings import settings
1617
1718 sys.path.append(shared.path_from_root('third_party'))
9697 # the EMSCRIPTEN_METADATA_MINOR
9798 )
9899
99 orig = open(wasm_file, 'rb').read()
100 orig = utils.read_binary(wasm_file)
100101 with open(wasm_file, 'wb') as f:
101102 f.write(orig[0:8]) # copy magic number and version
102103 # write the special section
1212
1313 sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
1414
15 from tools import shared
15 from tools import shared, utils
1616
1717 sys.path.append(shared.path_from_root('third_party'))
1818 sys.path.append(shared.path_from_root('third_party', 'ply'))
5454 p.parse(r'''
5555 interface VoidPtr {
5656 };
57 ''' + open(input_file).read())
57 ''' + utils.read_file(input_file))
5858 data = p.finish()
5959
6060 interfaces = {}
381381 def render_function(class_name, func_name, sigs, return_type, non_pointer,
382382 copy, operator, constructor, func_scope,
383383 call_content=None, const=False, array_attribute=False):
384 global mid_c, mid_js, js_impl_methods
385
386384 legacy_mode = CHECKS not in ['ALL', 'FAST']
387385 all_checks = CHECKS == 'ALL'
388386
520518 body += ' %s%s(%s)%s;\n' % (call_prefix, '_' + c_names[max_args], ', '.join(pre_arg + args), call_postfix)
521519 if cache:
522520 body += ' ' + cache + '\n'
523 mid_js += [r'''%sfunction%s(%s) {
521 mid_js.append(r'''%sfunction%s(%s) {
524522 %s
525 };''' % (CONSTRUCTOR_CLOSURE_SUPPRESSIONS, (' ' + func_name) if constructor else '', ', '.join(args), body[:-1])]
523 };''' % (CONSTRUCTOR_CLOSURE_SUPPRESSIONS, (' ' + func_name) if constructor else '', ', '.join(args), body[:-1]))
526524
527525 # C
528526
578576
579577 c_return_type = type_to_c(return_type)
580578 maybe_const = 'const ' if const else ''
581 mid_c += [r'''
579 mid_c.append(r'''
582580 %s%s EMSCRIPTEN_KEEPALIVE %s(%s) {
583581 %s %s%s%s;
584582 }
585 ''' % (maybe_const, type_to_c(class_name) if constructor else c_return_type, c_names[i], full_args, pre, return_prefix, call, return_postfix)]
583 ''' % (maybe_const, type_to_c(class_name) if constructor else c_return_type, c_names[i], full_args, pre, return_prefix, call, return_postfix))
586584
587585 if not constructor:
588586 if i == max_args:
589587 dec_args = ', '.join([type_to_cdec(raw[j]) + ' ' + args[j] for j in range(i)])
590588 js_call_args = ', '.join(['%s%s' % (('(int)' if sig[j] in interfaces else '') + take_addr_if_nonpointer(raw[j]), args[j]) for j in range(i)])
591589
592 js_impl_methods += [r''' %s %s(%s) %s {
590 js_impl_methods.append(r''' %s %s(%s) %s {
593591 %sEM_ASM_%s({
594592 var self = Module['getCache'](Module['%s'])[$0];
595593 if (!self.hasOwnProperty('%s')) throw 'a JSImplementation must implement all functions, you forgot %s::%s.';
603601 func_name,
604602 ','.join(['$%d' % i for i in range(1, max_args + 1)]),
605603 return_postfix,
606 (', ' if js_call_args else '') + js_call_args)]
604 (', ' if js_call_args else '') + js_call_args))
607605
608606
609607 for name, interface in interfaces.items():
640638 mid_js += ['\n// ' + name + '\n']
641639 mid_c += ['\n// ' + name + '\n']
642640
643 global js_impl_methods
644641 js_impl_methods = []
645642
646643 cons = interface.getExtendedAttribute('Constructor')