From b7aa50e4fc60103cf2836fce972acb3d2a960726 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 30 Jan 2024 16:01:40 -0800 Subject: [PATCH] Run all browser tests in 2gb mode --- .circleci/config.yml | 14 +---- src/library_html5_webgl.js | 3 +- test/browser/emmalloc_memgrowth.cpp | 55 ++++++++---------- test/fs/test_idbfs_sync.c | 47 ++++++---------- test/test_browser.py | 87 ++++++++++++++++++++++++----- 5 files changed, 117 insertions(+), 89 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dcf143e3a19f5..0662351a969bd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -811,19 +811,7 @@ jobs: steps: - run-tests-chrome: title: "browser_2gb" - test_targets: " - browser_2gb.test_gles2_uniform_arrays - browser_2gb.test_fetch_to_memory - browser_2gb.test_emscripten_animate_canvas_element_size_manual_css - browser_2gb.test_fulles2_sdlproc - browser_2gb.test_cubegeom* - browser_2gb.test_html5_webgl_create_context* - browser_2gb.test_main_thread_async_em_asm - browser_2gb.test_webgl2_* - browser_2gb.test_webgl_* - browser_2gb.test_sdl_image - browser_2gb.test_wasm_worker* - " + test_targets: "browser_2gb" test-browser-chrome-wasm64-4gb: executor: bionic steps: diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 7e374f02efddd..1d647c13a5202 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -14,8 +14,9 @@ var LibraryHtml5WebGL = { var len = arr.length; var writeLength = dstLength < len ? dstLength : len; var heap = heapType ? HEAPF32 : HEAP32; + dst = {{{ getHeapOffset('dst', 'float') }}}; for (var i = 0; i < writeLength; ++i) { - heap[(dst >> 2) + i] = arr[i]; + heap[dst + i] = arr[i]; } return len; }, diff --git a/test/browser/emmalloc_memgrowth.cpp b/test/browser/emmalloc_memgrowth.cpp index 21cf1a3972758..9e42332c31bf5 100644 --- a/test/browser/emmalloc_memgrowth.cpp +++ b/test/browser/emmalloc_memgrowth.cpp @@ -5,37 +5,30 @@ uint64_t nextAllocationSize = 16*1024*1024; bool allocHasFailed = false; -void grow_memory() -{ - uint8_t *ptr = (uint8_t*)malloc((size_t)nextAllocationSize); - EM_ASM({}, ptr); // Pass ptr out to confuse LLVM that it is used, so it won't optimize it away in -O1 and higher. - size_t heapSize = emscripten_get_heap_size(); - printf("Allocated %zu: %d. Heap size: %zu\n", (size_t)nextAllocationSize, ptr ? 1 : 0, heapSize); - if (ptr) - { - if (!allocHasFailed) - { - nextAllocationSize *= 2; - // Make sure we don't overflow, and also exercise malloc(-1) to gracefully return 0 in ABORTING_MALLOC=0 mode. - if (nextAllocationSize > 0xFFFFFFFFULL) - nextAllocationSize = 0xFFFFFFFFULL; - } - } - else - { - nextAllocationSize /= 2; - allocHasFailed = true; - } +void grow_memory() { + uint8_t *ptr = (uint8_t*)malloc((size_t)nextAllocationSize); + EM_ASM({}, ptr); // Pass ptr out to confuse LLVM that it is used, so it won't optimize it away in -O1 and higher. + size_t heapSize = emscripten_get_heap_size(); + printf("Allocated %zu: %d. Heap size: %zu\n", (size_t)nextAllocationSize, ptr ? 1 : 0, heapSize); + if (ptr) { + if (!allocHasFailed) { + nextAllocationSize *= 2; + // Make sure we don't overflow, and also exercise malloc(-1) to gracefully return 0 in ABORTING_MALLOC=0 mode. + if (nextAllocationSize > 0xFFFFFFFFULL) + nextAllocationSize = 0xFFFFFFFFULL; + } + } else { + nextAllocationSize /= 2; + allocHasFailed = true; + } } -int main() -{ - // Exhaust all available memory. - for(int i = 0; i < 50; ++i) - grow_memory(); - // If we get this far without crashing on OOM, we are ok! - printf("Test finished!\n"); -#ifdef REPORT_RESULT - REPORT_RESULT(0); -#endif +int main() { + // Exhaust all available memory. + for(int i = 0; i < 50; ++i) { + grow_memory(); + } + // If we get this far without crashing on OOM, we are ok! + printf("Test finished!\n"); + return 0; } diff --git a/test/fs/test_idbfs_sync.c b/test/fs/test_idbfs_sync.c index 2040e0417fb19..05f478ff4a3e0 100644 --- a/test/fs/test_idbfs_sync.c +++ b/test/fs/test_idbfs_sync.c @@ -15,8 +15,7 @@ int result = 1; -void success() -{ +void success() { REPORT_RESULT(result); #ifdef FORCE_EXIT emscripten_force_exit(0); @@ -24,10 +23,9 @@ void success() } void test() { - int fd; struct stat st; - + #if FIRST // for each file, we first make sure it doesn't currently exist @@ -49,22 +47,20 @@ void test() { fd = open("/working1/waka.txt", O_RDWR | O_CREAT, 0666); if (fd == -1) result = -5000 - errno; - else - { + else { if (write(fd,"az",2) != 2) result = -6000 - errno; if (close(fd) != 0) result = -7000 - errno; } - + // a file whose contents are random-ish string set by the test_browser.py file if ((stat("/working1/moar.txt", &st) != -1) || (errno != ENOENT)) result = -8000 - errno; fd = open("/working1/moar.txt", O_RDWR | O_CREAT, 0666); if (fd == -1) result = -9000 - errno; - else - { + else { if (write(fd, SECRET, strlen(SECRET)) != strlen(SECRET)) result = -10000 - errno; if (close(fd) != 0) @@ -92,8 +88,7 @@ void test() { fd = open("/working1/waka.txt", O_RDONLY); if (fd == -1) result = -17000 - errno; - else - { + else { char bf[4]; int bytes_read = read(fd,&bf[0],sizeof(bf)); if (bytes_read != 2) @@ -105,19 +100,17 @@ void test() { if (unlink("/working1/waka.txt") != 0) result = -21000 - errno; } - + // does the random-ish file exist and does it contain SECRET? fd = open("/working1/moar.txt", O_RDONLY); - if (fd == -1) + if (fd == -1) { result = -22000 - errno; - else - { + } else { char bf[256]; int bytes_read = read(fd,&bf[0],sizeof(bf)); - if (bytes_read != strlen(SECRET)) + if (bytes_read != strlen(SECRET)) { result = -23000; - else - { + } else { bf[strlen(SECRET)] = 0; if (strcmp(bf,SECRET) != 0) result = -24000; @@ -129,14 +122,13 @@ void test() { } // does the directory exist? - if (stat("/working1/dir", &st) != 0) + if (stat("/working1/dir", &st) != 0) { result = -27000 - errno; - else - { + } else { if (!S_ISDIR(st.st_mode)) result = -28000; - if (rmdir("/working1/dir") != 0) - result = -29000 - errno; + if (rmdir("/working1/dir") != 0) + result = -29000 - errno; } #endif @@ -164,20 +156,18 @@ void test() { ccall('success', 'v'); }); ); - } int main() { - EM_ASM( FS.mkdir('/working1'); FS.mount(IDBFS, {}, '/working1'); #if !FIRST - // syncfs(true, f) should not break on already-existing directories: - FS.mkdir('/working1/dir'); + // syncfs(true, f) should not break on already-existing directories: + FS.mkdir('/working1/dir'); #endif - + // sync from persisted state into memory and then // run the 'test' function FS.syncfs(true, function (err) { @@ -187,6 +177,5 @@ int main() { ); emscripten_exit_with_live_runtime(); - return 0; } diff --git a/test/test_browser.py b/test/test_browser.py index 3d625ee03748d..eab30eeccda88 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2048,14 +2048,18 @@ def test_gl_renderers(self): self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_2gb('render fails') + @no_4gb('render fails') def test_gl_stride(self): self.btest('gl_stride.c', reference='gl_stride.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_4gb('assertion failure') def test_gl_vertex_buffer_pre(self): self.btest('gl_vertex_buffer_pre.c', reference='gl_vertex_buffer_pre.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_4gb('assertion failure') def test_gl_vertex_buffer(self): self.btest('gl_vertex_buffer.c', reference='gl_vertex_buffer.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL'], reference_slack=1) @@ -2992,6 +2996,8 @@ def test_glfw3_hi_dpi_aware(self): 'memfile': (['-sWASM=0', '--memory-init-file=1'],) }) def test_sdl2_image(self, args): + if args: + self.require_wasm2js() # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.jpg') @@ -3262,6 +3268,7 @@ def test_sdl2_image_prepare_data(self): self.btest('test_sdl2_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not', '-sUSE_SDL=2', '-sUSE_SDL_IMAGE=2'], manually_trigger_reftest=True) @no_wasm64('SDL2 + wasm64') + @no_2gb('https://github.com/libsdl-org/SDL/issues/9052') @requires_graphics_hardware def test_sdl2_canvas_proxy(self): create_file('data.txt', 'datum') @@ -3293,6 +3300,7 @@ def test_sdl2_gl_read(self): self.btest_exit('test_sdl2_gl_read.c', args=['-sUSE_SDL=2']) @no_wasm64('SDL2 + wasm64') + @no_2gb('https://github.com/libsdl-org/SDL/issues/9052') @requires_graphics_hardware def test_sdl2_glmatrixmode_texture(self): self.btest('test_sdl2_glmatrixmode_texture.c', reference='browser/test_sdl2_glmatrixmode_texture.png', @@ -3356,10 +3364,12 @@ def test_sdl2_unwasteful(self): self.btest_exit('test_sdl2_unwasteful.cpp', args=['-sUSE_SDL=2', '-O1']) @no_wasm64('SDL2 + wasm64') + @no_2gb('https://github.com/libsdl-org/SDL/issues/9052') def test_sdl2_canvas_write(self): self.btest_exit('test_sdl2_canvas_write.cpp', args=['-sUSE_SDL=2']) @no_wasm64('SDL2 + wasm64') + @no_2gb('https://github.com/libsdl-org/SDL/issues/9052') @requires_graphics_hardware def test_sdl2_gl_frames_swap(self): def post_build(): @@ -3432,6 +3442,8 @@ def test_sdl2_mixer_music(self, formats, flags, music_name): '-sUSE_SDL=2', '-sUSE_SDL_MIXER=2', '-sSDL2_MIXER_FORMATS=' + ','.join(formats), + '-lc++', + '-lc++abi', ]) @requires_graphics_hardware @@ -3868,6 +3880,8 @@ def test_dynamic_link_pthread_many(self): self.btest_exit('main.cpp', args=['-Wno-experimental', '-pthread', '-sMAIN_MODULE=2', 'side1.wasm', 'side2.wasm']) + @no_2gb('uses INITIAL_MEMORY') + @no_4gb('uses INITIAL_MEMORY') def test_memory_growth_during_startup(self): create_file('data.dat', 'X' * (30 * 1024 * 1024)) self.btest('browser_test_hello_world.c', '0', args=['-sASSERTIONS', '-sALLOW_MEMORY_GROWTH', '-sINITIAL_MEMORY=16MB', '-sSTACK_SIZE=16384', '--preload-file', 'data.dat']) @@ -3960,17 +3974,24 @@ def test_pthread_main_thread_blocking_join(self): self.btest_exit('pthread/main_thread_join.cpp', args=['-O3', '-pthread', '-sPTHREAD_POOL_SIZE', '-sPROXY_TO_PTHREAD', '-sALLOW_BLOCKING_ON_MAIN_THREAD=0']) # Test the old GCC atomic __sync_fetch_and_op builtin operations. + @no_2gb('https://github.com/emscripten-core/emscripten/issues/21318') + @no_4gb('https://github.com/emscripten-core/emscripten/issues/21318') @requires_threads - def test_pthread_gcc_atomic_fetch_and_op(self): + @parameterized({ + '': (['-g'],), + 'O1': (['-O1', '-g'],), + 'O2': (['-O2'],), + 'O3': (['-O3'],), + 'Os': (['-Os'],), + }) + def test_pthread_gcc_atomic_fetch_and_op(self, args): self.emcc_args += ['-Wno-sync-fetch-and-nand-semantics-changed'] - for opt in [[], ['-O1'], ['-O2'], ['-O3'], ['-Os']]: - for debug in [[], ['-g']]: - args = opt + debug - print(args) - self.btest_exit('pthread/test_pthread_gcc_atomic_fetch_and_op.cpp', args=args + ['-pthread', '-sPTHREAD_POOL_SIZE=8']) + self.btest_exit('pthread/test_pthread_gcc_atomic_fetch_and_op.cpp', args=args + ['-pthread', '-sPTHREAD_POOL_SIZE=8']) # 64 bit version of the above test. @also_with_wasm2js + @no_2gb('https://github.com/emscripten-core/emscripten/issues/21318') + @no_4gb('https://github.com/emscripten-core/emscripten/issues/21318') @requires_threads def test_pthread_gcc_64bit_atomic_fetch_and_op(self): if not self.is_wasm(): @@ -3980,6 +4001,8 @@ def test_pthread_gcc_64bit_atomic_fetch_and_op(self): # Test the old GCC atomic __sync_op_and_fetch builtin operations. @also_with_wasm2js + @no_2gb('https://github.com/emscripten-core/emscripten/issues/21318') + @no_4gb('https://github.com/emscripten-core/emscripten/issues/21318') @requires_threads def test_pthread_gcc_atomic_op_and_fetch(self): self.emcc_args += ['-Wno-sync-fetch-and-nand-semantics-changed'] @@ -3987,6 +4010,8 @@ def test_pthread_gcc_atomic_op_and_fetch(self): # 64 bit version of the above test. @also_with_wasm2js + @no_2gb('https://github.com/emscripten-core/emscripten/issues/21318') + @no_4gb('https://github.com/emscripten-core/emscripten/issues/21318') @requires_threads def test_pthread_gcc_64bit_atomic_op_and_fetch(self): if not self.is_wasm(): @@ -4029,6 +4054,8 @@ def test_pthread_preallocates_workers(self): # Test that allocating a lot of threads doesn't regress. This needs to be checked manually! @requires_threads + @no_2gb('uses INITIAL_MEMORY') + @no_4gb('uses INITIAL_MEMORY') def test_pthread_large_pthread_allocation(self): self.btest_exit('pthread/test_large_pthread_allocation.cpp', args=['-sINITIAL_MEMORY=128MB', '-O3', '-pthread', '-sPTHREAD_POOL_SIZE=50']) @@ -4231,6 +4258,8 @@ def test_pthread_proxying_in_futex_wait(self): # Test that sbrk() operates properly in multithreaded conditions @requires_threads + @no_2gb('uses INITIAL_MEMORY') + @no_4gb('uses INITIAL_MEMORY') @parameterized({ '': (['-DABORTING_MALLOC=0', '-sABORTING_MALLOC=0'],), 'aborting_malloc': (['-DABORTING_MALLOC=1'],), @@ -4358,6 +4387,8 @@ def test_pthread_lsan(self, name, args): self.btest(Path('pthread', name + '.cpp'), expected='1', args=['-fsanitize=leak', '-pthread', '-sPROXY_TO_PTHREAD', '--pre-js', test_file('pthread', name + '.js')] + args) @no_wasm64('TODO: ASAN in memory64') + @no_2gb('ASAN + GLOBAL_BASE') + @no_4gb('ASAN + GLOBAL_BASE') @parameterized({ # Reusing the LSan test files for ASan. 'leak': ['test_pthread_lsan_leak', ['-gsource-map']], @@ -4368,11 +4399,15 @@ def test_pthread_asan(self, name, args): self.btest(Path('pthread', name + '.cpp'), expected='1', args=['-fsanitize=address', '-pthread', '-sPROXY_TO_PTHREAD', '--pre-js', test_file('pthread', name + '.js')] + args) @no_wasm64('TODO: ASAN in memory64') + @no_2gb('ASAN + GLOBAL_BASE') + @no_4gb('ASAN + GLOBAL_BASE') @requires_threads def test_pthread_asan_use_after_free(self): self.btest('pthread/test_pthread_asan_use_after_free.cpp', expected='1', args=['-fsanitize=address', '-pthread', '-sPROXY_TO_PTHREAD', '--pre-js', test_file('pthread/test_pthread_asan_use_after_free.js')]) @no_wasm64('TODO: ASAN in memory64') + @no_2gb('ASAN + GLOBAL_BASE') + @no_4gb('ASAN + GLOBAL_BASE') @no_firefox('https://github.com/emscripten-core/emscripten/issues/20006') @also_with_wasmfs @requires_threads @@ -4523,8 +4558,11 @@ def test_async_compile(self, opts, returncode): 'asan': (['-fsanitize=address'],) }) def test_manual_wasm_instantiate(self, args): - if self.is_wasm64() and args: - self.skipTest('TODO: ASAN in memory64') + if args: + if self.is_wasm64(): + self.skipTest('TODO: ASAN in memory64') + if self.is_2gb() or self.is_4gb(): + self.skipTest('asan doesnt support GLOBAL_BASE') 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') @@ -4578,7 +4616,7 @@ def test_small_js_flags(self): size = os.path.getsize('test.js') print('size:', size) # Note that this size includes test harness additions (for reporting the result, etc.). - if not self.is_wasm64(): + if not self.is_wasm64() and not self.is_2gb(): self.assertLess(abs(size - 4800), 100) # Tests that it is possible to initialize and render WebGL content in a @@ -5018,6 +5056,8 @@ def test_minimal_runtime_hello_thread(self, opts): 'proxy': (['-sPROXY_TO_PTHREAD'],) }) @requires_threads + @no_2gb('uses INITIAL_MEMORY') + @no_4gb('uses INITIAL_MEMORY') def test_pthread_growth_mainthread(self, emcc_args): self.emcc_args.remove('-Werror') self.btest_exit('pthread/test_pthread_memory_growth_mainthread.c', args=['-pthread', '-sPTHREAD_POOL_SIZE=2', '-sALLOW_MEMORY_GROWTH', '-sINITIAL_MEMORY=32MB', '-sMAXIMUM_MEMORY=256MB'] + emcc_args) @@ -5030,6 +5070,8 @@ def test_pthread_growth_mainthread(self, emcc_args): 'minimal': (['-sMINIMAL_RUNTIME', '-sMODULARIZE', '-sEXPORT_NAME=MyModule'],), }) @requires_threads + @no_2gb('uses INITIAL_MEMORY') + @no_4gb('uses INITIAL_MEMORY') def test_pthread_growth(self, emcc_args): self.emcc_args.remove('-Werror') self.btest_exit('pthread/test_pthread_memory_growth.c', args=['-pthread', '-sPTHREAD_POOL_SIZE=2', '-sALLOW_MEMORY_GROWTH', '-sINITIAL_MEMORY=32MB', '-sMAXIMUM_MEMORY=256MB', '-g'] + emcc_args) @@ -5577,6 +5619,7 @@ def test_4gb(self): # Tests that emmalloc supports up to 4GB Wasm heaps. @no_firefox('no 4GB support yet') + @no_4gb('uses MAXIMUM_MEMORY') def test_emmalloc_4gb(self): # For now, keep this in browser as this suite runs serially, which # means we don't compete for memory with anything else (and run it @@ -5587,6 +5630,7 @@ def test_emmalloc_4gb(self): # Test that it is possible to malloc() a huge 3GB memory block in 4GB mode using emmalloc. # Also test emmalloc-memvalidate and emmalloc-memvalidate-verbose build configurations. @no_firefox('no 4GB support yet') + @no_2gb('not enough space to run in this mode') @parameterized({ '': (['-sMALLOC=emmalloc'],), 'debug': (['-sMALLOC=emmalloc-debug'],), @@ -5594,14 +5638,21 @@ def test_emmalloc_4gb(self): 'memvalidate_verbose': (['-sMALLOC=emmalloc-memvalidate-verbose'],), }) def test_emmalloc_3gb(self, args): - self.btest_exit('alloc_3gb.c', - args=['-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH=1'] + args) + if self.is_4gb(): + self.set_setting('MAXIMUM_MEMORY', '8GB') + else: + self.set_setting('MAXIMUM_MEMORY', '4GB') + self.btest_exit('alloc_3gb.c', args=['-sALLOW_MEMORY_GROWTH=1'] + args) # Test that it is possible to malloc() a huge 3GB memory block in 4GB mode using dlmalloc. @no_firefox('no 4GB support yet') + @no_2gb('not enough space tp run in this mode') def test_dlmalloc_3gb(self): - self.btest_exit('alloc_3gb.c', - args=['-sMALLOC=dlmalloc', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH=1']) + if self.is_4gb(): + self.set_setting('MAXIMUM_MEMORY', '8GB') + else: + self.set_setting('MAXIMUM_MEMORY', '4GB') + self.btest_exit('alloc_3gb.c', args=['-sMALLOC=dlmalloc', '-sALLOW_MEMORY_GROWTH=1']) @no_wasm64() @parameterized({ @@ -5655,7 +5706,9 @@ def test_wasmfs_opfs_errors(self): @no_firefox('no 4GB support yet') def test_emmalloc_memgrowth(self, *args): - self.btest('emmalloc_memgrowth.cpp', expected='0', args=['-sMALLOC=emmalloc', '-sALLOW_MEMORY_GROWTH=1', '-sABORTING_MALLOC=0', '-sASSERTIONS=2', '-sMINIMAL_RUNTIME=1', '-sMAXIMUM_MEMORY=4GB']) + if not self.is_4gb(): + self.set_setting('MAXIMUM_MEMORY', '4GB') + self.btest_exit('emmalloc_memgrowth.cpp', args=['-sMALLOC=emmalloc', '-sALLOW_MEMORY_GROWTH=1', '-sABORTING_MALLOC=0', '-sASSERTIONS=2', '-sMINIMAL_RUNTIME=1']) @no_firefox('no 4GB support yet') @no_2gb('uses MAXIMUM_MEMORY') @@ -5910,6 +5963,8 @@ def setUp(self): self.set_setting('INITIAL_MEMORY', '4200mb') self.set_setting('GLOBAL_BASE', '4gb') self.emcc_args.append('-Wno-experimental') + # Without this we get a warning about GLOBAL_BASE being ignored when used with SIDE_MODULE + self.emcc_args.append('-Wno-unused-command-line-argument') self.require_wasm64() @@ -5917,7 +5972,7 @@ class browser64_2gb(browser): def setUp(self): super().setUp() self.set_setting('MEMORY64') - self.set_setting('INITIAL_MEMORY', '2200gb') + self.set_setting('INITIAL_MEMORY', '2200mb') self.set_setting('GLOBAL_BASE', '2gb') self.emcc_args.append('-Wno-experimental') self.require_wasm64() @@ -5928,3 +5983,5 @@ def setUp(self): super().setUp() self.set_setting('INITIAL_MEMORY', '2200mb') self.set_setting('GLOBAL_BASE', '2gb') + # Without this we get a warning about GLOBAL_BASE being ignored when used with SIDE_MODULE + self.emcc_args.append('-Wno-unused-command-line-argument')