diff --git a/ChangeLog.md b/ChangeLog.md index 2d3b87028d81d..2d100493b258d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -47,6 +47,9 @@ Current Trunk of ccache via emsdk, or from https://github.com/juj/ccache/tree/emscripten, and run explicitly with "ccache emcc ..." after installing, or automatically just with "emcc ..." after activating ccache via emsdk (#13498). +- Added support to use a custom set of substitution characters . # and ? to + ease passing arrays of C symbols on the command line to ASYNCIFY_* settings. + (#13477) - Using EM_ASM and EM_JS in a side module will now result in an error (since this is not implemented yet). This could effect users were previously inadvertently including (but not actually using) EM_ASM or EM_JS functions in diff --git a/emcc.py b/emcc.py index 839f791b3e9fd..47e96432d6bda 100755 --- a/emcc.py +++ b/emcc.py @@ -627,6 +627,15 @@ def is_dash_s_for_emcc(args, i): return arg.isidentifier() and arg.isupper() +def unmangle_symbols_from_cmdline(symbols): + def unmangle(x): + return x.replace('.', ' ').replace('#', '&').replace('?', ',') + + if type(symbols) is list: + return [unmangle(x) for x in symbols] + return unmangle(symbols) + + def parse_s_args(args): settings_changes = [] for i in range(len(args)): @@ -1459,6 +1468,10 @@ def default_setting(name, new_default): '_emscripten_stack_get_end', '_emscripten_stack_set_limits'] + shared.Settings.ASYNCIFY_ADD = unmangle_symbols_from_cmdline(shared.Settings.ASYNCIFY_ADD) + shared.Settings.ASYNCIFY_REMOVE = unmangle_symbols_from_cmdline(shared.Settings.ASYNCIFY_REMOVE) + shared.Settings.ASYNCIFY_ONLY = unmangle_symbols_from_cmdline(shared.Settings.ASYNCIFY_ONLY) + # SSEx is implemented on top of SIMD128 instruction set, but do not pass SSE flags to LLVM # so it won't think about generating native x86 SSE code. newargs = [x for x in newargs if x not in SIMD_INTEL_FEATURE_TOWER and x not in SIMD_NEON_FLAGS] diff --git a/src/settings.js b/src/settings.js index 77d7c83c18f7d..d970f5bfe77fe 100644 --- a/src/settings.js +++ b/src/settings.js @@ -719,6 +719,7 @@ var ASYNCIFY_STACK_SIZE = 4096; // to know you got this right), so this is not recommended unless you // really know what are doing, and need to optimize every bit of speed // and size. +// // The names in this list are names from the WebAssembly Names section. The // wasm backend will emit those names in *human-readable* form instead of // typical C++ mangling. For example, you should write Struct::func() @@ -730,7 +731,23 @@ var ASYNCIFY_STACK_SIZE = 4096; // changes which would mean a single list couldn't work for both -O0 and -O1 // builds, etc.). You can inspect the wasm binary to look for the actual names, // either directly or using wasm-objdump or wasm-dis, etc. +// // Simple '*' wildcard matching is supported. +// +// To avoid dealing with limitations in operating system shells or build system +// escaping, the following substitutions can be made: +// - ' ' -> '.', +// - '&' -> '#', +// - ',' -> '?'. +// +// That is, the function +// "foo(char const*, int&)" can be inputted as +// "foo(char.const*?.int#)" on the command line instead. +// +// Note: Whitespace is part of the function signature! I.e. +// "foo(char const *, int &)" will not match "foo(char const*, int&)", and +// neither would "foo(const char*, int &)". +// // [link] var ASYNCIFY_REMOVE = []; diff --git a/tests/browser/test_asyncify_tricky_function_sig.cpp b/tests/browser/test_asyncify_tricky_function_sig.cpp new file mode 100644 index 0000000000000..7e2c0de1c68a5 --- /dev/null +++ b/tests/browser/test_asyncify_tricky_function_sig.cpp @@ -0,0 +1,38 @@ +#include +#include + +volatile int x; + +int bar() { return 1; } + +__attribute__((noinline)) +int foo(const char *str, int &i) +{ + if (x == 1337) return bar(); // don't inline me + printf("foo %s\n", str); + emscripten_sleep(1); + printf("foo %d\n", i); + return 42; +} + +__attribute__((noinline)) +int foo2() +{ + if (x == 1337) return bar(); // don't inline me + printf("foo2 1\n"); + emscripten_sleep(1); + printf("foo2 2\n"); + return 43; +} + +int main() +{ + printf("main 1\n"); + int j = 42; + const char *str = "hello"; + int ret = foo(str, j); + printf("main %d\n", ret); + int ret2 = foo2(); + printf("ret2 %d\n", ret2); + REPORT_RESULT(ret + ret2); +} diff --git a/tests/test_browser.py b/tests/test_browser.py index e2a945a22227f..7d74e81e79f20 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3210,6 +3210,9 @@ def test_async(self): print(opts) self.btest('browser/async.cpp', '1', args=['-O' + str(opts), '-g2', '-s', 'ASYNCIFY']) + def test_asyncify_tricky_function_sig(self): + self.btest('browser/test_asyncify_tricky_function_sig.cpp', '85', args=['-s', 'ASYNCIFY_ONLY=[foo(char.const*?.int#),foo2(),main,__original_main]', '-s', 'ASYNCIFY=1']) + @requires_threads def test_async_in_pthread(self): self.btest('browser/async.cpp', '1', args=['-s', 'ASYNCIFY', '-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD', '-g'])