diff --git a/test/common.py b/test/common.py index d813583a42d28..21f852e3e331c 100644 --- a/test/common.py +++ b/test/common.py @@ -36,6 +36,7 @@ from tools.shared import EMCC, EMXX, DEBUG, EMCONFIGURE, EMCMAKE from tools.shared import get_canonical_temp_dir, path_from_root from tools.utils import MACOS, WINDOWS, read_file, read_binary, write_binary, exit_with_error +from tools.settings import COMPILE_TIME_SETTINGS from tools import shared, line_endings, building, config, utils logger = logging.getLogger('common') @@ -771,7 +772,7 @@ def require_jspi(self): # emcc warns about stack switching being experimental, and we build with # warnings-as-errors, so disable that warning self.emcc_args += ['-Wno-experimental'] - self.emcc_args += ['-sASYNCIFY=2'] + self.set_setting('ASYNCIFY', 2) if not self.is_wasm(): self.skipTest('JSPI is not currently supported for WASM2JS') @@ -959,9 +960,11 @@ def has_changed_setting(self, key): def clear_setting(self, key): self.settings_mods.pop(key, None) - def serialize_settings(self): + def serialize_settings(self, compile_only=False): ret = [] for key, value in self.settings_mods.items(): + if compile_only and key not in COMPILE_TIME_SETTINGS: + continue if value == 1: ret.append(f'-s{key}') elif type(value) is list: @@ -995,15 +998,15 @@ def add_on_exit(self, code): # param @main_file whether this is the main file of the test. some arguments # (like --pre-js) do not need to be passed when building # libraries, for example - def get_emcc_args(self, main_file=False, ldflags=True): + def get_emcc_args(self, main_file=False, compile_only=False): def is_ldflag(f): return any(f.startswith(s) for s in ['-sENVIRONMENT=', '--pre-js=', '--post-js=']) - args = self.serialize_settings() + self.emcc_args - if ldflags: - args += self.ldflags - else: + args = self.serialize_settings(compile_only) + self.emcc_args + if compile_only: args = [a for a in args if not is_ldflag(a)] + else: + args += self.ldflags if not main_file: for i, arg in enumerate(args): if arg in ('--pre-js', '--post-js'): @@ -1354,12 +1357,12 @@ def get_library(self, name, generated_libs, configure=['sh', './configure'], # build_dir = self.get_build_dir() output_dir = self.get_dir() - # get_library() is used to compile libraries, and not link executables, - # so we don't want to pass linker flags here (emscripten warns if you - # try to pass linker settings when compiling). emcc_args = [] if not native: - emcc_args = self.get_emcc_args(ldflags=False) + # get_library() is used to compile libraries, and not link executables, + # so we don't want to pass linker flags here (emscripten warns if you + # try to pass linker settings when compiling). + emcc_args = self.get_emcc_args(compile_only=True) hash_input = (str(emcc_args) + ' $ ' + str(env_init)).encode('utf-8') cache_name = name + ','.join([opt for opt in emcc_args if len(opt) < 7]) + '_' + hashlib.md5(hash_input).hexdigest() + cache_name_extra @@ -1408,7 +1411,7 @@ def run_process(self, cmd, check=True, **args): self.fail(f'subprocess exited with non-zero return code({e.returncode}): `{shared.shlex_join(cmd)}`') def emcc(self, filename, args=[], output_filename=None, **kwargs): # noqa - cmd = [compiler_for(filename), filename] + self.get_emcc_args(ldflags='-c' not in args) + args + cmd = [compiler_for(filename), filename] + self.get_emcc_args(compile_only='-c' in args) + args if output_filename: cmd += ['-o', output_filename] self.run_process(cmd, **kwargs) @@ -1662,10 +1665,6 @@ def get_freetype_library(self): def get_poppler_library(self, env_init=None): freetype = self.get_freetype_library() - # The fontconfig symbols are all missing from the poppler build - # e.g. FcConfigSubstitute - self.set_setting('ERROR_ON_UNDEFINED_SYMBOLS', 0) - self.emcc_args += [ '-I' + test_file('third_party/freetype/include'), '-I' + test_file('third_party/poppler/include') @@ -1681,6 +1680,9 @@ def get_poppler_library(self, env_init=None): '-Wno-unknown-pragmas', '-Wno-shift-negative-value', '-Wno-dynamic-class-memaccess', + # The fontconfig symbols are all missing from the poppler build + # e.g. FcConfigSubstitute + '-sERROR_ON_UNDEFINED_SYMBOLS=0', # Avoid warning about ERROR_ON_UNDEFINED_SYMBOLS being used at compile time '-Wno-unused-command-line-argument', '-Wno-js-compiler', @@ -2111,24 +2113,26 @@ def reftest(self, expected, manually_trigger=False): setupRefTest(); ''' % (reporting, basename, int(manually_trigger))) - def compile_btest(self, args, reporting=Reporting.FULL): + def compile_btest(self, filename, args, reporting=Reporting.FULL): # Inject support code for reporting results. This adds an include a header so testcases can # use REPORT_RESULT, and also adds a cpp file to be compiled alongside the testcase, which # contains the implementation of REPORT_RESULT (we can't just include that implementation in # the header as there may be multiple files being compiled here). if reporting != Reporting.NONE: # For basic reporting we inject JS helper funtions to report result back to server. - args += ['-DEMTEST_PORT_NUMBER=%d' % self.port, - '--pre-js', test_file('browser_reporting.js')] + args += ['--pre-js', test_file('browser_reporting.js')] if reporting == Reporting.FULL: - # If C reporting (i.e. REPORT_RESULT macro) is required - # also compile in report_result.c and forice-include report_result.h - args += ['-I' + TEST_ROOT, - '-include', test_file('report_result.h'), - test_file('report_result.c')] + # If C reporting (i.e. the REPORT_RESULT macro) is required we + # also include report_result.c and force-include report_result.h + self.run_process([EMCC, '-c', '-I' + TEST_ROOT, + '-DEMTEST_PORT_NUMBER=%d' % self.port, + test_file('report_result.c')] + self.get_emcc_args(compile_only=True)) + args += ['report_result.o', '-include', test_file('report_result.h')] if EMTEST_BROWSER == 'node': args.append('-DEMTEST_NODE') - self.run_process([EMCC] + self.get_emcc_args() + args) + if not os.path.exists(filename): + filename = test_file(filename) + self.run_process([compiler_for(filename), filename] + self.get_emcc_args() + args) def btest_exit(self, filename, assert_returncode=0, *args, **kwargs): """Special case of btest that reports its result solely via exiting @@ -2171,10 +2175,10 @@ def btest(self, filename, expected=None, reference=None, # manual_reference only makes sense for reference tests assert manual_reference is None outfile = output_basename + '.html' - args += [filename, '-o', outfile] + args += ['-o', outfile] # print('all args:', args) utils.delete_file(outfile) - self.compile_btest(args, reporting=reporting) + self.compile_btest(filename, args, reporting=reporting) self.assertExists(outfile) if post_build: post_build() diff --git a/test/test_browser.py b/test/test_browser.py index 70e1931b69b04..be3a439032752 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -261,8 +261,6 @@ def test_sdl1_es6(self): # as this test may take the focus away from the main test window # by opening a new window and possibly not closing it. def test_zzz_html_source_map(self): - if not has_browser(): - self.skipTest('need a browser') cpp_file = 'src.cpp' html_file = 'src.html' # browsers will try to 'guess' the corresponding original line if a @@ -288,9 +286,11 @@ def test_zzz_html_source_map(self): # sourceContent when the maps are relative paths delete_file(html_file) delete_file(html_file + '.map') - self.compile_btest(['src.cpp', '-o', 'src.html', '-gsource-map']) + self.compile_btest('src.cpp', ['-o', 'src.html', '-gsource-map']) self.assertExists(html_file) self.assertExists('src.wasm.map') + if not has_browser(): + self.skipTest('need a browser') webbrowser.open_new('file://' + html_file) print(''' If manually bisecting: @@ -436,7 +436,7 @@ def make_main_two_files(path1, path2, nonexistingpath): make_main('somefile.txt') # absolute becomes relative ensure_dir('dirrey') - self.compile_btest(['main.cpp', '--preload-file', absolute_src_path, '-o', 'dirrey/page.html'], reporting=Reporting.JS_ONLY) + self.compile_btest('main.cpp', ['--preload-file', absolute_src_path, '-o', 'dirrey/page.html'], reporting=Reporting.JS_ONLY) self.run_browser('dirrey/page.html', '/report_result?exit:0') # With FS.preloadFile @@ -455,11 +455,9 @@ def make_main_two_files(path1, path2, nonexistingpath): }) @requires_threads def test_preload_file_with_manual_data_download(self, args): - src = test_file('manual_download_data.cpp') - create_file('file.txt', '''Hello!''') - self.compile_btest([src, '-o', 'manual_download_data.js', '--preload-file', 'file.txt@/file.txt'] + args) + self.compile_btest('manual_download_data.cpp', ['-o', 'manual_download_data.js', '--preload-file', 'file.txt@/file.txt'] + args) shutil.copyfile(test_file('manual_download_data.html'), 'manual_download_data.html') # Move .data file out of server root to ensure that getPreloadedPackage is actually used @@ -504,7 +502,7 @@ def test_output_file_escaping(self): self.run_process([FILE_PACKAGER, data_file, '--use-preload-cache', '--indexedDB-name=testdb', '--preload', abs_txt + '@' + txt, '--js-output=' + data_js_file]) page_file = os.path.join(d, 'file with ' + tricky_part + '.html') abs_page_file = os.path.abspath(page_file) - self.compile_btest([cpp, '--pre-js', data_js_file, '-o', abs_page_file, '-sFORCE_FILESYSTEM'], reporting=Reporting.JS_ONLY) + self.compile_btest(cpp, ['--pre-js', data_js_file, '-o', abs_page_file, '-sFORCE_FILESYSTEM'], reporting=Reporting.JS_ONLY) self.run_browser(page_file, '/report_result?exit:0') @parameterized({ @@ -559,7 +557,7 @@ def test_preload_caching(self, extra_size): self.skipTest('chrome bug') create_file('somefile.txt', '''load me right before running the code please''' + ('_' * extra_size)) print('size:', os.path.getsize('somefile.txt')) - self.compile_btest(['main.c', '--use-preload-cache', '--js-library', 'test.js', '--preload-file', 'somefile.txt', '-o', 'page.html', '-sALLOW_MEMORY_GROWTH'], reporting=Reporting.JS_ONLY) + self.compile_btest('main.c', ['--use-preload-cache', '--js-library', 'test.js', '--preload-file', 'somefile.txt', '-o', 'page.html', '-sALLOW_MEMORY_GROWTH'], reporting=Reporting.JS_ONLY) self.run_browser('page.html', '/report_result?exit:0') self.run_browser('page.html', '/report_result?exit:1') @@ -609,7 +607,7 @@ def make_main(path): make_main('somefile.txt') self.run_process([FILE_PACKAGER, 'somefile.data', '--use-preload-cache', '--indexedDB-name=testdb', '--preload', 'somefile.txt', '--js-output=' + 'somefile.js']) - self.compile_btest(['main.c', '--js-library', 'test.js', '--pre-js', 'somefile.js', '-o', 'page.html', '-sFORCE_FILESYSTEM'], reporting=Reporting.JS_ONLY) + self.compile_btest('main.c', ['--js-library', 'test.js', '--pre-js', 'somefile.js', '-o', 'page.html', '-sFORCE_FILESYSTEM'], reporting=Reporting.JS_ONLY) self.run_browser('page.html', '/report_result?exit:0') self.run_browser('page.html', '/report_result?exit:1') @@ -649,7 +647,7 @@ def test_multifile(self): # by directory, and remove files to make sure self.set_setting('EXIT_RUNTIME') - self.compile_btest(['main.c', '--preload-file', 'subdirr', '-o', 'page.html'], reporting=Reporting.JS_ONLY) + self.compile_btest('main.c', ['--preload-file', 'subdirr', '-o', 'page.html'], reporting=Reporting.JS_ONLY) shutil.rmtree('subdirr') self.run_browser('page.html', '/report_result?exit:0') @@ -692,7 +690,7 @@ def test_custom_file_package_url(self): ''') self.set_setting('EXIT_RUNTIME') - self.compile_btest(['main.c', '--shell-file', 'shell.html', '--preload-file', 'subdirr/data1.txt', '-o', 'test.html'], reporting=Reporting.JS_ONLY) + self.compile_btest('main.c', ['--shell-file', 'shell.html', '--preload-file', 'subdirr/data1.txt', '-o', 'test.html'], reporting=Reporting.JS_ONLY) shutil.move('test.data', Path('cdn/test.data')) self.run_browser('test.html', '/report_result?exit:0') @@ -739,18 +737,18 @@ def setup(assetLocalization): def test(): # test test missing file should run xhr.onload with status different than 200, 304 or 206 setup("") - self.compile_btest(['main.cpp', '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']) + self.compile_btest('main.cpp', ['--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']) shutil.move('test.data', 'missing.data') self.run_browser('test.html', '/report_result?1') # test unknown protocol should go through xhr.onerror setup("unknown_protocol://") - self.compile_btest(['main.cpp', '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']) + self.compile_btest('main.cpp', ['--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']) self.run_browser('test.html', '/report_result?1') # test wrong protocol and port setup("https://localhost:8800/") - self.compile_btest(['main.cpp', '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']) + self.compile_btest('main.cpp', ['--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']) self.run_browser('test.html', '/report_result?1') test() @@ -890,7 +888,7 @@ def test_sdl_canvas_proxy(self): @requires_graphics_hardware def test_glgears_proxy_jstarget(self): # test .js target with --proxy-worker; emits 2 js files, client and worker - self.compile_btest([test_file('hello_world_gles_proxy.c'), '-o', 'test.js', '--proxy-to-worker', '-sGL_TESTING', '-lGL', '-lglut']) + self.compile_btest('hello_world_gles_proxy.c', ['-o', 'test.js', '--proxy-to-worker', '-sGL_TESTING', '-lGL', '-lglut']) shell_with_script('shell_minimal.html', 'test.html', '') self.reftest(test_file('gears.png')) self.post_manual_reftest() @@ -1152,7 +1150,7 @@ def test_sdl_mouse_offsets(self): ''') - self.compile_btest([test_file('browser/test_sdl_mouse.c'), '-DTEST_SDL_MOUSE_OFFSETS', '-O2', '--minify=0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js', '-lSDL', '-lGL', '-sEXIT_RUNTIME']) + self.compile_btest('browser/test_sdl_mouse.c', ['-DTEST_SDL_MOUSE_OFFSETS', '-O2', '--minify=0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js', '-lSDL', '-lGL', '-sEXIT_RUNTIME']) self.run_browser('page.html', '', '/report_result?exit:0') def test_glut_touchevents(self): @@ -1466,7 +1464,7 @@ def test_fs_lz4fs_package(self): print(' opts') self.btest_exit('fs/test_lz4fs.cpp', 2, args=['--pre-js', 'files.js', '-sLZ4', '-sFORCE_FILESYSTEM', '-O2']) print(' modularize') - self.compile_btest([test_file('fs/test_lz4fs.cpp'), '--pre-js', 'files.js', '-sLZ4', '-sFORCE_FILESYSTEM', '-sMODULARIZE', '-sEXIT_RUNTIME']) + self.compile_btest('fs/test_lz4fs.cpp', ['--pre-js', 'files.js', '-sLZ4', '-sFORCE_FILESYSTEM', '-sMODULARIZE', '-sEXIT_RUNTIME']) create_file('a.html', ''' ') self.run_browser('test.html', '/report_result?0') @@ -4476,7 +4472,7 @@ def test_in_flight_memfile_request(self, args, expected): self.set_setting('WASM', 0) print('plain html') - self.compile_btest([test_file('in_flight_memfile_request.c'), '-o', 'test.js']) + self.compile_btest('in_flight_memfile_request.c', ['-o', 'test.js']) create_file('test.html', '') # never when we provide our own HTML like this. self.run_browser('test.html', '/report_result?0') @@ -4539,7 +4535,7 @@ def test_async_compile(self): def test_manual_wasm_instantiate(self, args): if self.is_wasm64() and args: self.skipTest('TODO: ASAN in memory64') - self.compile_btest([test_file('manual_wasm_instantiate.cpp'), '-o', 'manual_wasm_instantiate.js'] + args) + self.compile_btest('manual_wasm_instantiate.cpp', ['-o', 'manual_wasm_instantiate.js'] + args) shutil.copyfile(test_file('manual_wasm_instantiate.html'), 'manual_wasm_instantiate.html') self.run_browser('manual_wasm_instantiate.html', '/report_result?1') @@ -4547,7 +4543,7 @@ def test_wasm_locate_file(self): # Test that it is possible to define "Module.locateFile(foo)" function to locate where worker.js will be loaded from. ensure_dir('cdn') create_file('shell2.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function(filename) { if (filename == "test.wasm") return "cdn/test.wasm"; else return filename; }, ')) - self.compile_btest([test_file('browser_test_hello_world.c'), '--shell-file', 'shell2.html', '-o', 'test.html']) + self.compile_btest('browser_test_hello_world.c', ['--shell-file', 'shell2.html', '-o', 'test.html']) shutil.move('test.wasm', Path('cdn/test.wasm')) self.run_browser('test.html', '/report_result?0') @@ -5057,7 +5053,7 @@ def test_pthread_reltime(self): def test_load_js_from_blob_with_pthreads(self): # TODO: enable this with wasm, currently pthreads/atomics have limitations self.set_setting('EXIT_RUNTIME') - self.compile_btest([test_file('pthread/hello_thread.c'), '-pthread', '-o', 'hello_thread_with_blob_url.js'], reporting=Reporting.JS_ONLY) + self.compile_btest('pthread/hello_thread.c', ['-pthread', '-o', 'hello_thread_with_blob_url.js'], reporting=Reporting.JS_ONLY) shutil.copyfile(test_file('pthread/main_js_as_blob_loader.html'), 'hello_thread_with_blob_url.html') self.run_browser('hello_thread_with_blob_url.html', '/report_result?exit:0') @@ -5100,9 +5096,8 @@ def test_single_file_in_web_environment_with_closure(self): def test_single_file_locate_file(self, args): if args: self.require_wasm2js() - args += [test_file('browser_test_hello_world.c'), '-o', 'test.js', '-sSINGLE_FILE'] - self.compile_btest(args) + self.compile_btest('browser_test_hello_world.c', ['-o', 'test.js', '-sSINGLE_FILE'] + args) create_file('test.html', ''' ') self.run_browser('test.html', '/report_result?0') self.assertExists('test.js') @@ -5136,7 +5131,7 @@ def test_single_file_worker_js(self): @requires_threads def test_pthreads_started_in_worker(self): self.set_setting('EXIT_RUNTIME') - self.compile_btest([test_file('pthread/test_pthread_atomics.cpp'), '-o', 'test.js', '-sINITIAL_MEMORY=64MB', '-pthread', '-sPTHREAD_POOL_SIZE=8'], reporting=Reporting.JS_ONLY) + self.compile_btest('pthread/test_pthread_atomics.cpp', ['-o', 'test.js', '-sINITIAL_MEMORY=64MB', '-pthread', '-sPTHREAD_POOL_SIZE=8'], reporting=Reporting.JS_ONLY) create_file('test.html', '''