From 3c8cfd5343d7dfd0fa25e13b58814658c7da9414 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 25 Oct 2016 15:13:56 +0300 Subject: [PATCH 01/86] Remove HEAPU8.buffer from transfer list in postMessage(). See https://bugzilla.mozilla.org/show_bug.cgi?id=1302036 and https://github.com/tc39/ecmascript_sharedmem/issues/98 --- src/library_pthread.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_pthread.js b/src/library_pthread.js index 2548870dd4266..9cf5649e0071d 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -326,7 +326,7 @@ var LibraryPThread = { DYNAMIC_BASE: DYNAMIC_BASE, DYNAMICTOP_PTR: DYNAMICTOP_PTR, PthreadWorkerInit: PthreadWorkerInit - }, [HEAPU8.buffer]); + }); PThread.unusedWorkerPool.push(worker); } }, From 1f5e49bceb01e3ace3c09584df935e0bc43552cc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 3 Nov 2016 14:43:54 -0700 Subject: [PATCH 02/86] Emmake binaryen (#4676) When emmake is run, we set env vars to cross-compile using emcc. But when building binaryen as a side task from such an invocation, we need to build it natively, so use a native building environment. Also fix up the native building environment to remove our extra cross-compiling vars. --- src/settings.js | 2 +- tests/test_sanity.py | 25 +++++++++++++++++++------ tools/shared.py | 7 +++++++ tools/system_libs.py | 5 +++-- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/settings.js b/src/settings.js index 2ab2e5ad7c8b0..4207306b20bb9 100644 --- a/src/settings.js +++ b/src/settings.js @@ -638,7 +638,7 @@ var BINARYEN = 0; // Whether to use [Binaryen](https://github.com/WebAssembly/bi // This will fetch the binaryen port and build it. (If, instead, you set // BINARYEN_ROOT in your ~/.emscripten file, then we use that instead // of the port, which can useful for local dev work on binaryen itself). -var BINARYEN_METHOD = ""; // See binaryen's src/js/post.js for details. +var BINARYEN_METHOD = ""; // See binaryen's src/js/wasm.js-post.js for details. var BINARYEN_SCRIPTS = ""; // An optional comma-separated list of script hooks to run after binaryen, // in binaryen's /scripts dir. var BINARYEN_IMPRECISE = 0; // Whether to apply imprecise/unsafe binaryen optimizations. If enabled, diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 4af0d76800171..c279bdd528dc2 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -955,13 +955,26 @@ def test_with_fake(report, expected): def test_binaryen(self): import tools.ports.binaryen as binaryen tag_file = Cache.get_path('binaryen_tag_' + binaryen.TAG + '.txt') - try_delete(tag_file) - # if BINARYEN_ROOT is set, we don't build the port. Check we do built it if not - restore() - config = open(CONFIG_FILE).read() - config = config.replace('BINARYEN_ROOT', '#') - open(CONFIG_FILE, 'w').write(config) + def prep(): + wipe() + self.do([PYTHON, EMCC, '--clear-ports']) + try_delete(tag_file) + # if BINARYEN_ROOT is set, we don't build the port. Check we do built it if not + restore() + config = open(CONFIG_FILE).read() + config = config.replace('BINARYEN_ROOT', '#') + open(CONFIG_FILE, 'w').write(config) + + print 'build using embuilder' + prep() subprocess.check_call([PYTHON, 'embuilder.py', 'build', 'binaryen']) assert os.path.exists(tag_file) subprocess.check_call([PYTHON, 'emcc.py', 'tests/hello_world.c', '-s', 'BINARYEN=1']) self.assertContained('hello, world!', run_js('a.out.js')) + + print 'see if building with emmake works (should not break native compilation of binaryen port' + prep() + subprocess.check_call([PYTHON, 'emmake.py', EMCC, 'tests/hello_world.c', '-s', 'BINARYEN=1']) + assert os.path.exists(tag_file) + self.assertContained('hello, world!', run_js('a.out.js')) + diff --git a/tools/shared.py b/tools/shared.py index a0b26e9de7749..173de2ef9e479 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1183,6 +1183,13 @@ def get_building_env(native=False): env['CXX'] = CLANG_CPP env['LD'] = CLANG env['CFLAGS'] = '-O2 -fno-math-errno' + # get a non-native one, and see if we have some of its effects - remove them if so + non_native = Building.get_building_env() + # the ones that a non-native would modify + EMSCRIPTEN_MODIFIES = ['LDSHARED', 'AR', 'CROSS_COMPILE', 'NM', 'RANLIB'] + for dangerous in EMSCRIPTEN_MODIFIES: + if env.get(dangerous) and env.get(dangerous) == non_native.get(dangerous): + del env[dangerous] # better to delete it than leave it, as the non-native one is definitely wrong return env env['CC'] = EMCC if not WINDOWS else 'python %r' % EMCC env['CXX'] = EMXX if not WINDOWS else 'python %r' % EMXX diff --git a/tools/system_libs.py b/tools/system_libs.py index ea8cfc847cac7..c6993f162aad4 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -584,6 +584,7 @@ def clear_project_build(name): @staticmethod def build_native(subdir): old = os.getcwd() + env = shared.Building.get_building_env(native=True) try: os.chdir(subdir) @@ -591,7 +592,7 @@ def build_native(subdir): cmake_build_type = 'Release' # Configure - subprocess.check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + cmake_build_type, '.']) + subprocess.check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + cmake_build_type, '.'], env=env) # Check which CMake generator CMake used so we know which form to pass parameters to make/msbuild/etc. build tool. generator = re.search('CMAKE_GENERATOR:INTERNAL=(.*)$', open('CMakeCache.txt', 'r').read(), re.MULTILINE).group(1) @@ -603,7 +604,7 @@ def build_native(subdir): elif 'Visual Studio' in generator: make_args = ['--config', cmake_build_type, '--', '/maxcpucount:' + num_cores] # Kick off the build. - subprocess.check_call(['cmake', '--build', '.'] + make_args) + subprocess.check_call(['cmake', '--build', '.'] + make_args, env=env) finally: os.chdir(old) From 37d75b4fb0c105d376073c431540895b95a25c06 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Nov 2016 19:02:04 -0700 Subject: [PATCH 03/86] Use binaryen --mem-base option (#4692) * use binaryen --mem-base option * update binaryen tag --- emcc.py | 2 ++ tools/ports/binaryen.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index 34db10bde587a..a728078a68dd1 100755 --- a/emcc.py +++ b/emcc.py @@ -2021,6 +2021,8 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati import_mem_init = memory_init_file and os.path.exists(memfile) and 'asmjs' not in shared.Settings.BINARYEN_METHOD and 'interpret-asm2wasm' not in shared.Settings.BINARYEN_METHOD if import_mem_init: cmd += ['--mem-init=' + memfile] + if not shared.Settings.RELOCATABLE: + cmd += ['--mem-base=' + str(shared.Settings.GLOBAL_BASE)] if shared.Building.is_wasm_only(): cmd += ['--wasm-only'] # this asm.js is code not intended to run as asm.js, it is only ever going to be wasm, an can contain special fastcomp-wasm support logging.debug('asm2wasm (asm.js => WebAssembly): ' + ' '.join(cmd)) diff --git a/tools/ports/binaryen.py b/tools/ports/binaryen.py index 5f29d8e9504e6..cf27151a35fae 100644 --- a/tools/ports/binaryen.py +++ b/tools/ports/binaryen.py @@ -1,6 +1,6 @@ import os, shutil, logging -TAG = 'version_18' +TAG = 'version_19' def needed(settings, shared, ports): if not settings.BINARYEN: return False From 63d2fb3e4f8604440dce662ceeaf63189568f794 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Mon, 7 Nov 2016 00:06:28 +0100 Subject: [PATCH 04/86] Add support for llvm.cos.f(32|64) intrinsics --- src/library.js | 2 ++ tests/core/test_llvm_intrinsics.c | 4 ++++ tests/core/test_llvm_intrinsics.out | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/library.js b/src/library.js index 499097fb603db..5f7475737f050 100644 --- a/src/library.js +++ b/src/library.js @@ -1476,6 +1476,8 @@ LibraryManager.library = { llvm_log_f64: 'Math_log', llvm_exp_f32: 'Math_exp', llvm_exp_f64: 'Math_exp', + llvm_cos_f32: 'Math_cos', + llvm_cos_f64: 'Math_cos', llvm_sin_f32: 'Math_sin', llvm_sin_f64: 'Math_sin', llvm_trunc_f32: 'Math_trunc', diff --git a/tests/core/test_llvm_intrinsics.c b/tests/core/test_llvm_intrinsics.c index 3f847208e99f0..7f3859ae4251b 100644 --- a/tests/core/test_llvm_intrinsics.c +++ b/tests/core/test_llvm_intrinsics.c @@ -19,6 +19,8 @@ extern float llvm_trunc_f32(float x); extern double llvm_trunc_f64(double x); extern float llvm_floor_f32(float x); extern double llvm_floor_f64(double x); +extern float llvm_cos_f32(float x); +extern double llvm_cos_f64(double x); extern float llvm_sin_f32(float x); extern double llvm_sin_f64(double x); extern float llvm_exp2_f32(float x); @@ -83,6 +85,8 @@ int main(void) { printf("%d\n", (int)llvm_trunc_f64(-12.42)); printf("%d\n", (int)llvm_floor_f32(27.665f)); printf("%d\n", (int)llvm_floor_f64(-8.95)); + printf("%.1f\n", llvm_cos_f32(0.0f * 3.14/180)); + printf("%.1f\n", llvm_cos_f64(180.0 * 3.14/180)); printf("%.1f\n", llvm_sin_f32(90.0f * 3.14/180)); printf("%.1f\n", llvm_sin_f64(270.0 * 3.14/180)); diff --git a/tests/core/test_llvm_intrinsics.out b/tests/core/test_llvm_intrinsics.out index da7d57744a42f..2438218a9c31c 100644 --- a/tests/core/test_llvm_intrinsics.out +++ b/tests/core/test_llvm_intrinsics.out @@ -27,6 +27,8 @@ llvm_expect_i32: -9 1.0 -1.0 +1.0 +-1.0 exp2_f32 8.0 exp2_f64 22.6 log2_f32 4.0 From 14bbeeba72457b20cc8cf27f3f05b3d5bc3ae40e Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Mon, 7 Nov 2016 00:32:02 +0100 Subject: [PATCH 05/86] Add support for llvm.ceil.f(32|64) intrinsics --- AUTHORS | 2 +- src/library.js | 2 ++ tests/core/test_llvm_intrinsics.c | 19 ++++++++++++++++--- tests/core/test_llvm_intrinsics.out | 12 ++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index ee229f60ad85b..a6bf010d5d89b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -264,4 +264,4 @@ a license to everyone to use it as detailed in LICENSE.) * Kagami Sascha Rosylight * Benny Jacobs * Ray Brown - +* Christopher Serr diff --git a/src/library.js b/src/library.js index 499097fb603db..b41fbeeee18d9 100644 --- a/src/library.js +++ b/src/library.js @@ -1480,6 +1480,8 @@ LibraryManager.library = { llvm_sin_f64: 'Math_sin', llvm_trunc_f32: 'Math_trunc', llvm_trunc_f64: 'Math_trunc', + llvm_ceil_f32: 'Math_ceil', + llvm_ceil_f64: 'Math_ceil', llvm_floor_f32: 'Math_floor', llvm_floor_f64: 'Math_floor', llvm_round_f32: 'Math_round', diff --git a/tests/core/test_llvm_intrinsics.c b/tests/core/test_llvm_intrinsics.c index 3f847208e99f0..e74481c91dfaf 100644 --- a/tests/core/test_llvm_intrinsics.c +++ b/tests/core/test_llvm_intrinsics.c @@ -17,6 +17,8 @@ extern float llvm_powi_f32(float x, int32_t y); extern double llvm_powi_f64(double x, int32_t y); extern float llvm_trunc_f32(float x); extern double llvm_trunc_f64(double x); +extern float llvm_ceil_f32(float x); +extern double llvm_ceil_f64(double x); extern float llvm_floor_f32(float x); extern double llvm_floor_f64(double x); extern float llvm_sin_f32(float x); @@ -28,9 +30,6 @@ extern double llvm_log2_f64(double x); extern float llvm_log10_f32(float x); extern double llvm_log10_f64(double x); -extern double llvm_ceil_f64(double x); -extern double llvm_floor_f64(double x); - extern float llvm_copysign_f32(float x, float y); extern double llvm_copysign_f64(double x, double y); @@ -93,6 +92,13 @@ int main(void) { printf("log10_f32 %.1f\n", llvm_log10_f32(1000)); printf("log10_f64 %.1f\n", llvm_log10_f64(2000)); + printf("llvm_ceil_f32 %.1f\n", llvm_ceil_f32(1.4f)); + printf("llvm_ceil_f32 %.1f\n", llvm_ceil_f32(1.5f)); + printf("llvm_ceil_f32 %.1f\n", llvm_ceil_f32(1.6f)); + printf("llvm_ceil_f32 %.1f\n", llvm_ceil_f32(-1.4f)); + printf("llvm_ceil_f32 %.1f\n", llvm_ceil_f32(-1.5f)); + printf("llvm_ceil_f32 %.1f\n", llvm_ceil_f32(-1.6f)); + printf("llvm_ceil_f64 %.1f\n", llvm_ceil_f64(1.4)); printf("llvm_ceil_f64 %.1f\n", llvm_ceil_f64(1.5)); printf("llvm_ceil_f64 %.1f\n", llvm_ceil_f64(1.6)); @@ -100,6 +106,13 @@ int main(void) { printf("llvm_ceil_f64 %.1f\n", llvm_ceil_f64(-1.5)); printf("llvm_ceil_f64 %.1f\n", llvm_ceil_f64(-1.6)); + printf("llvm_floor_f32 %.1f\n", llvm_floor_f32(1.4f)); + printf("llvm_floor_f32 %.1f\n", llvm_floor_f32(1.5f)); + printf("llvm_floor_f32 %.1f\n", llvm_floor_f32(1.6f)); + printf("llvm_floor_f32 %.1f\n", llvm_floor_f32(-1.4f)); + printf("llvm_floor_f32 %.1f\n", llvm_floor_f32(-1.5f)); + printf("llvm_floor_f32 %.1f\n", llvm_floor_f32(-1.6f)); + printf("llvm_floor_f64 %.1f\n", llvm_floor_f64(1.4)); printf("llvm_floor_f64 %.1f\n", llvm_floor_f64(1.5)); printf("llvm_floor_f64 %.1f\n", llvm_floor_f64(1.6)); diff --git a/tests/core/test_llvm_intrinsics.out b/tests/core/test_llvm_intrinsics.out index da7d57744a42f..afe4f45e389e5 100644 --- a/tests/core/test_llvm_intrinsics.out +++ b/tests/core/test_llvm_intrinsics.out @@ -33,12 +33,24 @@ log2_f32 4.0 log2_f64 4.3 log10_f32 3.0 log10_f64 3.3 +llvm_ceil_f32 2.0 +llvm_ceil_f32 2.0 +llvm_ceil_f32 2.0 +llvm_ceil_f32 -1.0 +llvm_ceil_f32 -1.0 +llvm_ceil_f32 -1.0 llvm_ceil_f64 2.0 llvm_ceil_f64 2.0 llvm_ceil_f64 2.0 llvm_ceil_f64 -1.0 llvm_ceil_f64 -1.0 llvm_ceil_f64 -1.0 +llvm_floor_f32 1.0 +llvm_floor_f32 1.0 +llvm_floor_f32 1.0 +llvm_floor_f32 -2.0 +llvm_floor_f32 -2.0 +llvm_floor_f32 -2.0 llvm_floor_f64 1.0 llvm_floor_f64 1.0 llvm_floor_f64 1.0 From e329b47f0963ad97f2448eb89b001b018b91543c Mon Sep 17 00:00:00 2001 From: Guillaume Blanc Date: Mon, 7 Nov 2016 23:09:59 +0100 Subject: [PATCH 06/86] Fixes #4317, GLFW mouse buttons mapping. (#4659) * Fixes GLFW mouse buttons mapping. The mapping was actually done in onMouseButtonChanged, but not on onMouseButtonDown and onMouseButtonUp. * Fixes #4317, Adds GLFW mouse buttons unit tests. * GLFW mouse buttons refactoring. * Integrates glfwGetMouseButton unit tests to existing glfw_event.c file. * Removes unused glfw3_events.c file which was replaced by the generic glfw_events.c. * Fixes glfw_events unit tests which now differentiates mouse and keyboard tests. * Fixes glfw2 arrow key mappings. --- src/library_glfw.js | 39 ++++++----- tests/glfw3_events.c | 150 ------------------------------------------ tests/glfw_events.c | 67 ++++++++++++++----- tests/test_browser.py | 2 +- 4 files changed, 74 insertions(+), 184 deletions(-) delete mode 100644 tests/glfw3_events.c diff --git a/src/library_glfw.js b/src/library_glfw.js index 42a3a48239818..cb234d8d05fce 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -208,10 +208,10 @@ var LibraryGLFW = { case 0x86:return (256+24); // DOM_VK_F23 -> GLFW_KEY_F23 case 0x87:return (256+25); // DOM_VK_F24 -> GLFW_KEY_F24 case 0x88:return (256+26); // 0x88 (not used?) -> GLFW_KEY_F25 - case 0x27:return (256+27); // DOM_VK_RIGHT -> GLFW_KEY_RIGHT - case 0x25:return (256+28); // DOM_VK_LEFT -> GLFW_KEY_LEFT - case 0x28:return (256+29); // DOM_VK_DOWN -> GLFW_KEY_DOWN - case 0x26:return (256+30); // DOM_VK_UP -> GLFW_KEY_UP + case 0x27:return (256+30); // DOM_VK_RIGHT -> GLFW_KEY_RIGHT + case 0x25:return (256+29); // DOM_VK_LEFT -> GLFW_KEY_LEFT + case 0x28:return (256+28); // DOM_VK_DOWN -> GLFW_KEY_DOWN + case 0x26:return (256+27); // DOM_VK_UP -> GLFW_KEY_UP case 0x10:return (256+31); // DOM_VK_SHIFT -> GLFW_KEY_LSHIFT // #define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32) case 0x11:return (256+33); // DOM_VK_CONTROL -> GLFW_KEY_LCTRL @@ -408,6 +408,20 @@ var LibraryGLFW = { #endif }, + DOMToGLFWMouseButton: function(event) { + // DOM and glfw have different button codes. + // See http://www.w3schools.com/jsref/event_button.asp. + var eventButton = event['button']; + if (eventButton > 0) { + if (eventButton == 1) { + eventButton = 2; + } else { + eventButton = 1; + } + } + return eventButton; + }, + onMouseenter: function(event) { if (!GLFW.active) return; @@ -435,20 +449,15 @@ var LibraryGLFW = { if (event.target != Module["canvas"]) return; + eventButton = GLFW.DOMToGLFWMouseButton(event); + if (status == 1) { // GLFW_PRESS + GLFW.active.buttons |= (1 << eventButton); try { event.target.setCapture(); } catch (e) {} - } - - // DOM and glfw have different button codes - var eventButton = event['button']; - if (eventButton > 0) { - if (eventButton == 1) { - eventButton = 2; - } else { - eventButton = 1; - } + } else { // GLFW_RELEASE + GLFW.active.buttons &= ~(1 << eventButton); } #if USE_GLFW == 2 @@ -462,13 +471,11 @@ var LibraryGLFW = { onMouseButtonDown: function(event) { if (!GLFW.active) return; - GLFW.active.buttons |= (1 << event['button']); GLFW.onMouseButtonChanged(event, 1); // GLFW_PRESS }, onMouseButtonUp: function(event) { if (!GLFW.active) return; - GLFW.active.buttons &= ~(1 << event['button']); GLFW.onMouseButtonChanged(event, 0); // GLFW_RELEASE }, diff --git a/tests/glfw3_events.c b/tests/glfw3_events.c deleted file mode 100644 index 48efab8553d90..0000000000000 --- a/tests/glfw3_events.c +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include - -#define MULTILINE(...) #__VA_ARGS__ -#define WIDTH 640 -#define HEIGHT 480 - -// Setup tests -typedef struct { - double x, y; - int button; - int action; - int modify; -} test_args_t; - -typedef struct { - char cmd[80]; - test_args_t args; -} test_t; - -// Javascript event.button 0 = left, 1 = middle, 2 = right -test_t g_tests[] = { - { "Module.injectMouseEvent(10.0, 10.0, 'mousedown', 0)", { 10.0, 10.0, GLFW_MOUSE_BUTTON_1, GLFW_PRESS, -1 } }, - { "Module.injectMouseEvent(10.0, 20.0, 'mouseup', 0)", { 10.0, 20.0, GLFW_MOUSE_BUTTON_1, GLFW_RELEASE, -1 } }, - { "Module.injectMouseEvent(10.0, 30.0, 'mousedown', 2)", { 10.0, 30.0, GLFW_MOUSE_BUTTON_2, GLFW_PRESS, -1 } }, - { "Module.injectMouseEvent(10.0, 40.0, 'mouseup', 2)", { 10.0, 40.0, GLFW_MOUSE_BUTTON_2, GLFW_RELEASE, -1 } }, - //{ "Module.injectMouseEvent(10.0, 50.0, 'mousewheel', 0)", { 10.0, 50.0, -1, -1, -1 } }, - //{ "Module.injectMouseEvent(10.0, 60.0, 'mousemove', 0)", { 10.0, 60.0, -1, -1, -1 } } - { "keydown(32)", { 0, 0, GLFW_KEY_SPACE, GLFW_PRESS, -1 } }, - { "keyup(32)", { 0, 0, GLFW_KEY_SPACE, GLFW_RELEASE, -1 } }, - { "keydown(32)", { 0, 0, GLFW_KEY_SPACE, GLFW_PRESS, -1 } }, - { "keydown(32)", { 0, 0, GLFW_KEY_SPACE, GLFW_REPEAT, -1 } }, - { "keydown(32)", { 0, 0, GLFW_KEY_SPACE, GLFW_REPEAT, -1 } }, - { "keyup(32)", { 0, 0, GLFW_KEY_SPACE, GLFW_RELEASE, -1 } }, -}; - -static unsigned int g_test_actual = 0; -static unsigned int g_test_count = sizeof(g_tests) / sizeof(test_t); -static unsigned int g_state = 0; - -static void on_mouse_callback(GLFWwindow* window, int button, int action, int modify) -{ - test_args_t args = g_tests[g_test_actual].args; - if (args.button == button && args.action == action) - { - printf("Test on_mouse_callback: OK\n"); - g_state |= 1 << g_test_actual; - } - else - { - printf("Test %d: FAIL\n", g_test_actual); - } -} - -static void on_mouse_move(GLFWwindow* window, double x, double y) -{ - test_args_t args = g_tests[g_test_actual].args; - if (args.x == x && args.y == y) - { - printf("Test on_mouse_move: OK\n"); - g_state |= 1 << g_test_actual; - } - else - { - printf("Test %d: FAIL\n", g_test_actual); - } -} - -static void on_mouse_wheel(GLFWwindow* window, double x, double y) -{ - test_args_t args = g_tests[g_test_actual].args; - if (args.x == x && args.y == y) - { - printf("Test on_mouse_wheel: OK\n"); - g_state |= 1 << g_test_actual; - } - else - { - printf("Test %d: FAIL\n", g_test_actual); - } -} - -static void on_key_action(GLFWwindow* window, int key, int scancode, int action, int mods) -{ - test_args_t args = g_tests[g_test_actual].args; - if (args.button == key && args.action == action) - { - printf("Test on_key_action: OK\n"); - g_state |= 1 << g_test_actual; - } - else - { - printf("Test %d: FAIL\n", g_test_actual); - } -} - -static void on_error(int error, const char *msg) -{ - printf("%d: %s\n", error, msg); -} - -int main() -{ - GLFWwindow * _mainWindow = NULL; - int result = 0; - unsigned int success = 0; - - emscripten_run_script(MULTILINE( - Module.injectMouseEvent = function(x, y, event_, button) { - var event = document.createEvent("MouseEvents"); - var canvas = Module['canvas']; - event.initMouseEvent(event_, true, true, window, 0, canvas.offsetLeft + x, canvas.offsetTop + y, canvas.offsetLeft + x, canvas.offsetTop + y, 0, 0, 0, 0, button, null); - canvas.dispatchEvent(event); - } - )); - - glfwSetErrorCallback(on_error); - glfwInit(); - printf("%s\n", glfwGetVersionString()); - - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - _mainWindow = glfwCreateWindow(WIDTH, HEIGHT, "glfw3_events", NULL, NULL); - glfwMakeContextCurrent(_mainWindow); - - glfwSetMouseButtonCallback(_mainWindow, on_mouse_callback); - glfwSetCursorPosCallback(_mainWindow, on_mouse_move); - glfwSetScrollCallback(_mainWindow, on_mouse_wheel); - glfwSetKeyCallback(_mainWindow, on_key_action); - //glfwSetCharCallback(_mainWindow, ...); - - for (int i = 0; i < g_test_count; ++i) - { - g_test_actual = i; - emscripten_run_script(g_tests[g_test_actual].cmd); - } - - glfwTerminate(); - - success = (1 << (sizeof(g_tests) / sizeof(test_t))) - 1; // (2^count)-1 - -#ifdef REPORT_RESULT - result = g_state == success; - REPORT_RESULT(); -#else - printf("%d == %d = %d", g_state, success, g_state == success); -#endif - - return 0; -} diff --git a/tests/glfw_events.c b/tests/glfw_events.c index 4b8fea11b6caa..96928ed2d71d4 100644 --- a/tests/glfw_events.c +++ b/tests/glfw_events.c @@ -13,6 +13,7 @@ // Setup tests typedef struct { + int mouse; double x, y; int button; int action; @@ -26,22 +27,32 @@ // Javascript event.button 0 = left, 1 = middle, 2 = right test_t g_tests[] = { - { "Module.injectMouseEvent(10.0, 10.0, 'mousedown', 0)", { 10.0, 10.0, GLFW_MOUSE_BUTTON_1, GLFW_PRESS, -1 } }, - { "Module.injectMouseEvent(10.0, 20.0, 'mouseup', 0)", { 10.0, 20.0, GLFW_MOUSE_BUTTON_1, GLFW_RELEASE, -1 } }, - { "Module.injectMouseEvent(10.0, 30.0, 'mousedown', 2)", { 10.0, 30.0, GLFW_MOUSE_BUTTON_2, GLFW_PRESS, -1 } }, - { "Module.injectMouseEvent(10.0, 40.0, 'mouseup', 2)", { 10.0, 40.0, GLFW_MOUSE_BUTTON_2, GLFW_RELEASE, -1 } }, + { "Module.injectMouseEvent(10.0, 10.0, 'mousedown', 0)", { 1, 10.0, 10.0, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, -1 } }, + { "Module.injectMouseEvent(10.0, 20.0, 'mouseup', 0)", { 1, 10.0, 20.0, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, -1 } }, + { "Module.injectMouseEvent(10.0, 30.0, 'mousedown', 1)", { 1, 10.0, 30.0, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, -1 } }, + { "Module.injectMouseEvent(10.0, 40.0, 'mouseup', 1)", { 1, 10.0, 40.0, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, -1 } }, + { "Module.injectMouseEvent(10.0, 30.0, 'mousedown', 2)", { 1, 10.0, 30.0, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, -1 } }, + { "Module.injectMouseEvent(10.0, 40.0, 'mouseup', 2)", { 1, 10.0, 40.0, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, -1 } }, //{ "Module.injectMouseEvent(10.0, 50.0, 'mousewheel', 0)", { 10.0, 50.0, -1, -1, -1 } }, //{ "Module.injectMouseEvent(10.0, 60.0, 'mousemove', 0)", { 10.0, 60.0, -1, -1, -1 } } - { "Module.injectKeyEvent('keydown', 0x08)", { 0.0, 0.0, GLFW_KEY_BACKSPACE, GLFW_PRESS, -1 } }, - { "Module.injectKeyEvent('keyup', 0x08)", { 0.0, 0.0, GLFW_KEY_BACKSPACE, GLFW_RELEASE, -1 } }, - { "Module.injectKeyEvent('keydown', 0x09)", { 0.0, 0.0, GLFW_KEY_TAB, GLFW_PRESS, -1 } }, - { "Module.injectKeyEvent('keydown', 0x70)", { 0.0, 0.0, GLFW_KEY_F1, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keydown', 8)", { 0, 0.0, 0.0, GLFW_KEY_BACKSPACE, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 8)", { 0, 0.0, 0.0, GLFW_KEY_BACKSPACE, GLFW_RELEASE, -1 } }, + { "Module.injectKeyEvent('keydown', 9)", { 0, 0.0, 0.0, GLFW_KEY_TAB, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keydown', 112)", { 0, 0.0, 0.0, GLFW_KEY_F1, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keydown', 37)", { 0, 0.0, 0.0, GLFW_KEY_LEFT, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 37)", { 0, 0.0, 0.0, GLFW_KEY_LEFT, GLFW_RELEASE, -1 } }, + { "Module.injectKeyEvent('keydown', 39)", { 0, 0.0, 0.0, GLFW_KEY_RIGHT, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 39)", { 0, 0.0, 0.0, GLFW_KEY_RIGHT, GLFW_RELEASE, -1 } }, + { "Module.injectKeyEvent('keydown', 38)", { 0, 0.0, 0.0, GLFW_KEY_UP, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 38)", { 0, 0.0, 0.0, GLFW_KEY_UP, GLFW_RELEASE, -1 } }, + { "Module.injectKeyEvent('keydown', 40)", { 0, 0.0, 0.0, GLFW_KEY_DOWN, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 40)", { 0, 0.0, 0.0, GLFW_KEY_DOWN, GLFW_RELEASE, -1 } }, #if USE_GLFW == 2 - { "Module.injectKeyEvent('keydown', 0x1B)", { 0.0, 0.0, GLFW_KEY_ESC, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keydown', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESC, GLFW_PRESS, -1 } }, #else - { "Module.injectKeyEvent('keydown', 0x1B)", { 0.0, 0.0, GLFW_KEY_ESCAPE, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keydown', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESCAPE, GLFW_PRESS, -1 } }, #endif }; @@ -50,9 +61,9 @@ static unsigned int g_state = 0; #if USE_GLFW == 2 - static void on_mouse_button_vallback(int button, int action) + static void on_mouse_button_callback(int button, int action) #else - static void on_mouse_button_vallback(GLFWwindow* window, int button, int action, int modify) + static void on_mouse_button_callback(GLFWwindow* window, int button, int action, int modify) #endif { test_args_t args = g_tests[g_test_actual].args; @@ -153,16 +164,14 @@ canvas.dispatchEvent(keyboardEvent); }; )); - glfwInit(); - #if USE_GLFW == 2 glfwOpenWindow(WIDTH, HEIGHT, 5, 6, 5, 0, 0, 0, GLFW_WINDOW); // != GL_TRUE) glfwSetMousePosCallback(on_mouse_move); - glfwSetMouseButtonCallback(on_mouse_button_vallback); + glfwSetMouseButtonCallback(on_mouse_button_callback); glfwSetKeyCallback(on_key_callback); //glfwSetCharCallback(...); #else @@ -174,7 +183,7 @@ _mainWindow = glfwCreateWindow(WIDTH, HEIGHT, "glfw3_events", NULL, NULL); glfwMakeContextCurrent(_mainWindow); - glfwSetMouseButtonCallback(_mainWindow, on_mouse_button_vallback); + glfwSetMouseButtonCallback(_mainWindow, on_mouse_button_callback); glfwSetCursorPosCallback(_mainWindow, on_mouse_move); glfwSetScrollCallback(_mainWindow, on_mouse_wheel); glfwSetKeyCallback(_mainWindow, on_key_callback); @@ -184,7 +193,31 @@ for (int i = 0; i < g_test_count; ++i) { g_test_actual = i; - emscripten_run_script(g_tests[g_test_actual].cmd); + test_t test = g_tests[g_test_actual]; + emscripten_run_script(test.cmd); + + if (test.args.mouse) { + #if USE_GLFW == 2 + if (glfwGetMouseButton(test.args.button) != test.args.action) + #else + if (glfwGetMouseButton(_mainWindow, test.args.button) != test.args.action) + #endif + { + printf("Test %d: FAIL\n", g_test_actual); + g_state &= ~(1 << g_test_actual); + } + } else { + // Keyboard. + #if USE_GLFW == 2 + if (glfwGetKey(test.args.button) != test.args.action) + #else + if (glfwGetKey(_mainWindow, test.args.button) != test.args.action) + #endif + { + printf("Test %d: FAIL\n", g_test_actual); + g_state &= ~(1 << g_test_actual); + } + } } glfwTerminate(); diff --git a/tests/test_browser.py b/tests/test_browser.py index 8f063b8387d16..4e00a91feff59 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1333,7 +1333,7 @@ def test_glfw(self): def test_glfw_minimal(self): self.btest('glfw_minimal.c', '1', args=[]) self.btest('glfw_minimal.c', '1', args=['-s', 'USE_GLFW=2']) - + def test_egl(self): open(os.path.join(self.get_dir(), 'test_egl.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl.c')).read())) From 0d1e32c4be537bf938ab24813c138eabb9f29238 Mon Sep 17 00:00:00 2001 From: russa Date: Tue, 8 Nov 2016 11:29:42 +0100 Subject: [PATCH 07/86] explicitly enforce binary reading mode in file2json.py, fixing #4688 in order to avoid premature end of reading (can occur or Windows when binary mode is not explictly set) --- tools/file2json.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/file2json.py b/tools/file2json.py index f26f28645973a..06770e7a9166a 100644 --- a/tools/file2json.py +++ b/tools/file2json.py @@ -12,7 +12,7 @@ import os, sys -data = open(sys.argv[1], 'r').read() +data = open(sys.argv[1], 'rb').read() sdata = map(lambda x: str(ord(x)) + ',', data) sdata[-1] = sdata[-1].replace(',', '') lined = [] @@ -31,7 +31,7 @@ ''' or (but this fails, we get a string at runtime?) -data = open(sys.argv[1], 'r').read() +data = open(sys.argv[1], 'rb').read() counter = 0 print '[', for i in range(len(data)): From 6c22952045691e94041bff838e6d20d3f9c9654e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 8 Nov 2016 16:00:09 +0200 Subject: [PATCH 08/86] When canOwn=true is passed to MEMFS write functions, a view can be passed in that only addresses a subportion of the underlying ArrayBuffer. Define the semantics of that scenario to mean that only the bytes pointed to by the subview can be taken ownership of, and not the bytes outside the view. (Previously passing a view to a subportion of an ArrayBuffer would throw an exception when later appending to it. --- src/library_memfs.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/library_memfs.js b/src/library_memfs.js index 249db2951d462..5b1cd2f28d029 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -67,7 +67,7 @@ mergeInto(LibraryManager.library, { } else if (FS.isFile(node.mode)) { node.node_ops = MEMFS.ops_table.file.node; node.stream_ops = MEMFS.ops_table.file.stream; - node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.buffer.byteLength which gives the whole capacity. + node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. @@ -119,7 +119,7 @@ mergeInto(LibraryManager.library, { #endif if (!node.contents || node.contents.subarray) { // Keep using a typed array if creating a new storage, or if old one was a typed array as well. - var prevCapacity = node.contents ? node.contents.buffer.byteLength : 0; + var prevCapacity = node.contents ? node.contents.length : 0; if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough. // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to @@ -274,6 +274,9 @@ mergeInto(LibraryManager.library, { }, // Writes the byte range (buffer[offset], buffer[offset+length]) to offset 'position' into the file pointed by 'stream' + // canOwn: A boolean that tells if this function can take ownership of the passed in buffer from the subbuffer portion + // that the typed array view 'buffer' points to. The underlying ArrayBuffer can be larger than that, but + // canOwn=true will not take ownership of the portion outside the bytes addressed by the view. write: function(stream, buffer, offset, length, position, canOwn) { if (!length) return 0; var node = stream.node; From 7122dd8e6ea1630e25bf5480992882300dd66149 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 8 Nov 2016 15:21:13 -0800 Subject: [PATCH 09/86] check js engines in jsrun only if they fail ; followup for #4608 --- tools/jsrun.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tools/jsrun.py b/tools/jsrun.py index 1ca4db96155de..b746c12e69156 100644 --- a/tools/jsrun.py +++ b/tools/jsrun.py @@ -84,8 +84,6 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo # commands += os.path.basename(curr) + ',' + json.dumps(args) + '\n' # open(commands_file, 'w').write(commands) - if not skip_check: - require_engine(engine) command = make_command(filename, engine, args) try: if cwd is not None: os.environ['EMCC_BUILD_DIR'] = os.getcwd() @@ -95,16 +93,31 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo stdout=stdout, stderr=stderr, cwd=cwd) + except Exception, e: + # the failure may be because the engine is not present. show the proper + # error in that case + if not skip_check: + require_engine(engine) + # if we got here, then require_engine succeeded, so we can raise the original error + raise e finally: if cwd is not None: del os.environ['EMCC_BUILD_DIR'] timeout = 15*60 if check_timeout else None if TRACK_PROCESS_SPAWNS: logging.info('Blocking on process ' + str(proc.pid) + ': ' + str(command) + (' for ' + str(timeout) + ' seconds' if timeout else ' until it finishes.')) - ret = timeout_run( - proc, - timeout, - 'Execution', - full_output=full_output) + try: + ret = timeout_run( + proc, + timeout, + 'Execution', + full_output=full_output) + except Exception, e: + # the failure may be because the engine does not work. show the proper + # error in that case + if not skip_check: + require_engine(engine) + # if we got here, then require_engine succeeded, so we can raise the original error + raise e if assert_returncode is not None and proc.returncode is not assert_returncode: raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)[:error_limit]) return ret From f1b6667eeca0a73653189d6a44946a5d53a03955 Mon Sep 17 00:00:00 2001 From: russa Date: Wed, 9 Nov 2016 17:09:27 +0100 Subject: [PATCH 10/86] added name to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index c17ac199be99e..0a02ae2f47822 100644 --- a/AUTHORS +++ b/AUTHORS @@ -237,3 +237,4 @@ a license to everyone to use it as detailed in LICENSE.) * Charles Vaughn (copyright owned by Tableau Software, Inc.) * Pierre Krieger * Jakob Stoklund Olesen +* Aaron Ruß (copyright owned by DFKI GmbH) From 17dd2cd2e1d59e2b927c975ccbf30db90bb14961 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 9 Nov 2016 13:27:56 -0800 Subject: [PATCH 11/86] add a test for symbol map demangling --- tests/test_core.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_core.py b/tests/test_core.py index efa32228bcb87..cd4759916fc84 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6122,6 +6122,30 @@ def test_demangle_stacks(self): self.do_run_in_out_file_test('tests', 'core', 'test_demangle_stacks') + @no_emterpreter + @no_wasm_backend() + def test_demangle_stacks_symbol_map(self): + Settings.DEMANGLE_SUPPORT = 1 + if '-O' in str(self.emcc_args): + self.emcc_args += ['--llvm-opts', '0'] + self.emcc_args += ['--emit-symbol-map'] + self.do_run(open(path_from_root('tests', 'core', 'test_demangle_stacks.c')).read(), 'abort') + # make sure the shortened name is the right one + symbols = open('src.cpp.o.js.symbols').read().split(os.linesep) + for line in symbols: + if ':' not in line: continue + short, full = line.split(':') + if 'Aborter' in full: + short_aborter = short + full_aborter = full + if SPIDERMONKEY_ENGINE and os.path.exists(SPIDERMONKEY_ENGINE[0]): + output = run_js('src.cpp.o.js', engine=SPIDERMONKEY_ENGINE, stderr=PIPE, full_output=True, assert_returncode=None) + # we may see the full one, if -g, or the short one if not + if ' ' + short_aborter + ' ' not in output and ' ' + full_aborter + ' ' not in output: + # stack traces may also be ' name ' or 'name@' etc + if '\n' + short_aborter + ' ' not in output and '\n' + full_aborter + ' ' not in output and 'wasm-function[' + short_aborter + ']' not in output: + self.assertContained(' ' + short_aborter + ' ' + '\n' + ' ' + full_aborter + ' ', output) + def test_tracing(self): Building.COMPILER_TEST_OPTS += ['--tracing'] From 6936cdea6bed705f0d3343acac2bff7cab95f865 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 9 Nov 2016 12:04:28 -0800 Subject: [PATCH 12/86] support --emit-symbol-map in wasm, and add testing --- emcc.py | 7 +++++-- tests/test_other.py | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/emcc.py b/emcc.py index a728078a68dd1..ff78c76516fe9 100755 --- a/emcc.py +++ b/emcc.py @@ -1732,7 +1732,7 @@ def run_passes(passes, title, just_split, just_concat): if shared.Settings.PRECISE_F32: passes = ['asmPreciseF32'] + passes if (emit_symbol_map or shared.Settings.CYBERDWARF) and 'minifyNames' in passes: - passes += ['symbolMap='+target+'.symbols'] + passes += ['symbolMap=' + target + '.symbols'] if profiling_funcs and 'minifyNames' in passes: passes += ['profilingFuncs'] if JSOptimizer.minify_whitespace and 'last' in passes: @@ -2040,7 +2040,10 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati subprocess.check_call(cmd) if 'native-wasm' in shared.Settings.BINARYEN_METHOD or 'interpret-binary' in shared.Settings.BINARYEN_METHOD: cmd = [os.path.join(binaryen_bin, 'wasm-as'), wasm_text_target, '-o', wasm_binary_target] - if debug_level >= 2 or profiling_funcs: cmd += ['-g'] + if debug_level >= 2 or profiling_funcs: + cmd += ['-g'] + if emit_symbol_map or shared.Settings.CYBERDWARF: + cmd += ['--symbolmap=' + target + '.symbols'] logging.debug('wasm-as (text => binary): ' + ' '.join(cmd)) subprocess.check_call(cmd) if shared.Settings.BINARYEN_SCRIPTS: diff --git a/tests/test_other.py b/tests/test_other.py index e538fc62d5b06..359e52dd9dabd 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -3168,16 +3168,18 @@ def test(src, nums): def test_symbol_map(self): for m in [0, 1]: - self.clear() - cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O2'] - if m: cmd += ['--emit-symbol-map'] - print cmd - stdout, stderr = Popen(cmd, stderr=PIPE).communicate() - assert ('''wrote symbol map file''' in stderr) == m, stderr - assert (os.path.exists('a.out.js.symbols') == m), stderr - if m: - symbols = open('a.out.js.symbols').read() - assert ':_main' in symbols + for wasm in [0, 1]: + print m, wasm + self.clear() + cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O2'] + if m: cmd += ['--emit-symbol-map'] + if wasm: cmd += ['-s', 'WASM=1'] + print cmd + stdout, stderr = Popen(cmd, stderr=PIPE).communicate() + assert (os.path.exists('a.out.js.symbols') == m), stderr + if m: + symbols = open('a.out.js.symbols').read() + assert ':_main' in symbols def test_bc_to_bc(self): # emcc should 'process' bitcode to bitcode. build systems can request this if From e28ab293b977e6b3106b048e318b678d84ede180 Mon Sep 17 00:00:00 2001 From: AlexPerrot Date: Thu, 10 Nov 2016 02:50:44 +0100 Subject: [PATCH 13/86] convert parameters to boolean in WebGL functions (#4703) --- src/library_gl.js | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/library_gl.js b/src/library_gl.js index 44793e9efebd7..708a3bd774c54 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -2979,7 +2979,7 @@ var LibraryGL = { view = new Float32Array(view); #endif } - GLctx.uniformMatrix2fv(location, transpose, view); + GLctx.uniformMatrix2fv(location, !!transpose, view); }, glUniformMatrix3fv__sig: 'viiii', @@ -3011,7 +3011,7 @@ var LibraryGL = { view = new Float32Array(view); #endif } - GLctx.uniformMatrix3fv(location, transpose, view); + GLctx.uniformMatrix3fv(location, !!transpose, view); }, glUniformMatrix4fv__sig: 'viiii', @@ -3050,7 +3050,7 @@ var LibraryGL = { view = new Float32Array(view); #endif } - GLctx.uniformMatrix4fv(location, transpose, view); + GLctx.uniformMatrix4fv(location, !!transpose, view); }, #if USE_WEBGL2 @@ -7256,7 +7256,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateVertexAttribPointer(size, type, stride, ptr); #endif - GLctx.vertexAttribPointer(index, size, type, normalized, stride, ptr); + GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); }, #if USE_WEBGL2 @@ -7459,6 +7459,23 @@ var LibraryGL = { glDrawBuffersEXT: 'glDrawBuffers', + // passthrough functions with GLboolean parameters + + glColorMask__sig: 'viiii', + glColorMask: function(red, green, blue, alpha) { + GLctx.colorMask(!!red, !!green, !!blue, !!alpha); + }, + + glDepthMask__sig: 'vi', + glDepthMask: function(flag) { + GLctx.depthMask(!!flag); + }, + + glSampleCoverage__sig: 'vii', + glSampleCoverage: function(value, invert) { + GLctx.sampleCoverage(value, !!invert); + }, + // signatures of simple pass-through functions, see later glActiveTexture__sig: 'vi', @@ -7478,12 +7495,10 @@ var LibraryGL = { glBlendFuncSeparate__sig: 'viiii', glBlendColor__sig: 'vffff', glPolygonOffset__sig: 'vii', - glColorMask__sig: 'viiii', glStencilOp__sig: 'viii', glStencilOpSeparate__sig: 'viiii', glGenerateMipmap__sig: 'vi', glHint__sig: 'vii', - glDepthMask__sig: 'vi', glViewport__sig: 'viiii', glDepthFunc__sig: 'vi', glStencilMask__sig: 'vi', @@ -7494,7 +7509,6 @@ var LibraryGL = { glClearColor__sig: 'viiii', glIsEnabled__sig: 'ii', glFrontFace__sig: 'vi', - glSampleCoverage__sig: 'vii', #if USE_WEBGL2 glVertexAttribI4i__sig: 'viiiii', glVertexAttribI4ui__sig: 'viiiii', @@ -7516,10 +7530,10 @@ var LibraryGL = { // Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name var glFuncs = [[0, 'finish flush'], - [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil depthMask stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation isEnabled*'], - [2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset vertexAttrib1f sampleCoverage'], + [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation isEnabled*'], + [2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset vertexAttrib1f'], [3, 'texParameteri texParameterf vertexAttrib2f stencilFunc stencilOp'], - [4, 'viewport clearColor scissor vertexAttrib3f colorMask renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'], + [4, 'viewport clearColor scissor vertexAttrib3f renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'], [5, 'vertexAttrib4f'], [6, ''], [7, ''], From d6d4e48c8ce5c1063f972977d5823c086a70e48e Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Thu, 10 Nov 2016 11:05:44 -0800 Subject: [PATCH 14/86] Explicitly add unix defines to clang args (#4718) Explicitly add unix defines to clang args for wasm backend, to match the asm.js backend. Fixes zlib test for wasm backend. --- tests/test_core.py | 1 - tools/shared.py | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index efa32228bcb87..e3676c72c91f8 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5327,7 +5327,6 @@ def test_sqlite(self): includes=[path_from_root('tests', 'sqlite')], force_c=True) - @no_wasm_backend() def test_zlib(self): if '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args and not self.is_wasm(): # without asm, closure minifies Math.imul badly self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage diff --git a/tools/shared.py b/tools/shared.py index 173de2ef9e479..15d619eea38bc 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -928,7 +928,10 @@ def get_llvm_target(): if LLVM_TARGET == WASM_TARGET: # wasm target does not automatically define emscripten stuff, so do it here. COMPILER_OPTS = COMPILER_OPTS + ['-DEMSCRIPTEN', - '-D__EMSCRIPTEN__'] + '-D__EMSCRIPTEN__', + '-Dunix', + '-D__unix', + '-D__unix__'] # Changes to default clang behavior From c0eb2d860077e952b37074e5c886563130482182 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 10 Nov 2016 13:53:28 -0800 Subject: [PATCH 15/86] add a test for warning+guidance on wasm memory size incompatibility issues --- tests/test_other.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_other.py b/tests/test_other.py index e538fc62d5b06..b30bcca010236 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6912,6 +6912,15 @@ def test_binaryen_names(self): print sizes assert sizes["['-O2']"] < sizes["['-O2', '--profiling-funcs']"], 'when -profiling-funcs, the size increases due to function names' + def test_binaryen_warn_mem(self): + if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey') + # if user changes TOTAL_MEMORY at runtime, the wasm module may not accept the memory import if it is too big/small + open('pre.js', 'w').write('var Module = { TOTAL_MEMORY: 50*1024*1024 };\n') + subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1', '-s', 'TOTAL_MEMORY=' + str(16*1024*1024), '--pre-js', 'pre.js']) + out = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, full_output=True, stderr=PIPE) + self.assertContained('imported Memory with incompatible size', out) + self.assertContained('Memory size incompatibility issues may be due to changing TOTAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set TOTAL_MEMORY at runtime to something smaller than it was at compile time).', out) + def test_wasm_targets(self): for f in ['a.wasm', 'a.wast']: process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-o', f], stdout=PIPE, stderr=PIPE) From 505cd44f8c4bc9330152880471bf71a0ee29ca36 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 10 Nov 2016 13:58:18 -0800 Subject: [PATCH 16/86] verify that memory growth does indeed avoid memory size incompatibility issues in wasm --- tests/test_other.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index b30bcca010236..988147d103413 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6916,10 +6916,14 @@ def test_binaryen_warn_mem(self): if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey') # if user changes TOTAL_MEMORY at runtime, the wasm module may not accept the memory import if it is too big/small open('pre.js', 'w').write('var Module = { TOTAL_MEMORY: 50*1024*1024 };\n') - subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1', '-s', 'TOTAL_MEMORY=' + str(16*1024*1024), '--pre-js', 'pre.js']) - out = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, full_output=True, stderr=PIPE) + subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'TOTAL_MEMORY=' + str(16*1024*1024), '--pre-js', 'pre.js']) + out = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, full_output=True, stderr=PIPE, assert_returncode=None) self.assertContained('imported Memory with incompatible size', out) self.assertContained('Memory size incompatibility issues may be due to changing TOTAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set TOTAL_MEMORY at runtime to something smaller than it was at compile time).', out) + self.assertNotContained('hello, world!', out) + # and with memory growth, all should be good + subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'TOTAL_MEMORY=' + str(16*1024*1024), '--pre-js', 'pre.js', '-s', 'ALLOW_MEMORY_GROWTH=1']) + self.assertContained('hello, world!', run_js('a.out.js', engine=SPIDERMONKEY_ENGINE)) def test_wasm_targets(self): for f in ['a.wasm', 'a.wast']: From ea9e3b663845a78b90502a6051bb457a6b5f2e52 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 10 Nov 2016 16:48:19 -0800 Subject: [PATCH 17/86] update binaryen tag --- tools/ports/binaryen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ports/binaryen.py b/tools/ports/binaryen.py index cf27151a35fae..b70147f80e685 100644 --- a/tools/ports/binaryen.py +++ b/tools/ports/binaryen.py @@ -1,6 +1,6 @@ import os, shutil, logging -TAG = 'version_19' +TAG = 'version_20' def needed(settings, shared, ports): if not settings.BINARYEN: return False From af59ea26dbf1b3dc8fed7ea09270933b94f8dcd7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 10 Nov 2016 16:56:27 -0800 Subject: [PATCH 18/86] add a test for 64-bit inputs to EM_ASM (#4708) --- tests/test_other.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_other.py b/tests/test_other.py index f9a40f96c926f..ad5d01881cb7b 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6425,6 +6425,20 @@ def test_memory_growth_noasm(self): src = open('a.out.js').read() assert 'use asm' not in src + def test_EM_ASM_i64(self): + open('src.cpp', 'w').write(''' +#include +#include + +int main() { + EM_ASM_ARGS({ + Module.print('inputs: ' + $0 + ', ' + $1 + '.'); + }, int64_t(0x12345678ABCDEF1FLL)); +} +''') + out, err = Popen([PYTHON, EMCC, 'src.cpp', '-Oz'], stderr=PIPE).communicate() + self.assertContained('LLVM ERROR: EM_ASM should not receive i64s as inputs, they are not valid in JS', err) + def test_eval_ctors(self): print 'non-terminating ctor' src = r''' From 7c6a37b7fa78742790e91a50705714c2d4e0ea3d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 10 Nov 2016 19:20:28 -0800 Subject: [PATCH 19/86] fix other.test_cmake_with_embind_cpp11_mode, avoid assuming the emscripten dir is in the path (#4690) --- tests/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_other.py b/tests/test_other.py index ad5d01881cb7b..cf151ff1e60e1 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -583,7 +583,7 @@ def test_cmake_with_embind_cpp11_mode(self): try: os.chdir(tempdirname) - configure = ['emcmake.bat' if WINDOWS else 'emcmake', 'cmake', path_from_root('tests', 'cmake', 'cmake_with_emval')] + args + configure = [path_from_root('emcmake.bat' if WINDOWS else 'emcmake'), 'cmake', path_from_root('tests', 'cmake', 'cmake_with_emval')] + args print str(configure) subprocess.check_call(configure) build = ['cmake', '--build', '.'] From 58b02924cba69eae765754042af41aa242e2cd75 Mon Sep 17 00:00:00 2001 From: w-vi Date: Wed, 2 Nov 2016 12:25:43 +0100 Subject: [PATCH 20/86] Allows no-rethrow in node.js env. Adresses #4643 --- AUTHORS | 2 +- src/settings.js | 5 +++++ src/shell.js | 2 ++ tests/test_other.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 428282569e061..171a697df7922 100644 --- a/AUTHORS +++ b/AUTHORS @@ -266,4 +266,4 @@ a license to everyone to use it as detailed in LICENSE.) * Ray Brown * Christopher Serr * Aaron Ruß (copyright owned by DFKI GmbH) - +* Vilibald Wanča diff --git a/src/settings.js b/src/settings.js index 4207306b20bb9..b0c30c8b3e5d7 100644 --- a/src/settings.js +++ b/src/settings.js @@ -295,6 +295,11 @@ var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catc var EXCEPTION_CATCHING_WHITELIST = []; // Enables catching exception in the listed functions only, if // DISABLE_EXCEPTION_CATCHING = 2 is set +var NODEJS_CATCH_EXIT = 1; // If disabled than in node.js environment the exit call will not be handled correctly it + // will throw an exception directly. Usefull if using C/C++ code as a library so + // exceptions thrown in the JS code are not caught and rethrown which obfuscates the + // original issue. + // For more explanations of this option, please visit // https://github.com/kripken/emscripten/wiki/Asyncify var ASYNCIFY = 0; // Whether to enable asyncify transformation diff --git a/src/shell.js b/src/shell.js index 48b76ee8bfa13..2d61a78adc0dd 100644 --- a/src/shell.js +++ b/src/shell.js @@ -115,12 +115,14 @@ if (ENVIRONMENT_IS_NODE) { module['exports'] = Module; } +#if NODEJS_CATCH_EXIT process['on']('uncaughtException', function(ex) { // suppress ExitStatus exceptions from showing an error if (!(ex instanceof ExitStatus)) { throw ex; } }); +#endif Module['inspect'] = function () { return '[Emscripten Module object]'; }; } diff --git a/tests/test_other.py b/tests/test_other.py index e538fc62d5b06..002dc0e7e2597 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -2555,6 +2555,39 @@ def test_module_exports_with_closure(self): try_delete(path_from_root('tests', 'Module-exports', 'test.js.map')) try_delete(path_from_root('tests', 'Module-exports', 'test.js.mem')) + def test_node_catch_exit(self): + # Test that in node.js exceptions are not caught if NODEJS_EXIT_CATCH=0 + if NODE_JS not in JS_ENGINES: + return + + open(os.path.join(self.get_dir(), 'count.c'), 'w').write(''' + #include + int count(const char *str) { + return (int)strlen(str); + } + ''') + + open(os.path.join(self.get_dir(), 'index.js'), 'w').write(''' + const count = require('./count.js'); + + console.log(xxx); //< here is the ReferenceError + ''') + + reference_error_text = 'console.log(xxx); //< here is the ReferenceError'; + + subprocess.check_call([PYTHON, EMCC, os.path.join(self.get_dir(), 'count.c'), '-o', 'count.js']) + + # Check that the ReferenceError is caught and rethrown and thus the original error line is masked + self.assertNotContained(reference_error_text, + run_js ('index.js', engine=NODE_JS, stderr=STDOUT, assert_returncode=None)) + + subprocess.check_call([PYTHON, EMCC, os.path.join(self.get_dir(), 'count.c'), '-o', 'count.js', '-s', 'NODEJS_CATCH_EXIT=0']) + + # Check that the ReferenceError is not caught + self.assertContained(reference_error_text, + run_js ('index.js', engine=NODE_JS, stderr=STDOUT, assert_returncode=None)) + + def test_fs_stream_proto(self): open('src.cpp', 'wb').write(r''' #include From 0d60cc866007d7e45460132fba21a630541a0fbd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 11 Nov 2016 10:23:32 -0800 Subject: [PATCH 21/86] ignore the memory growth function in eliminateDeadGlobals (#4721) it isn't valid asm.js, so it's asm.js structure must be ignored in that pass. before this fix, we altered its content in an incorrect manner, breaking memory growth + only my code. --- .../optimizer/eliminateDeadGlobals-output.js | 23 ++++++++++++++++++- tests/optimizer/eliminateDeadGlobals.js | 16 ++++++++++++- tools/js-optimizer.js | 12 +++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/tests/optimizer/eliminateDeadGlobals-output.js b/tests/optimizer/eliminateDeadGlobals-output.js index d1015d07d97fe..daa1d65a93db8 100644 --- a/tests/optimizer/eliminateDeadGlobals-output.js +++ b/tests/optimizer/eliminateDeadGlobals-output.js @@ -2,7 +2,12 @@ var Module = {}; Module["asm"] = (function(global, env, buffer) { "use asm"; var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); var HEAPF64 = new global.Float64Array(buffer); var STACKTOP = env.STACKTOP | 0; var _atoi = env._atoi; @@ -12,6 +17,19 @@ Module["asm"] = (function(global, env, buffer) { var _memcpy = env._memcpy; var __ZdaPv = env.__ZdaPv; var __ZdlPv = env.__ZdlPv; + function _emscripten_replace_memory(newBuffer) { + if (byteLength(newBuffer) & 16777215 || byteLength(newBuffer) <= 16777215 || byteLength(newBuffer) > 2147483648) return false; + HEAP8 = new Int8View(newBuffer); + HEAP16 = new Int16View(newBuffer); + HEAP32 = new Int32View(newBuffer); + HEAPU8 = new Uint8View(newBuffer); + HEAPU16 = new Uint16View(newBuffer); + HEAPU32 = new Uint32View(newBuffer); + HEAPF32 = new Float32View(newBuffer); + HEAPF64 = new Float64View(newBuffer); + buffer = newBuffer; + return true; + } function _main(i1, i2) { i1 = i1 | 0; i2 = i2 | 0; @@ -168,7 +186,10 @@ Module["asm"] = (function(global, env, buffer) { return; } return { - _main: _main + _main: _main, + _emscripten_replace_memory: _emscripten_replace_memory }; }); + + diff --git a/tests/optimizer/eliminateDeadGlobals.js b/tests/optimizer/eliminateDeadGlobals.js index 41ceb848ca9eb..e2217cd0d29d2 100644 --- a/tests/optimizer/eliminateDeadGlobals.js +++ b/tests/optimizer/eliminateDeadGlobals.js @@ -65,6 +65,20 @@ Module["asm"] = (function(global,env,buffer) { var __ZdlPv=env.__ZdlPv; var tempFloat = 0.0; + function _emscripten_replace_memory(newBuffer) { + if (byteLength(newBuffer) & 16777215 || byteLength(newBuffer) <= 16777215 || byteLength(newBuffer) > 2147483648) return false; + HEAP8 = new Int8View(newBuffer); + HEAP16 = new Int16View(newBuffer); + HEAP32 = new Int32View(newBuffer); + HEAPU8 = new Uint8View(newBuffer); + HEAPU16 = new Uint16View(newBuffer); + HEAPU32 = new Uint32View(newBuffer); + HEAPF32 = new Float32View(newBuffer); + HEAPF64 = new Float64View(newBuffer); + buffer = newBuffer; + return true; + } + // EMSCRIPTEN_START_FUNCS function _main(i1, i2) { i1 = i1 | 0; @@ -228,6 +242,6 @@ function runPostSets() {} // EMSCRIPTEN_END_FUNCS - return { _main: _main }; + return { _main: _main, _emscripten_replace_memory: _emscripten_replace_memory }; }) ; diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 307969e66cb06..6fc4cc446e974 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -7713,16 +7713,22 @@ function eliminateDeadGlobals(ast) { for (var i = 0; i < stats.length; i++) { var asmFunc = stats[i]; if (asmFunc[0] === 'defun') { - var asmData = normalizeAsm(asmFunc); + // the memory growth function does not contain valid asm.js, and can be ignored + var isAsmJS = asmFunc[1] !== '_emscripten_replace_memory'; + if (isAsmJS) { + var asmData = normalizeAsm(asmFunc); + } traverse(asmFunc, function(node, type) { if (type == 'name') { var name = node[1]; - if (!(name in asmData.params || name in asmData.vars)) { + if (!isAsmJS || !(name in asmData.params || name in asmData.vars)) { used[name] = 1; } } }); - denormalizeAsm(asmFunc, asmData); + if (isAsmJS) { + denormalizeAsm(asmFunc, asmData); + } } else { traverse(asmFunc, function(node, type) { if (type == 'name') { From 9888213a5655485a66763f52266e3b5dc1f6d3c1 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 11 Nov 2016 13:00:22 -0800 Subject: [PATCH 22/86] Don't make opt_level 0 imply debug_level 3 (#4722) This behavior is surprising because it is inconsistent with other compilers, and also means that there is no way to generate a binary without optimizations and without symbols. (A common use case for this is a "fastbuild" mode). --- emcc.py | 1 - tests/test_other.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/emcc.py b/emcc.py index ff78c76516fe9..5187a9b51325c 100755 --- a/emcc.py +++ b/emcc.py @@ -777,7 +777,6 @@ def detect_fixed_language_mode(args): if js_opts is None: js_opts = opt_level >= 2 if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] - if opt_level == 0: debug_level = max(3, debug_level) if memory_init_file is None: memory_init_file = opt_level >= 2 # TODO: support source maps with js_transform diff --git a/tests/test_other.py b/tests/test_other.py index cf151ff1e60e1..cc047513d388b 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6908,7 +6908,7 @@ def test_binaryen_and_precise_f32(self): def test_binaryen_names(self): sizes = {} for args, expect_names in [ - ([], True), # -O0 has debug info by default + ([], False), (['-g'], True), (['-O1'], False), (['-O2'], False), From d986aa2fe9a5579a9d76c7750030c5c4d7310643 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 11 Nov 2016 17:06:22 -0800 Subject: [PATCH 23/86] Change default binaryen method to running it natively, no fallbacks to interpreter (#4725) * change default binaryen method to running it natively, no fallbacks to interpreting * fix other.test_binaryen_and_precise_f32 * add a test for the default binaryen method --- emcc.py | 2 -- src/settings.js | 3 ++- tests/test_other.py | 11 +++++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/emcc.py b/emcc.py index 5187a9b51325c..caaa37b05cae0 100755 --- a/emcc.py +++ b/emcc.py @@ -1195,8 +1195,6 @@ def check(input_file): debug_level = max(1, debug_level) # keep whitespace readable, for asm.js parser simplicity shared.Settings.GLOBAL_BASE = 1024 # leave some room for mapping global vars assert not shared.Settings.SPLIT_MEMORY, 'WebAssembly does not support split memory' - if not shared.Settings.BINARYEN_METHOD: - shared.Settings.BINARYEN_METHOD = 'native-wasm,interpret-binary' assert not shared.Settings.INCLUDE_FULL_LIBRARY, 'The WebAssembly libc overlaps with JS libs, so INCLUDE_FULL_LIBRARY does not just work (FIXME)' # if root was not specified in -s, it might be fixed in ~/.emscripten, copy from there if not shared.Settings.BINARYEN_ROOT: diff --git a/src/settings.js b/src/settings.js index e6a9e4c2c4253..bee214654dd89 100644 --- a/src/settings.js +++ b/src/settings.js @@ -643,7 +643,8 @@ var BINARYEN = 0; // Whether to use [Binaryen](https://github.com/WebAssembly/bi // This will fetch the binaryen port and build it. (If, instead, you set // BINARYEN_ROOT in your ~/.emscripten file, then we use that instead // of the port, which can useful for local dev work on binaryen itself). -var BINARYEN_METHOD = ""; // See binaryen's src/js/wasm.js-post.js for details. +var BINARYEN_METHOD = "native-wasm"; // How we should run WebAssembly code. By default, we run it natively. + // See binaryen's src/js/wasm.js-post.js for more details and options. var BINARYEN_SCRIPTS = ""; // An optional comma-separated list of script hooks to run after binaryen, // in binaryen's /scripts dir. var BINARYEN_IMPRECISE = 0; // Whether to apply imprecise/unsafe binaryen optimizations. If enabled, diff --git a/tests/test_other.py b/tests/test_other.py index 9f0363ca5936b..e9ec7a93b026c 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6932,8 +6932,8 @@ def test_binaryen_and_precise_f32(self): print args, expect try_delete('a.out.js') with clean_write_access_to_canonical_temp_dir(): - output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args + ['-s', 'BINARYEN=1'], stdout=PIPE, stderr=PIPE).communicate() - assert expect == (' -emscripten-precise-f32' in err) + output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'] + args, stdout=PIPE, stderr=PIPE).communicate() + assert expect == (' -emscripten-precise-f32' in err), err self.assertContained('hello, world!', run_js('a.out.js')) finally: del os.environ['EMCC_DEBUG'] @@ -6974,6 +6974,13 @@ def test_binaryen_warn_mem(self): subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'TOTAL_MEMORY=' + str(16*1024*1024), '--pre-js', 'pre.js', '-s', 'ALLOW_MEMORY_GROWTH=1']) self.assertContained('hello, world!', run_js('a.out.js', engine=SPIDERMONKEY_ENGINE)) + def test_binaryen_default_method(self): + subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1']) + # might or might not fail, we don't care, just check which method is tried + out = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, full_output=True, stderr=PIPE, assert_returncode=None) + self.assertContained('trying binaryen method: native-wasm', out) # native is the default + assert out.count('trying binaryen method') == 1, 'must not try any other method' + def test_wasm_targets(self): for f in ['a.wasm', 'a.wast']: process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-o', f], stdout=PIPE, stderr=PIPE) From 4cf15ef0cb5eac0991eb8739e3c818ba58b0b396 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 11 Nov 2016 17:12:03 -0800 Subject: [PATCH 24/86] Use binaryen --mem-max flag, and add testing (#4723) * use binaryen --mem-max flag, and add testing * update binaryen tag --- emcc.py | 2 ++ src/settings.js | 3 +++ tests/test_other.py | 22 ++++++++++++++++++++++ tools/ports/binaryen.py | 2 +- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index caaa37b05cae0..1d438530dbb62 100755 --- a/emcc.py +++ b/emcc.py @@ -2020,6 +2020,8 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati cmd += ['--mem-init=' + memfile] if not shared.Settings.RELOCATABLE: cmd += ['--mem-base=' + str(shared.Settings.GLOBAL_BASE)] + if shared.Settings.BINARYEN_MEM_MAX >= 0: + cmd += ['--mem-max=' + str(shared.Settings.BINARYEN_MEM_MAX)] if shared.Building.is_wasm_only(): cmd += ['--wasm-only'] # this asm.js is code not intended to run as asm.js, it is only ever going to be wasm, an can contain special fastcomp-wasm support logging.debug('asm2wasm (asm.js => WebAssembly): ' + ' '.join(cmd)) diff --git a/src/settings.js b/src/settings.js index bee214654dd89..7926a42f7965d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -653,6 +653,9 @@ var BINARYEN_IMPRECISE = 0; // Whether to apply imprecise/unsafe binaryen optimi var BINARYEN_PASSES = ""; // A comma-separated list of passes to run in the binaryen optimizer, // for example, "dce,precompute,vacuum". // When set, this overrides the default passes we would normally run. +var BINARYEN_MEM_MAX = -1; // Set the maximum size of memory in the wasm module (in bytes). + // Without this, TOTAL_MEMORY is used (as it is used for the initial value), + // or if memory growth is enabled, no limit is set. This overrides both of those. var BINARYEN_ROOT = ""; // Directory where we can find Binaryen. Will be automatically set for you, // but you can set it to override if you are a Binaryen developer. diff --git a/tests/test_other.py b/tests/test_other.py index e9ec7a93b026c..3f20a69884087 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6981,6 +6981,28 @@ def test_binaryen_default_method(self): self.assertContained('trying binaryen method: native-wasm', out) # native is the default assert out.count('trying binaryen method') == 1, 'must not try any other method' + def test_binaryen_mem(self): + for args, expect_initial, expect_max in [ + (['-s', 'TOTAL_MEMORY=20971520'], 320, 320), + (['-s', 'TOTAL_MEMORY=20971520', '-s', 'ALLOW_MEMORY_GROWTH=1'], 320, None), + (['-s', 'TOTAL_MEMORY=20971520', '-s', 'BINARYEN_MEM_MAX=41943040'], 320, 640), + (['-s', 'TOTAL_MEMORY=20971520', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'BINARYEN_MEM_MAX=41943040'], 320, 640), + ]: + cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-s', 'WASM=1', '-O2', '-s', 'BINARYEN_METHOD="interpret-s-expr"'] + args + print ' '.join(cmd) + subprocess.check_call(cmd) + wast = open('a.out.wast').read() + lines = wast.split('\n') + for line in lines: + if '(import "env" "memory" (memory ' in line: + parts = line.strip().replace('(', '').replace(')', '').split(' ') + print parts + assert parts[5] == str(expect_initial) + if not expect_max: + assert len(parts) == 6 + else: + assert parts[6] == str(expect_max) + def test_wasm_targets(self): for f in ['a.wasm', 'a.wast']: process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-o', f], stdout=PIPE, stderr=PIPE) diff --git a/tools/ports/binaryen.py b/tools/ports/binaryen.py index b70147f80e685..58bcb8a7003c8 100644 --- a/tools/ports/binaryen.py +++ b/tools/ports/binaryen.py @@ -1,6 +1,6 @@ import os, shutil, logging -TAG = 'version_20' +TAG = 'version_21' def needed(settings, shared, ports): if not settings.BINARYEN: return False From 599fec12570593badd945e3f8f6fc670374e4183 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 12 Nov 2016 10:36:23 -0800 Subject: [PATCH 25/86] other.test_binaryen_default_method depends on spidermonkey --- tests/test_other.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_other.py b/tests/test_other.py index 3f20a69884087..1559a1d234746 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6975,6 +6975,7 @@ def test_binaryen_warn_mem(self): self.assertContained('hello, world!', run_js('a.out.js', engine=SPIDERMONKEY_ENGINE)) def test_binaryen_default_method(self): + if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey') subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1']) # might or might not fail, we don't care, just check which method is tried out = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, full_output=True, stderr=PIPE, assert_returncode=None) From 50d60272c294948ceaaa78361f80e8a09d335800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 13 Nov 2016 15:03:33 +0200 Subject: [PATCH 26/86] Add documentation for Emscripten preprocessor macros. Remove legacy "Alternatives to emcc" doc section. --- site/source/docs/compiling/Building-Projects.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/site/source/docs/compiling/Building-Projects.rst b/site/source/docs/compiling/Building-Projects.rst index 95fdada0613f3..f96bc2257c3d4 100644 --- a/site/source/docs/compiling/Building-Projects.rst +++ b/site/source/docs/compiling/Building-Projects.rst @@ -268,17 +268,17 @@ The :ref:`Tutorial` showed how :ref:`emcc ` can be used to compile sing In addition to the capabilities it shares with *gcc*, *emcc* supports options to optimize code, control what debug information is emitted, generate HTML and other output formats, etc. These options are documented in the :ref:`emcc tool reference ` (``./emcc --help`` on the command line). -Alternatives to emcc -==================== - -.. tip:: Do not attempt to bypass *emcc* and call the Emscripten tools directly from your build system. +Detecting Emscripten in Preprocessor +==================================== -You can in theory call *clang*, *llvm-ld*, and the other tools yourself. This is however considered dangerous because by default: +Emscripten provides the following preprocessor macros that can be used to identify the compiler version and platform: -- *Clang* does not use the Emscripten-bundled headers, which can lead to various errors. -- *llvm-ld* uses unsafe/unportable LLVM optimizations. + * The preprocessor define ``__EMSCRIPTEN__`` is always defined when compiling programs with Emscripten. + * The preprocessor variables ``__EMSCRIPTEN_major__``, ``__EMSCRIPTEN_minor__`` and ``__EMSCRIPTEN_tiny__`` specify, as integers, the currently used Emscripten compiler version. + * Emscripten behaves like a variant of Unix, so the preprocessor defines ``unix``, ``__unix`` and ``__unix__`` are always present when compiling code with Emscripten. + * When targeting SSEx SIMD APIs using one of the command line compiler flags ``-msse``, ``-msse2``, ``-msse3``, ``-mssse3``, or ``-msse4.1``, one or more of the preprocessor flags ``__SSE__``, ``__SSE2__``, ``__SSE3__``, ``__SSSE3__``, ``__SSE4_1__`` will be present to indicate available support for these instruction sets. + * If targeting the pthreads multithreading support with the compiler & linker flag ``-s USE_PTHREADS=1``, the preprocessr define ``__EMSCRIPTEN_PTHREADS__`` will be present. -*Emcc* automatically ensures the tools are configured and used properly. Examples / test code From 98e80cfed3bf45fcbf4e99c508cbbb76b84595f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 13 Nov 2016 15:18:04 +0200 Subject: [PATCH 27/86] Document more Emscripten platform preprocessors. --- site/source/docs/compiling/Building-Projects.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/site/source/docs/compiling/Building-Projects.rst b/site/source/docs/compiling/Building-Projects.rst index f96bc2257c3d4..a202a09954a2d 100644 --- a/site/source/docs/compiling/Building-Projects.rst +++ b/site/source/docs/compiling/Building-Projects.rst @@ -276,9 +276,14 @@ Emscripten provides the following preprocessor macros that can be used to identi * The preprocessor define ``__EMSCRIPTEN__`` is always defined when compiling programs with Emscripten. * The preprocessor variables ``__EMSCRIPTEN_major__``, ``__EMSCRIPTEN_minor__`` and ``__EMSCRIPTEN_tiny__`` specify, as integers, the currently used Emscripten compiler version. * Emscripten behaves like a variant of Unix, so the preprocessor defines ``unix``, ``__unix`` and ``__unix__`` are always present when compiling code with Emscripten. + * Emscripten uses Clang/LLVM as its underlying codegen compiler, so the preprocessor defines ``__llvm__`` and ``__clang__`` are defined, and the preprocessor defines ``__clang_major__``, ``__clang_minor__`` and ``__clang_patchlevel__`` indicate the version of Clang that is used. + * Clang/LLVM is GCC-compatible, so the preprocessor defines ``__GNUC__``, ``__GNUC_MINOR__`` and ``__GNUC_PATCHLEVEL__`` are also defined to represent the level of GCC compatibility that Clang/LLVM provides. + * The preprocessor string ``__VERSION__`` indicates the GCC compatible version, which is expanded to also show Emscripten version information. + * Likewise, ``__clang_version__`` is present and indicates both Emscripten and LLVM version information. + * Emscripten is a 32-bit platform, so ``size_t`` is a 32-bit unsigned integer, ``__POINTER_WIDTH__=32``, ``__SIZEOF_LONG__=4`` and ``__LONG_MAX__`` equals ``2147483647L``. + * When targeting asm.js, the preprocessor defines ``__asmjs`` and ``__asmjs__`` are present. * When targeting SSEx SIMD APIs using one of the command line compiler flags ``-msse``, ``-msse2``, ``-msse3``, ``-mssse3``, or ``-msse4.1``, one or more of the preprocessor flags ``__SSE__``, ``__SSE2__``, ``__SSE3__``, ``__SSSE3__``, ``__SSE4_1__`` will be present to indicate available support for these instruction sets. - * If targeting the pthreads multithreading support with the compiler & linker flag ``-s USE_PTHREADS=1``, the preprocessr define ``__EMSCRIPTEN_PTHREADS__`` will be present. - + * If targeting the pthreads multithreading support with the compiler & linker flag ``-s USE_PTHREADS=1``, the preprocessor define ``__EMSCRIPTEN_PTHREADS__`` will be present. Examples / test code From b6012fb7ba259e67dd7cd4f87377de0cbdb04eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 13 Nov 2016 20:21:22 +0200 Subject: [PATCH 28/86] Add test for FS.write() with canOwn=true to a view that is a subview of a larger buffer and improve comments. --- src/library_memfs.js | 6 ++++-- tests/fs/test_write.cpp | 35 +++++++++++++++++++++++++++++++++++ tests/fs/test_write.out | 1 + tests/test_core.py | 6 ++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/fs/test_write.cpp create mode 100644 tests/fs/test_write.out diff --git a/src/library_memfs.js b/src/library_memfs.js index 5b1cd2f28d029..475266b08f24c 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -276,14 +276,16 @@ mergeInto(LibraryManager.library, { // Writes the byte range (buffer[offset], buffer[offset+length]) to offset 'position' into the file pointed by 'stream' // canOwn: A boolean that tells if this function can take ownership of the passed in buffer from the subbuffer portion // that the typed array view 'buffer' points to. The underlying ArrayBuffer can be larger than that, but - // canOwn=true will not take ownership of the portion outside the bytes addressed by the view. + // canOwn=true will not take ownership of the portion outside the bytes addressed by the view. This means that + // with canOwn=true, creating a copy of the bytes is avoided, but the caller shouldn't touch the passed in range + // of bytes anymore since their contents now represent file data inside the filesystem. write: function(stream, buffer, offset, length, position, canOwn) { if (!length) return 0; var node = stream.node; node.timestamp = Date.now(); if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array? - if (canOwn) { // Can we just reuse the buffer we are given? + if (canOwn) { #if ASSERTIONS assert(position === 0, 'canOwn must imply no weird position inside the file'); #endif diff --git a/tests/fs/test_write.cpp b/tests/fs/test_write.cpp new file mode 100644 index 0000000000000..6b940ec348ee0 --- /dev/null +++ b/tests/fs/test_write.cpp @@ -0,0 +1,35 @@ +// https://github.com/kripken/emscripten/pull/4705: Test that FS.write() with canOwn=true works. + +#include +#include +#include + +#include + +int main() +{ + EM_ASM( + var stream = FS.open('testfile', 'w+'); + + var data = new Uint8Array(128); + var str = "Hello! "; + stringToUTF8Array(str, data, 0, lengthBytesUTF8(str)+1); + data = data.subarray(0, lengthBytesUTF8(str)); + FS.write(stream, data, 0, lengthBytesUTF8(str), 0, /*canOwn=*/true); + var pos = lengthBytesUTF8(str); + + str = '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'; + data = new Uint8Array(100); + stringToUTF8Array(str, data, 0, lengthBytesUTF8(str)+1); + FS.write(stream, data, 0, lengthBytesUTF8(str)+1, pos, /*canOwn=*/false); + + FS.close(stream); + ); + + std::ifstream file("testfile"); + std::string line; + getline(file, line); + std::cout << "read " << line << std::endl; + + return 0; +} diff --git a/tests/fs/test_write.out b/tests/fs/test_write.out new file mode 100644 index 0000000000000..e4d4cfa783e44 --- /dev/null +++ b/tests/fs/test_write.out @@ -0,0 +1 @@ +read Hello! 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 \ No newline at end of file diff --git a/tests/test_core.py b/tests/test_core.py index efa32228bcb87..d5ff956a2b023 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4451,6 +4451,12 @@ def test_fs_writeFile(self): out = path_from_root('tests', 'fs', 'test_writeFile.out') self.do_run_from_file(src, out) + def test_fs_write(self): + self.emcc_args = ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1'] + src = path_from_root('tests', 'fs', 'test_write.cpp') + out = path_from_root('tests', 'fs', 'test_write.out') + self.do_run_from_file(src, out) + def test_fs_emptyPath(self): src = path_from_root('tests', 'fs', 'test_emptyPath.c') out = path_from_root('tests', 'fs', 'test_emptyPath.out') From a255996e2183b60a1b38426d1e4e245944cd3a16 Mon Sep 17 00:00:00 2001 From: Jacob Gravelle Date: Tue, 8 Nov 2016 13:08:27 -0800 Subject: [PATCH 29/86] Remove unnecessary specification of CMAKE_(C|CXX)_COMPILER_TARGET We already pass -target=LLVM_TARGET, no need to hardcode the triple for libraries. --- cmake/Modules/Platform/Emscripten.cmake | 2 -- tests/test_core.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/cmake/Modules/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake index c91deb4d4dcc0..b53cc713d70ce 100644 --- a/cmake/Modules/Platform/Emscripten.cmake +++ b/cmake/Modules/Platform/Emscripten.cmake @@ -134,8 +134,6 @@ if (EMSCRIPTEN_FORCE_COMPILERS) set(CMAKE_CXX_COMPILER_ID Clang) set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT 98) - set(CMAKE_C_COMPILER_TARGET "asmjs-unknown-emscripten") - set(CMAKE_CXX_COMPILER_TARGET "asmjs-unknown-emscripten") set(CMAKE_C_PLATFORM_ID "emscripten") set(CMAKE_CXX_PLATFORM_ID "emscripten") diff --git a/tests/test_core.py b/tests/test_core.py index a64420b41f585..f27ecb829e3a4 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5222,7 +5222,6 @@ def test_gcc_unmangler(self): self.do_run(open(path_from_root('third_party', 'gcc_demangler.c')).read(), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj']) - @no_wasm_backend() def test_lua(self): if self.emcc_args: self.emcc_args = ['-g1'] + self.emcc_args @@ -5306,7 +5305,6 @@ def process(filename): ['font.ttf', 'ea', '40', '32', '0'], no_build=True) - @no_wasm_backend() def test_sqlite(self): # gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c self.banned_js_engines = [NODE_JS] # OOM in older node @@ -5355,7 +5353,6 @@ def test_zlib(self): includes=[path_from_root('tests', 'zlib'), os.path.join(self.get_dir(), 'building', 'zlib')], force_c=True) - @no_wasm_backend() def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long Settings.DEAD_FUNCTIONS = ['__ZSt9terminatev'] From 28b0cccaeec15f8bdcfcf8d4c02eda3747e6b015 Mon Sep 17 00:00:00 2001 From: Jacob Gravelle Date: Tue, 8 Nov 2016 13:27:55 -0800 Subject: [PATCH 30/86] i64 and float fixes mean most printf tests just work --- tests/test_core.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index f27ecb829e3a4..e144d356fe458 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -85,11 +85,9 @@ def test_sintvars(self): self.do_run_in_out_file_test('tests', 'core', 'test_sintvars', force_c=True) - @no_wasm_backend('printf is truncating the output of i64s') def test_i64(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_2(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_2') @@ -101,29 +99,24 @@ def test_i64_4(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_4') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_b(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_b') def test_i64_cmp(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_cmp') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_cmp2(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_cmp2') def test_i64_double(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_double') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_umul(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_umul') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_precise(self): self.do_run_in_out_file_test('tests', 'core', 'test_i64_precise') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_precise_unneeded(self): # Verify that even if we ask for precision, if it is not needed it is not included Settings.PRECISE_I64_MATH = 1 @@ -132,13 +125,11 @@ def test_i64_precise_unneeded(self): code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() assert 'goog.math.Long' not in code, 'i64 precise math should never be included, musl does its own printfing' - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_precise_needed(self): # and now one where we do Settings.PRECISE_I64_MATH = 1 self.do_run_in_out_file_test('tests', 'core', 'test_i64_precise_needed') - @no_wasm_backend('printf is truncating the output of i64s') def test_i64_llabs(self): Settings.PRECISE_I64_MATH = 2 @@ -165,7 +156,6 @@ def test_i64_varargs(self): def test_vararg_copy(self): self.do_run_in_out_file_test('tests', 'va_arg', 'test_va_copy') - @no_wasm_backend('printf is truncating the output of really big doubles') def test_llvm_fabs(self): Settings.PRECISE_F32 = 1 self.do_run_in_out_file_test('tests', 'core', 'test_llvm_fabs') @@ -207,7 +197,6 @@ def test_llvm_intrinsics(self): self.do_run_in_out_file_test('tests', 'core', 'test_llvm_intrinsics') - @no_wasm_backend('printf is truncating the output of i64s') def test_bswap64(self): test_path = path_from_root('tests', 'core', 'test_bswap64') src, output = (test_path + s for s in ('.c', '.out')) @@ -480,7 +469,6 @@ def test_unsigned(self): def test_bitfields(self): self.do_run_in_out_file_test('tests', 'core', 'test_bitfields') - @no_wasm_backend('printf is incorrectly handling float values') def test_floatvars(self): self.do_run_in_out_file_test('tests', 'core', 'test_floatvars') @@ -499,7 +487,6 @@ def test_zerodiv(self): def test_zero_multiplication(self): self.do_run_in_out_file_test('tests', 'core', 'test_zero_multiplication') - @no_wasm_backend('printf is incorrectly handling float values') def test_isnan(self): self.do_run_in_out_file_test('tests', 'core', 'test_isnan') @@ -529,7 +516,6 @@ def test_math_lgamma(self): Settings.MAIN_MODULE = 1 self.do_run_from_file(src, output) - @no_wasm_backend('frexp seems to be failing. printf relies on frexp for float formatting, so that probably causes the print failure') def test_frexp(self): self.do_run_in_out_file_test('tests', 'core', 'test_frexp') @@ -543,7 +529,6 @@ def test_rounding(self): def test_fcvt(self): self.do_run_in_out_file_test('tests', 'core', 'test_fcvt') - @no_wasm_backend('printf is truncating the output of i64s') def test_llrint(self): self.do_run_in_out_file_test('tests', 'core', 'test_llrint') @@ -3885,7 +3870,6 @@ def test_strtod(self): def test_strtok(self): self.do_run_in_out_file_test('tests', 'core', 'test_strtok') - @no_wasm_backend('printf is truncating the output of i64s') def test_parseInt(self): src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read() @@ -3906,7 +3890,6 @@ def test_printf_2(self): def test_printf_float(self): self.do_run_in_out_file_test('tests', 'printf', 'test_float') - @no_wasm_backend('printf is truncating octal numbers at the first digit') def test_printf_octal(self): self.do_run_in_out_file_test('tests', 'printf', 'test_octal') @@ -3916,7 +3899,6 @@ def test_vprintf(self): def test_vsnprintf(self): self.do_run_in_out_file_test('tests', 'core', 'test_vsnprintf') - @no_wasm_backend('printf is incorrectly handling float values') def test_printf_more(self): self.do_run_in_out_file_test('tests', 'core', 'test_printf_more') @@ -4013,7 +3995,6 @@ def test_sscanf_other_whitespace(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_other_whitespace') - @no_wasm_backend('printf is truncating the output of i64s') def test_sscanf_3(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_3') @@ -4307,7 +4288,6 @@ def process(filename): expected = open(path_from_root('tests', 'fcntl', 'output.txt'), 'r').read() self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h']) - @no_wasm_backend('printf is truncating octal numbers at the first digit') def test_fcntl_open(self): src = open(path_from_root('tests', 'fcntl-open', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read() @@ -6860,9 +6840,8 @@ def test_emscripten_log(self): Success! ''') - @no_wasm_backend() def test_float_literals(self): - self.do_run_from_file(path_from_root('tests', 'test_float_literals.cpp'), path_from_root('tests', 'test_float_literals.out')) + self.do_run_in_out_file_test('tests', 'test_float_literals') def test_exit_status(self): src = r''' From be699fbd548054177cedb6ca0ebe27bb9862df36 Mon Sep 17 00:00:00 2001 From: Jacob Gravelle Date: Tue, 8 Nov 2016 13:35:12 -0800 Subject: [PATCH 31/86] Due to userstack changes, sscanf mostly works, except for some float values --- .../{test_sscanf_hex.c => test_sscanf_hex.cpp} | 0 tests/test_core.py | 17 +++++------------ 2 files changed, 5 insertions(+), 12 deletions(-) rename tests/core/{test_sscanf_hex.c => test_sscanf_hex.cpp} (100%) diff --git a/tests/core/test_sscanf_hex.c b/tests/core/test_sscanf_hex.cpp similarity index 100% rename from tests/core/test_sscanf_hex.c rename to tests/core/test_sscanf_hex.cpp diff --git a/tests/test_core.py b/tests/test_core.py index e144d356fe458..a5437140ab910 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -625,7 +625,6 @@ def ensure_stack_restore_count(function_name, expected_count): ensure_stack_restore_count('function _alloca_gets_restored', 1) ensure_stack_restore_count('function _stack_usage', 1) - @no_wasm_backend('for some reasons emscripten_asm_const_ii gets called? and has a bogus memory address that causes a trap') def test_strings(self): test_path = path_from_root('tests', 'core', 'test_strings') src, output = (test_path + s for s in ('.c', '.out')) @@ -744,7 +743,6 @@ def test_assert(self): def test_libcextra(self): self.do_run_in_out_file_test('tests', 'core', 'test_libcextra') - @no_wasm_backend('for some reasons emscripten_asm_const_ii gets called? and has a bogus memory address that causes a trap') def test_regex(self): self.do_run_in_out_file_test('tests', 'core', 'test_regex') @@ -1496,7 +1494,7 @@ def test_set_align(self): self.do_run_in_out_file_test('tests', 'core', 'test_set_align') - @no_wasm_backend('sscanf seems to be rewriting local variables') + @no_wasm_backend('printf is incorrectly handling float values') def test_emscripten_api(self): check = ''' def process(filename): @@ -3921,11 +3919,11 @@ def test_fnmatch(self): print 'flip assertions off' self.do_run_in_out_file_test('tests', 'core', 'fnmatch') - @no_wasm_backend('sscanf seems to be rewriting local variables') + @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf') - @no_wasm_backend('sscanf seems to be rewriting local variables') + @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf_2(self): # doubles for ftype in ['float', 'double']: @@ -3981,15 +3979,12 @@ def test_sscanf_2(self): Pass: 0.000012 0.000012 Pass: 0.000012 0.000012''') - @no_wasm_backend('sscanf seems to be rewriting local variables') def test_sscanf_n(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_n') - @no_wasm_backend('sscanf seems to be rewriting local variables') def test_sscanf_whitespace(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_whitespace') - @no_wasm_backend('sscanf seems to be rewriting local variables') def test_sscanf_other_whitespace(self): Settings.SAFE_HEAP = 0 # use i16s in printf @@ -4004,22 +3999,20 @@ def test_sscanf_4(self): def test_sscanf_5(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_5') - @no_wasm_backend('sscanf seems to be rewriting local variables') def test_sscanf_6(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_6') def test_sscanf_skip(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_skip') - @no_wasm_backend('sscanf seems to be rewriting local variables') + @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf_caps(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_caps') - @no_wasm_backend('for some reasons emscripten_asm_const_ii gets called? and has a bogus memory address that causes a trap') def test_sscanf_hex(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_hex') - @no_wasm_backend('sscanf seems to be rewriting local variables') + @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf_float(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_float') From 05aedae90873a86170d8f04c56031b83f37c6a29 Mon Sep 17 00:00:00 2001 From: Jacob Gravelle Date: Tue, 8 Nov 2016 13:36:16 -0800 Subject: [PATCH 32/86] Miscellaneous tests that seem to work now, add a note why stack_overflow tests fail --- tests/test_core.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index a5437140ab910..e12bca64a8d58 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1982,7 +1982,6 @@ def test_structbyval(self): generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() print >> sys.stderr, 'skipping C/C++ conventions warning check, since not i386-pc-linux-gnu' - @no_wasm_backend('qsort is sorting improperly') def test_stdlibs(self): # safe heap prints a warning that messes up our output. Settings.SAFE_HEAP = 0 @@ -2151,6 +2150,7 @@ def test_flexarray_struct(self): def test_bsearch(self): self.do_run_in_out_file_test('tests', 'core', 'test_bsearch') + @no_wasm_backend("wasm backend has no support for fastcomp's -emscripten-assertions flag") def test_stack_overflow(self): Settings.ASSERTIONS = 1 self.do_run(open(path_from_root('tests', 'core', 'stack_overflow.cpp')).read(), 'Stack overflow!') @@ -4021,7 +4021,6 @@ def test_langinfo(self): expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read() self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h']) - @no_wasm_backend('Does not dump .mem file') def test_files(self): self.banned_js_engines = [SPIDERMONKEY_ENGINE] # closure can generate variables called 'gc', which pick up js shell stuff if '-O2' in self.emcc_args and not self.is_wasm(): @@ -4286,7 +4285,6 @@ def test_fcntl_open(self): expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read() self.do_run(src, expected, force_c=True, extra_emscripten_args=['-H', 'libc/fcntl.h']) - @no_wasm_backend() def test_fcntl_misc(self): add_pre_run = ''' def process(filename): @@ -5189,7 +5187,6 @@ def test_simd_dyncall(self): src, output = (test_path + s for s in ('.cpp', '.txt')) self.do_run_from_file(src, output) - @no_wasm_backend() def test_gcc_unmangler(self): Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('third_party')] @@ -5561,7 +5558,7 @@ def clean(text): Settings.ALLOW_MEMORY_GROWTH = 0 do_test() - @no_wasm_backend() + @no_wasm_backend('unknown relocation: $environ') def test_python(self): Settings.EMULATE_FUNCTION_POINTER_CASTS = 1 @@ -7146,7 +7143,7 @@ def test_fs_dict(self): self.emcc_args += ['--pre-js', 'pre.js'] self.do_run('', 'object\nobject\nobject') - @no_wasm_backend() + @no_wasm_backend("wasm backend has no support for fastcomp's -emscripten-assertions flag") def test_stack_overflow_check(self): args = self.emcc_args + ['-s', 'TOTAL_STACK=1048576'] self.emcc_args = args + ['-s', 'STACK_OVERFLOW_CHECK=1', '-s', 'ASSERTIONS=0'] From aba919acb9f78d88c71abcc1d4ea85e65cc648be Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 14 Nov 2016 09:52:37 -0800 Subject: [PATCH 33/86] Ban V8 from test_demangle_stacks It hasn't been fully updated for 0xd "names" section yet. --- tests/test_core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_core.py b/tests/test_core.py index a64420b41f585..97aefdc04fe8a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6121,6 +6121,7 @@ def test_emulate_function_pointer_casts(self): @no_wasm_backend() def test_demangle_stacks(self): + self.banned_js_engines = [V8_ENGINE] # https://bugs.chromium.org/p/v8/issues/detail?id=5632 Settings.DEMANGLE_SUPPORT = 1 if '-O' in str(self.emcc_args): self.emcc_args += ['--profiling-funcs', '--llvm-opts', '0'] From d7a491f4a9d13ea9a3095e377187ee644516e28d Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 14 Nov 2016 09:55:02 -0800 Subject: [PATCH 34/86] Only ban if wasm --- tests/test_core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_core.py b/tests/test_core.py index 97aefdc04fe8a..0d06027ee4d84 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6121,7 +6121,8 @@ def test_emulate_function_pointer_casts(self): @no_wasm_backend() def test_demangle_stacks(self): - self.banned_js_engines = [V8_ENGINE] # https://bugs.chromium.org/p/v8/issues/detail?id=5632 + if self.is_wasm(): + self.banned_js_engines = [V8_ENGINE] # https://bugs.chromium.org/p/v8/issues/detail?id=5632 Settings.DEMANGLE_SUPPORT = 1 if '-O' in str(self.emcc_args): self.emcc_args += ['--profiling-funcs', '--llvm-opts', '0'] From 580a56a90281a310dbe1756a0f104c66174129c8 Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Mon, 14 Nov 2016 10:09:23 -0800 Subject: [PATCH 35/86] Make embind mostly work with wasm_backend (#4724) Disables registering a long double memory view on wasm backend. Adds a test to verify long double breaks for wasm backend but not other targets. Adds a static assert to typed_memory_view to move a user-facing failure from runtime to compile time, with a clearer error message. --- system/include/emscripten/wire.h | 10 +++++++++ system/lib/embind/bind.cpp | 7 +++--- tests/test_core.py | 38 ++++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 25539dd25f3dd..fb906bdeac7da 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -379,6 +379,14 @@ namespace emscripten { auto toWireType(T&& v) -> typename BindingType::WireType { return BindingType::toWireType(std::forward(v)); } + + template + constexpr bool typeSupportsMemoryView() { + return (std::is_floating_point::value && + (sizeof(T) == 4 || sizeof(T) == 8)) || + (std::is_integral::value && + (sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4)); + } } template @@ -399,6 +407,8 @@ namespace emscripten { // as it merely aliases the C heap. template inline memory_view typed_memory_view(size_t size, const T* data) { + static_assert(internal::typeSupportsMemoryView(), + "type of typed_memory_view is invalid"); return memory_view(size, data); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 7d9afdc26a4ce..ebd041ca0fe9f 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -71,9 +72,7 @@ namespace { template constexpr TypedArrayIndex getTypedArrayIndex() { - static_assert( - (std::is_floating_point::value && (sizeof(T) == 4 || sizeof(T) == 8)) || - (std::is_integral::value && (sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4)), + static_assert(internal::typeSupportsMemoryView(), "type does not map to a typed array"); return std::is_floating_point::value ? (sizeof(T) == 4 @@ -144,5 +143,7 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { register_memory_view("emscripten::memory_view"); register_memory_view("emscripten::memory_view"); +#if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__ register_memory_view("emscripten::memory_view"); +#endif } diff --git a/tests/test_core.py b/tests/test_core.py index e12bca64a8d58..0c2f7be915a0b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1457,7 +1457,7 @@ def test_bigarray(self): def test_mod_globalstruct(self): self.do_run_in_out_file_test('tests', 'core', 'test_mod_globalstruct') - @no_wasm_backend('long doubles are f64s in wasm backend') + @no_wasm_backend('long doubles are f128s in wasm backend') def test_pystruct(self): def test(): self.do_run_in_out_file_test('tests', 'test_pystruct') @@ -6195,7 +6195,6 @@ def test2(): Settings.ASSERTIONS = 1 self.do_run(src, output) - @no_wasm_backend() def test_embind(self): Building.COMPILER_TEST_OPTS += ['--bind'] @@ -6217,7 +6216,6 @@ def test_embind(self): ''' self.do_run(src, 'abs(-10): 10\nabs(-11): 11'); - @no_wasm_backend() def test_embind_2(self): Settings.NO_EXIT_RUNTIME = 1 # we emit some post.js that we need to see Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js'] @@ -6240,7 +6238,6 @@ def test_embind_2(self): ''' self.do_run(src, 'lerp 166'); - @no_wasm_backend() def test_embind_3(self): Settings.NO_EXIT_RUNTIME = 1 # we emit some post.js that we need to see Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js'] @@ -6270,6 +6267,39 @@ def test_embind_3(self): ''' self.do_run(src, 'UnboundTypeError: Cannot call compute due to unbound types: Pi'); + @no_wasm_backend('long doubles are f128s in wasm backend') + def test_embind_4(self): + Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js'] + open('post.js', 'w').write(''' + function printFirstElement() { + Module.print(Module.getBufferView()[0]); + } + ''') + src = r''' + #include + #include + #include + #include + using namespace emscripten; + + const size_t kBufferSize = 1024; + long double buffer[kBufferSize]; + val getBufferView(void) { + val v = val(typed_memory_view(kBufferSize, buffer)); + return v; + } + EMSCRIPTEN_BINDINGS(my_module) { + function("getBufferView", &getBufferView); + } + + int main(int argc, char **argv) { + buffer[0] = 107; + EM_ASM(printFirstElement()); + return 0; + } + ''' + self.do_run(src, '107') + @no_wasm_backend() def test_scriptaclass(self): Settings.EXPORT_BINDINGS = 1 From 367171a014639c850103344da1b85104530a61af Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 12 May 2015 11:40:12 +0200 Subject: [PATCH 36/86] fixing issue where memberFunction is set before all overloads are registered, this causes memberFunction to appear as overloadTable[undefined] later. --- src/embind/embind.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index e0e39a8bf96cd..ade3bdb1af12d 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1949,6 +1949,8 @@ var LibraryEmbind = { // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. if (undefined === proto[methodName].overloadTable) { + // Set argCount in case an overload is registered later + memberFunction.argCount = argCount - 2; proto[methodName] = memberFunction; } else { proto[methodName].overloadTable[argCount - 2] = memberFunction; From 7d976fb8ff1ce657c64fab1d53670d39ea927dd7 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 12 May 2015 17:44:40 +0200 Subject: [PATCH 37/86] add tests to check that embind does not put undefined entries in the overload table --- tests/embind/embind.test.js | 16 ++++++++++++++++ tests/embind/embind_test.cpp | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 0ca77a2b4c689..0487bdc2f7682 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -876,6 +876,22 @@ module({ p.delete(); }); */ + + test("no undefined entry in overload table when depending on already bound types", function() { + var dummy_overloads = cm.MultipleOverloadsDependingOnDummy.prototype.dummy; + // check if the overloadTable is correctly named + // it can be minimized if using closure compiler + if (dummy_overloads.hasOwnProperty('overloadTable')) { + assert.false(dummy_overloads.overloadTable.hasOwnProperty('undefined')); + } + + // this part should fail anyway if there is no overloadTable + var dependOnDummy = new cm.MultipleOverloadsDependingOnDummy(); + var dummy = dependOnDummy.dummy(); + dependOnDummy.dummy(dummy); + dummy.delete(); + dependOnDummy.delete(); + }); }); BaseFixture.extend("vector", function() { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index c2065dccfbd39..96ac906f3ae09 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -2294,6 +2294,19 @@ struct ConstAndNonConst { } }; +class DummyForOverloads {}; + +class MultipleOverloadsDependingOnDummy { +public: + DummyForOverloads dummy() { + return DummyForOverloads(); + } + + DummyForOverloads dummy(DummyForOverloads d) { + return d; + } +}; + EMSCRIPTEN_BINDINGS(overloads) { function("overloaded_function", select_overload(&overloaded_function)); function("overloaded_function", select_overload(&overloaded_function)); @@ -2337,6 +2350,14 @@ EMSCRIPTEN_BINDINGS(overloads) { class_("ConstAndNonConst") .function("method", select_const(&ConstAndNonConst::method)) ; + + class_("DummyForOverloads").constructor(); + + class_("MultipleOverloadsDependingOnDummy") + .constructor() + .function("dummy", select_overload(&MultipleOverloadsDependingOnDummy::dummy)) + .function("dummy", select_overload(&MultipleOverloadsDependingOnDummy::dummy)) + ; } // tests for out-of-order registration From 6086d96a0965d3a7d9da8edf84f5eeeb927cf5fd Mon Sep 17 00:00:00 2001 From: AlexPerrot Date: Thu, 17 Nov 2016 14:50:42 +0100 Subject: [PATCH 38/86] add test for overloadTable of free functions --- tests/embind/embind.test.js | 12 ++++++++++++ tests/embind/embind_test.cpp | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 0487bdc2f7682..4bff00813aa74 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -892,6 +892,18 @@ module({ dummy.delete(); dependOnDummy.delete(); }); + + test("no undefined entry in overload table for free functions", function() { + var dummy_free_func = cm.getDummy; + console.log(dummy_free_func); + + if (dummy_free_func.hasOwnProperty('overloadTable')) { + assert.false(dummy_free_func.overloadTable.hasOwnProperty('undefined')); + } + + var dummy = cm.getDummy(); + cm.getDummy(dummy); + }); }); BaseFixture.extend("vector", function() { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 96ac906f3ae09..989f6ebfc8b32 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -2307,6 +2307,14 @@ class MultipleOverloadsDependingOnDummy { } }; +DummyForOverloads getDummy() { + return DummyForOverloads(); +} + +DummyForOverloads getDummy(DummyForOverloads d) { + return d; +} + EMSCRIPTEN_BINDINGS(overloads) { function("overloaded_function", select_overload(&overloaded_function)); function("overloaded_function", select_overload(&overloaded_function)); From 03c0041a53396ff2736a99ef01871ab08ee1abed Mon Sep 17 00:00:00 2001 From: AlexPerrot Date: Thu, 17 Nov 2016 14:53:42 +0100 Subject: [PATCH 39/86] fix for undefined entry in overloadTable of free functions --- src/embind/embind.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index ade3bdb1af12d..e39ac1a912fb6 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -144,6 +144,7 @@ var LibraryEmbind = { } else { Module[name] = value; + Module[name].argCount = numArguments; } }, From a5db951b948d73c1d33371f544c77a18e4982da3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 17 Nov 2016 14:56:45 -0800 Subject: [PATCH 40/86] do not use our clang to build binaryen natively, as it fails on some OS X setups. Followup for #4676. See binaryen issue 822 (#4734) --- tests/test_sanity.py | 13 ++++++++----- tools/shared.py | 9 +++++++++ tools/system_libs.py | 7 ++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index c279bdd528dc2..66e8e7019752c 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -955,6 +955,7 @@ def test_with_fake(report, expected): def test_binaryen(self): import tools.ports.binaryen as binaryen tag_file = Cache.get_path('binaryen_tag_' + binaryen.TAG + '.txt') + def prep(): wipe() self.do([PYTHON, EMCC, '--clear-ports']) @@ -969,12 +970,14 @@ def prep(): prep() subprocess.check_call([PYTHON, 'embuilder.py', 'build', 'binaryen']) assert os.path.exists(tag_file) - subprocess.check_call([PYTHON, 'emcc.py', 'tests/hello_world.c', '-s', 'BINARYEN=1']) + subprocess.check_call([PYTHON, 'emcc.py', 'tests/hello_world.c', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"']) self.assertContained('hello, world!', run_js('a.out.js')) - print 'see if building with emmake works (should not break native compilation of binaryen port' + print 'see we show an error for emmake (we cannot build natively under emmake)' prep() - subprocess.check_call([PYTHON, 'emmake.py', EMCC, 'tests/hello_world.c', '-s', 'BINARYEN=1']) - assert os.path.exists(tag_file) - self.assertContained('hello, world!', run_js('a.out.js')) + try_delete('a.out.js') + out = self.do([PYTHON, 'emmake.py', EMCC, 'tests/hello_world.c', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"']) + assert not os.path.exists(tag_file) + assert not os.path.exists('a.out.js') + self.assertContained('For example, for binaryen, do "python embuilder.py build binaryen"', out) diff --git a/tools/shared.py b/tools/shared.py index 15d619eea38bc..c9ce4ea7850a8 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1215,6 +1215,15 @@ def get_building_env(native=False): env['CROSS_COMPILE'] = path_from_root('em') # produces /path/to/emscripten/em , which then can have 'cc', 'ar', etc appended to it return env + # if we are in emmake mode, i.e., we changed the env to run emcc etc., then show the message and abort + @staticmethod + def ensure_no_emmake(message): + non_native = Building.get_building_env() + if os.environ.get('CC') == non_native.get('CC'): + # the environment CC is the one we change to when forcing our em* tools + logging.error(message) + sys.exit(1) + # Finds the given executable 'program' in PATH. Operates like the Unix tool 'which'. @staticmethod def which(program): diff --git a/tools/system_libs.py b/tools/system_libs.py index c6993f162aad4..4cd6d811c5f44 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -583,8 +583,9 @@ def clear_project_build(name): @staticmethod def build_native(subdir): + shared.Building.ensure_no_emmake('We cannot build the native system library in "%s" when under the influence of emmake/emconfigure. To avoid this, create system dirs beforehand, so they are not auto-built on demand. For example, for binaryen, do "python embuilder.py build binaryen"' % subdir) + old = os.getcwd() - env = shared.Building.get_building_env(native=True) try: os.chdir(subdir) @@ -592,7 +593,7 @@ def build_native(subdir): cmake_build_type = 'Release' # Configure - subprocess.check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + cmake_build_type, '.'], env=env) + subprocess.check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + cmake_build_type, '.']) # Check which CMake generator CMake used so we know which form to pass parameters to make/msbuild/etc. build tool. generator = re.search('CMAKE_GENERATOR:INTERNAL=(.*)$', open('CMakeCache.txt', 'r').read(), re.MULTILINE).group(1) @@ -604,7 +605,7 @@ def build_native(subdir): elif 'Visual Studio' in generator: make_args = ['--config', cmake_build_type, '--', '/maxcpucount:' + num_cores] # Kick off the build. - subprocess.check_call(['cmake', '--build', '.'] + make_args, env=env) + subprocess.check_call(['cmake', '--build', '.'] + make_args) finally: os.chdir(old) From 834d78e085cd8d3848f534be9c937baa9460e3e5 Mon Sep 17 00:00:00 2001 From: junji hashimoto Date: Wed, 23 Nov 2016 04:29:47 +0900 Subject: [PATCH 41/86] Fix handling invalid path of chdir (#4749) --- src/library_fs.js | 3 +++ tests/unistd/curdir.c | 20 ++++++++++++++++++++ tests/unistd/curdir.out | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/src/library_fs.js b/src/library_fs.js index 0a8795cec860a..1b60f2ad29804 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1227,6 +1227,9 @@ mergeInto(LibraryManager.library, { }, chdir: function(path) { var lookup = FS.lookupPath(path, { follow: true }); + if (lookup.node === null) { + throw new FS.ErrnoError(ERRNO_CODES.ENOENT); + } if (!FS.isDir(lookup.node.mode)) { throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR); } diff --git a/tests/unistd/curdir.c b/tests/unistd/curdir.c index c266fc35ddbcb..bbc0139ac28f3 100644 --- a/tests/unistd/curdir.c +++ b/tests/unistd/curdir.c @@ -31,6 +31,26 @@ int main() { errno = 0; printf("\n"); + printf("chdir(dir): %d\n", chdir("/dir")); + printf("errno: %d\n", errno); + if (!errno) { + errno = 0; + printf("getcwd: %s\n", getcwd(buffer, 256)); + printf("errno: %d\n", errno); + } + errno = 2; + printf("\n"); + + printf("chdir(\"\"): %d\n", chdir("")); + printf("errno: %d\n", errno); + if (!errno) { + errno = 0; + printf("getcwd: %s\n", getcwd(buffer, 256)); + printf("errno: %d\n", errno); + } + errno = 2; + printf("\n"); + printf("chdir(device): %d\n", chdir("/device")); printf("errno: %d\n", errno); if (!errno) { diff --git a/tests/unistd/curdir.out b/tests/unistd/curdir.out index 65fab9eba573d..40eefd9a66618 100644 --- a/tests/unistd/curdir.out +++ b/tests/unistd/curdir.out @@ -4,6 +4,12 @@ errno: 0 chdir(file): -1 errno: 20 +chdir(dir): -1 +errno: 2 + +chdir(""): -1 +errno: 2 + chdir(device): -1 errno: 20 From 7d57c75250a8bb8e6f7dcc2c1264390f86696b0e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 23 Nov 2016 21:25:59 -0800 Subject: [PATCH 42/86] clean up bullet benchmark invocation --- tests/test_benchmark.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 7713fd281307d..6f4c440dd23b4 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -631,9 +631,7 @@ def lib_builder(name, native, env_init): os.path.join('src', '.libs', 'libLinearMath.a')], configure_args=['--disable-demos','--disable-dependency-tracking'], native=native, cache_name_extra=name, env_init=env_init) - emcc_args = ['-s', 'DEAD_FUNCTIONS=["__ZSt9terminatev"]'] - - self.do_benchmark('bullet', src, '\nok.\n', emcc_args=emcc_args, shared_args=['-I' + path_from_root('tests', 'bullet', 'src'), + self.do_benchmark('bullet', src, '\nok.\n', shared_args=['-I' + path_from_root('tests', 'bullet', 'src'), '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks')], lib_builder=lib_builder) def zzz_test_zzz_lzma(self): From 65ca2ee7127acf12c9448b1259ecd63eab13a155 Mon Sep 17 00:00:00 2001 From: Guillaume Blanc Date: Mon, 28 Nov 2016 20:55:38 +0100 Subject: [PATCH 43/86] Fixes glfwGetMouseButton which isn't working if no callback function is set to glfwSetMouseButtonCallback. (#4752) --- src/library_glfw.js | 4 ++- tests/glfw_events.c | 80 ++++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index cb234d8d05fce..7a970522afda7 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -443,7 +443,7 @@ var LibraryGLFW = { }, onMouseButtonChanged: function(event, status) { - if (!GLFW.active || !GLFW.active.mouseButtonFunc) return; + if (!GLFW.active) return; Browser.calculateMouseEvent(event); @@ -460,6 +460,8 @@ var LibraryGLFW = { GLFW.active.buttons &= ~(1 << eventButton); } + if (!GLFW.active.mouseButtonFunc) return; + #if USE_GLFW == 2 Runtime.dynCall('vii', GLFW.active.mouseButtonFunc, [eventButton, status]); #endif diff --git a/tests/glfw_events.c b/tests/glfw_events.c index 96928ed2d71d4..3bb359773d4f9 100644 --- a/tests/glfw_events.c +++ b/tests/glfw_events.c @@ -39,7 +39,9 @@ { "Module.injectKeyEvent('keydown', 8)", { 0, 0.0, 0.0, GLFW_KEY_BACKSPACE, GLFW_PRESS, -1 } }, { "Module.injectKeyEvent('keyup', 8)", { 0, 0.0, 0.0, GLFW_KEY_BACKSPACE, GLFW_RELEASE, -1 } }, { "Module.injectKeyEvent('keydown', 9)", { 0, 0.0, 0.0, GLFW_KEY_TAB, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 9)", { 0, 0.0, 0.0, GLFW_KEY_TAB, GLFW_RELEASE, -1 } }, { "Module.injectKeyEvent('keydown', 112)", { 0, 0.0, 0.0, GLFW_KEY_F1, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 112)", { 0, 0.0, 0.0, GLFW_KEY_F1, GLFW_RELEASE, -1 } }, { "Module.injectKeyEvent('keydown', 37)", { 0, 0.0, 0.0, GLFW_KEY_LEFT, GLFW_PRESS, -1 } }, { "Module.injectKeyEvent('keyup', 37)", { 0, 0.0, 0.0, GLFW_KEY_LEFT, GLFW_RELEASE, -1 } }, { "Module.injectKeyEvent('keydown', 39)", { 0, 0.0, 0.0, GLFW_KEY_RIGHT, GLFW_PRESS, -1 } }, @@ -51,8 +53,10 @@ #if USE_GLFW == 2 { "Module.injectKeyEvent('keydown', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESC, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESC, GLFW_RELEASE, -1 } }, #else { "Module.injectKeyEvent('keydown', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESCAPE, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keyup', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESCAPE, GLFW_RELEASE, -1 } }, #endif }; @@ -133,8 +137,8 @@ int main() { - int result = 0; - unsigned int success = 0; + int result = 1; + unsigned int success = (1 << (sizeof(g_tests) / sizeof(test_t))) - 1; // (2^count)-1; emscripten_run_script(MULTILINE( Module.injectMouseEvent = function(x, y, event_, button) { @@ -171,8 +175,6 @@ glfwOpenWindow(WIDTH, HEIGHT, 5, 6, 5, 0, 0, 0, GLFW_WINDOW); // != GL_TRUE) glfwSetMousePosCallback(on_mouse_move); - glfwSetMouseButtonCallback(on_mouse_button_callback); - glfwSetKeyCallback(on_key_callback); //glfwSetCharCallback(...); #else glfwSetErrorCallback(on_error); @@ -183,49 +185,59 @@ _mainWindow = glfwCreateWindow(WIDTH, HEIGHT, "glfw3_events", NULL, NULL); glfwMakeContextCurrent(_mainWindow); - glfwSetMouseButtonCallback(_mainWindow, on_mouse_button_callback); glfwSetCursorPosCallback(_mainWindow, on_mouse_move); glfwSetScrollCallback(_mainWindow, on_mouse_wheel); - glfwSetKeyCallback(_mainWindow, on_key_callback); //glfwSetCharCallback(_mainWindow, ...); #endif - for (int i = 0; i < g_test_count; ++i) + for (int p = 0; p < 2 && result; ++p) // 2 passes, with and without callbacks. { - g_test_actual = i; - test_t test = g_tests[g_test_actual]; - emscripten_run_script(test.cmd); - - if (test.args.mouse) { - #if USE_GLFW == 2 - if (glfwGetMouseButton(test.args.button) != test.args.action) - #else - if (glfwGetMouseButton(_mainWindow, test.args.button) != test.args.action) - #endif - { - printf("Test %d: FAIL\n", g_test_actual); - g_state &= ~(1 << g_test_actual); - } - } else { - // Keyboard. - #if USE_GLFW == 2 - if (glfwGetKey(test.args.button) != test.args.action) - #else - if (glfwGetKey(_mainWindow, test.args.button) != test.args.action) - #endif - { - printf("Test %d: FAIL\n", g_test_actual); - g_state &= ~(1 << g_test_actual); + printf("Running Test pass %d\n", p); + + #if USE_GLFW == 2 + glfwSetMouseButtonCallback(p == 0 ? NULL : on_mouse_button_callback); + glfwSetKeyCallback(p == 0 ? NULL : on_key_callback); + #else + glfwSetMouseButtonCallback(_mainWindow, p == 0 ? NULL : on_mouse_button_callback); + glfwSetKeyCallback(_mainWindow, p == 0 ? NULL : on_key_callback); + #endif + g_state = p == 0 ? success : 0; + + for (int i = 0; i < g_test_count; ++i) + { + g_test_actual = i; + test_t test = g_tests[g_test_actual]; + emscripten_run_script(test.cmd); + + if (test.args.mouse) { + #if USE_GLFW == 2 + if (glfwGetMouseButton(test.args.button) != test.args.action) + #else + if (glfwGetMouseButton(_mainWindow, test.args.button) != test.args.action) + #endif + { + printf("Test %d: FAIL\n", g_test_actual); + g_state &= ~(1 << g_test_actual); + } + } else { + // Keyboard. + #if USE_GLFW == 2 + if (glfwGetKey(test.args.button) != test.args.action) + #else + if (glfwGetKey(_mainWindow, test.args.button) != test.args.action) + #endif + { + printf("Test %d: FAIL\n", g_test_actual); + g_state &= ~(1 << g_test_actual); + } } } + result = g_state == success; } glfwTerminate(); - success = (1 << (sizeof(g_tests) / sizeof(test_t))) - 1; // (2^count)-1 - #ifdef REPORT_RESULT - result = g_state == success; REPORT_RESULT(); #else printf("%d == %d = %d", g_state, success, g_state == success); From a360daab271d884c0103e32e4143c6d0aa541165 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 30 Nov 2016 14:28:16 -0800 Subject: [PATCH 44/86] test cleanup --- tests/test_core.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index eb8731999fa11..db4b732fc40a7 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -626,14 +626,10 @@ def ensure_stack_restore_count(function_name, expected_count): ensure_stack_restore_count('function _stack_usage', 1) def test_strings(self): - test_path = path_from_root('tests', 'core', 'test_strings') - src, output = (test_path + s for s in ('.c', '.out')) - - self.do_run_from_file(src, output, ['wowie', 'too', '74']) + test_path = path_from_root('tests', 'core', 'test_strings') + src, output = (test_path + s for s in ('.c', '.out')) - if self.emcc_args == []: - gen = open(self.in_dir('src.cpp.o.js')).read() - assert ('var __str1;' in gen) == named + self.do_run_from_file(src, output, ['wowie', 'too', '74']) def test_strcmp_uni(self): self.do_run_in_out_file_test('tests', 'core', 'test_strcmp_uni') From dafadb2f4f210426c841c0f1a605fafd43a97a3d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 30 Nov 2016 14:28:37 -0800 Subject: [PATCH 45/86] fix missing dependency of gethostbyname on htons #4761 --- src/deps_info.json | 2 +- tests/test_sockets.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/deps_info.json b/src/deps_info.json index 9f8798eff0f87..18e290a89f2a2 100644 --- a/src/deps_info.json +++ b/src/deps_info.json @@ -20,7 +20,7 @@ "freelocale": ["free"], "nl_langinfo": ["malloc"], "inet_ntoa": ["malloc"], - "gethostbyname": ["malloc"], + "gethostbyname": ["malloc", "htons"], "gethostbyname_r": ["free"], "getaddrinfo": ["malloc", "htonl", "htons", "ntohs"], "_inet_ntop6_raw": ["ntohs"], diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 6d2a387e14731..80237c20e73e1 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -338,6 +338,16 @@ def test_gethostbyname(self): def test_getprotobyname(self): self.do_run(open(path_from_root('tests', 'sockets', 'test_getprotobyname.c')).read(), 'success') + def test_link(self): + self.emcc_args += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] + self.do_run(r''' +#include + +int main () { + void* thing = gethostbyname("bing.com"); + return 0; +}''', '', force_c=True) + def test_sockets_echo(self): sockets_include = '-I'+path_from_root('tests', 'sockets') From f0d9f3d39971152408995301b19b7ff5ffa35431 Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Wed, 30 Nov 2016 15:35:13 -0800 Subject: [PATCH 46/86] Add support for importing globals in wasm_backend (#4742) --- emscripten.py | 20 ++++++++++++++------ tests/test_core.py | 10 +++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/emscripten.py b/emscripten.py index e98efebb20c10..aec62ebb49bac 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1422,12 +1422,16 @@ def asmjs_mangle(name): # in metadata[declares], the invoke wrappers will be generated in # this script later. import_type = parts[3][1:] + import_name = parts[2][1:-1] if import_type == 'memory': continue - assert import_type == 'func', 'No support for imports other than functions and memories' - func_name = parts[2][1:-1] - if not func_name.startswith('invoke_'): - metadata['declares'].append(func_name) + elif import_type == 'func': + if not import_name.startswith('invoke_'): + metadata['declares'].append(import_name) + elif import_type == 'global': + metadata['externs'].append('_' + import_name) + else: + assert False, 'Unhandled import type "%s"' % import_type elif line.startswith(' (func '): parts = line.split() func_name = parts[1][1:] @@ -1435,8 +1439,12 @@ def asmjs_mangle(name): elif line.startswith(' (export '): parts = line.split() export_name = parts[1][1:-1] - assert asmjs_mangle(export_name) not in metadata['exports'] - metadata['exports'].append(export_name) + export_type = parts[2][1:] + if export_type == 'func': + assert asmjs_mangle(export_name) not in metadata['exports'] + metadata['exports'].append(export_name) + else: + assert False, 'Unhandled export type "%s"' % export_type metadata['declares'] = filter(lambda x: not x.startswith('emscripten_asm_const'), metadata['declares']) # we emit those ourselves diff --git a/tests/test_core.py b/tests/test_core.py index db4b732fc40a7..3f8b06ecff1cc 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2043,8 +2043,8 @@ def test_tcgetattr(self): src = open(path_from_root('tests', 'termios', 'test_tcgetattr.c'), 'r').read() self.do_run(src, 'success', force_c=True) - @no_wasm_backend("tzname is included in library.js, but s2wasm doesn't know about it " - "at link time (unknown relocation $tzname)") + @no_wasm_backend('ctime relies on stackSave/stackRestore that is only generated in asmjs; ' + 'need to implement something similar in s2wasm') def test_time(self): src = open(path_from_root('tests', 'time', 'src.cpp'), 'r').read() expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read() @@ -2071,8 +2071,6 @@ def test_strptime_days(self): def test_strptime_reentrant(self): self.do_run_in_out_file_test('tests', 'core', 'test_strptime_reentrant') - @no_wasm_backend("tzname is included in library.js, but s2wasm doesn't know about it " - "at link time (unknown relocation $tzname)") def test_strftime(self): self.do_run_in_out_file_test('tests', 'core', 'test_strftime') @@ -4584,7 +4582,6 @@ def test_posixtime(self): def test_uname(self): self.do_run_in_out_file_test('tests', 'core', 'test_uname') - @no_wasm_backend('unknown relocation: $environ') def test_env(self): src = open(path_from_root('tests', 'env', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'env', 'output.txt'), 'r').read() @@ -4593,7 +4590,6 @@ def test_env(self): expected.replace('{{{ THIS_PROGRAM }}}', './this.program') # spidermonkey, v8 ]) - @no_wasm_backend('unknown relocation: $environ') def test_environ(self): src = open(path_from_root('tests', 'env', 'src-mini.c'), 'r').read() expected = open(path_from_root('tests', 'env', 'output-mini.txt'), 'r').read() @@ -5554,7 +5550,7 @@ def clean(text): Settings.ALLOW_MEMORY_GROWTH = 0 do_test() - @no_wasm_backend('unknown relocation: $environ') + @no_wasm_backend("python.bc was compiled with asmjs, and we don't have unified triples") def test_python(self): Settings.EMULATE_FUNCTION_POINTER_CASTS = 1 From d650883c6850f5d6867433c24844908ec1f0e949 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Dec 2016 15:59:48 -0800 Subject: [PATCH 47/86] fix test_demangle_stacks_symbol_map --- tests/test_core.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 3f8b06ecff1cc..d1a04a00a39c9 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6092,8 +6092,10 @@ def test_demangle_stacks(self): @no_wasm_backend() def test_demangle_stacks_symbol_map(self): Settings.DEMANGLE_SUPPORT = 1 - if '-O' in str(self.emcc_args): + if '-O' in str(self.emcc_args) and '-O0' not in self.emcc_args and '-O1' not in self.emcc_args and '-g' not in self.emcc_args: self.emcc_args += ['--llvm-opts', '0'] + else: + return self.skip("without opts, we don't emit a symbol map") self.emcc_args += ['--emit-symbol-map'] self.do_run(open(path_from_root('tests', 'core', 'test_demangle_stacks.c')).read(), 'abort') # make sure the shortened name is the right one @@ -6104,13 +6106,15 @@ def test_demangle_stacks_symbol_map(self): if 'Aborter' in full: short_aborter = short full_aborter = full + print 'full:', full_aborter, 'short:', short_aborter if SPIDERMONKEY_ENGINE and os.path.exists(SPIDERMONKEY_ENGINE[0]): output = run_js('src.cpp.o.js', engine=SPIDERMONKEY_ENGINE, stderr=PIPE, full_output=True, assert_returncode=None) # we may see the full one, if -g, or the short one if not if ' ' + short_aborter + ' ' not in output and ' ' + full_aborter + ' ' not in output: # stack traces may also be ' name ' or 'name@' etc if '\n' + short_aborter + ' ' not in output and '\n' + full_aborter + ' ' not in output and 'wasm-function[' + short_aborter + ']' not in output: - self.assertContained(' ' + short_aborter + ' ' + '\n' + ' ' + full_aborter + ' ', output) + if '\n' + short_aborter + '@' not in output and '\n' + full_aborter + '@' not in output: + self.assertContained(' ' + short_aborter + ' ' + '\n' + ' ' + full_aborter + ' ', output) def test_tracing(self): Building.COMPILER_TEST_OPTS += ['--tracing'] From a047a2c8e72006ca7eeadaace0f6dd8f83c33798 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Dec 2016 16:12:48 -0800 Subject: [PATCH 48/86] fix browser.test_sdl_key, which broke when -O0 stopped having -g ; the test used to rely on code not being gc'd, which optimizations do, so use EM_ASM instead of emscripten_run_script --- tests/sdl_key.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/sdl_key.c b/tests/sdl_key.c index 3f3036de8cc5e..169d53d006a47 100644 --- a/tests/sdl_key.c +++ b/tests/sdl_key.c @@ -66,10 +66,10 @@ int main(int argc, char **argv) { emscripten_set_main_loop(one, 0, 0); - emscripten_run_script("keydown(1250);keydown(38);keyup(38);keyup(1250);"); // alt, up - emscripten_run_script("keydown(1248);keydown(1249);keydown(40);keyup(40);keyup(1249);keyup(1248);"); // ctrl, shift, down - emscripten_run_script("keydown(37);keyup(37);"); // left - emscripten_run_script("keydown(39);keyup(39);"); // right + EM_ASM({keydown(1250);keydown(38);keyup(38);keyup(1250);}); // alt, up + EM_ASM({keydown(1248);keydown(1249);keydown(40);keyup(40);keyup(1249);keyup(1248);}); // ctrl, shift, down + EM_ASM({keydown(37);keyup(37);}); // left + EM_ASM({keydown(39);keyup(39);}); // right #ifdef TEST_SLEEP printf("sleep...\n"); @@ -78,9 +78,9 @@ int main(int argc, char **argv) { printf("rise!\n"); #endif - emscripten_run_script("keydown(65);keyup(65);"); // a - emscripten_run_script("keydown(66);keyup(66);"); // b - emscripten_run_script("keydown(100);keyup(100);"); // trigger the end + EM_ASM({keydown(65);keyup(65);}); // a + EM_ASM({keydown(66);keyup(66);}); // b + EM_ASM({keydown(100);keyup(100);}); // trigger the end return 0; } From 18c146356fa9f032dd3eabf20be6e66620a67518 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Dec 2016 16:18:27 -0800 Subject: [PATCH 49/86] don't warn on memory growth removing opts in wasm, since there it is fast (#4768) --- emcc.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/emcc.py b/emcc.py index 1d438530dbb62..8af5674d24f45 100755 --- a/emcc.py +++ b/emcc.py @@ -1052,10 +1052,6 @@ def check(input_file): assert not use_closure_compiler, 'cannot use closure compiler on shared modules' assert not shared.Settings.ALLOW_MEMORY_GROWTH, 'memory growth is not supported with shared modules yet' - if shared.Settings.ALLOW_MEMORY_GROWTH: - logging.warning('not all asm.js optimizations are possible with ALLOW_MEMORY_GROWTH, disabling those') - shared.Settings.ASM_JS = 2 # memory growth does not validate as asm.js http://discourse.wicg.io/t/request-for-comments-switching-resizing-heaps-in-asm-js/641/23 - if shared.Settings.EMULATE_FUNCTION_POINTER_CASTS: shared.Settings.ALIASING_FUNCTION_POINTERS = 0 @@ -1216,6 +1212,12 @@ def check(input_file): # * and js mem inits are useful for avoiding a side file, but the wasm module avoids that anyhow memory_init_file = True + if shared.Settings.ALLOW_MEMORY_GROWTH and shared.Settings.ASM_JS == 1: + # this is an issue in asm.js, but not wasm + if not shared.Settings.WASM or 'asmjs' in shared.Settings.BINARYEN_METHOD: + logging.warning('not all asm.js optimizations are possible with ALLOW_MEMORY_GROWTH, disabling those') + shared.Settings.ASM_JS = 2 # memory growth does not validate as asm.js http://discourse.wicg.io/t/request-for-comments-switching-resizing-heaps-in-asm-js/641/23 + if js_opts: shared.Settings.RUNNING_JS_OPTS = 1 From 1614fd397719239ce50478570de1d540dfd22b05 Mon Sep 17 00:00:00 2001 From: Alex Hixon Date: Sun, 4 Dec 2016 12:51:51 +1100 Subject: [PATCH 50/86] fix missing dependency of recv, send on htons --- AUTHORS | 1 + src/deps_info.json | 4 +++- tests/test_sockets.py | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 171a697df7922..1538ab336f7d5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -267,3 +267,4 @@ a license to everyone to use it as detailed in LICENSE.) * Christopher Serr * Aaron Ruß (copyright owned by DFKI GmbH) * Vilibald Wanča +* Alex Hixon diff --git a/src/deps_info.json b/src/deps_info.json index 18e290a89f2a2..ff5cb49c7a8ba 100644 --- a/src/deps_info.json +++ b/src/deps_info.json @@ -44,6 +44,8 @@ "bind": ["htonl", "htons", "ntohs"], "connect": ["htonl", "htons", "ntohs"], "socket": ["htonl", "htons", "ntohs"], - "sleep": ["usleep"] + "sleep": ["usleep"], + "recv": ["htons"], + "send": ["htons"] } diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 80237c20e73e1..66291797af3dd 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -343,8 +343,13 @@ def test_link(self): self.do_run(r''' #include +#include +#include + int main () { void* thing = gethostbyname("bing.com"); + ssize_t rval = recv (0, thing, 0, 0); + rval = send (0, thing, 0, 0); return 0; }''', '', force_c=True) From fdc57b6f7c76b7e8589a41ad2db867e6878f0f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 4 Dec 2016 04:39:05 +0200 Subject: [PATCH 51/86] Fix allocation of output string in emscripten_run_script_string() to not truncate the string if it has characters outside 7-bit ASCII set. Fixes #4766. --- src/library.js | 5 +++-- tests/test_core.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 764931b102fdd..5413f0cd22f68 100644 --- a/src/library.js +++ b/src/library.js @@ -3831,9 +3831,10 @@ LibraryManager.library = { emscripten_run_script_string: function(ptr) { {{{ makeEval("var s = eval(Pointer_stringify(ptr)) + '';") }}} var me = _emscripten_run_script_string; - if (!me.bufferSize || me.bufferSize < s.length+1) { + var len = lengthBytesUTF8(s); + if (!me.bufferSize || me.bufferSize < len+1) { if (me.bufferSize) _free(me.buffer); - me.bufferSize = s.length+1; + me.bufferSize = len+1; me.buffer = _malloc(me.bufferSize); } stringToUTF8(s, me.buffer, me.bufferSize); diff --git a/tests/test_core.py b/tests/test_core.py index d1a04a00a39c9..4fe99de077e9f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1508,6 +1508,21 @@ def process(filename): self.do_run_in_out_file_test('tests', 'core', 'test_emscripten_api', post_build=check) + def test_emscripten_run_script_string_utf8(self): + src = r''' + #include + #include + #include + #include + + int main() { + const char *str = emscripten_run_script_string("'\\u2603 \\u2603 \\u2603 Hello!'"); + printf("length of returned string: %d. Position of substring 'Hello': %d\n", strlen(str), strstr(str, "Hello")-str); + return 0; + } + ''' + self.do_run(src, '''length of returned string: 18. Position of substring 'Hello': 12''') + def test_emscripten_get_now(self): self.banned_js_engines = [V8_ENGINE] # timer limitations in v8 shell From 6a148a2548b4387784e251961b9a24b000c03e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 25 Oct 2016 00:05:05 +0300 Subject: [PATCH 52/86] If environment variable EMSCRIPTEN_STRICT is set, don't pass the preprocessor define EMSCRIPTEN to compiled code. --- emcc.py | 5 ++++- tools/shared.py | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index 8af5674d24f45..e0d023e62f699 100755 --- a/emcc.py +++ b/emcc.py @@ -250,7 +250,10 @@ def filter_emscripten_options(argv): if compiler == shared.EMCC: compiler = [shared.PYTHON, shared.EMCC] else: compiler = [compiler] cmd = compiler + list(filter_emscripten_options(sys.argv[1:])) - if not use_js: cmd += shared.EMSDK_OPTS + ['-D__EMSCRIPTEN__', '-DEMSCRIPTEN'] + if not use_js: + cmd += shared.EMSDK_OPTS + ['-D__EMSCRIPTEN__'] + # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. + if not os.environ.get('EMSCRIPTEN_STRICT') or int(os.environ.get('EMSCRIPTEN_STRICT')) == 0: cmd += ['-DEMSCRIPTEN'] if use_js: cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists logging.debug('just configuring: ' + ' '.join(cmd)) diff --git a/tools/shared.py b/tools/shared.py index c9ce4ea7850a8..485c91a80f76d 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -927,12 +927,14 @@ def get_llvm_target(): if LLVM_TARGET == WASM_TARGET: # wasm target does not automatically define emscripten stuff, so do it here. - COMPILER_OPTS = COMPILER_OPTS + ['-DEMSCRIPTEN', - '-D__EMSCRIPTEN__', + COMPILER_OPTS = COMPILER_OPTS + ['-D__EMSCRIPTEN__', '-Dunix', '-D__unix', '-D__unix__'] + # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. + if not os.environ.get('EMSCRIPTEN_STRICT') or int(os.environ.get('EMSCRIPTEN_STRICT')) == 0: COMPILER_OPTS += ['-DEMSCRIPTEN'] + # Changes to default clang behavior # Implicit functions can cause horribly confusing function pointer type errors, see #2175 From 8e3bf5b6218270fdc1c5f59c07458c6c8bcb0a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 25 Oct 2016 00:11:54 +0300 Subject: [PATCH 53/86] -s ERROR_ON_UNDEFINED_SYMBOLS=1 should be the default value, so set it in strict mode. --- tools/shared.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/shared.py b/tools/shared.py index 485c91a80f76d..c7704376736e9 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1098,6 +1098,11 @@ def load(self, args=[]): settings = re.sub(r'var ([\w\d]+)', r'self.attrs["\1"]', settings) exec settings + # Apply default values for settings that are configured from environment variables. + if os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0: + # The default value -s ERROR_ON_UNDEFINED_SYMBOLS=0 is deprecated. Use the default value 1 in strict mode. + self.attrs['ERROR_ON_UNDEFINED_SYMBOLS'] = 1 + # Apply additional settings. First -O, then -s for i in range(len(args)): if args[i].startswith('-O'): From b8e913002e98f5572b4b8a0cadde9727528991c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 25 Oct 2016 00:25:08 +0300 Subject: [PATCH 54/86] Convert "emcc: cannot find library" warning to an option configurable with -s ERROR_ON_MISSING_LIBRARIES=0/1. Default to 0, but in EMSCRIPTEN_STRICT mode, default to 1. --- emcc.py | 8 +++++++- src/settings.js | 13 +++++++++++++ tools/shared.py | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index e0d023e62f699..bf9423ff9f312 100755 --- a/emcc.py +++ b/emcc.py @@ -938,7 +938,13 @@ def detect_fixed_language_mode(args): if found: break if found: break if not found and lib not in ['GL', 'GLU', 'glut', 'm', 'c', 'SDL', 'stdc++', 'pthread']: # whitelist our default libraries - logging.warning('emcc: cannot find library "%s"', lib) + emscripten_strict_mode = os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0 + error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes + if error_on_missing_libraries: + logging.fatal('emcc: cannot find library "%s"', lib) + exit(1) + else: + logging.warning('emcc: cannot find library "%s"', lib) # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so # ignore dynamic linking, since multiple dynamic linkings can interfere with each other diff --git a/src/settings.js b/src/settings.js index 7926a42f7965d..3b6ae646ed3bd 100644 --- a/src/settings.js +++ b/src/settings.js @@ -501,6 +501,19 @@ var WARN_ON_UNDEFINED_SYMBOLS = 1; // If set to 1, we will warn on any undefined var ERROR_ON_UNDEFINED_SYMBOLS = 0; // If set to 1, we will give a compile-time error on any // undefined symbols (see WARN_ON_UNDEFINED_SYMBOLS). + // The default value for this is currently 0, but will be + // transitioned to 1 in the future. To keep relying on + // building with -s ERROR_ON_UNDEFINED_SYMBOLS=0 setting, + // prefer to set that option explicitly in your build system. + +var ERROR_ON_MISSING_LIBRARIES = 0; // If set to 1, any -lfoo directives pointing to nonexisting + // library files will issue a linker error. + + // The default value for this is currently 0, but will be + // transitioned to 1 in the future. To keep relying on + // building with -s ERROR_ON_MISSING_LIBRARIES=0 setting, + // prefer to set that option explicitly in your build system. + var SMALL_XHR_CHUNKS = 0; // Use small chunk size for binary synchronous XHR's in Web Workers. // Used for testing. // See test_chunked_synchronous_xhr in runner.py and library.js. diff --git a/tools/shared.py b/tools/shared.py index c7704376736e9..d0f23ea2adae8 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1102,6 +1102,7 @@ def load(self, args=[]): if os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0: # The default value -s ERROR_ON_UNDEFINED_SYMBOLS=0 is deprecated. Use the default value 1 in strict mode. self.attrs['ERROR_ON_UNDEFINED_SYMBOLS'] = 1 + self.attrs['ERROR_ON_MISSING_LIBRARIES'] = 1 # Apply additional settings. First -O, then -s for i in range(len(args)): From 4e1eabec6ecdfe220a9a9cf0551147e4bf32e226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 25 Oct 2016 00:27:30 +0300 Subject: [PATCH 55/86] Remove Emscripten include path system/include/emscripten in EMSCRIPTEN_STRICT build mode. --- tools/shared.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index d0f23ea2adae8..016a859608e82 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -952,13 +952,17 @@ def get_llvm_target(): C_INCLUDE_PATHS = [ path_from_root('system', 'include', 'compat'), path_from_root('system', 'include'), - path_from_root('system', 'include', 'emscripten'), path_from_root('system', 'include', 'SSE'), path_from_root('system', 'include', 'libc'), path_from_root('system', 'lib', 'libc', 'musl', 'arch', 'emscripten'), path_from_root('system', 'local', 'include') ] + # The system include path system/include/emscripten/ is deprecated, i.e. instead of #include , one should pass in #include . + # This path is not available in EMSCRIPTEN_STRICT mode. + if not os.environ.get('EMSCRIPTEN_STRICT') or int(os.environ.get('EMSCRIPTEN_STRICT')) == 0: + C_INCLUDE_PATHS += [path_from_root('system', 'include', 'emscripten')] + CXX_INCLUDE_PATHS = [ path_from_root('system', 'include', 'libcxx'), path_from_root('system', 'lib', 'libcxxabi', 'include') From f2d975a124bed4f0cdc282e311b965911f59318d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 25 Oct 2016 00:37:45 +0300 Subject: [PATCH 56/86] Add EMSCRIPTEN_STRICT as a linker setting as well. --- emcc.py | 2 +- src/settings.js | 4 ++++ tools/shared.py | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/emcc.py b/emcc.py index bf9423ff9f312..1db9c8ba4d251 100755 --- a/emcc.py +++ b/emcc.py @@ -938,7 +938,7 @@ def detect_fixed_language_mode(args): if found: break if found: break if not found and lib not in ['GL', 'GLU', 'glut', 'm', 'c', 'SDL', 'stdc++', 'pthread']: # whitelist our default libraries - emscripten_strict_mode = os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0 + emscripten_strict_mode = (os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0) or 'EMSCRIPTEN_STRICT=1' in settings_changes error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes if error_on_missing_libraries: logging.fatal('emcc: cannot find library "%s"', lib) diff --git a/src/settings.js b/src/settings.js index 3b6ae646ed3bd..054f7d5733b59 100644 --- a/src/settings.js +++ b/src/settings.js @@ -487,6 +487,10 @@ var LINKABLE = 0; // If set to 1, this file can be linked with others, either as // LINKABLE of 0 is very useful in that we can reduce the size of the // generated code very significantly, by removing everything not actually used. +var EMSCRIPTEN_STRICT = 0; // Emscripten 'strict' build mode: Drop supporting any deprecated build options. + // Set the environment variable EMSCRIPTEN_STRICT=1 or pass -s EMSCRIPTEN_STRICT=1 + // to test that a codebase builds nicely in forward compatible manner. + var WARN_ON_UNDEFINED_SYMBOLS = 1; // If set to 1, we will warn on any undefined symbols that // are not resolved by the library_*.js files. Note that // it is common in large projects to diff --git a/tools/shared.py b/tools/shared.py index 016a859608e82..b785431e34fd3 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1104,7 +1104,8 @@ def load(self, args=[]): # Apply default values for settings that are configured from environment variables. if os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0: - # The default value -s ERROR_ON_UNDEFINED_SYMBOLS=0 is deprecated. Use the default value 1 in strict mode. + # Specify default values for Emscripten strict mode. + self.attrs['EMSCRIPTEN_STRICT'] = 1 self.attrs['ERROR_ON_UNDEFINED_SYMBOLS'] = 1 self.attrs['ERROR_ON_MISSING_LIBRARIES'] = 1 From 1b3fe4241f1e39039b3bd0368eea3235a227a796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 25 Oct 2016 01:04:00 +0300 Subject: [PATCH 57/86] In EMSCRIPTEN_STRICT mode, stop autolinking to all system provided JS libraries, but instead require explicitly specifying which ones to link to on command line. --- emcc.py | 41 +++++++++++++++++++++++++------ src/modules.js | 65 ++++++++++++++++++++++++++++++++----------------- src/settings.js | 3 +++ 3 files changed, 80 insertions(+), 29 deletions(-) diff --git a/emcc.py b/emcc.py index 1db9c8ba4d251..16a33c1104ca8 100755 --- a/emcc.py +++ b/emcc.py @@ -921,6 +921,8 @@ def detect_fixed_language_mode(args): if separate_asm: shared.Settings.SEPARATE_ASM = os.path.basename(asm_target) + system_js_libraries = [] + # Find library files for i, lib in libs: logging.debug('looking for library "%s"', lib) @@ -937,14 +939,39 @@ def detect_fixed_language_mode(args): break if found: break if found: break - if not found and lib not in ['GL', 'GLU', 'glut', 'm', 'c', 'SDL', 'stdc++', 'pthread']: # whitelist our default libraries - emscripten_strict_mode = (os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0) or 'EMSCRIPTEN_STRICT=1' in settings_changes - error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes - if error_on_missing_libraries: - logging.fatal('emcc: cannot find library "%s"', lib) - exit(1) + if not found: + # Some native libraries are implemented in Emscripten as system side JS libraries + js_system_libraries = { + 'c': '', + 'EGL': 'library_egl.js', + 'GL': 'library_gl.js', + 'GLESv2': 'library_gl.js', + 'GLEW': 'library_glew.js', + 'glfw': 'library_glfw.js', + 'glfw3': 'library_glfw.js', + 'GLU': '', + 'glut': 'library_glut.js', + 'm': '', + 'openal': 'library_openal.js', + 'pthread': '', + 'SDL': 'library_sdl.js', + 'stdc++': '' + } + if lib in js_system_libraries: + if len(js_system_libraries[lib]) > 0: + system_js_libraries += [js_system_libraries[lib]] + elif lib.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + lib)): + system_js_libraries += ['library_' + lib] else: - logging.warning('emcc: cannot find library "%s"', lib) + emscripten_strict_mode = (os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0) or 'EMSCRIPTEN_STRICT=1' in settings_changes + error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes + if error_on_missing_libraries: + logging.fatal('emcc: cannot find library "%s"', lib) + exit(1) + else: + logging.warning('emcc: cannot find library "%s"', lib) + + settings_changes.append('SYSTEM_JS_LIBRARIES="' + ','.join(system_js_libraries) + '"') # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so # ignore dynamic linking, since multiple dynamic linkings can interfere with each other diff --git a/src/modules.js b/src/modules.js index aaff60faefe9f..ef8a1a08182b3 100644 --- a/src/modules.js +++ b/src/modules.js @@ -96,41 +96,62 @@ var LibraryManager = { load: function() { if (this.library) return; + // Core system libraries (always linked against) var libraries = [ 'library.js', 'library_browser.js', 'library_formatString.js', 'library_path.js', - 'library_syscall.js' + 'library_syscall.js', + 'library_html5.js' ]; + if (!NO_FILESYSTEM) { + // Core filesystem libraries (always linked against, unless -s NO_FILESYSTEM=1 is specified) libraries = libraries.concat([ 'library_fs.js', - 'library_idbfs.js', 'library_memfs.js', - 'library_nodefs.js', - 'library_sockfs.js', - 'library_workerfs.js', 'library_tty.js', - 'library_lz4.js', + ]); + + // Additional filesystem libraries (in strict mode, link to these explicitly via -lxxx.js) + if (!EMSCRIPTEN_STRICT) { + libraries = libraries.concat([ + 'library_idbfs.js', + 'library_nodefs.js', + 'library_sockfs.js', + 'library_workerfs.js', + 'library_lz4.js', + ]); + } + } + + // Additional JS libraries (in strict mode, link to these explicitly via -lxxx.js) + if (!EMSCRIPTEN_STRICT) { + libraries = libraries.concat([ + 'library_sdl.js', + 'library_gl.js', + 'library_glut.js', + 'library_xlib.js', + 'library_egl.js', + 'library_openal.js', + 'library_glfw.js', + 'library_uuid.js', + 'library_glew.js', + 'library_signals.js', + 'library_idbstore.js', + 'library_async.js', + 'library_vr.js' ]); } - libraries = libraries.concat([ - 'library_sdl.js', - 'library_gl.js', - 'library_glut.js', - 'library_xlib.js', - 'library_egl.js', - 'library_openal.js', - 'library_glfw.js', - 'library_uuid.js', - 'library_glew.js', - 'library_html5.js', - 'library_signals.js', - 'library_idbstore.js', - 'library_async.js', - 'library_vr.js' - ]).concat(additionalLibraries); + + // If there are any explicitly specified system JS libraries to link to, add those to link. + if (SYSTEM_JS_LIBRARIES) { + SYSTEM_JS_LIBRARIES = SYSTEM_JS_LIBRARIES.split(','); + libraries = libraries.concat(SYSTEM_JS_LIBRARIES); + } + + libraries = libraries.concat(additionalLibraries); if (BOOTSTRAPPING_STRUCT_INFO) libraries = ['library_bootstrap_structInfo.js', 'library_formatString.js']; if (ONLY_MY_CODE) { diff --git a/src/settings.js b/src/settings.js index 054f7d5733b59..2d4e14d6a72c7 100644 --- a/src/settings.js +++ b/src/settings.js @@ -518,6 +518,9 @@ var ERROR_ON_MISSING_LIBRARIES = 0; // If set to 1, any -lfoo directives pointin // building with -s ERROR_ON_MISSING_LIBRARIES=0 setting, // prefer to set that option explicitly in your build system. +var SYSTEM_JS_LIBRARIES = []; // Specifies a list of Emscripten-provided JS libraries to link against. + // (internal, use -lfoo or -lfoo.js to link to Emscripten system JS libraries) + var SMALL_XHR_CHUNKS = 0; // Use small chunk size for binary synchronous XHR's in Web Workers. // Used for testing. // See test_chunked_synchronous_xhr in runner.py and library.js. From 72c97d188b778377d7d310a0aac1c0a5fd1b7321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 26 Oct 2016 12:16:31 +0300 Subject: [PATCH 58/86] Rename Emscripten strict mode to EMCC_STRICT=1 env var/-s STRICT=1 linker flag. --- emcc.py | 4 ++-- src/modules.js | 4 ++-- src/settings.js | 6 +++--- tools/shared.py | 14 +++++++++----- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/emcc.py b/emcc.py index 16a33c1104ca8..f7553cb83b918 100755 --- a/emcc.py +++ b/emcc.py @@ -253,7 +253,7 @@ def filter_emscripten_options(argv): if not use_js: cmd += shared.EMSDK_OPTS + ['-D__EMSCRIPTEN__'] # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. - if not os.environ.get('EMSCRIPTEN_STRICT') or int(os.environ.get('EMSCRIPTEN_STRICT')) == 0: cmd += ['-DEMSCRIPTEN'] + if not shared.is_emscripten_strict(): cmd += ['-DEMSCRIPTEN'] if use_js: cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists logging.debug('just configuring: ' + ' '.join(cmd)) @@ -963,7 +963,7 @@ def detect_fixed_language_mode(args): elif lib.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + lib)): system_js_libraries += ['library_' + lib] else: - emscripten_strict_mode = (os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0) or 'EMSCRIPTEN_STRICT=1' in settings_changes + emscripten_strict_mode = shared.is_emscripten_strict() or 'STRICT=1' in settings_changes error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes if error_on_missing_libraries: logging.fatal('emcc: cannot find library "%s"', lib) diff --git a/src/modules.js b/src/modules.js index ef8a1a08182b3..4c1c8a676e81b 100644 --- a/src/modules.js +++ b/src/modules.js @@ -115,7 +115,7 @@ var LibraryManager = { ]); // Additional filesystem libraries (in strict mode, link to these explicitly via -lxxx.js) - if (!EMSCRIPTEN_STRICT) { + if (!STRICT) { libraries = libraries.concat([ 'library_idbfs.js', 'library_nodefs.js', @@ -127,7 +127,7 @@ var LibraryManager = { } // Additional JS libraries (in strict mode, link to these explicitly via -lxxx.js) - if (!EMSCRIPTEN_STRICT) { + if (!STRICT) { libraries = libraries.concat([ 'library_sdl.js', 'library_gl.js', diff --git a/src/settings.js b/src/settings.js index 2d4e14d6a72c7..badd9e527a3c5 100644 --- a/src/settings.js +++ b/src/settings.js @@ -487,9 +487,9 @@ var LINKABLE = 0; // If set to 1, this file can be linked with others, either as // LINKABLE of 0 is very useful in that we can reduce the size of the // generated code very significantly, by removing everything not actually used. -var EMSCRIPTEN_STRICT = 0; // Emscripten 'strict' build mode: Drop supporting any deprecated build options. - // Set the environment variable EMSCRIPTEN_STRICT=1 or pass -s EMSCRIPTEN_STRICT=1 - // to test that a codebase builds nicely in forward compatible manner. +var STRICT = 0; // Emscripten 'strict' build mode: Drop supporting any deprecated build options. + // Set the environment variable EMCC_STRICT=1 or pass -s STRICT=1 + // to test that a codebase builds nicely in forward compatible manner. var WARN_ON_UNDEFINED_SYMBOLS = 1; // If set to 1, we will warn on any undefined symbols that // are not resolved by the library_*.js files. Note that diff --git a/tools/shared.py b/tools/shared.py index b785431e34fd3..dcacdb1e6c426 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -472,6 +472,10 @@ def find_temp_directory(): def get_emscripten_version(path): return open(path).read().strip().replace('"', '') +# Returns true if Emscripten is running in 'strict' mode, in which deprecated compiler features are not supported. +def is_emscripten_strict(): + return (os.environ.get('EMCC_STRICT') and int(os.environ.get('EMCC_STRICT')) != 0) or Settings.STRICT + # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) # exists. # The test runner always does this check (through |force|). emcc does this less frequently, @@ -933,7 +937,7 @@ def get_llvm_target(): '-D__unix__'] # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. - if not os.environ.get('EMSCRIPTEN_STRICT') or int(os.environ.get('EMSCRIPTEN_STRICT')) == 0: COMPILER_OPTS += ['-DEMSCRIPTEN'] + if not is_emscripten_strict(): COMPILER_OPTS += ['-DEMSCRIPTEN'] # Changes to default clang behavior @@ -959,8 +963,8 @@ def get_llvm_target(): ] # The system include path system/include/emscripten/ is deprecated, i.e. instead of #include , one should pass in #include . - # This path is not available in EMSCRIPTEN_STRICT mode. - if not os.environ.get('EMSCRIPTEN_STRICT') or int(os.environ.get('EMSCRIPTEN_STRICT')) == 0: + # This path is not available in Emscripten strict mode. + if not is_emscripten_strict(): C_INCLUDE_PATHS += [path_from_root('system', 'include', 'emscripten')] CXX_INCLUDE_PATHS = [ @@ -1103,9 +1107,9 @@ def load(self, args=[]): exec settings # Apply default values for settings that are configured from environment variables. - if os.environ.get('EMSCRIPTEN_STRICT') and int(os.environ.get('EMSCRIPTEN_STRICT')) != 0: + if is_emscripten_strict(): # Specify default values for Emscripten strict mode. - self.attrs['EMSCRIPTEN_STRICT'] = 1 + self.attrs['STRICT'] = 1 self.attrs['ERROR_ON_UNDEFINED_SYMBOLS'] = 1 self.attrs['ERROR_ON_MISSING_LIBRARIES'] = 1 From 381eca8d997e9175f5c8e11eb317e11f5cd741b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 26 Oct 2016 12:31:32 +0300 Subject: [PATCH 59/86] Add root level include emscripten.h so that both forms #include and #include can be used in the future. --- system/include/emscripten.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 system/include/emscripten.h diff --git a/system/include/emscripten.h b/system/include/emscripten.h new file mode 100644 index 0000000000000..b1aad2034aad2 --- /dev/null +++ b/system/include/emscripten.h @@ -0,0 +1 @@ +#include "emscripten/emscripten.h" From af265a581a528a5e7c0fd1ee7bdb724e7b720059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 26 Oct 2016 21:40:02 +0300 Subject: [PATCH 60/86] Finalize EMCC_STRICT mode for linking to libraries. Improve browser suite to pass in EMCC_STRICT mode. --- emcc.py | 14 +- src/library_fs.js | 18 ++- src/modules.js | 7 +- tests/test_browser.py | 332 +++++++++++++++++++++--------------------- tools/shared.py | 7 +- 5 files changed, 208 insertions(+), 170 deletions(-) diff --git a/emcc.py b/emcc.py index f7553cb83b918..1f031e809cc9f 100755 --- a/emcc.py +++ b/emcc.py @@ -954,12 +954,18 @@ def detect_fixed_language_mode(args): 'm': '', 'openal': 'library_openal.js', 'pthread': '', + 'X11': 'library_xlib.js', 'SDL': 'library_sdl.js', - 'stdc++': '' + 'stdc++': '', + 'uuid': 'library_uuid.js' } if lib in js_system_libraries: if len(js_system_libraries[lib]) > 0: system_js_libraries += [js_system_libraries[lib]] + + # TODO: This is unintentional due to historical reasons. Improve EGL to use HTML5 API to avoid depending on GLUT. + if lib == 'EGL': system_js_libraries += ['library_glut.js'] + elif lib.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + lib)): system_js_libraries += ['library_' + lib] else: @@ -971,6 +977,12 @@ def detect_fixed_language_mode(args): else: logging.warning('emcc: cannot find library "%s"', lib) + # Certain linker flags imply some link libraries to be pulled in by default. + if 'EMTERPRETIFY_ASYNC=1' in settings_changes: system_js_libraries += ['library_async.js'] + if 'ASYNCIFY=1' in settings_changes: system_js_libraries += ['library_async.js'] + if 'LZ4=1' in settings_changes: system_js_libraries += ['library_lz4.js'] + if 'USE_SDL=1' in settings_changes: system_js_libraries += ['library_sdl.js'] + if 'USE_SDL=2' in settings_changes: system_js_libraries += ['library_egl.js', 'library_glut.js', 'library_gl.js'] settings_changes.append('SYSTEM_JS_LIBRARIES="' + ','.join(system_js_libraries) + '"') # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so diff --git a/src/library_fs.js b/src/library_fs.js index 1b60f2ad29804..e581d93354fad 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1,5 +1,15 @@ mergeInto(LibraryManager.library, { - $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$PATH', '$TTY', '$MEMFS', '$IDBFS', '$NODEFS', '$WORKERFS', 'stdin', 'stdout', 'stderr'], + $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$PATH', '$TTY', '$MEMFS', +#if __EMSCRIPTEN_HAS_idbfs_js__ + '$IDBFS', +#endif +#if __EMSCRIPTEN_HAS_nodefs_js__ + '$NODEFS', +#endif +#if __EMSCRIPTEN_HAS_workerfs_js__ + '$WORKERFS', +#endif + 'stdin', 'stdout', 'stderr'], $FS__postset: 'FS.staticInit();' + '__ATINIT__.unshift(function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() });' + '__ATMAIN__.push(function() { FS.ignorePermissions = false });' + @@ -1382,9 +1392,15 @@ mergeInto(LibraryManager.library, { FS.filesystems = { 'MEMFS': MEMFS, +#if __EMSCRIPTEN_HAS_idbfs_js__ 'IDBFS': IDBFS, +#endif +#if __EMSCRIPTEN_HAS_nodefs_js__ 'NODEFS': NODEFS, +#endif +#if __EMSCRIPTEN_HAS_workerfs_js__ 'WORKERFS': WORKERFS, +#endif }; }, init: function(input, output, error) { diff --git a/src/modules.js b/src/modules.js index 4c1c8a676e81b..c9238c3cf3e76 100644 --- a/src/modules.js +++ b/src/modules.js @@ -102,6 +102,7 @@ var LibraryManager = { 'library_browser.js', 'library_formatString.js', 'library_path.js', + 'library_signals.js', 'library_syscall.js', 'library_html5.js' ]; @@ -138,7 +139,6 @@ var LibraryManager = { 'library_glfw.js', 'library_uuid.js', 'library_glew.js', - 'library_signals.js', 'library_idbstore.js', 'library_async.js', 'library_vr.js' @@ -148,6 +148,11 @@ var LibraryManager = { // If there are any explicitly specified system JS libraries to link to, add those to link. if (SYSTEM_JS_LIBRARIES) { SYSTEM_JS_LIBRARIES = SYSTEM_JS_LIBRARIES.split(','); + // For each system JS library library_xxx.js, add a preprocessor token __EMSCRIPTEN_HAS_xxx_js__ so that code can conditionally dead code eliminate out + // if a particular feature is not being linked in. + for (var i = 0; i < SYSTEM_JS_LIBRARIES.length; ++i) { + global['__EMSCRIPTEN_HAS_' + SYSTEM_JS_LIBRARIES[i].replace('.', '_').replace('library_', '') + '__'] = 1 + } libraries = libraries.concat(SYSTEM_JS_LIBRARIES); } diff --git a/tests/test_browser.py b/tests/test_browser.py index 4e00a91feff59..425831b0665f6 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -62,8 +62,8 @@ def setUpClass(self): print def test_sdl1(self): - self.btest('hello_world_sdl.cpp', reference='htmltest.png') - self.btest('hello_world_sdl.cpp', reference='htmltest.png', args=['-s', 'USE_SDL=1']) # is the default anyhow + self.btest('hello_world_sdl.cpp', reference='htmltest.png', args=['-lSDL', '-lGL']) + self.btest('hello_world_sdl.cpp', reference='htmltest.png', args=['-s', 'USE_SDL=1', '-lGL']) # is the default anyhow def test_html_source_map(self): cpp_file = os.path.join(self.get_dir(), 'src.cpp') @@ -560,11 +560,11 @@ def test(): #test() def test_sdl_swsurface(self): - self.btest('sdl_swsurface.c', expected='1') + self.btest('sdl_swsurface.c', args=['-lSDL', '-lGL'], expected='1') def test_sdl_surface_lock_opts(self): # Test Emscripten-specific extensions to optimize SDL_LockSurface and SDL_UnlockSurface. - self.btest('hello_world_sdl.cpp', reference='htmltest.png', message='You should see "hello, world!" and a colored cube.', args=['-DTEST_SDL_LOCK_OPTS']) + self.btest('hello_world_sdl.cpp', reference='htmltest.png', message='You should see "hello, world!" and a colored cube.', args=['-DTEST_SDL_LOCK_OPTS', '-lSDL', '-lGL']) def test_sdl_image(self): # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init @@ -575,7 +575,7 @@ def test_sdl_image(self): for dest, dirname, basename in [('screenshot.jpg', '/', 'screenshot.jpg'), ('screenshot.jpg@/assets/screenshot.jpg', '/assets', 'screenshot.jpg')]: Popen([ - PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-o', 'page.html', '-O2', '--memory-init-file', str(mem), + PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-o', 'page.html', '-O2', '-lSDL', '-lGL', '--memory-init-file', str(mem), '--preload-file', dest, '-DSCREENSHOT_DIRNAME="' + dirname + '"', '-DSCREENSHOT_BASENAME="' + basename + '"', '--use-preload-plugins' ]).communicate() self.run_browser('page.html', '', '/report_result?600') @@ -584,7 +584,7 @@ def test_sdl_image_jpeg(self): shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpeg')) open(os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read())) Popen([ - PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), '-o', 'page.html', + PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), '-o', 'page.html', '-lSDL', '-lGL', '--preload-file', 'screenshot.jpeg', '-DSCREENSHOT_DIRNAME="/"', '-DSCREENSHOT_BASENAME="screenshot.jpeg"', '--use-preload-plugins' ]).communicate() self.run_browser('page.html', '', '/report_result?600') @@ -592,36 +592,36 @@ def test_sdl_image_jpeg(self): def test_sdl_image_prepare(self): # load an image file, get pixel data. shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not')) - self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'], also_proxied=True) + self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not', '-lSDL', '-lGL'], also_proxied=True) def test_sdl_image_prepare_data(self): # load an image file, get pixel data. shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not')) - self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not']) + self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not', '-lSDL', '-lGL']) def test_sdl_image_must_prepare(self): # load an image file, get pixel data. shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpg')) - self.btest('sdl_image_must_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.jpg']) + self.btest('sdl_image_must_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.jpg', '-lSDL', '-lGL']) def test_sdl_stb_image(self): # load an image file, get pixel data. shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not')) - self.btest('sdl_stb_image.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not']) + self.btest('sdl_stb_image.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not', '-lSDL', '-lGL']) def test_sdl_stb_image_data(self): # load an image file, get pixel data. shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not')) - self.btest('sdl_stb_image_data.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not']) + self.btest('sdl_stb_image_data.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not', '-lSDL', '-lGL']) def test_sdl_canvas(self): self.clear() - self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-lSDL', '-lGL']) # some extra coverage self.clear() - self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-O0', '-s', 'SAFE_HEAP=1']) + self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-O0', '-s', 'SAFE_HEAP=1', '-lSDL', '-lGL']) self.clear() - self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-O2', '-s', 'SAFE_HEAP=1']) + self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-O2', '-s', 'SAFE_HEAP=1', '-lSDL', '-lGL']) def post_manual_reftest(self, reference=None): self.reftest(path_from_root('tests', self.reference if reference is None else reference)) @@ -647,10 +647,10 @@ def post_manual_reftest(self, reference=None): def test_sdl_canvas_proxy(self): open('data.txt', 'w').write('datum') - self.btest('sdl_canvas_proxy.c', reference='sdl_canvas_proxy.png', args=['--proxy-to-worker', '--preload-file', 'data.txt'], manual_reference=True, post_build=self.post_manual_reftest) + self.btest('sdl_canvas_proxy.c', reference='sdl_canvas_proxy.png', args=['--proxy-to-worker', '--preload-file', 'data.txt', '-lSDL', '-lGL'], manual_reference=True, post_build=self.post_manual_reftest) def test_glgears_proxy(self): - self.btest('hello_world_gles_proxy.c', reference='gears.png', args=['--proxy-to-worker', '-s', 'GL_TESTING=1', '-DSTATIC_GEARS=1'], manual_reference=True, post_build=self.post_manual_reftest) + self.btest('hello_world_gles_proxy.c', reference='gears.png', args=['--proxy-to-worker', '-s', 'GL_TESTING=1', '-DSTATIC_GEARS=1', '-lGL', '-lglut'], manual_reference=True, post_build=self.post_manual_reftest) # test noProxy option applied at runtime @@ -682,7 +682,7 @@ def copy(to, js_mod, html_mod = lambda x: x): def test_glgears_proxy_jstarget(self): # test .js target with --proxy-worker; emits 2 js files, client and worker - Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles_proxy.c'), '-o', 'test.js', '--proxy-to-worker', '-s', 'GL_TESTING=1']).communicate() + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles_proxy.c'), '-o', 'test.js', '--proxy-to-worker', '-s', 'GL_TESTING=1', '-lGL', '-lglut']).communicate() open('test.html', 'w').write(open(path_from_root('src', 'shell_minimal.html')).read().replace('{{{ SCRIPT }}}', '')) self.post_manual_reftest('gears.png') self.run_browser('test.html', None, '/report_result?0') @@ -694,8 +694,8 @@ def test_sdl_canvas_alpha(self): Module['arguments'] = ['-0']; ''') - self.btest('sdl_canvas_alpha.c', reference='sdl_canvas_alpha.png', reference_slack=12) - self.btest('sdl_canvas_alpha.c', args=['--pre-js', 'flag_0.js'], reference='sdl_canvas_alpha_flag_0.png', reference_slack=12) + self.btest('sdl_canvas_alpha.c', args=['-lSDL', '-lGL'], reference='sdl_canvas_alpha.png', reference_slack=12) + self.btest('sdl_canvas_alpha.c', args=['--pre-js', 'flag_0.js', '-lSDL', '-lGL'], reference='sdl_canvas_alpha_flag_0.png', reference_slack=12) def test_sdl_key(self): @@ -734,7 +734,7 @@ def test_sdl_key(self): ''' % ('setTimeout(function() {' if delay else '', '}, 1);' if delay else '', 'setTimeout(function() {' if delay else '', '}, 1);' if delay else '')) open(os.path.join(self.get_dir(), 'sdl_key.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_key.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html'] + defines + emterps + ['--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main']''', '-s', 'NO_EXIT_RUNTIME=1']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html'] + defines + emterps + ['--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main']''', '-s', 'NO_EXIT_RUNTIME=1', '-lSDL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?223092870') def test_sdl_key_proxy(self): @@ -781,7 +781,7 @@ def post(): ''') open('test.html', 'w').write(html) - self.btest('sdl_key_proxy.c', '223092870', args=['--proxy-to-worker', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''', '-s', 'NO_EXIT_RUNTIME=1'], manual_reference=True, post_build=post) + self.btest('sdl_key_proxy.c', '223092870', args=['--proxy-to-worker', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''', '-s', 'NO_EXIT_RUNTIME=1', '-lSDL', '-lGL'], manual_reference=True, post_build=post) def test_keydown_preventdefault_proxy(self): def post(): @@ -858,7 +858,7 @@ def test_sdl_text(self): ''') open(os.path.join(self.get_dir(), 'sdl_text.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_text.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_text.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_text.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''', '-lSDL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_sdl_mouse(self): @@ -891,7 +891,7 @@ def test_sdl_mouse(self): ''') open(os.path.join(self.get_dir(), 'sdl_mouse.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_mouse.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js', '-lSDL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_sdl_mouse_offsets(self): @@ -969,14 +969,14 @@ def test_sdl_mouse_offsets(self): ''') open(os.path.join(self.get_dir(), 'sdl_mouse.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_mouse.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-DTEST_SDL_MOUSE_OFFSETS', '-O2', '--minify', '0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-DTEST_SDL_MOUSE_OFFSETS', '-O2', '--minify', '0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js', '-lSDL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_glut_touchevents(self): - self.btest('glut_touchevents.c', '1') + self.btest('glut_touchevents.c', '1', args=['-lglut']) def test_glut_wheelevents(self): - self.btest('glut_wheelevents.c', '1') + self.btest('glut_wheelevents.c', '1', args=['-lglut']) def test_sdl_joystick_1(self): # Generates events corresponding to the Working Draft of the HTML5 Gamepad API. @@ -1011,7 +1011,7 @@ def test_sdl_joystick_1(self): ''') open(os.path.join(self.get_dir(), 'sdl_joystick.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_joystick.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_joystick.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_joystick.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js', '-lSDL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?2') def test_sdl_joystick_2(self): @@ -1051,7 +1051,7 @@ def test_sdl_joystick_2(self): ''') open(os.path.join(self.get_dir(), 'sdl_joystick.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_joystick.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_joystick.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_joystick.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js', '-lSDL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?2') def test_webgl_context_attributes(self): @@ -1093,14 +1093,14 @@ def test_webgl_context_attributes(self): shutil.copyfile(filepath, temp_filepath) # perform tests with attributes activated - self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED']) - self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED']) - self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED']) + self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglut', '-lGLEW']) + self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lSDL', '-lGLEW']) + self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglfw', '-lGLEW']) # perform tests with attributes desactivated - self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js']) - self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js']) - self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js']) + self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-lGL', '-lglut', '-lGLEW']) + self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-lGL', '-lSDL', '-lGLEW']) + self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-lGL', '-lglfw', '-lGLEW']) def test_emscripten_get_now(self): self.btest('emscripten_get_now.cpp', '1') @@ -1124,8 +1124,8 @@ def test_fs_idbfs_sync(self): for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]: for extra in [[], ['-DEXTRA_WORK']]: secret = str(time.time()) - self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=mode + ['-DFIRST', '-DSECRET=\"' + secret + '\"', '-s', '''EXPORTED_FUNCTIONS=['_main', '_test', '_success']''']) - self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=mode + ['-DSECRET=\"' + secret + '\"', '-s', '''EXPORTED_FUNCTIONS=['_main', '_test', '_success']'''] + extra) + self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=mode + ['-lidbfs.js', '-DFIRST', '-DSECRET=\"' + secret + '\"', '-s', '''EXPORTED_FUNCTIONS=['_main', '_test', '_success']''']) + self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=mode + ['-lidbfs.js', '-DSECRET=\"' + secret + '\"', '-s', '''EXPORTED_FUNCTIONS=['_main', '_test', '_success']'''] + extra) def test_fs_idbfs_fsync(self): # sync from persisted state into memory before main() @@ -1142,7 +1142,7 @@ def test_fs_idbfs_fsync(self): }; ''') - args = ['--pre-js', 'pre.js', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1']; + args = ['--pre-js', 'pre.js', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-lidbfs.js'] for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]: secret = str(time.time()) self.btest(path_from_root('tests', 'fs', 'test_idbfs_fsync.c'), '1', force_c=True, args=args + mode + ['-DFIRST', '-DSECRET=\"' + secret + '\"', '-s', '''EXPORTED_FUNCTIONS=['_main', '_success']''']) @@ -1169,14 +1169,14 @@ def test_fs_workerfs_read(self): }, '/work'); }; ''' % (secret, secret2)) - self.btest(path_from_root('tests', 'fs', 'test_workerfs_read.c'), '1', force_c=True, args=['--pre-js', 'pre.js', '-DSECRET=\"' + secret + '\"', '-DSECRET2=\"' + secret2 + '\"', '--proxy-to-worker']) + self.btest(path_from_root('tests', 'fs', 'test_workerfs_read.c'), '1', force_c=True, args=['-lworkerfs.js', '--pre-js', 'pre.js', '-DSECRET=\"' + secret + '\"', '-DSECRET2=\"' + secret2 + '\"', '--proxy-to-worker']) def test_fs_workerfs_package(self): open('file1.txt', 'w').write('first') if not os.path.exists('sub'): os.makedirs('sub') open(os.path.join('sub', 'file2.txt'), 'w').write('second') Popen([PYTHON, FILE_PACKAGER, 'files.data', '--preload', 'file1.txt', os.path.join('sub', 'file2.txt'), '--separate-metadata', '--js-output=files.js']).communicate() - self.btest(os.path.join('fs', 'test_workerfs_package.cpp'), '1', args=['--proxy-to-worker']) + self.btest(os.path.join('fs', 'test_workerfs_package.cpp'), '1', args=['-lworkerfs.js', '--proxy-to-worker']) def test_fs_lz4fs_package(self): # generate data @@ -1230,17 +1230,17 @@ def test_idbstore(self): secret = str(time.time()) for stage in [0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 4, 2, 5]: self.clear() - self.btest(path_from_root('tests', 'idbstore.c'), str(stage), force_c=True, args=['-DSTAGE=' + str(stage), '-DSECRET=\"' + secret + '\"']) + self.btest(path_from_root('tests', 'idbstore.c'), str(stage), force_c=True, args=['-lidbstore.js', '-DSTAGE=' + str(stage), '-DSECRET=\"' + secret + '\"']) def test_idbstore_sync(self): secret = str(time.time()) self.clear() - self.btest(path_from_root('tests', 'idbstore_sync.c'), '6', force_c=True, args=['-DSECRET=\"' + secret + '\"', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '--memory-init-file', '1', '-O3', '-g2']) + self.btest(path_from_root('tests', 'idbstore_sync.c'), '6', force_c=True, args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '--memory-init-file', '1', '-O3', '-g2']) def test_idbstore_sync_worker(self): secret = str(time.time()) self.clear() - self.btest(path_from_root('tests', 'idbstore_sync_worker.c'), '6', force_c=True, args=['-DSECRET=\"' + secret + '\"', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '--memory-init-file', '1', '-O3', '-g2', '--proxy-to-worker', '-s', 'TOTAL_MEMORY=75000000']) + self.btest(path_from_root('tests', 'idbstore_sync_worker.c'), '6', force_c=True, args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '--memory-init-file', '1', '-O3', '-g2', '--proxy-to-worker', '-s', 'TOTAL_MEMORY=75000000']) def test_force_exit(self): self.btest('force_exit.c', force_c=True, expected='17') @@ -1256,94 +1256,94 @@ def test_sdl_pumpevents(self): document.dispatchEvent(event); } ''') - self.btest('sdl_pumpevents.c', expected='7', args=['--pre-js', 'pre.js']) + self.btest('sdl_pumpevents.c', expected='7', args=['--pre-js', 'pre.js', '-lSDL', '-lGL']) def test_sdl_canvas_size(self): self.btest('sdl_canvas_size.c', expected='1', - args=['-O2', '--minify', '0', '--shell-file', path_from_root('tests', 'sdl_canvas_size.html')]) + args=['-O2', '--minify', '0', '--shell-file', path_from_root('tests', 'sdl_canvas_size.html'), '-lSDL', '-lGL']) def test_sdl_gl_read(self): # SDL, OpenGL, readPixels open(os.path.join(self.get_dir(), 'sdl_gl_read.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_gl_read.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_gl_read.c'), '-o', 'something.html']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_gl_read.c'), '-o', 'something.html', '-lSDL', '-lGL']).communicate() self.run_browser('something.html', '.', '/report_result?1') def test_sdl_gl_mapbuffers(self): - self.btest('sdl_gl_mapbuffers.c', expected='1', args=['-s', 'FULL_ES3=1'], + self.btest('sdl_gl_mapbuffers.c', expected='1', args=['-s', 'FULL_ES3=1', '-lSDL', '-lGL'], message='You should see a blue triangle.') def test_sdl_ogl(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with gray at the top.') def test_sdl_ogl_defaultmatrixmode(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_defaultMatrixMode.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with gray at the top.') def test_sdl_ogl_p(self): # Immediate mode with pointers shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_p.c', reference='screenshot-gray.png', reference_slack=1, - args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with gray at the top.') def test_sdl_ogl_proc_alias(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_proc_alias.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['-O2', '-g2', '-s', 'INLINING_LIMIT=1', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins']) + args=['-O2', '-g2', '-s', 'INLINING_LIMIT=1', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL']) def test_sdl_fog_simple(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_simple.c', reference='screenshot-fog-simple.png', - args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with fog.') def test_sdl_fog_negative(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_negative.c', reference='screenshot-fog-negative.png', - args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with fog.') def test_sdl_fog_density(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_density.c', reference='screenshot-fog-density.png', - args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with fog.') def test_sdl_fog_exp2(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_exp2.c', reference='screenshot-fog-exp2.png', - args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with fog.') def test_sdl_fog_linear(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_linear.c', reference='screenshot-fog-linear.png', reference_slack=1, - args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins', '-lSDL', '-lGL'], message='You should see an image with fog.') def test_glfw(self): - self.btest('glfw.c', '1', args=['-s', 'LEGACY_GL_EMULATION=1']) - self.btest('glfw.c', '1', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', 'USE_GLFW=2']) + self.btest('glfw.c', '1', args=['-s', 'LEGACY_GL_EMULATION=1', '-lglfw', '-lGL']) + self.btest('glfw.c', '1', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', 'USE_GLFW=2', '-lglfw', '-lGL']) def test_glfw_minimal(self): - self.btest('glfw_minimal.c', '1', args=[]) - self.btest('glfw_minimal.c', '1', args=['-s', 'USE_GLFW=2']) + self.btest('glfw_minimal.c', '1', args=['-lglfw', '-lGL']) + self.btest('glfw_minimal.c', '1', args=['-s', 'USE_GLFW=2', '-lglfw', '-lGL']) def test_egl(self): open(os.path.join(self.get_dir(), 'test_egl.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl.c')).read())) - Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl.c'), '-o', 'page.html']).communicate() + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl.c'), '-o', 'page.html', '-lEGL', '-lGL']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_egl_width_height(self): open(os.path.join(self.get_dir(), 'test_egl_width_height.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl_width_height.c')).read())) - Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl_width_height.c'), '-o', 'page.html']).communicate() + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl_width_height.c'), '-o', 'page.html', '-lEGL', '-lGL']).communicate() self.run_browser('page.html', 'Should print "(300, 150)" -- the size of the canvas in pixels', '/report_result?1') def test_worker(self): @@ -1454,31 +1454,31 @@ def test_chunked_synchronous_xhr(self): def test_glgears(self): self.btest('hello_world_gles.c', reference='gears.png', reference_slack=3, - args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html', + args=['-DHAVE_BUILTIN_SINCOS', '-lGL', '-lglut'], outfile='something.html', message='You should see animating gears.') def test_glgears_long(self): for proxy in [0, 1]: print 'proxy', proxy - self.btest('hello_world_gles.c', expected=map(str, range(30, 500)), args=['-DHAVE_BUILTIN_SINCOS', '-DLONGTEST'] + (['--proxy-to-worker'] if proxy else []), timeout=30) + self.btest('hello_world_gles.c', expected=map(str, range(30, 500)), args=['-DHAVE_BUILTIN_SINCOS', '-DLONGTEST', '-lGL', '-lglut'] + (['--proxy-to-worker'] if proxy else []), timeout=30) def test_glgears_animation(self): es2_suffix = ['', '_full', '_full_944'] for full_es2 in [0, 1, 2]: print full_es2 Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html', - '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', + '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', '-lGL', '-lglut', '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + (['-s', 'FULL_ES2=1'] if full_es2 else []), ).communicate() self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') def test_fulles2_sdlproc(self): - self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1']) + self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1', '-lGL', '-lSDL', '-lglut']) def test_glgears_deriv(self): self.btest('hello_world_gles_deriv.c', reference='gears.png', reference_slack=2, - args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html', + args=['-DHAVE_BUILTIN_SINCOS', '-lGL', '-lglut'], outfile='something.html', message='You should see animating gears.') with open('something.html') as f: assert 'gl-matrix' not in f.read(), 'Should not include glMatrix when not needed' @@ -1498,14 +1498,14 @@ def book_path(*pathelems): for program in programs: print program basename = os.path.basename(program) - args = [] + args = ['-lGL', '-lEGL', '-lX11'] if basename == 'CH10_MultiTexture.bc': shutil.copyfile(book_path('Chapter_10', 'MultiTexture', 'basemap.tga'), os.path.join(self.get_dir(), 'basemap.tga')) shutil.copyfile(book_path('Chapter_10', 'MultiTexture', 'lightmap.tga'), os.path.join(self.get_dir(), 'lightmap.tga')) - args = ['--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga'] + args += ['--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga'] elif basename == 'CH13_ParticleSystem.bc': shutil.copyfile(book_path('Chapter_13', 'ParticleSystem', 'smoke.tga'), os.path.join(self.get_dir(), 'smoke.tga')) - args = ['--preload-file', 'smoke.tga', '-O2'] # test optimizations and closure here as well for more coverage + args += ['--preload-file', 'smoke.tga', '-O2'] # test optimizations and closure here as well for more coverage self.btest(program, reference=book_path(basename.replace('.bc', '.png')), args=args, timeout=30) @@ -1532,11 +1532,11 @@ def test_gles2_emulation(self): path_from_root('tests', 'glbook', 'Common', 'esShader.c'), path_from_root('tests', 'glbook', 'Common', 'esShapes.c'), path_from_root('tests', 'glbook', 'Common', 'esTransform.c'), - '-s', 'FULL_ES2=1', + '-s', 'FULL_ES2=1', '-lGL', '-lEGL', '-lX11', '--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga', '--preload-file', 'smoke.tga']) def test_emscripten_api(self): - self.btest('emscripten_api_browser.cpp', '1', args=['-s', '''EXPORTED_FUNCTIONS=['_main', '_third']''']) + self.btest('emscripten_api_browser.cpp', '1', args=['-s', '''EXPORTED_FUNCTIONS=['_main', '_third']''', '-lSDL']) def test_emscripten_api2(self): def setup(): @@ -1563,7 +1563,7 @@ def test_emscripten_api_infloop(self): def test_emscripten_fs_api(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) # preloaded *after* run - self.btest('emscripten_fs_api_browser.cpp', '1') + self.btest('emscripten_fs_api_browser.cpp', '1', args=['-lSDL']) def test_emscripten_fs_api2(self): self.btest('emscripten_fs_api_browser2.cpp', '1', args=['-s', "ASSERTIONS=0"]) @@ -1583,80 +1583,80 @@ def test_emscripten_main_loop_setimmediate(self): self.btest('emscripten_main_loop_setimmediate.cpp', '1', args=args) def test_sdl_quit(self): - self.btest('sdl_quit.c', '1') + self.btest('sdl_quit.c', '1', args=['-lSDL', '-lGL']) def test_sdl_resize(self): - self.btest('sdl_resize.c', '1') + self.btest('sdl_resize.c', '1', args=['-lSDL', '-lGL']) def test_glshaderinfo(self): - self.btest('glshaderinfo.cpp', '1') + self.btest('glshaderinfo.cpp', '1', args=['-lGL', '-lglut']) def test_glgetattachedshaders(self): - self.btest('glgetattachedshaders.c', '1') + self.btest('glgetattachedshaders.c', '1', args=['-lGL', '-lEGL']) def test_sdlglshader(self): - self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_sdlglshader2(self): - self.btest('sdlglshader2.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True) + self.btest('sdlglshader2.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], also_proxied=True) def test_gl_glteximage(self): - self.btest('gl_teximage.c', '1') + self.btest('gl_teximage.c', '1', args=['-lGL', '-lSDL']) def test_gl_textures(self): - self.btest('gl_textures.cpp', '0') + self.btest('gl_textures.cpp', '0', args=['-lGL']) def test_gl_ps(self): # pointers and a shader shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], reference_slack=1) + self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '--use-preload-plugins'], reference_slack=1) def test_gl_ps_packed(self): # packed data that needs to be strided shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], reference_slack=1) + self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '--use-preload-plugins'], reference_slack=1) def test_gl_ps_strides(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins']) + self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '--use-preload-plugins']) def test_gl_ps_worker(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_worker.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins'], reference_slack=1, also_proxied=True) + self.btest('gl_ps_worker.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '--use-preload-plugins'], reference_slack=1, also_proxied=True) def test_gl_renderers(self): - self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_gl_stride(self): - self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_gl_vertex_buffer_pre(self): - self.btest('gl_vertex_buffer_pre.c', reference='gl_vertex_buffer_pre.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('gl_vertex_buffer_pre.c', reference='gl_vertex_buffer_pre.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_gl_vertex_buffer(self): - self.btest('gl_vertex_buffer.c', reference='gl_vertex_buffer.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1) + self.btest('gl_vertex_buffer.c', reference='gl_vertex_buffer.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], reference_slack=1) def test_gles2_uniform_arrays(self): - self.btest('gles2_uniform_arrays.cpp', args=['-s', 'GL_ASSERTIONS=1'], expected=['1'], also_proxied=True) + self.btest('gles2_uniform_arrays.cpp', args=['-s', 'GL_ASSERTIONS=1', '-lGL', '-lSDL'], expected=['1'], also_proxied=True) def test_gles2_conformance(self): - self.btest('gles2_conformance.cpp', args=['-s', 'GL_ASSERTIONS=1'], expected=['1']) + self.btest('gles2_conformance.cpp', args=['-s', 'GL_ASSERTIONS=1', '-lGL', '-lSDL'], expected=['1']) def test_matrix_identity(self): - self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840', '1588195328'], args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840', '1588195328'], args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_pre(self): - self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1']) - self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', 'RELOCATABLE=1']) + self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) + self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '-s', 'RELOCATABLE=1']) def test_cubegeom_pre2(self): - self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1', '-s', 'LEGACY_GL_EMULATION=1']) # some coverage for GL_DEBUG not breaking the build + self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) # some coverage for GL_DEBUG not breaking the build def test_cubegeom_pre3(self): - self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom(self): - self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True) + self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], also_proxied=True) def test_cubegeom_proc(self): open('side.c', 'w').write(r''' @@ -1671,87 +1671,87 @@ def test_cubegeom_proc(self): } ''') for opts in [0, 1]: - self.btest('cubegeom_proc.c', reference='cubegeom.png', args=['-O' + str(opts), 'side.c', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_proc.c', reference='cubegeom.png', args=['-O' + str(opts), 'side.c', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_glew(self): - self.btest('cubegeom_glew.c', reference='cubegeom.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_glew.c', reference='cubegeom.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lGLEW', '-lSDL']) def test_cubegeom_color(self): - self.btest('cubegeom_color.c', reference='cubegeom_color.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_color.c', reference='cubegeom_color.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_normal(self): - self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True) + self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], also_proxied=True) def test_cubegeom_normal_dap(self): # draw is given a direct pointer to clientside memory, no element array buffer - self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True) + self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], also_proxied=True) def test_cubegeom_normal_dap_far(self): # indices do nto start from 0 - self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_normal_dap_far_range(self): # glDrawRangeElements - self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_normal_dap_far_glda(self): # use glDrawArrays - self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_normal_dap_far_glda_quad(self): # with quad - self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_mt(self): - self.btest('cubegeom_mt.c', reference='cubegeom_mt.png', args=['-s', 'LEGACY_GL_EMULATION=1']) # multitexture + self.btest('cubegeom_mt.c', reference='cubegeom_mt.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) # multitexture def test_cubegeom_color2(self): - self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True) + self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], also_proxied=True) def test_cubegeom_texturematrix(self): - self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_fog(self): - self.btest('cubegeom_fog.c', reference='cubegeom_fog.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_fog.c', reference='cubegeom_fog.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_pre_vao(self): - self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_pre2_vao(self): - self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_pre2_vao2(self): - self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_cubegeom_u4fv_2(self): - self.btest('cubegeom_u4fv_2.c', reference='cubegeom_u4fv_2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) - self.btest('cubegeom_u4fv_2.c', reference='cubegeom_u4fv_2.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', 'SPLIT_MEMORY=16777216']) # check for uniform4fv slice being valid in split memory + self.btest('cubegeom_u4fv_2.c', reference='cubegeom_u4fv_2.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) + self.btest('cubegeom_u4fv_2.c', reference='cubegeom_u4fv_2.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '-s', 'SPLIT_MEMORY=16777216']) # check for uniform4fv slice being valid in split memory def test_cube_explosion(self): - self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True) + self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], also_proxied=True) def test_glgettexenv(self): - self.btest('glgettexenv.c', args=['-s', 'LEGACY_GL_EMULATION=1'], expected=['1']) + self.btest('glgettexenv.c', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL'], expected=['1']) def test_sdl_canvas_blank(self): - self.btest('sdl_canvas_blank.c', reference='sdl_canvas_blank.png') + self.btest('sdl_canvas_blank.c', args=['-lSDL', '-lGL'], reference='sdl_canvas_blank.png') def test_sdl_canvas_palette(self): - self.btest('sdl_canvas_palette.c', reference='sdl_canvas_palette.png') + self.btest('sdl_canvas_palette.c', args=['-lSDL', '-lGL'], reference='sdl_canvas_palette.png') def test_sdl_canvas_twice(self): - self.btest('sdl_canvas_twice.c', reference='sdl_canvas_twice.png') + self.btest('sdl_canvas_twice.c', args=['-lSDL', '-lGL'], reference='sdl_canvas_twice.png') def test_sdl_set_clip_rect(self): - self.btest('sdl_set_clip_rect.c', reference='sdl_set_clip_rect.png') + self.btest('sdl_set_clip_rect.c', args=['-lSDL', '-lGL'], reference='sdl_set_clip_rect.png') def test_sdl_maprgba(self): - self.btest('sdl_maprgba.c', reference='sdl_maprgba.png', reference_slack=3) + self.btest('sdl_maprgba.c', args=['-lSDL', '-lGL'], reference='sdl_maprgba.png', reference_slack=3) def test_sdl_create_rgb_surface_from(self): - self.btest('sdl_create_rgb_surface_from.c', reference='sdl_create_rgb_surface_from.png') + self.btest('sdl_create_rgb_surface_from.c', args=['-lSDL', '-lGL'], reference='sdl_create_rgb_surface_from.png') def test_sdl_rotozoom(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('sdl_rotozoom.c', reference='sdl_rotozoom.png', args=['--preload-file', 'screenshot.png', '--use-preload-plugins'], reference_slack=3) + self.btest('sdl_rotozoom.c', reference='sdl_rotozoom.png', args=['--preload-file', 'screenshot.png', '--use-preload-plugins', '-lSDL', '-lGL'], reference_slack=3) def test_sdl_gfx_primitives(self): - self.btest('sdl_gfx_primitives.c', reference='sdl_gfx_primitives.png', reference_slack=1) + self.btest('sdl_gfx_primitives.c', args=['-lSDL', '-lGL'], reference='sdl_gfx_primitives.png', reference_slack=1) def test_sdl_canvas_palette_2(self): open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' @@ -1772,30 +1772,30 @@ def test_sdl_canvas_palette_2(self): Module['arguments'] = ['-b']; ''') - self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_r.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-r.js']) - self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_g.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-g.js']) - self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_b.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-b.js']) + self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_r.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-r.js', '-lSDL', '-lGL']) + self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_g.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-g.js', '-lSDL', '-lGL']) + self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_b.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-b.js', '-lSDL', '-lGL']) def test_sdl_alloctext(self): - self.btest('sdl_alloctext.c', expected='1', args=['-O2', '-s', 'TOTAL_MEMORY=' + str(1024*1024*8)]) + self.btest('sdl_alloctext.c', expected='1', args=['-O2', '-s', 'TOTAL_MEMORY=' + str(1024*1024*8), '-lSDL', '-lGL']) def test_sdl_surface_refcount(self): - self.btest('sdl_surface_refcount.c', expected='1') + self.btest('sdl_surface_refcount.c', args=['-lSDL'], expected='1') def test_sdl_free_screen(self): - self.btest('sdl_free_screen.cpp', reference='htmltest.png') + self.btest('sdl_free_screen.cpp', args=['-lSDL', '-lGL'], reference='htmltest.png') def test_glbegin_points(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '--use-preload-plugins']) + self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '--use-preload-plugins']) def test_s3tc(self): shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds')) - self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_s3tc_ffp_only(self): shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds')) - self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1', '-s', 'GL_FFP_ONLY=1']) + self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1', '-s', 'GL_FFP_ONLY=1', '-lGL', '-lSDL']) def test_s3tc_crunch(self): try: @@ -1813,7 +1813,7 @@ def test(args): shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed - self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js', '-s', 'LEGACY_GL_EMULATION=1', '-lGL']) test([]) test(['text.txt']) # also package a non-crunch file @@ -1830,30 +1830,30 @@ def test_s3tc_crunch_split(self): # load several datafiles/outputs of file packa shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed - self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1', '-lGL']) def test_aniso(self): if SPIDERMONKEY_ENGINE in JS_ENGINES: # asm.js-ification check - Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate() + Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '-Wno-incompatible-pointer-types']).communicate() Settings.ASM_JS = 1 self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js', assert_returncode=None) print 'passed asm test' shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds') - self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1']) + self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL', '-Wno-incompatible-pointer-types']) def test_tex_nonbyte(self): - self.btest('tex_nonbyte.c', reference='tex_nonbyte.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('tex_nonbyte.c', reference='tex_nonbyte.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_float_tex(self): - self.btest('float_tex.cpp', reference='float_tex.png') + self.btest('float_tex.cpp', reference='float_tex.png', args=['-lGL', '-lglut']) def test_subdata(self): - self.btest('gl_subdata.cpp', reference='float_tex.png') + self.btest('gl_subdata.cpp', reference='float_tex.png', args=['-lGL', '-lglut']) def test_perspective(self): - self.btest('perspective.c', reference='perspective.png', args=['-s', 'LEGACY_GL_EMULATION=1']) + self.btest('perspective.c', reference='perspective.png', args=['-s', 'LEGACY_GL_EMULATION=1', '-lGL', '-lSDL']) def test_runtimelink(self): main, supp = self.setup_runtimelink_test() @@ -2102,7 +2102,7 @@ def test_emrun(self): # This does not actually verify anything except that --cpuprofiler and --memoryprofiler compiles. # Run interactive.test_cpuprofiler_memoryprofiler for interactive testing. def test_cpuprofiler_memoryprofiler(self): - self.btest('hello_world_gles.c', expected='0', args=['-DLONGTEST=1', '-DTEST_MEMORYPROFILER_ALLOCATIONS_MAP=1', '-O2', '--cpuprofiler', '--memoryprofiler'], timeout=30) + self.btest('hello_world_gles.c', expected='0', args=['-DLONGTEST=1', '-DTEST_MEMORYPROFILER_ALLOCATIONS_MAP=1', '-O2', '--cpuprofiler', '--memoryprofiler', '-lGL', '-lglut'], timeout=30) def test_uuid(self): # Run with ./runner.py browser.test_uuid @@ -2111,7 +2111,7 @@ def test_uuid(self): # First run tests in Node and/or SPIDERMONKEY using run_js. Use closure compiler so we can check that # require('crypto').randomBytes and window.crypto.getRandomValues doesn't get minified out. - Popen([PYTHON, EMCC, '-O2', '--closure', '1', path_from_root('tests', 'uuid', 'test.c'), '-o', 'test.js'], stdout=PIPE, stderr=PIPE).communicate() + Popen([PYTHON, EMCC, '-O2', '--closure', '1', path_from_root('tests', 'uuid', 'test.c'), '-o', 'test.js', '-luuid'], stdout=PIPE, stderr=PIPE).communicate() test_js_closure = open('test.js').read() @@ -2127,13 +2127,13 @@ def test_uuid(self): try_delete(path_from_root('tests', 'uuid', 'test.js.map')) # Now run test in browser - self.btest(path_from_root('tests', 'uuid', 'test.c'), '1') + self.btest(path_from_root('tests', 'uuid', 'test.c'), '1', args=['-luuid']) def test_glew(self): - self.btest(path_from_root('tests', 'glew.c'), expected='1') - self.btest(path_from_root('tests', 'glew.c'), args=['-s', 'LEGACY_GL_EMULATION=1'], expected='1') - self.btest(path_from_root('tests', 'glew.c'), args=['-DGLEW_MX'], expected='1') - self.btest(path_from_root('tests', 'glew.c'), args=['-s', 'LEGACY_GL_EMULATION=1', '-DGLEW_MX'], expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-lGL', '-lSDL', '-lGLEW'], expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-lGL', '-lSDL', '-lGLEW', '-s', 'LEGACY_GL_EMULATION=1'], expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-lGL', '-lSDL', '-lGLEW', '-DGLEW_MX'], expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-lGL', '-lSDL', '-lGLEW', '-s', 'LEGACY_GL_EMULATION=1', '-DGLEW_MX'], expected='1') def test_doublestart_bug(self): open('pre.js', 'w').write(r''' @@ -2155,39 +2155,39 @@ def test_html5(self): def test_html5_webgl_create_context(self): for opts in [[], ['-O2', '-g1', '--closure', '1'], ['-s', 'FULL_ES2=1']]: print opts - self.btest(path_from_root('tests', 'webgl_create_context.cpp'), args=opts, expected='0', timeout=20) + self.btest(path_from_root('tests', 'webgl_create_context.cpp'), args=opts + ['-lGL'], expected='0', timeout=20) # Verify bug https://github.com/kripken/emscripten/issues/4556: creating a WebGL context to Module.canvas without an ID explicitly assigned to it. def test_html5_webgl_create_context2(self): - self.btest(path_from_root('tests', 'webgl_create_context2.cpp'), args=['--shell-file', path_from_root('tests', 'webgl_create_context2_shell.html')], expected='0', timeout=20) + self.btest(path_from_root('tests', 'webgl_create_context2.cpp'), args=['--shell-file', path_from_root('tests', 'webgl_create_context2_shell.html'), '-lGL'], expected='0', timeout=20) def test_html5_webgl_destroy_context(self): for opts in [[], ['-O2', '-g1'], ['-s', 'FULL_ES2=1']]: print opts - self.btest(path_from_root('tests', 'webgl_destroy_context.cpp'), args=opts + ['--shell-file', path_from_root('tests/webgl_destroy_context_shell.html'), '-s', 'NO_EXIT_RUNTIME=1'], expected='0', timeout=20) + self.btest(path_from_root('tests', 'webgl_destroy_context.cpp'), args=opts + ['--shell-file', path_from_root('tests/webgl_destroy_context_shell.html'), '-s', 'NO_EXIT_RUNTIME=1', '-lGL'], expected='0', timeout=20) def test_webgl_context_params(self): if WINDOWS: return self.skip('SKIPPED due to bug https://bugzilla.mozilla.org/show_bug.cgi?id=1310005 - WebGL implementation advertises implementation defined GL_IMPLEMENTATION_COLOR_READ_TYPE/FORMAT pair that it cannot read with') - self.btest(path_from_root('tests', 'webgl_color_buffer_readpixels.cpp'), expected='0', timeout=20) + self.btest(path_from_root('tests', 'webgl_color_buffer_readpixels.cpp'), args=['-lGL'], expected='0', timeout=20) def test_webgl2(self): for opts in [[], ['-O2', '-g1', '--closure', '1'], ['-s', 'FULL_ES2=1']]: print opts - self.btest(path_from_root('tests', 'webgl2.cpp'), args=['-s', 'USE_WEBGL2=1'] + opts, expected='0') + self.btest(path_from_root('tests', 'webgl2.cpp'), args=['-s', 'USE_WEBGL2=1', '-lGL'] + opts, expected='0') def test_webgl2_objects(self): - self.btest(path_from_root('tests', 'webgl2_objects.cpp'), args=['-s', 'USE_WEBGL2=1'], expected='0') + self.btest(path_from_root('tests', 'webgl2_objects.cpp'), args=['-s', 'USE_WEBGL2=1', '-lGL'], expected='0') def test_webgl2_ubos(self): - self.btest(path_from_root('tests', 'webgl2_ubos.cpp'), args=['-s', 'USE_WEBGL2=1'], expected='0') + self.btest(path_from_root('tests', 'webgl2_ubos.cpp'), args=['-s', 'USE_WEBGL2=1', '-lGL'], expected='0') def test_webgl_with_closure(self): - self.btest(path_from_root('tests', 'webgl_with_closure.cpp'), args=['-O2', '-s', 'USE_WEBGL2=1', '--closure', '1'], expected='0') + self.btest(path_from_root('tests', 'webgl_with_closure.cpp'), args=['-O2', '-s', 'USE_WEBGL2=1', '--closure', '1', '-lGL'], expected='0') def test_sdl_touch(self): for opts in [[], ['-O2', '-g1', '--closure', '1']]: print opts - self.btest(path_from_root('tests', 'sdl_touch.c'), args=opts + ['-DAUTOMATE_SUCCESS=1'], expected='0') + self.btest(path_from_root('tests', 'sdl_touch.c'), args=opts + ['-DAUTOMATE_SUCCESS=1', '-lSDL', '-lGL'], expected='0') def test_html5_mouse(self): for opts in [[], ['-O2', '-g1', '--closure', '1']]: @@ -2197,7 +2197,7 @@ def test_html5_mouse(self): def test_sdl_mousewheel(self): for opts in [[], ['-O2', '-g1', '--closure', '1']]: print opts - self.btest(path_from_root('tests', 'test_sdl_mousewheel.c'), args=opts + ['-DAUTOMATE_SUCCESS=1'], expected='0') + self.btest(path_from_root('tests', 'test_sdl_mousewheel.c'), args=opts + ['-DAUTOMATE_SUCCESS=1', '-lSDL', '-lGL'], expected='0') def test_codemods(self): for opt_level in [0, 2]: @@ -2313,11 +2313,11 @@ def in_html(expected, args=[]): in_html('200', ['-s', 'FORCE_FILESYSTEM=1']) def test_glfw3(self): - self.btest(path_from_root('tests', 'glfw3.c'), args=['-s', 'LEGACY_GL_EMULATION=1', '-s', 'USE_GLFW=3'], expected='1') + self.btest(path_from_root('tests', 'glfw3.c'), args=['-s', 'LEGACY_GL_EMULATION=1', '-s', 'USE_GLFW=3', '-lglfw', '-lGL'], expected='1') def test_glfw_events(self): - self.btest(path_from_root('tests', 'glfw_events.c'), args=['-s', 'USE_GLFW=2', "-DUSE_GLFW=2"], expected='1') - self.btest(path_from_root('tests', 'glfw_events.c'), args=['-s', 'USE_GLFW=3', "-DUSE_GLFW=3"], expected='1') + self.btest(path_from_root('tests', 'glfw_events.c'), args=['-s', 'USE_GLFW=2', "-DUSE_GLFW=2", '-lglfw', '-lGL'], expected='1') + self.btest(path_from_root('tests', 'glfw_events.c'), args=['-s', 'USE_GLFW=3', "-DUSE_GLFW=3", '-lglfw', '-lGL'], expected='1') def test_asm_swapping(self): self.clear() @@ -2747,7 +2747,7 @@ def test_emterpreter_async_sleep2_safeheap(self): self.btest('emterpreter_async_sleep2_safeheap.cpp', '17', args=['-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-Oz', '-profiling', '-s', 'SAFE_HEAP=1', '-s', 'ASSERTIONS=1', '-s', 'EMTERPRETIFY_WHITELIST=["_main","_callback","_fix"]']) def test_sdl_audio_beep_sleep(self): - self.btest('sdl_audio_beep_sleep.cpp', '1', args=['-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-Os', '-s', 'ASSERTIONS=1', '-s', 'DISABLE_EXCEPTION_CATCHING=0', '-profiling', '-s', 'SAFE_HEAP=1'], timeout=60) + self.btest('sdl_audio_beep_sleep.cpp', '1', args=['-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-Os', '-s', 'ASSERTIONS=1', '-s', 'DISABLE_EXCEPTION_CATCHING=0', '-profiling', '-s', 'SAFE_HEAP=1', '-lSDL'], timeout=60) def test_mainloop_reschedule(self): self.btest('mainloop_reschedule.cpp', '1', args=['-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-Os'], timeout=30) @@ -2905,9 +2905,9 @@ def test_dynamic_link_glemu(self): return (const char *)glGetString(GL_EXTENSIONS); } ''') - Popen([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.js']).communicate() + Popen([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.js', '-lSDL']).communicate() - self.btest(self.in_dir('main.cpp'), '1', args=['-s', 'MAIN_MODULE=1', '-O2', '-s', 'LEGACY_GL_EMULATION=1', '--pre-js', 'pre.js']) + self.btest(self.in_dir('main.cpp'), '1', args=['-s', 'MAIN_MODULE=1', '-O2', '-s', 'LEGACY_GL_EMULATION=1', '-lSDL', '-lGL', '--pre-js', 'pre.js']) def test_memory_growth_during_startup(self): open('data.dat', 'w').write('X' * (30*1024*1024)) @@ -3276,11 +3276,11 @@ def test_utf16_textdecoder(self): def test_webgl_offscreen_canvas_in_pthread(self): for args in [[], ['-DTEST_CHAINED_WEBGL_CONTEXT_PASSING']]: - self.btest('gl_in_pthread.cpp', expected='1', args=args + ['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT=1']) + self.btest('gl_in_pthread.cpp', expected='1', args=args + ['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT=1', '-lGL']) def test_webgl_offscreen_canvas_in_mainthread_after_pthread(self): for args in [[], ['-DTEST_MAIN_THREAD_EXPLICIT_COMMIT']]: - self.btest('gl_in_mainthread_after_pthread.cpp', expected='0', args=args+['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT=1']) + self.btest('gl_in_mainthread_after_pthread.cpp', expected='0', args=args+['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT=1', '-lGL']) # Tests the feature that shell html page can preallocate the typed array and place it to Module.buffer before loading the script page. # In this build mode, the -s TOTAL_MEMORY=xxx option will be ignored. diff --git a/tools/shared.py b/tools/shared.py index dcacdb1e6c426..84784a3efd7b3 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -474,7 +474,12 @@ def get_emscripten_version(path): # Returns true if Emscripten is running in 'strict' mode, in which deprecated compiler features are not supported. def is_emscripten_strict(): - return (os.environ.get('EMCC_STRICT') and int(os.environ.get('EMCC_STRICT')) != 0) or Settings.STRICT + if os.environ.get('EMCC_STRICT') and int(os.environ.get('EMCC_STRICT')) != 0: return True + try: + return Settings.STRICT + except: + pass + return False # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) # exists. From 1b4e784c7bef6e07a5a521451299c04ee6753b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 19 Nov 2016 20:19:42 +0200 Subject: [PATCH 61/86] Move the deduction of which system JS libraries to link to class Building in tools/shared.py. --- emcc.py | 37 +------------------------------------ tools/shared.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/emcc.py b/emcc.py index 1f031e809cc9f..240c4ae5c98bb 100755 --- a/emcc.py +++ b/emcc.py @@ -940,42 +940,7 @@ def detect_fixed_language_mode(args): if found: break if found: break if not found: - # Some native libraries are implemented in Emscripten as system side JS libraries - js_system_libraries = { - 'c': '', - 'EGL': 'library_egl.js', - 'GL': 'library_gl.js', - 'GLESv2': 'library_gl.js', - 'GLEW': 'library_glew.js', - 'glfw': 'library_glfw.js', - 'glfw3': 'library_glfw.js', - 'GLU': '', - 'glut': 'library_glut.js', - 'm': '', - 'openal': 'library_openal.js', - 'pthread': '', - 'X11': 'library_xlib.js', - 'SDL': 'library_sdl.js', - 'stdc++': '', - 'uuid': 'library_uuid.js' - } - if lib in js_system_libraries: - if len(js_system_libraries[lib]) > 0: - system_js_libraries += [js_system_libraries[lib]] - - # TODO: This is unintentional due to historical reasons. Improve EGL to use HTML5 API to avoid depending on GLUT. - if lib == 'EGL': system_js_libraries += ['library_glut.js'] - - elif lib.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + lib)): - system_js_libraries += ['library_' + lib] - else: - emscripten_strict_mode = shared.is_emscripten_strict() or 'STRICT=1' in settings_changes - error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes - if error_on_missing_libraries: - logging.fatal('emcc: cannot find library "%s"', lib) - exit(1) - else: - logging.warning('emcc: cannot find library "%s"', lib) + system_js_libraries += shared.Building.path_to_system_js_libraries(lib) # Certain linker flags imply some link libraries to be pulled in by default. if 'EMTERPRETIFY_ASYNC=1' in settings_changes: system_js_libraries += ['library_async.js'] diff --git a/tools/shared.py b/tools/shared.py index 84784a3efd7b3..357c3efc0c8b3 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1999,6 +1999,50 @@ def ensure_struct_info(info_path): import gen_struct_info gen_struct_info.main(['-qo', info_path, path_from_root('src/struct_info.json')]) + @staticmethod + # Given the name of a special Emscripten-implemented system library, returns an array of absolute paths to JS library + # files inside emscripten/src/ that corresponds to the library name. + def path_to_system_js_libraries(library_name): + # Some native libraries are implemented in Emscripten as system side JS libraries + js_system_libraries = { + 'c': '', + 'EGL': 'library_egl.js', + 'GL': 'library_gl.js', + 'GLESv2': 'library_gl.js', + 'GLEW': 'library_glew.js', + 'glfw': 'library_glfw.js', + 'glfw3': 'library_glfw.js', + 'GLU': '', + 'glut': 'library_glut.js', + 'm': '', + 'openal': 'library_openal.js', + 'pthread': '', + 'X11': 'library_xlib.js', + 'SDL': 'library_sdl.js', + 'stdc++': '', + 'uuid': 'library_uuid.js' + } + library_files = [] + if library_name in js_system_libraries: + if len(js_system_libraries[library_name]) > 0: + library_files += [js_system_libraries[library_name]] + + # TODO: This is unintentional due to historical reasons. Improve EGL to use HTML5 API to avoid depending on GLUT. + if library_name == 'EGL': library_files += ['library_glut.js'] + + elif library_name.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + library_name)): + library_files += ['library_' + library_name] + else: + emscripten_strict_mode = shared.is_emscripten_strict() or 'STRICT=1' in settings_changes + error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes + if error_on_missing_libraries: + logging.fatal('emcc: cannot find library "%s"', library_name) + exit(1) + else: + logging.warning('emcc: cannot find library "%s"', library_name) + + return library_files + # compatibility with existing emcc, etc. scripts Cache = cache.Cache(debug=DEBUG_CACHE) chunkify = cache.chunkify From 11e463473f7541967539a5640edcafe23eeaef4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 22 Nov 2016 04:06:24 +0200 Subject: [PATCH 62/86] Apply the set of system JS libraries based on the link settings via a code path in shared.Building. --- emcc.py | 7 ++----- tools/shared.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/emcc.py b/emcc.py index 240c4ae5c98bb..fe8a824c50453 100755 --- a/emcc.py +++ b/emcc.py @@ -943,11 +943,8 @@ def detect_fixed_language_mode(args): system_js_libraries += shared.Building.path_to_system_js_libraries(lib) # Certain linker flags imply some link libraries to be pulled in by default. - if 'EMTERPRETIFY_ASYNC=1' in settings_changes: system_js_libraries += ['library_async.js'] - if 'ASYNCIFY=1' in settings_changes: system_js_libraries += ['library_async.js'] - if 'LZ4=1' in settings_changes: system_js_libraries += ['library_lz4.js'] - if 'USE_SDL=1' in settings_changes: system_js_libraries += ['library_sdl.js'] - if 'USE_SDL=2' in settings_changes: system_js_libraries += ['library_egl.js', 'library_glut.js', 'library_gl.js'] + system_js_libraries += shared.Building.path_to_system_js_libraries_for_settings(settings_changes) + settings_changes.append('SYSTEM_JS_LIBRARIES="' + ','.join(system_js_libraries) + '"') # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so diff --git a/tools/shared.py b/tools/shared.py index 357c3efc0c8b3..0ea72f217341c 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2043,6 +2043,18 @@ def path_to_system_js_libraries(library_name): return library_files + @staticmethod + # Given a list of Emscripten link settings, returns a list of paths to system JS libraries + # that should get linked automatically in to the build when those link settings are present. + def path_to_system_js_libraries_for_settings(link_settings): + system_js_libraries =[] + if 'EMTERPRETIFY_ASYNC=1' in link_settings: system_js_libraries += ['library_async.js'] + if 'ASYNCIFY=1' in link_settings: system_js_libraries += ['library_async.js'] + if 'LZ4=1' in link_settings: system_js_libraries += ['library_lz4.js'] + if 'USE_SDL=1' in link_settings: system_js_libraries += ['library_sdl.js'] + if 'USE_SDL=2' in link_settings: system_js_libraries += ['library_egl.js', 'library_glut.js', 'library_gl.js'] + return system_js_libraries + # compatibility with existing emcc, etc. scripts Cache = cache.Cache(debug=DEBUG_CACHE) chunkify = cache.chunkify From 12d47b086d139fbd7c5b21e1c30522e63366e3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 22 Nov 2016 04:07:44 +0200 Subject: [PATCH 63/86] Indentation fix in src/library_fs.js --- src/library_fs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/library_fs.js b/src/library_fs.js index e581d93354fad..3aa3214485716 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1,15 +1,15 @@ mergeInto(LibraryManager.library, { $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$PATH', '$TTY', '$MEMFS', #if __EMSCRIPTEN_HAS_idbfs_js__ - '$IDBFS', + '$IDBFS', #endif #if __EMSCRIPTEN_HAS_nodefs_js__ - '$NODEFS', + '$NODEFS', #endif #if __EMSCRIPTEN_HAS_workerfs_js__ - '$WORKERFS', + '$WORKERFS', #endif - 'stdin', 'stdout', 'stderr'], + 'stdin', 'stdout', 'stderr'], $FS__postset: 'FS.staticInit();' + '__ATINIT__.unshift(function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() });' + '__ATMAIN__.push(function() { FS.ignorePermissions = false });' + From 815a35bd149bd8c7d575cc9b97e0a57c54490bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 22 Nov 2016 05:11:30 +0200 Subject: [PATCH 64/86] Revise how EMCC_STRICT and -s STRICT=1 are read so that they are always visible. --- emcc.py | 28 +++++++++++++++++++++++++++- tests/test_other.py | 21 +++++++++++++++++++++ tools/shared.py | 28 +--------------------------- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/emcc.py b/emcc.py index fe8a824c50453..3a722c92f4f4a 100755 --- a/emcc.py +++ b/emcc.py @@ -253,7 +253,8 @@ def filter_emscripten_options(argv): if not use_js: cmd += shared.EMSDK_OPTS + ['-D__EMSCRIPTEN__'] # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. - if not shared.is_emscripten_strict(): cmd += ['-DEMSCRIPTEN'] + if not shared.Settings.STRICT: + cmd += ['-DEMSCRIPTEN'] if use_js: cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists logging.debug('just configuring: ' + ' '.join(cmd)) @@ -921,6 +922,22 @@ def detect_fixed_language_mode(args): if separate_asm: shared.Settings.SEPARATE_ASM = os.path.basename(asm_target) + if 'EMCC_STRICT' in os.environ: + shared.Settings.STRICT = int(os.environ.get('EMCC_STRICT')) + + STRICT = ([None] + filter(lambda x: x.startswith('STRICT='), settings_changes))[-1] + if STRICT: + shared.Settings.STRICT = int(STRICT[len('STRICT='):]) + + if shared.Settings.STRICT: + shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS = 1 + shared.Settings.ERROR_ON_MISSING_LIBRARIES = 1 + + # Libraries are searched before settings_changes are applied, so pull its value from the command line already here. + ERROR_ON_MISSING_LIBRARIES = ([None] + filter(lambda x: x.startswith('ERROR_ON_MISSING_LIBRARIES='), settings_changes))[-1] + if ERROR_ON_MISSING_LIBRARIES: + shared.Settings.ERROR_ON_MISSING_LIBRARIES = int(ERROR_ON_MISSING_LIBRARIES[len('ERROR_ON_MISSING_LIBRARIES='):]) + system_js_libraries = [] # Find library files @@ -1009,6 +1026,15 @@ def check(input_file): if shared.get_llvm_target() == shared.WASM_TARGET: shared.Settings.WASM_BACKEND = 1 + if not shared.Settings.STRICT: + # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. + shared.COMPILER_OPTS += ['-DEMSCRIPTEN'] + + # The system include path system/include/emscripten/ is deprecated, i.e. instead of #include , one should pass in #include . + # This path is not available in Emscripten strict mode. + if shared.USE_EMSDK: + shared.C_INCLUDE_PATHS += [shared.path_from_root('system', 'include', 'emscripten')] + # Use settings try: diff --git a/tests/test_other.py b/tests/test_other.py index 1559a1d234746..269aaf1a13f53 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -7040,3 +7040,24 @@ def test_check_engine(self): except SystemExit as e: caught_exit = e.code self.assertEqual(1, caught_exit, 'Did not catch SystemExit with bogus JS engine') + + def test_error_on_missing_libraries(self): + env = os.environ.copy() + if 'EMCC_STRICT' in env: del env['EMCC_STRICT'] + + process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-lsomenonexistingfile', '-s', 'STRICT=1'], stdout=PIPE, stderr=PIPE, env=env) + process.communicate() + assert process.returncode is not 0, '-llsomenonexistingfile is an error in strict mode' + + process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-lsomenonexistingfile', '-s', 'ERROR_ON_MISSING_LIBRARIES=0'], stdout=PIPE, stderr=PIPE, env=env) + process.communicate() + assert process.returncode is 0, '-llsomenonexistingfile is not an error if -s ERROR_ON_MISSING_LIBRARIES=0 is passed' + + process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-lsomenonexistingfile', '-s', 'STRICT=1', '-s', 'ERROR_ON_MISSING_LIBRARIES=0'], stdout=PIPE, stderr=PIPE, env=env) + process.communicate() + assert process.returncode is 0, '-s ERROR_ON_MISSING_LIBRARIES=0 should override -s STRICT=1' + + process = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-lsomenonexistingfile', '-s', 'STRICT=0'], stdout=PIPE, stderr=PIPE, env=env) + process.communicate() + # TODO: TEMPORARY: When -s ERROR_ON_MISSING_LIBRARIES=1 becomes the default, change the following line to expect failure instead of 0. + assert process.returncode is 0, '-llsomenonexistingfile is not yet an error in non-strict mode' diff --git a/tools/shared.py b/tools/shared.py index 0ea72f217341c..dea4cb92a61be 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -472,15 +472,6 @@ def find_temp_directory(): def get_emscripten_version(path): return open(path).read().strip().replace('"', '') -# Returns true if Emscripten is running in 'strict' mode, in which deprecated compiler features are not supported. -def is_emscripten_strict(): - if os.environ.get('EMCC_STRICT') and int(os.environ.get('EMCC_STRICT')) != 0: return True - try: - return Settings.STRICT - except: - pass - return False - # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) # exists. # The test runner always does this check (through |force|). emcc does this less frequently, @@ -941,9 +932,6 @@ def get_llvm_target(): '-D__unix', '-D__unix__'] - # The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead. - if not is_emscripten_strict(): COMPILER_OPTS += ['-DEMSCRIPTEN'] - # Changes to default clang behavior # Implicit functions can cause horribly confusing function pointer type errors, see #2175 @@ -967,11 +955,6 @@ def get_llvm_target(): path_from_root('system', 'local', 'include') ] - # The system include path system/include/emscripten/ is deprecated, i.e. instead of #include , one should pass in #include . - # This path is not available in Emscripten strict mode. - if not is_emscripten_strict(): - C_INCLUDE_PATHS += [path_from_root('system', 'include', 'emscripten')] - CXX_INCLUDE_PATHS = [ path_from_root('system', 'include', 'libcxx'), path_from_root('system', 'lib', 'libcxxabi', 'include') @@ -1111,13 +1094,6 @@ def load(self, args=[]): settings = re.sub(r'var ([\w\d]+)', r'self.attrs["\1"]', settings) exec settings - # Apply default values for settings that are configured from environment variables. - if is_emscripten_strict(): - # Specify default values for Emscripten strict mode. - self.attrs['STRICT'] = 1 - self.attrs['ERROR_ON_UNDEFINED_SYMBOLS'] = 1 - self.attrs['ERROR_ON_MISSING_LIBRARIES'] = 1 - # Apply additional settings. First -O, then -s for i in range(len(args)): if args[i].startswith('-O'): @@ -2033,9 +2009,7 @@ def path_to_system_js_libraries(library_name): elif library_name.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + library_name)): library_files += ['library_' + library_name] else: - emscripten_strict_mode = shared.is_emscripten_strict() or 'STRICT=1' in settings_changes - error_on_missing_libraries = (emscripten_strict_mode and not 'ERROR_ON_MISSING_LIBRARIES=0' in settings_changes) or 'ERROR_ON_MISSING_LIBRARIES=1' in settings_changes - if error_on_missing_libraries: + if Settings.ERROR_ON_MISSING_LIBRARIES: logging.fatal('emcc: cannot find library "%s"', library_name) exit(1) else: From 022c4db2109c6cf581ce38fe3f432c634c055a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 22 Nov 2016 05:16:18 +0200 Subject: [PATCH 65/86] Add test for scenario when not explicitly linking to system JS libraries. --- tests/test_browser.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_browser.py b/tests/test_browser.py index 425831b0665f6..11e42c0b07110 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -61,6 +61,12 @@ def setUpClass(self): print 'Running the browser tests. Make sure the browser allows popups from localhost.' print + def test_sdl1_in_emscripten_nonstrict_mode(self): + if 'EMCC_STRICT' in os.environ and int(os.environ['EMCC_STRICT']): return self.skip('This test requires being run in non-strict mode (EMCC_STRICT env. variable unset)') + # TODO: This test is verifying behavior that will be deprecated at some point in the future, remove this test once + # system JS libraries are no longer automatically linked to anymore. + self.btest('hello_world_sdl.cpp', reference='htmltest.png') + def test_sdl1(self): self.btest('hello_world_sdl.cpp', reference='htmltest.png', args=['-lSDL', '-lGL']) self.btest('hello_world_sdl.cpp', reference='htmltest.png', args=['-s', 'USE_SDL=1', '-lGL']) # is the default anyhow From 08b70e5669995485bf0dbf57f10bfc70fd95dde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 7 Dec 2016 03:01:22 +0200 Subject: [PATCH 66/86] Accept EMCC_STRICT=somethingotherthanzero as true for EMCC_STRICT --- emcc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index 3a722c92f4f4a..c12d4d71558d2 100755 --- a/emcc.py +++ b/emcc.py @@ -923,7 +923,7 @@ def detect_fixed_language_mode(args): shared.Settings.SEPARATE_ASM = os.path.basename(asm_target) if 'EMCC_STRICT' in os.environ: - shared.Settings.STRICT = int(os.environ.get('EMCC_STRICT')) + shared.Settings.STRICT = os.environ.get('EMCC_STRICT') != '0' STRICT = ([None] + filter(lambda x: x.startswith('STRICT='), settings_changes))[-1] if STRICT: From 0efac40f87a8028dda26e467e2f19ed12822c84f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 6 Dec 2016 15:57:40 -1000 Subject: [PATCH 67/86] export static base and bump for binaryen (#4767) --- src/jsifier.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jsifier.js b/src/jsifier.js index 2428828203dda..33580613da635 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -299,7 +299,10 @@ function JSify(data, functionsOnly) { print('// STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); // comment as metadata only } if (BINARYEN) { + // export static base and bump, needed for linking in wasm binary's memory, dynamic linking, etc. print('var STATIC_BUMP = {{{ STATIC_BUMP }}};'); + print('Module["STATIC_BASE"] = STATIC_BASE;'); + print('Module["STATIC_BUMP"] = STATIC_BUMP;'); } } var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); From 267c4eee72bb3e9f48c03f94981778e2bbd7e11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 7 Dec 2016 08:12:17 +0200 Subject: [PATCH 68/86] Add export of JS lib ifdefs for all libs, even when not in strict mode. --- src/modules.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules.js b/src/modules.js index c9238c3cf3e76..7cfa7235c0971 100644 --- a/src/modules.js +++ b/src/modules.js @@ -147,17 +147,17 @@ var LibraryManager = { // If there are any explicitly specified system JS libraries to link to, add those to link. if (SYSTEM_JS_LIBRARIES) { - SYSTEM_JS_LIBRARIES = SYSTEM_JS_LIBRARIES.split(','); - // For each system JS library library_xxx.js, add a preprocessor token __EMSCRIPTEN_HAS_xxx_js__ so that code can conditionally dead code eliminate out - // if a particular feature is not being linked in. - for (var i = 0; i < SYSTEM_JS_LIBRARIES.length; ++i) { - global['__EMSCRIPTEN_HAS_' + SYSTEM_JS_LIBRARIES[i].replace('.', '_').replace('library_', '') + '__'] = 1 - } libraries = libraries.concat(SYSTEM_JS_LIBRARIES); } libraries = libraries.concat(additionalLibraries); + // For each JS library library_xxx.js, add a preprocessor token __EMSCRIPTEN_HAS_xxx_js__ so that code can conditionally dead code eliminate out + // if a particular feature is not being linked in. + for (var i = 0; i < libraries.length; ++i) { + global['__EMSCRIPTEN_HAS_' + libraries[i].replace('.', '_').replace('library_', '') + '__'] = 1 + } + if (BOOTSTRAPPING_STRUCT_INFO) libraries = ['library_bootstrap_structInfo.js', 'library_formatString.js']; if (ONLY_MY_CODE) { libraries = []; From 8455fba3aab3e2b3384f51352f2a17c61f006064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 7 Dec 2016 08:12:37 +0200 Subject: [PATCH 69/86] Fix typo in looking up path_from_root() --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index dea4cb92a61be..5037efa35fc7a 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2006,7 +2006,7 @@ def path_to_system_js_libraries(library_name): # TODO: This is unintentional due to historical reasons. Improve EGL to use HTML5 API to avoid depending on GLUT. if library_name == 'EGL': library_files += ['library_glut.js'] - elif library_name.endswith('.js') and os.path.isfile(shared.path_from_root('src', 'library_' + library_name)): + elif library_name.endswith('.js') and os.path.isfile(path_from_root('src', 'library_' + library_name)): library_files += ['library_' + library_name] else: if Settings.ERROR_ON_MISSING_LIBRARIES: From d4c92a2836e00811962fbbc129cf2a1813154724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 30 Aug 2016 00:30:10 +0300 Subject: [PATCH 70/86] Fix benign off by one error in library_syscall getdents64 implementation. --- src/library_syscall.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_syscall.js b/src/library_syscall.js index 0e89393589cb8..f5de05907d17f 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -969,7 +969,7 @@ var SyscallsLibrary = { stream.getdents = FS.readdir(stream.path); } var pos = 0; - while (stream.getdents.length > 0 && pos + {{{ C_STRUCTS.dirent.__size__ }}} < count) { + while (stream.getdents.length > 0 && pos + {{{ C_STRUCTS.dirent.__size__ }}} <= count) { var id; var type; var name = stream.getdents.pop(); From 5043eac8d5789834396bf4375ee41f238f753eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 7 Dec 2016 22:54:18 +0200 Subject: [PATCH 71/86] Recognize that Emterpreter and SharedArrayBuffer/pthreads builds are not mutually compatible. Helps to clean up error message to a more readable form, encountered in #4771. --- emcc.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index 8af5674d24f45..b6995f9e3d318 100755 --- a/emcc.py +++ b/emcc.py @@ -1151,13 +1151,16 @@ def check(input_file): if shared.Settings.USE_PTHREADS: if shared.Settings.LINKABLE: - logging.error('-s LINKABLE=1 is not supported with -s USE_PTHREADS=1!') + logging.error('-s LINKABLE=1 is not supported with -s USE_PTHREADS>0!') exit(1) if shared.Settings.SIDE_MODULE: - logging.error('-s SIDE_MODULE=1 is not supported with -s USE_PTHREADS=1!') + logging.error('-s SIDE_MODULE=1 is not supported with -s USE_PTHREADS>0!') exit(1) if shared.Settings.MAIN_MODULE: - logging.error('-s MAIN_MODULE=1 is not supported with -s USE_PTHREADS=1!') + logging.error('-s MAIN_MODULE=1 is not supported with -s USE_PTHREADS>0!') + exit(1) + if shared.Settings.EMTERPRETIFY: + logging.error('-s EMTERPRETIFY=1 is not supported with -s USE_PTHREADS>0!') exit(1) if shared.Settings.OUTLINING_LIMIT: From 1e9e18c65428887c4781314530fb29bd8fa662fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 8 Dec 2016 02:32:11 +0200 Subject: [PATCH 72/86] Remove panner and listener .setVelocity() calls, which got forcibly removed from the WebAudio spec. Closes #4587. See https://github.com/WebAudio/web-audio-api/issues/372. --- src/library_openal.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/library_openal.js b/src/library_openal.js index 17b750533b7e9..83844843a2bb7 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -397,7 +397,9 @@ var LibraryOpenAL = { this._velocity[0] = val[0]; this._velocity[1] = val[1]; this._velocity[2] = val[2]; - if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]); + // TODO: The velocity values are not currently used to implement a doppler effect. + // If support for doppler effect is reintroduced, compute the doppler + // speed pitch factor and apply it here. }, get direction() { return this._direction; @@ -504,7 +506,8 @@ var LibraryOpenAL = { panner.maxDistance = src.maxDistance; panner.rolloffFactor = src.rolloffFactor; panner.setPosition(src.position[0], src.position[1], src.position[2]); - panner.setVelocity(src.velocity[0], src.velocity[1], src.velocity[2]); + // TODO: If support for doppler effect is reintroduced, compute the doppler + // speed pitch factor and apply it here. panner.connect(AL.currentContext.gain); // Disconnect from the default source. @@ -1367,7 +1370,9 @@ var LibraryOpenAL = { AL.currentContext.ctx.listener._velocity[0] = v1; AL.currentContext.ctx.listener._velocity[1] = v2; AL.currentContext.ctx.listener._velocity[2] = v3; - AL.currentContext.ctx.listener.setVelocity(v1, v2, v3); + // TODO: The velocity values are not currently used to implement a doppler effect. + // If support for doppler effect is reintroduced, compute the doppler + // speed pitch factor and apply it here. break; default: #if OPENAL_DEBUG @@ -1402,7 +1407,9 @@ var LibraryOpenAL = { AL.currentContext.ctx.listener._velocity[0] = x; AL.currentContext.ctx.listener._velocity[1] = y; AL.currentContext.ctx.listener._velocity[2] = z; - AL.currentContext.ctx.listener.setVelocity(x, y, z); + // TODO: The velocity values are not currently used to implement a doppler effect. + // If support for doppler effect is reintroduced, compute the doppler + // speed pitch factor and apply it here. break; case 0x100F /* AL_ORIENTATION */: var x = {{{ makeGetValue('values', '0', 'float') }}}; From 8adff069ecfdc341042bf592b786fb3103dba913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 7 Dec 2016 23:38:39 +0200 Subject: [PATCH 73/86] Fix Windows benchmark runner to apply the needed cmdline args and environment vars to build with Clang natively, and skip running the benchmarks on engines that haven't been configured up. --- tests/test_benchmark.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 6f4c440dd23b4..5f9e9ba2e05a3 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -68,8 +68,8 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat if lib_builder: native_args = native_args + lib_builder(self.name, native=True, env_init={ 'CC': self.cc, 'CXX': self.cxx }) if not native_exec: compiler = self.cxx if filename.endswith('cpp') else self.cc - cmd = [compiler, '-fno-math-errno', filename, '-o', filename+'.native'] + self.args + shared_args + native_args - process = Popen(cmd, stdout=PIPE, stderr=parent.stderr_redirect) + cmd = [compiler, '-fno-math-errno', filename, '-o', filename+'.native'] + self.args + shared_args + native_args + get_clang_native_args() + process = Popen(cmd, stdout=PIPE, stderr=parent.stderr_redirect, env=get_clang_native_env()) output = process.communicate() if process.returncode is not 0: print >> sys.stderr, "Building native executable with command failed", ' '.join(cmd) @@ -132,12 +132,16 @@ def run(self, args): # Benchmarkers try: benchmarkers_error = '' - benchmarkers = [ - NativeBenchmarker('clang', CLANG_CC, CLANG), - JSBenchmarker('sm-asmjs', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2']), - JSBenchmarker('sm-wasm', SPIDERMONKEY_ENGINE, ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'BINARYEN_IMPRECISE=1']), - JSBenchmarker('v8-wasm', V8_ENGINE, ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'BINARYEN_IMPRECISE=1']), - ] + benchmarkers = [NativeBenchmarker('clang', CLANG_CC, CLANG)] + if SPIDERMONKEY_ENGINE and SPIDERMONKEY_ENGINE[0]: + benchmarkers += [ + JSBenchmarker('sm-asmjs', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2']), + JSBenchmarker('sm-wasm', SPIDERMONKEY_ENGINE, ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'BINARYEN_IMPRECISE=1']) + ] + if V8_ENGINE and V8_ENGINE[0]: + benchmarkers += [ + JSBenchmarker('v8-wasm', V8_ENGINE, ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'BINARYEN_IMPRECISE=1']) + ] except Exception, e: benchmarkers_error = str(e) benchmarkers = [] From 84d15f14054e096ed095149f6b2b42bca68fa36f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Dec 2016 15:49:01 -1000 Subject: [PATCH 74/86] Link in objects when they provide commons we need, not just defs (#4764) * link in objects when they provide commons we need, not just defs #4763 * test commons linking --- tests/test_other.py | 27 +++++++++++++++++++++++++++ tools/shared.py | 7 ++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index 1559a1d234746..cfdd132f0577b 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -855,6 +855,33 @@ def build(path, args): assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs' + def test_commons_link(self): + open('a.h', 'w').write(r''' +#if !defined(A_H) +#define A_H +extern int foo[8]; +#endif +''') + open('a.c', 'w').write(r''' +#include "a.h" +int foo[8]; +''') + open('main.c', 'w').write(r''' +#include +#include "a.h" + +int main() { + printf("|%d|\n", foo[0]); + return 0; +} +''') + + subprocess.check_call([PYTHON, EMCC, '-o', 'a.o', 'a.c']) + subprocess.check_call([PYTHON, EMAR, 'rv', 'library.a', 'a.o']) + subprocess.check_call([PYTHON, EMCC, '-o', 'main.o', 'main.c']) + subprocess.check_call([PYTHON, EMCC, '-o', 'a.js', 'main.o', 'library.a', '-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1']) + self.assertContained('|0|', run_js('a.js')) + def test_outline(self): if WINDOWS and not Building.which('mingw32-make'): return self.skip('Skipping other.test_outline: This test requires "mingw32-make" tool in PATH on Windows to drive a Makefile build of zlib') diff --git a/tools/shared.py b/tools/shared.py index c9ce4ea7850a8..2c674600bc001 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1456,15 +1456,16 @@ def make_paths_absolute(f): # returns True. def consider_object(f, force_add=False): new_symbols = Building.llvm_nm(f) - do_add = force_add or not unresolved_symbols.isdisjoint(new_symbols.defs) + provided = new_symbols.defs.union(new_symbols.commons) + do_add = force_add or not unresolved_symbols.isdisjoint(provided) if do_add: logging.debug('adding object %s to link' % (f)) # Update resolved_symbols table with newly resolved symbols - resolved_symbols.update(new_symbols.defs) + resolved_symbols.update(provided) # Update unresolved_symbols table by adding newly unresolved symbols and # removing newly resolved symbols. unresolved_symbols.update(new_symbols.undefs.difference(resolved_symbols)) - unresolved_symbols.difference_update(new_symbols.defs) + unresolved_symbols.difference_update(provided) actual_files.append(f) return do_add From 5387c1e5f1f55b69c41b94cf044062c59e052f0b Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 9 Dec 2016 09:38:40 -0800 Subject: [PATCH 75/86] Remove use of combiner-alias-analysis flag from wasm backend's llc The flag has been removed from llc upstream in https://reviews.llvm.org/D14834 --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index aec62ebb49bac..a2977408d40d1 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1329,7 +1329,7 @@ def emscript_wasm_backend(infile, settings, outfile, libraries=None, compiler_en '-o', temp_s] backend_args += ['-thread-model=single'] # no threads support in backend, tell llc to not emit atomics # disable slow and relatively unimportant optimization passes - backend_args += ['-combiner-alias-analysis=false', '-combiner-global-alias-analysis=false'] + backend_args += ['-combiner-global-alias-analysis=false'] # asm.js-style exception handling if settings['DISABLE_EXCEPTION_CATCHING'] != 1: From 862668d4aae7c7444b9ca9896460359438c58410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 7 Dec 2016 21:29:38 +0200 Subject: [PATCH 76/86] Add testing for getdents64 syscall buffer sizes. --- tests/fs/test_getdents64.cpp | 53 ++++++++++++++++++++++++++++++++++++ tests/test_core.py | 4 +++ 2 files changed, 57 insertions(+) create mode 100644 tests/fs/test_getdents64.cpp diff --git a/tests/fs/test_getdents64.cpp b/tests/fs/test_getdents64.cpp new file mode 100644 index 0000000000000..ae0927642beff --- /dev/null +++ b/tests/fs/test_getdents64.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE (sizeof(dirent)*2) + +int main(int argc, char *argv[]) +{ + int fd = open(".", O_RDONLY | O_DIRECTORY); + assert(fd > 0); + + printf("sizeof(dirent): %d, sizeof(buffer): %d\n", sizeof(dirent), BUF_SIZE); + + bool first = true; + + for(;;) + { + char buf[BUF_SIZE]; + int nread = getdents(fd, (dirent*)buf, BUF_SIZE); + assert(nread != -1); + if (nread == 0) + break; + + // In this test, we provide enough space to read two dirent entries at a time. + // Test that on the first iteration of the loop we get exactly two entries. (there's at least "." and ".." in each directory) + assert(nread == BUF_SIZE || !first); + first = false; + + printf("--------------- nread=%d ---------------\n", nread); + printf("i-node# file type d_reclen d_off d_name\n"); + int bpos = 0; + while(bpos < nread) + { + dirent *d = (dirent *)(buf + bpos); + printf("%8ld ", (long)d->d_ino); + char d_type = *(buf + bpos + d->d_reclen - 1); + printf("%-10s ", (d_type == DT_REG) ? "regular" : + (d_type == DT_DIR) ? "directory" : + (d_type == DT_FIFO) ? "FIFO" : + (d_type == DT_SOCK) ? "socket" : + (d_type == DT_LNK) ? "symlink" : + (d_type == DT_BLK) ? "block dev" : + (d_type == DT_CHR) ? "char dev" : "???"); + printf("%4d %10lld %s\n", d->d_reclen, (long long) d->d_off, d->d_name); + bpos += d->d_reclen; + } + } +} \ No newline at end of file diff --git a/tests/test_core.py b/tests/test_core.py index 4fe99de077e9f..144ce06c5243f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4117,6 +4117,10 @@ def test_mount(self): src = open(path_from_root('tests', 'fs', 'test_mount.c'), 'r').read() self.do_run(src, 'success', force_c=True) + def test_getdents64(self): + src = open(path_from_root('tests', 'fs', 'test_getdents64.cpp'), 'r').read() + self.do_run(src, '..') + def test_fwrite_0(self): test_path = path_from_root('tests', 'core', 'test_fwrite_0') src, output = (test_path + s for s in ('.c', '.out')) From e248322dc186fd8b523c722ed67eb5a56cc0849f Mon Sep 17 00:00:00 2001 From: AlexPerrot Date: Sat, 10 Dec 2016 15:04:02 +0100 Subject: [PATCH 77/86] fix embind test for overloads of free functions --- tests/embind/embind_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 989f6ebfc8b32..0c03ca54d188f 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -2366,6 +2366,9 @@ EMSCRIPTEN_BINDINGS(overloads) { .function("dummy", select_overload(&MultipleOverloadsDependingOnDummy::dummy)) .function("dummy", select_overload(&MultipleOverloadsDependingOnDummy::dummy)) ; + + function("getDummy", select_overload(&getDummy)); + function("getDummy", select_overload(&getDummy)); } // tests for out-of-order registration From e101571c57abde43837ca39aa629f9bd403b4e04 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 14 Dec 2016 16:20:47 -0800 Subject: [PATCH 78/86] --cflags option (#4776) Allows getting the flags emcc passes to clang. --- emcc.py | 20 ++++++++++++++++++-- site/source/docs/tools_reference/emcc.rst | 3 +++ tests/test_other.py | 11 +++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/emcc.py b/emcc.py index b6995f9e3d318..1ea34a40eb97f 100755 --- a/emcc.py +++ b/emcc.py @@ -115,6 +115,8 @@ def run(): if len(sys.argv) <= 1 or ('--help' not in sys.argv and len(sys.argv) >= 2 and sys.argv[1] != '--version'): shared.check_sanity(force=DEBUG) + misc_temp_files = shared.configuration.get_temp_files() + # Handle some global flags if len(sys.argv) == 1: @@ -181,6 +183,22 @@ def run(): print shared.get_llvm_target() exit(0) + elif '--cflags' in sys.argv: + # fake running the command, to see the full args we pass to clang + debug_env = os.environ.copy() + debug_env['EMCC_DEBUG'] = '1' + args = filter(lambda x: x != '--cflags', sys.argv) + with misc_temp_files.get_file(suffix='.o') as temp_target: + input_file = 'hello_world.c' + out, err = subprocess.Popen([shared.PYTHON] + args + [shared.path_from_root('tests', input_file), '-c', '-o', temp_target], stderr=subprocess.PIPE, env=debug_env).communicate() + lines = filter(lambda x: shared.CLANG_CC in x and input_file in x, err.split(os.linesep)) + line = lines[0] + assert 'running:' in line + parts = line.split(' ')[2:] + parts = filter(lambda x: x != '-c' and x != '-o' and input_file not in x and temp_target not in x and '-emit-llvm' not in x, parts) + print ' '.join(parts) + exit(0) + def is_minus_s_for_emcc(newargs, i): assert newargs[i] == '-s' if i+1 < len(newargs) and '=' in newargs[i+1] and not newargs[i+1].startswith('-'): # -s OPT=VALUE is for us, -s by itself is a linker option @@ -397,8 +415,6 @@ def log_time(name): use_cxx = True - misc_temp_files = shared.configuration.get_temp_files() - try: with ToolchainProfiler.profile_block('parse arguments and setup'): ## Parse args diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index 595a9942d5ef9..157733343ce83 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -450,6 +450,9 @@ Options that are modified or new in *emcc* are listed below: ``--output-eol windows|linux`` Specifies the line ending to generate for the text files that are outputted. If "--output-eol windows" is passed, the final output files will have Windows \r\n line endings in them. With "--output-eol linux", the final generated files will be written with Unix \n line endings. +``--cflags`` + Prints out the flags ``emcc`` would pass to ``clang`` to compile source code to object/bitcode form. You can use this to invoke clang yourself, and then run ``emcc`` on those outputs just for the final linking+conversion to JS. + .. _emcc-environment-variables: Environment variables diff --git a/tests/test_other.py b/tests/test_other.py index cfdd132f0577b..f4c25eabd9e56 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -398,6 +398,17 @@ def test_emcc_cache_flag(self): os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove. shutil.rmtree(tempdirname) + def test_emcc_cflags(self): + # see we print them out + output = Popen([PYTHON, EMCC, '--cflags'], stdout=PIPE, stderr=PIPE).communicate() + flags = output[0].strip() + self.assertContained(' '.join(COMPILER_OPTS), flags) + # check they work + cmd = [CLANG, path_from_root('tests', 'hello_world.cpp')] + flags.split(' ') + ['-c', '-emit-llvm', '-o', 'a.bc'] + subprocess.check_call(cmd) + subprocess.check_call([PYTHON, EMCC, 'a.bc']) + self.assertContained('hello, world!', run_js(self.in_dir('a.out.js'))) + def test_emar_em_config_flag(self): # We expand this in case the EM_CONFIG is ~/.emscripten (default) config = os.path.expanduser(EM_CONFIG) From a8360389175a2ffc9cecd42c5d0412d37b990d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 15 Dec 2016 11:30:46 +0200 Subject: [PATCH 79/86] Explicitly reject -s BINARYEN_METHOD='someinvalidoption' modes that aren't recognized. --- emcc.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/emcc.py b/emcc.py index 1ea34a40eb97f..7132cb07d6f44 100755 --- a/emcc.py +++ b/emcc.py @@ -2008,6 +2008,14 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati print jsrun.run_js(shared.path_from_root('tools', 'js-optimizer.js'), shared.NODE_JS, args=[asm_target, 'eliminateDeadGlobals', 'last', 'asm'], stdout=open(temp, 'w')) shutil.move(temp, asm_target) + if shared.Settings.BINARYEN_METHOD: + methods = shared.Settings.BINARYEN_METHOD.split(',') + valid_methods = ['asmjs', 'native-wasm', 'interpret-s-expr', 'interpret-binary', 'interpret-asm2wasm'] + for m in methods: + if not m.strip() in valid_methods: + logging.error('Unrecognized BINARYEN_METHOD "' + m.strip() + '" specified! Please pass a comma-delimited list containing one or more of: ' + ','.join(valid_methods)) + sys.exit(1) + if shared.Settings.BINARYEN: logging.debug('using binaryen, with method: ' + shared.Settings.BINARYEN_METHOD) binaryen_bin = os.path.join(shared.Settings.BINARYEN_ROOT, 'bin') From 363de14fd2e7b2acc2e5164f6b1cfe84355bd187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 15 Dec 2016 14:07:45 +0200 Subject: [PATCH 80/86] Remove 'o' option (preserve created file timestamps) when running llvm-ar to extract archive files, because of an LLVM bug that causes it to fail on FAT32 filesystems (https://llvm.org/bugs/show_bug.cgi?id=31389), and since the code path in question does not need the timestamps. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index 2c674600bc001..89faec2d505ea 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1496,7 +1496,7 @@ def get_archive_contents(f): dirname = os.path.dirname(content) if dirname: safe_ensure_dirs(dirname) - Popen([LLVM_AR, 'xo', f], stdout=PIPE).communicate() # if absolute paths, files will appear there. otherwise, in this directory + Popen([LLVM_AR, 'x', f], stdout=PIPE).communicate() # if absolute paths, files will appear there. otherwise, in this directory contents = map(lambda content: os.path.join(temp_dir, content), contents) contents = filter(os.path.exists, map(os.path.abspath, contents)) contents = filter(Building.is_bitcode, contents) From f00b433105ea9280ee7ecd2b085908f880f7b292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 15 Dec 2016 14:47:46 +0200 Subject: [PATCH 81/86] Fix test_demangle_stacks_symbol_map on Windows (os.linesep should be used only on files opened in binary mode on Windows, but if a file is opened in text mode, it will have \n line endings in memory as usual --- tests/test_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_core.py b/tests/test_core.py index 144ce06c5243f..9c658f84088d5 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6118,7 +6118,7 @@ def test_demangle_stacks_symbol_map(self): self.emcc_args += ['--emit-symbol-map'] self.do_run(open(path_from_root('tests', 'core', 'test_demangle_stacks.c')).read(), 'abort') # make sure the shortened name is the right one - symbols = open('src.cpp.o.js.symbols').read().split(os.linesep) + symbols = open('src.cpp.o.js.symbols').read().split('\n') for line in symbols: if ':' not in line: continue short, full = line.split(':') From 9a648a8ea2541ea50f40b9d54e638299f4beeb2d Mon Sep 17 00:00:00 2001 From: Vladimir Davidovich Date: Thu, 15 Dec 2016 21:56:44 +0300 Subject: [PATCH 82/86] Implement retrieval of ALC_FREQUENCY, ALC_MONO_SOURCES, ALC_STEREO_SOURCES. Fix bugs. (#4746) * Implement retrieval of ALC_FREQUENCY, ALC_MONO_SOURCES, ALC_STEREO_SOURCES * fix "Uncaught ReferenceError: _alSource3f is not defined" when calling alSource3i * adding myself to AUTHORS * Allocating a new AudioContext is an extremely heavy operation, so let's require AL.currentContext for ALC_FREQUENCY --- AUTHORS | 1 + src/library_openal.js | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 1538ab336f7d5..0441963dded57 100644 --- a/AUTHORS +++ b/AUTHORS @@ -268,3 +268,4 @@ a license to everyone to use it as detailed in LICENSE.) * Aaron Ruß (copyright owned by DFKI GmbH) * Vilibald Wanča * Alex Hixon +* Vladimir Davidovich diff --git a/src/library_openal.js b/src/library_openal.js index 83844843a2bb7..6d71f723f5b20 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -314,6 +314,25 @@ var LibraryOpenAL = { } {{{ makeSetValue('data', '0', '0', 'i32') }}}; break; + case 0x1007 /* ALC_FREQUENCY */: + if (!device) { + AL.alcErr = 0xA001 /* ALC_INVALID_DEVICE */; + return 0; + } + if (!AL.currentContext) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return 0; + } + {{{ makeSetValue('data', '0', 'AL.currentContext.ctx.sampleRate', 'i32') }}}; + break; + case 0x1010 /* ALC_MONO_SOURCES */: + case 0x1011 /* ALC_STEREO_SOURCES */: + if (!device) { + AL.alcErr = 0xA001 /* ALC_INVALID_DEVICE */; + return 0; + } + {{{ makeSetValue('data', '0', '0x7FFFFFFF', 'i32') }}}; + break; case 0x20003 /* ALC_MAX_AUXILIARY_SENDS */: if (!device) { AL.currentContext.err = 0xA001 /* ALC_INVALID_DEVICE */; @@ -609,7 +628,7 @@ var LibraryOpenAL = { } }, - alSource3i: ['alSource3f'], + alSource3i__deps: ['alSource3f'], alSource3i: function(source, param, v1, v2, v3) { _alSource3f(source, param, v1, v2, v3); }, From 79fd45230830c08903ce0732339ccde011b40d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 16 Dec 2016 15:44:21 +0200 Subject: [PATCH 83/86] Add test for BINARYEN_METHOD validation. --- tests/test_other.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_other.py b/tests/test_other.py index f4c25eabd9e56..8d593eb68e5f0 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -7012,6 +7012,11 @@ def test_binaryen_warn_mem(self): subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1', '-s', 'BINARYEN_METHOD="native-wasm"', '-s', 'TOTAL_MEMORY=' + str(16*1024*1024), '--pre-js', 'pre.js', '-s', 'ALLOW_MEMORY_GROWTH=1']) self.assertContained('hello, world!', run_js('a.out.js', engine=SPIDERMONKEY_ENGINE)) + def test_binaryen_invalid_method(self): + proc = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-o', 'test.js', '-s', "BINARYEN_METHOD='invalid'"]) + proc.communicate() + assert proc.returncode != 0 + def test_binaryen_default_method(self): if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey') subprocess.check_call([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-s', 'WASM=1']) From 9b727e8fff5748fea1a3ee175fcc4ef97de7ea3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 17 Dec 2016 12:36:04 +0200 Subject: [PATCH 84/86] Apply code review to Emscripten strict mode. --- emcc.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/emcc.py b/emcc.py index c12d4d71558d2..ac093036f94c2 100755 --- a/emcc.py +++ b/emcc.py @@ -925,18 +925,23 @@ def detect_fixed_language_mode(args): if 'EMCC_STRICT' in os.environ: shared.Settings.STRICT = os.environ.get('EMCC_STRICT') != '0' - STRICT = ([None] + filter(lambda x: x.startswith('STRICT='), settings_changes))[-1] - if STRICT: - shared.Settings.STRICT = int(STRICT[len('STRICT='):]) + # Libraries are searched before settings_changes are applied, so apply the value for STRICT and ERROR_ON_MISSING_LIBRARIES from + # command line already now. + + def get_last_setting_change(setting): + return ([None] + filter(lambda x: x.startswith(setting + '='), settings_changes))[-1] + + strict_cmdline = get_last_setting_change('STRICT') + if strict_cmdline: + shared.Settings.STRICT = int(strict_cmdline[len('STRICT='):]) if shared.Settings.STRICT: shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS = 1 shared.Settings.ERROR_ON_MISSING_LIBRARIES = 1 - # Libraries are searched before settings_changes are applied, so pull its value from the command line already here. - ERROR_ON_MISSING_LIBRARIES = ([None] + filter(lambda x: x.startswith('ERROR_ON_MISSING_LIBRARIES='), settings_changes))[-1] - if ERROR_ON_MISSING_LIBRARIES: - shared.Settings.ERROR_ON_MISSING_LIBRARIES = int(ERROR_ON_MISSING_LIBRARIES[len('ERROR_ON_MISSING_LIBRARIES='):]) + error_on_missing_libraries_cmdline = get_last_setting_change('ERROR_ON_MISSING_LIBRARIES') + if error_on_missing_libraries_cmdline: + shared.Settings.ERROR_ON_MISSING_LIBRARIES = int(error_on_missing_libraries_cmdline[len('ERROR_ON_MISSING_LIBRARIES='):]) system_js_libraries = [] From 485a49bfc891c8cda62998e7cd3a426607b0a8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 19 Dec 2016 20:10:50 +0200 Subject: [PATCH 85/86] Fix bug after PR #4665 that rebuilding SDL2 with -s USE_SDL2=1 after emcc --clear-ports would fail. --- src/modules.js | 2 +- tools/shared.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules.js b/src/modules.js index 7cfa7235c0971..927f12c8d48f2 100644 --- a/src/modules.js +++ b/src/modules.js @@ -147,7 +147,7 @@ var LibraryManager = { // If there are any explicitly specified system JS libraries to link to, add those to link. if (SYSTEM_JS_LIBRARIES) { - libraries = libraries.concat(SYSTEM_JS_LIBRARIES); + libraries = libraries.concat(SYSTEM_JS_LIBRARIES.split(',')); } libraries = libraries.concat(additionalLibraries); diff --git a/tools/shared.py b/tools/shared.py index 378f7e3e5653d..9dd73e4fb5a5d 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2028,7 +2028,7 @@ def path_to_system_js_libraries_for_settings(link_settings): if 'LZ4=1' in link_settings: system_js_libraries += ['library_lz4.js'] if 'USE_SDL=1' in link_settings: system_js_libraries += ['library_sdl.js'] if 'USE_SDL=2' in link_settings: system_js_libraries += ['library_egl.js', 'library_glut.js', 'library_gl.js'] - return system_js_libraries + return map(lambda x: path_from_root('src', x), system_js_libraries) # compatibility with existing emcc, etc. scripts Cache = cache.Cache(debug=DEBUG_CACHE) From 6dc4ac5f9e4d8484e273e4dcc554f809738cedd6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 23 Dec 2016 15:47:45 -0800 Subject: [PATCH 86/86] 1.37.0 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index eaece033767de..a9eeadaa59718 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -"1.36.14" +"1.37.0"