emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.91k stars 3.32k forks source link

Adding symbol into `EXPORTED_RUNTIME_METHODS` from macro in JS library doesn't work since 3.1.60 #23057

Open toyobayashi opened 1 day ago

toyobayashi commented 1 day ago

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.60 (42a6ea2052f19f70d7d994e8c324bcad2f1f8939)
clang version 19.0.0git (https:/github.com/llvm/llvm-project bc9823cf60bf91cc8b45248c4205cd2c67b2a3d5)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /Users/toyobayashi/code/github/emsdk/upstream/bin

Reproduce repository: https://github.com/toyobayashi/emscripten-exported-runtime-methods-3160-repro

Full link command and output with -v appended: https://github.com/toyobayashi/emscripten-exported-runtime-methods-3160-repro/actions/runs/12132338450/job/33826053152

lib.c:

#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE
void _my_library_init() {}

lib.js:

{{{ ((DEFAULT_LIBRARY_FUNCS_TO_INCLUDE instanceof Set ? DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.add("$myLibraryInit") : DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.indexOf("$myLibraryInit") === -1 ? DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push("$myLibraryInit") : undefined), "") }}}
{{{ ((EXPORTED_RUNTIME_METHODS instanceof Set ? EXPORTED_RUNTIME_METHODS.add("myLibraryInit") : EXPORTED_RUNTIME_METHODS.indexOf("myLibraryInit") === -1 ? EXPORTED_RUNTIME_METHODS.push("myLibraryInit") : undefined), "") }}}

addToLibrary({
  $myLibraryInitOptions: {},
  $myLibraryInit (options) {
    Object.assign(myLibraryInitOptions, options || {})
    __my_library_init()
  },
  $myLibraryInit__deps: ['_my_library_init', '$myLibraryInitOptions'],
})

Command:

emcc -sMODULARIZE=1 -sEXPORT_NAME=lib --js-library=./src/lib.js -v -o ./out/lib.js ./src/lib.c

index.js:

const init = require('./out/lib.js')
init().then(Module => {
  console.log(Module.myLibraryInit)
  Module.myLibraryInit()
})

3.1.59 output:

[Function: myLibraryInit]

3.1.60 and latest 3.1.73 output:

Aborted('myLibraryInit' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ))
/home/runner/work/emscripten-exported-runtime-methods-3160-repro/emscripten-exported-runtime-methods-3160-repro/out/lib.js:597
  var e = new WebAssembly.RuntimeError(what);
          ^

RuntimeError: Aborted('myLibraryInit' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ))
    at abort (/home/runner/work/emscripten-exported-runtime-methods-3160-repro/emscripten-exported-runtime-methods-3160-repro/out/lib.js:597:[11](https://github.com/toyobayashi/emscripten-exported-runtime-methods-3160-repro/actions/runs/12132338450/job/33826053152#step:7:12))
    at Object.get (/home/runner/work/emscripten-exported-runtime-methods-3160-repro/emscripten-exported-runtime-methods-3160-repro/out/lib.js:918:9)
    at /home/runner/work/emscripten-exported-runtime-methods-3160-repro/emscripten-exported-runtime-methods-3160-repro/index.js:3:22

Node.js v20.18.1
toyobayashi commented 1 day ago

It seems that DEFAULT_LIBRARY_FUNCS_TO_INCLUDE still works because after I removed the first line of JS library, myLibraryInit went into missingLibrarySymbols from unexportedSymbols and function itself didn't exist in output JS file.

sbc100 commented 13 hours ago

So you are looking to force the export of a symbol simply by the inclusion of a JS library? This seems like a reasonable request, but the doing it way you are seems a little dependent on emscripten internals.

Would using the -sEXPORTED_RUNTIME_METHODS command line flag not work in this case for some reason?

toyobayashi commented 6 hours ago

Yes, I have always done this in my js libraries, because I want to control what symbols are exported as the author of the library, and if the exported symbols change in the future, it will be invisible to the users of the library, without requiring user to manually modify -sEXPORTED_RUNTIME_METHODS

sbc100 commented 5 hours ago

OK, I'll see if I can come with an officially blessed way to do this.