emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.84k stars 3.31k forks source link

Unable to export c++ functions via EXPORTED_FUNCTIONS as they get namemangled and are unrecognized. #15841

Open JarekToro opened 2 years ago

JarekToro commented 2 years ago

Please include the following in your bug report:

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.0.0-git (3fd52e107187b8a169bb04a02b9f982c8a075205)
clang version 14.0.0 (/srcdest/llvm-project 4348cd42c385e71b63e5da7e492172cff6a79d7b)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /opt/emscripten-llvm/bin

Failing command line in full:


target_compile_options(geos PRIVATE
         -fPIC
        --no-entry
        "SHELL:-s SIDE_MODULE=2")

target_link_options(geos PRIVATE
        "SHELL:-s LLD_REPORT_UNDEFINED=1"
        "SHELL:-s EXPORT_ALL=1"
        "SHELL:-s FILESYSTEM=0"
        "SHELL:-s WASM=1"
        "SHELL:-s EXPORTED_FUNCTIONS=['geos::index::srttree::SimpleStrTree']"
        "SHELL:-s WASM_BIGINT=1"
        "SHELL:-s SIDE_MODULE=2")

target_link_libraries(main_program PRIVATE geos)

target_compile_options(main_program PRIVATE -fPIC "SHELL:-s MAIN_MODULE=2")

target_link_options(
    main_program
    PRIVATE
        --no-entry
        --bind
        "SHELL:-s LLD_REPORT_UNDEFINED=1"
        "SHELL:-s MAIN_MODULE=2"
        "SHELL:-s ENVIRONMENT=web"
        "SHELL:-s WASM=1"
        "SHELL:-s WASM_BIGINT=1"
    "SHELL:-s MODULARIZE=1"
    "SHELL:-s ALLOW_MEMORY_GROWTH=1"
    "SHELL:-s FILESYSTEM=0"
    "SHELL:-s USE_ES6_IMPORT_META=1"
    "SHELL:-s EXPORT_ES6=1"
    "SHELL: -s USE_CLOSURE_COMPILER=1"
    "SHELL:-s EXPORT_NAME=\"MainProgram\""
)

While SimpleStrTree is exported.

This is thrown because of the name mangling.

error: undefined symbol: _ZTVN4geos5index7strtree13SimpleSTRtreeE (referenced by top-level compiled C/C++ code)
warning: __ZTVN4geos5index7strtree13SimpleSTRtreeE may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library

If I Manually Add __ZTVN4geos5index7strtree13SimpleSTRtreeE to the exported EXPORTED_FUNCTIONS it works as expected.

sbc100 commented 2 years ago

First of all I noticed that you are using the SHELL: syntax in your target_link_options. However, If you remove the space betwee the -s and the options name (e.g, -sMAIN_MODULE=2) then this should not be needed. Unrelated to this issue but should simplify your CMakeLists.txt.

Regarding the EXPORTED_FUNCTIONS list, that is indeed a list of C symbol names, which means that if you want to export C++ symbols then you will need to specify the mangled name (i.e. the actual/underlying symbol name).

I think the problem here is that you are using -sSIDE_MODULE=2 to build the side module. If you build the side module instead with just -sSIDE_MODULE then I think it should solve your problem and all non-hidden symbols will be exported by default.

JarekToro commented 2 years ago

Thanks appreciate the cmakelist info. I'm relatively new to the c++ world. However the SIDE_MODULE=2 was deliberately set. Geos is a large lib and we only use a small part of it. Also because of licensing we cannot link it statically. When I manually enter all the mangled names the code is reduced to about a third of its size. So Im guessing that's the only solution is to manually find and enter the mangled names? Are there tools to help automate the retrieval of the mangled names?

haley-dot-yang commented 8 months ago

@JarekToro Hi, could you please share how you get the mangling function names?

haley-dot-yang commented 8 months ago

@JarekToro Hi, could you please share how you get the mangling function names?

OK, I use llvm-nm, and now I get the function mangling name

sbc100 commented 8 months ago

Probably better / simple to just export C symbols. You can do that either via EMSCIPTEN_KEEPALIVE tags on functions in the source, or via extern "C" .. in the source and EXPORTED_FUNCTIONS on the command line.

Exporting C++ functions directly is almost never desirable IIUC.

haley-dot-yang commented 8 months ago

Probably better / simple to just export C symbols. You can do that either via EMSCIPTEN_KEEPALIVE tags on functions in the source, or via extern "C" .. in the source and EXPORTED_FUNCTIONS on the command line.

Exporting C++ functions directly is almost never desirable IIUC.

Thanks for your reply. However, currently we are working on a big commercial C++ project, add extern "C" or EMSCIPTEN_KEEPALIVE seems not quite possible.

sbc100 commented 8 months ago

Can I ask why are you trying to export the C++ functions? Are you trying to call them directly from JS? Don't your need somethink like embind if you want to acheive this?

Another option is to great a new wasm_exports.cpp file in your project and then export the C symbols that you need.

e.g. :

extern "C" {

xxx SimpleStrTree(yyy) {
   return geos::index::srttree::SimpleStrTree();
}

}

No need to modify the original source then.

Still it begs the question as to who you are going construct the arguments or use the return values form JS (without something like embind).

haley-dot-yang commented 8 months ago

We want to generate a sharable wasm file that includes specific cpp functions. As we do not want those function which not in the specific list to be included in the sharable file, I try to use SIDE_MODULE=2 and EXPORTED_FUNCTIONS to achieve this goal.

haley-dot-yang commented 8 months ago

Simply speaking, I want to achieve that multiple web apps can share a common wasm on my device, and the common wasm should include a specific function list. So I tried SIDE_MODULE and EXPORTED_FUNCTIONS to see if they can cooperate to realize my goal. Can I get any suggestions?

sbc100 commented 8 months ago

Who is going to be calling the function in the this "common wasm".

Emscripten does support multiple main modules calling into a shared side module, so if that works for you I would use the MAIN_MODULE=2 / SIDE_MODULE=2 system.

Normally you would contol which which symbols are import/exported via __attribute__((visibility)) in the source code, but if you can't modify the source code and its doesn't currently contain the correct visibility attributes when yes you will end up needing to using -sEXPORTED_FUNCTIONS. I recommend using using -sEXPORTED_FUNCTIONS=@filename.txt and listing you exports one per line in that file.

We only support mangled names in the EXPORTED_FUNCTIONS list I'm afraid, and I don't think we want to try to change that at this point.

haley-dot-yang commented 8 months ago

Thank you very much for all your kind reply and suggestions :) I will get a try