From fe16f98a701840fd152d6c01600896b91bbd5f76 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 20 Dec 2018 11:58:10 -0500 Subject: [PATCH] Fix #283: Handle function pointers in dylib with signatures not in main --- .circleci/config.yml | 4 +-- emsdk/patches/dynCall_so.patch | 46 ++++++++++++++++++++++++++++++++++ src/main.c | 26 ------------------- test/test_scipy.py | 4 +++ 4 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 emsdk/patches/dynCall_so.patch create mode 100644 test/test_scipy.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 92f657ac4..a74b7cb8c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: - restore_cache: keys: - - v1-emsdk-{{ checksum "emsdk/Makefile" }}-v11- + - v1-emsdk-{{ checksum "emsdk/Makefile" }}-v12- - run: name: build @@ -36,7 +36,7 @@ jobs: paths: - ./emsdk/emsdk - ~/.ccache - key: v1-emsdk-{{ checksum "emsdk/Makefile" }}-v11-{{ .BuildNum }} + key: v1-emsdk-{{ checksum "emsdk/Makefile" }}-v12-{{ .BuildNum }} - persist_to_workspace: root: . diff --git a/emsdk/patches/dynCall_so.patch b/emsdk/patches/dynCall_so.patch new file mode 100644 index 000000000..3f637b541 --- /dev/null +++ b/emsdk/patches/dynCall_so.patch @@ -0,0 +1,46 @@ +diff --git a/emsdk/emscripten/tag-1.38.12/src/library.js b/emsdk/emscripten/tag-1.38.12/src/library.js +index 82537bb3e..8e2e43128 100644 +--- a/emsdk/emscripten/tag-1.38.12/src/library.js ++++ b/emsdk/emscripten/tag-1.38.12/src/library.js +@@ -1781,6 +1781,12 @@ LibraryManager.library = { + } + } + ++ for (var sym in lib_module) { ++ if (sym.startsWith('dynCall_') && !Module.hasOwnProperty(sym)) { ++ Module[sym] = lib_module[sym]; ++ } ++ } ++ + // Not all browsers support Object.keys(). + var handle = 1; + for (var key in DLFCN.loadedLibs) { +diff --git a/emsdk/emscripten/tag-1.38.12/src/support.js b/emsdk/emscripten/tag-1.38.12/src/support.js +index cff68fbe2..3a4e51dca 100644 +--- a/emsdk/emscripten/tag-1.38.12/src/support.js ++++ b/emsdk/emscripten/tag-1.38.12/src/support.js +@@ -211,9 +211,21 @@ function loadWebAssemblyModule(binary, loadAsync) { + if (prop.startsWith('invoke_')) { + // A missing invoke, i.e., an invoke for a function type + // present in the dynamic library but not in the main JS, +- // and the dynamic library cannot provide JS for it. Use +- // the generic "X" invoke for it. +- return env[prop] = invoke_X; ++ // and the dynamic library cannot provide JS for it. Generate ++ // a closure for it. ++ var dynCallName = 'dynCall_' + prop.slice(7); ++ env[prop] = function() { ++ var sp = stackSave(); ++ try { ++ var args = Array.prototype.slice.call(arguments); ++ return Module[dynCallName].apply(null, args); ++ } catch(e) { ++ stackRestore(sp); ++ if (typeof e !== 'number' && e !== 'longjmp') throw e; ++ Module["setThrew"](1, 0); ++ } ++ } ++ return env[prop]; + } + // if not a global, then a function - call it indirectly + return env[prop] = function() { diff --git a/src/main.c b/src/main.c index 394ee5e05..1861b9409 100644 --- a/src/main.c +++ b/src/main.c @@ -10,32 +10,6 @@ #include "python2js.h" #include "runpython.h" -/* - TODO: This is a workaround for a weird emscripten compiler bug. The - matplotlib/_qhull.so extension makes function pointer calls with these - signatures, but since nothing with that signature exists in the MAIN_MODULE, - it can't link the SIDE_MODULE. Creating these dummy functions here seems to - work around the problem. -*/ - -void -__foo(double x) -{} - -void -__foo2(double x, double y) -{} - -void -__foo3(double x, double y, double z) -{} - -void -__foo4(int a, double b, int c, int d, int e) -{} - -/* END WORKAROUND */ - int main(int argc, char** argv) { diff --git a/test/test_scipy.py b/test/test_scipy.py new file mode 100644 index 000000000..afd973f5b --- /dev/null +++ b/test/test_scipy.py @@ -0,0 +1,4 @@ +def test_brentq(selenium_standalone): + selenium_standalone.load_package("scipy") + selenium_standalone.run("from scipy.optimize import brentq") + selenium_standalone.run("brentq(lambda x: x, -1, 1)")