Search code examples
rustbuildemscripten

How can you link a Rust library with a C app into one WASM file using Emscripten?


I have a project that links a C library with a C app using Emscripten. I would like to replace the C library with a library written in Rust. How can this be accomplished?

I know that there are two relevant WASM targets in Rust, the normal wasm32-unknown-unknown one and the wasm32-unknown-emscripten one. I'm guessing the latter target is necessary for it to work with the Emscripten compiler? But how do I tell Emscripten to use a .wasm library rather than a .a library?

There may be other ways of linking Rust and C code together into a .wasm but I think I do need to stick with Emscripten as I require its Asyncify feature (and in the future will use its WASMFS system too.)


Solution

  • This is actually quite straightforward!

    So first, make sure your Rust project is set to build a static library:

    [lib]
    crate-type=["staticlib"]
    

    Then compile your Rust project with the correct target, wasm32-unknown-emscripten:

    cargo build --target=wasm32-unknown-emscripten
    

    Then you can simply link the static lib into your C/C++ app. Note that you'll probably want to use a variable to handle the different paths for dev and release builds. I'm using CMake:

    if (${CMAKE_BUILD_TYPE} STREQUAL Release)
        set(REMGLK_RS_LIB_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/remglk/target/wasm32-unknown-emscripten/release)
    else()
        set(REMGLK_RS_LIB_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/remglk/target/wasm32-unknown-emscripten/debug)
    endif()
    
    target_link_libraries(app_target ${REMGLK_RS_LIB_FOLDER}/libremglk_capi.a)
    

    Lastly, I needed to change the linker language to C++, as otherwise using panic!() seems to result in exception errors when the final app is only C, not C++. Depending on what features of Rust you use this may not be necessary.

    set_target_properties(app_target PROPERTIES LINKER_LANGUAGE CXX)