How to export C function in Emscripten when using CMake

3.6k Views Asked by At

In this tutorial it shows the following example for exporting C functions

./emcc tests/hello_function.cpp -o function.html -s EXPORTED_FUNCTIONS='["_int_sqrt"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'

I would like to do the same except that I use CMake like this

cd bin
emcmake cmake ../src
emmake make

What is the canonical way of specifying -s in emmake? Should I add it to CMakeLists.txt like

set(EXPORTED_FUNCTIONS '["_int_sqrt"]')

or do something similar?

3

There are 3 best solutions below

1
On BEST ANSWER

What I figured out so far is that it can be achieved CMake with the following settings

# Here you can add -s flag during compiling object files
add_definitions("-s EXPORTED_RUNTIME_METHODS='[\"ccall\",\"cwrap\"]'")
add_definitions("-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\",\"cwrap\"]'")
add_definitions("-s EXPORTED_FUNCTIONS='[\"_testInt\"]'")
# Here you can add -s flag during linking
set_target_properties(web_mealy_compiler PROPERTIES LINK_FLAGS "-s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap']")
# Set this if you want to to generate sample html file
set(CMAKE_EXECUTABLE_SUFFIX ".html")

Then you should be able to call C functions from javascript as follows:

<script type="text/javascript">
     
    Module['onRuntimeInitialized'] = function() {
     
        console.log("wasm loaded ");
        
        console.log(Module.ccall); // make sure it's not undefined
        console.log(Module._testInt); // make sure it's not undefined
        console.log(Module._testInt()); // this should work
        console.log( Module.ccall('testInt', // name of C function
            'number', // return type
             [], // argument types
             []) // argument values
        );
    }
</script>

And this is my definition of C function:

#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int testInt(){
    return 69420;
}
0
On

I just ran into exactly the same issue and even started one on the Emscripten github page (see here).

What worked for me was to put all the Emscripten specific flags into one long string which I then added with target_compile_options and target_link_options.

  set(EMS
      "SHELL:-s EXPORTED_FUNCTIONS=['_main','_malloc','_int_sqrt'] -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap']"
  )
  target_compile_options(EmscriptenExample PRIVATE ${EMS})
  target_link_options(EmscriptenExample PRIVATE ${EMS})

It's important to drop both, double quotes and whitespaces from the list of functions otherwise it won't work. At least with CMake 3.17.3 escaping the double quotes did not work for me.

/edit For the sake of completeness: Emscripten now allows to remove the whitespace between the -s prefix and the actual flag. This makes it possible to actually use CMake's own target_*_options functions, e.g.:

target_link_options(target PRIVATE -sEXPORTED_FUNCTIONS=['_main','_foo','_bar'])
0
On

This is the simplest/cleanest way now:

target_link_options(target PRIVATE
        -sEXPORTED_FUNCTIONS=['_main','_foo','_bar'])

And if you have more -s settings (and you probably will) you can add them within this function call, or you can call target_link_options multiple times, both work. It seems quite accommodating, I haven't needed to escape anything.