emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.63k stars 3.29k forks source link

basic wasm workers example fails at runtime with "Cannot use 'import.meta' outside a module" #19007

Closed dr-matt closed 1 year ago

dr-matt commented 1 year ago

I can't seem to get wasm workers running, even in a simplified and isolated example. Briefly, the browser (most recent chrome and edge) outputs the following error:

Uncaught SyntaxError: Cannot use 'import.meta' outside a module (at thread-test.js:3:27)
    at onmessage (thread-test.ww.js:1:208)

When the emscripten-generated worker thread-test.ww.js tries to call importScripts() to import the main emscripten-generated file thread-test.js, the above problem is triggered.

More details below; please let me know what other information would be helpful.

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.31 (e88336121cfe6da4a96c88e46f314552f07dfed0)
clang version 17.0.0 (https://github.com/llvm/llvm-project 1142e6c7c795de7f80774325a07ed49bc95a48c9)
Target: wasm32-unknown-emscripten
Thread model: posix

Full link command and output with -v appended: (note: this was run indirectly using emcmake)

/home/user/emscripten/emsdk/upstream/emscripten/em++ -O3 -DNDEBUG --bind -sENVIRONMENT=web,worker -sFILESYSTEM=0 -flto -sEXPORT_ES6=1 -sMODULARIZE -sALLOW_MEMORY_GROWTH -sWASM_WORKERS  -v @CMakeFiles/thread-test.dir/objects1.rsp -o thread-test.js
 "/home/user/emscripten/emsdk/upstream/bin/clang" --version
 "/home/user/emscripten/emsdk/upstream/bin/wasm-ld" -o thread-test.wasm CMakeFiles/thread-test.dir/thread-test.cpp.o -L/home/user/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lto /home/user/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lto/crtbegin.o --whole-archive -lembind-rtti --no-whole-archive -lGL-ww -lal -lhtml5 -lstubs -lnoexit -lc-ww -ldlmalloc-ww -lcompiler_rt-ww -lc++-ww-noexcept -lc++abi-ww-noexcept -lsockets-ww -lwasm_workers -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --allow-undefined-file=/tmp/tmpmcnsf96d.undefined --import-memory --shared-memory --strip-debug --export-if-defined=main --export-if-defined=emscripten_wasm_worker_initialize --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=__main_argc_argv --export=stackSave --export=stackRestore --export=stackAlloc --export=__wasm_call_ctors --export=__errno_location --export=__get_temp_ret --export=__set_temp_ret --export=malloc --export=free --export-table -z stack-size=65536 --initial-memory=16777216 --no-entry --max-memory=2147483648 --global-base=1024
 "/home/user/emscripten/emsdk/upstream/bin/wasm-emscripten-finalize" --dyncalls-i64 --pass-arg=legalize-js-interface-exported-helpers thread-test.wasm -o thread-test.wasm --detect-features
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/src/compiler.js /tmp/tmprw2jm15g.json
 "/home/user/emscripten/emsdk/upstream/bin/wasm-opt" --strip-dwarf --post-emscripten -O3 --low-memory-unused --zero-filled-memory --pass-arg=directize-initial-contents-immutable --strip-debug --strip-producers thread-test.wasm -o thread-test.wasm --mvp-features --enable-threads --enable-bulk-memory --enable-mutable-globals --enable-sign-ext
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emscripten_temp_afzhbiu7/thread-test.js AJSDCE minifyWhitespace --exportES6 -o /tmp/emscripten_temp_afzhbiu7/thread-test.jso1.js
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emcc_acorn_info_m1_s6rou.js emitDCEGraph noPrint --exportES6
 "/home/user/emscripten/emsdk/upstream/bin/wasm-metadce" --graph-file=/tmp/emcc_dce_graph_l73xvk4x.json thread-test.wasm -o thread-test.wasm --mvp-features --enable-threads --enable-bulk-memory --enable-mutable-globals --enable-sign-ext
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emcc_acorn_info_fqzho244.js applyDCEGraphRemovals minifyWhitespace --exportES6 -o /tmp/emscripten_temp_afzhbiu7/thread-test.jso2.js
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emscripten_temp_afzhbiu7/thread-test.jso2.js AJSDCE minifyWhitespace --exportES6 -o /tmp/emscripten_temp_afzhbiu7/thread-test.jso3.js
 "/home/user/emscripten/emsdk/upstream/bin/wasm-opt" --strip-dwarf --minify-imports-and-exports-and-modules thread-test.wasm -o thread-test.wasm --mvp-features --enable-threads --enable-bulk-memory --enable-mutable-globals --enable-sign-ext
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emcc_acorn_info_99jcp3ap.js applyImportAndExportNameChanges minifyWhitespace --exportES6 -o /tmp/emscripten_temp_afzhbiu7/thread-test.jso4.js
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/preprocessor.js /tmp/emscripten_temp_afzhbiu7/settings.js wasm_worker.js --expandMacros
 "/home/user/emscripten/emsdk/node/14.18.2_64bit/bin/node" /home/user/emscripten/emsdk/upstream/emscripten/tools/acorn-optimizer.js /home/user/projects/wasm/build/no-simd.no-threads/thread-test.ww.js minifyWhitespace --exportES6

The c++ code in thread-test.cpp is adapted from the wasm workers hello world example:

#include <emscripten/bind.h>
#include <emscripten/wasm_worker.h>
#include <stdio.h>

void run_in_worker()
{
  printf("* * * * * * * * * * Hello from wasm worker!\n");
}

void run() {
  emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024);
  emscripten_wasm_worker_post_function_v(worker, run_in_worker);
}

EMSCRIPTEN_BINDINGS(thread_test) {
  emscripten::function("run", &run);
}

Simple usage in an html file:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Threads Test</title>
  </head>
  <body>
    <h3>Hello World</h3>
    <script>
      const loadModule = async () => {
        const Module = await import('/js/thread-test.js');
        const testModule = await Module.default();
        testModule.run();                                                       
      }                                                                         
      loadModule();                                                               
    </script>                                                                   
  </body>                                                                       
</html>                                                                                                    
sbc100 commented 1 year ago

I imagine it could be that wasm workers might not yet be tested with MODUARLIZE and/or EXPORT_ES6. Does your example work if you don't use those options?

dr-matt commented 1 year ago

@sbc100 you may be right. Without MODULARIZE the behavior is the same, though I think that flag may be internally enabled if EXPORT_ES6 is turned on. Removing both flags and modifying how the module is loaded and called, the example does work as expected.

So perhaps wasm workers do not currently work properly with EXPORT_ES6 - is this already a known issue?

edit: #17664

sbc100 commented 1 year ago

Yes EXPORT_ES6 sets MODULARIZE internally.

And yes this looks like a dupe of #17664. Closing as duplicate.