C to Wasm for Lazy People
export C functions to WebAssembly for lazy people
2021-06-24
- I suspect you've already have Emscripten (https://emscripten.org/) installed.
- Make sure, you've included the proper paths, so you can issue
emccfrom command line. If not sure, visit Emscripten's documentation and see how it's done. (tip:source emsdk_env.shon your Emscripten installation folder - I assume you use bash). - OK. First, create C file. Name it with something unique, like
demo.c
demo.c source
double divide_numbers(double a, double b) {
return a / b;
}
double multiply_numbers(double a, double b) {
return a * b;
}
int main(int argc, char** argv) {
return -1;
}
- Now you need to compile it using Emscripten's magic:
emcc demo.c -o "myfuncs.js" -s EXPORTED_FUNCTIONS='["_multiply_numbers", "_divide_numbers"]' -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]' -s MODULARIZE=1 -s 'EXPORT_NAME="moduleFactory"'. Let's elaborate a bit on this. This code creates two files namedmyfuncs.jsandmyfuncs.wasm. The actual WebAssembly code is inside thewasmfile (oh really?). The Javascript file does the dirty work of loading the WebAssembly code and giving us the tools to export our functionsdivide_numbersandmultiply_numberson our code. Be careful to add a_prefix on theEXPORTED_FUNCTIONSarray. Moreover, don't forget to instructemccto modularize the output using-s MODULARIZE=1 -s 'EXPORT_NAME="moduleFactory"option to output a factory method namedmoduleFactory. We'll see how this factory works on the next step. - Let's create an HTML page that'll demonstrate our first exploration in WebAssembly. I name it
demo.html.
demo.html source
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<script type="text/javascript" src="myfuncs.js"></script>
<script>
// initialize Emscripten stack and then move on :-)
moduleFactory().then(function(Module){
var multiplyNumbers = Module.cwrap('multiply_numbers','number',['number','number']);
window.alert('3*4=' + multiplyNumbers(3,4));
var divideNumbers = Module.cwrap('divide_numbers','number',['number','number']);
window.alert('3/4=' + divideNumbers(3,4));
})
</script>
</body>
</html>
- So as you may infer from the code above, the
moduleFactorymodule factory is loaded when we include themyfuncs.jsEmscripten interfacing file. Next, we handlemoduleFactory's promise which returns aModuleobject containing two methods namedcwrapandccallwhich do the dirty work of exposing our exported functions or running them directly, respectively. I usecwrapas I think its style is a bit cleaner, according to my taste. In short the syntax isvar myFunctionName = Module.cwrap('function_name_without_dash', 'output_type', ['argument_types']). In our case, we export a function namedmultiply_numberswhich returns anumber(it's JS no number types, don't forget), takes as input two arguments of typenumber, and assign it into themultiplyNumbersfunction. - Now you think we're done. Forget it. Modern browsers will complain if you try to access
demo.htmlusingfile://protocol (yeap it's CORS). You need to serve it madame/sir! So Python comes to the rescue. Just issuepython3 -m http.serveror for Python2python -m SimpleHTTPServerand point tohttp://localhost:8000/demo.htmland have fun. I assume you issued those commands on the same directory containingdemo.html,myfuncs.jsandmyfuncs.wasm. - Enjoy!
Crafted with ❤ in Crete. © 2022-2024