wasi-sdk icon indicating copy to clipboard operation
wasi-sdk copied to clipboard

Building a wasm library without needing to define a `main()`

Open arvid-norlander opened this issue 1 year ago • 8 comments

I'm new to wasm, so I may be misunderstanding things. I'm using the wasi-sdk.cmake file to build a library that I will load as a plugin into a native program using WAMR.

However, in order to get a .wasm file out (and not a .a file) I need to use add_executable(mylib.wasm src/test.cpp) in cmake, which complains about missing the main entrypoint. I could of course provide a dummy, but that seems pointless.

  • If I use add_library(mylib.wasm src/test.cpp) I get a .a archive instead.
  • If I use add_library(mylib.wasm SHARED src/test.cpp) I get:
    clang-16: error: argument unused during compilation: '-shared' [-Werror,-Wunused-command-line-argument]
    
    (and it tries to create mylib.wasm.so which is not what I want, I think?) If I do allow errors (which is against the policy at my workplace), it still claims to need a main:
    wasm-ld: error: /opt/wasi-sdk/bin/../share/wasi-sysroot/lib/wasm32-wasi/libc.a(__main_void.o): undefined symbol: main
    

What is the proper way to create a plugin style library using wasi-sdk (using cmake)? I will be calling functions from the host, I do not need a main as far as I know (I wouldn't need this in a native loadable library for sure).

arvid-norlander avatar Jul 03 '23 13:07 arvid-norlander

maybe using exec-model.

target_link_options(reactor
  PRIVATE
    -mexec-model=reactor
)

lum1n0us avatar Sep 04 '23 00:09 lum1n0us

Yes, that worked in the end (discovered a few weeks ago, but forgot to update this bug report). Perhaps the documentation should be a bit better though, especially for people who are new to WASM (it was not at all clear to me that "reactor" had anything to do with "library")

arvid-norlander avatar Sep 04 '23 09:09 arvid-norlander

The problem is that the term "library" in a build system normally means just a part of a program (either as a static or dynamic library). What a reactor is is a full (statically linked) program without a main function. There was no existing term for that so WASI invented the term "reactor". I believe in future versions that term will actually be dropped, but that is the history of the term.

If what you really want is a dynamically loaded library (which is how most plugin systems are built) then WASI doesn't currently support that, but there are efforts to port/standardize the dynamic linking system used by emscripten, so it maybe be possible in the future.

One way to tell if you need to use DSOs if that if your plugins share memory with each other or with some "main" program or with other shared libraries. With "reactors" each module has own complete copy of libc, along with all its global data, which makes calling across the program boundaries more like an RPC to completely separate program.

sbc100 avatar Sep 06 '23 17:09 sbc100

One way to tell if you need to use DSOs if that if your plugins share memory with each other or with some "main" program or with other shared libraries. With "reactors" each module has own complete copy of libc, along with all its global data, which makes calling across the program boundaries more like an RPC to completely separate program.

My plugins are completely separate, though sharing libc (and thus reducing memory usage) would be nice.

arvid-norlander avatar Sep 07 '23 08:09 arvid-norlander

It seems there are different ways, please correct me if I was wrong @sbc100

  • add an embedded as a bridge between libc-module-instance and plugin-main-module-instance. It is a shared-nothing model. both libc-module-instance and plugin-main-module-instance have their own linear memory. Embedded should copy/transfer data between two memories(RPC). libc-module-instance like a service to respond requests from variant plugins. there will be only one libc-module-instances in the system.

  • another one likes shared-everything model. Treat libc as a separate module instance and let every plugin-main-module-instance import libc-module-instance. Every plugin-main-module-instance has its owned libc-module-instance. And two instances share a linear-memory. Since both plugin-main and libc are in language C or C++, it is able to share data layout in this case

lum1n0us avatar Sep 07 '23 09:09 lum1n0us

It seems there are different ways, please correct me if I was wrong @sbc100

  • add an embedded as a bridge between libc-module-instance and plugin-main-module-instance. It is a shared-nothing model. both libc-module-instance and plugin-main-module-instance have their own linear memory. Embedded should copy/transfer data between two memories(RPC). libc-module-instance like a service to respond requests from variant plugins. there will be only one libc-module-instances in the system.
  • another one likes shared-everything model. Treat libc as a separate module instance and let every plugin-main-module-instance import libc-module-instance. Every plugin-main-module-instance has its owned libc-module-instance. And two instances share a linear-memory. Since both plugin-main and libc are in language C or C++, it is able to share data layout in this case

Basically yes. Note that wasi-sdk does not currently support shared-everything linking or any kind of runtime linking. The only implementation that I know of today is in emscripten.

In the emscripten model the main module includes libc and the side module(s) import all the libc symbols from the main module: https://emscripten.org/docs/compiling/Dynamic-Linking.html

sbc100 avatar Sep 07 '23 17:09 sbc100

In the emscripten model the main module includes libc and the side module(s) import all the libc symbols from the main module: https://emscripten.org/docs/compiling/Dynamic-Linking.html

Reading this, it doesn't look like emscripten supports this model for it's WASI support? Only in the web case? Or at least WASI not not explicitly mentioned on that page.

arvid-norlander avatar Sep 08 '23 07:09 arvid-norlander

In the emscripten model the main module includes libc and the side module(s) import all the libc symbols from the main module: https://emscripten.org/docs/compiling/Dynamic-Linking.html

Reading this, it doesn't look like emscripten supports this model for it's WASI support? Only in the web case? Or at least WASI not not explicitly mentioned on that page.

Yes, that is correct.

sbc100 avatar Sep 08 '23 07:09 sbc100