Boring
This is a simple function in c. Compiling it to wasm and calling it from javascript is surprisingly easy. No toolchain needed, if you already have clang.
int sum(int a, int b){ return a + b; }I won't bother explaining the linker and compiler flags, they are pretty self explanatory.
clang --target=wasm32 -nostdlib -Wl,--no-entry -Wl,--export-all -o add.wasm add.c
python -m http.server 8000This frustrated me so I decided to simply base64 encode the whole binary and embed it as a string. This took a bit of googling to get right but now the encoded wasm is decoded and loaded properly. The javascript is simple enough and it's pretty easy to understand how our c functon might be used just like any other javascript one.
// The base64 const wasmBase64 = "AGFzbQEAAAABCgJgAABgAn9/AX8DAwIAAQUDAQACBj8KfwFBgIgEC38AQYAIC38AQYAIC38AQYAIC38AQYCIBAt/AEGACAt/AEGAiAQLfwBBgIAIC38AQQALfwBBAQsHpwEMBm1lbW9yeQIAEV9fd2FzbV9jYWxsX2N0b3JzAAADc3VtAAEMX19kc29faGFuZGxlAwEKX19kYXRhX2VuZAMCC19fc3RhY2tfbG93AwMMX19zdGFja19oaWdoAwQNX19nbG9iYWxfYmFzZQMFC19faGVhcF9iYXNlAwYKX19oZWFwX2VuZAMHDV9fbWVtb3J5X2Jhc2UDCAxfX3RhYmxlX2Jhc2UDCQpCAgIACz0BBn8jgICAgAAhAkEQIQMgAiADayEEIAQgADYCDCAEIAE2AgggBCgCDCEFIAQoAgghBiAFIAZqIQcgBw8LAD8EbmFtZQAJCHN1bS53YXNtARkCABFfX3dhc21fY2FsbF9jdG9ycwEDc3VtBxIBAA9fX3N0YWNrX3BvaW50ZXIAJglwcm9kdWNlcnMBDHByb2Nlc3NlZC1ieQEFY2xhbmcGMTguMS44ACwPdGFyZ2V0X2ZlYXR1cmVzAisPbXV0YWJsZS1nbG9iYWxzKwhzaWduLWV4dA=="; const decodedWasm = atob(wasmBase64); const wasmBinary = new Uint8Array(decodedWasm.length); for (let i = 0; i < decodedWasm.length; i++) { wasmBinary[i]=decodedWasm.charCodeAt(i); // Instantiate the WebAssembly module const wasmModule=new WebAssembly.Module(wasmBinary); const wasmInstance=new WebAssembly.Instance(wasmModule); // Test the sum function, and alert the result alert(wasmInstance.exports.sum(1,2));
This code is a simple example from a c library I have compiled to wasm. The library in question can be found here and was chosen because of its lack of dependence on the stdlib. While probably intended for embeded systems, this also makes it convinient to compile to wasm without need for any dependencies or special runtime sillines. I found that:
clang -Wall example.c sha256.c -o example.execompiled things just fine on windows and I compiled sha256.c to wasm with:
clang --target=wasm32 -nostdlib -Wl,--no-entry -Wl,--export-all -o sha256.wasm sha256.c
#include "sha256.h" #includeAs you can see, example.c shows how we might call the sha256_hex function by passing in an array of bytes and their length, followed by a buffer which will contain the output.#include int main(void) { /* Input text. */ const char *text = "Hello, World!"; /* Char array to store the hexadecimal SHA-256 string. */ /* Must be 65 characters big (or larger). */ /* The last character will be the null-character. */ char hex[SHA256_HEX_SIZE]; /* Compute SHA-256 sum. */ sha256_hex(text, strlen(text), hex); /* Print result. */ printf("The SHA-256 sum of \"%s\" is:\n\n", text); printf("%s\n\n", hex); return 0; }
const text = document.getElementById('text').value; // get the input from the user const textenc = new TextEncoder().encode(text); // encode the text const textArray = new Uint8Array(memory.buffer, 0, textenc.length); // create a new Uint8Array for the encoded user input within the wasm memory buffer textArray.set(textenc); // this is the output array which will store the sha256 hash const array = new Uint8Array(memory.buffer, textenc.length, 65); sha256_hex(textArray.byteOffset, textArray.length, array.byteOffset); alert(new TextDecoder('utf8').decode(array)); // decode the output array and alert the result, if all went correctly, we should have the sha256 hash of the input!
Since a simple webserver won't serve wasm files with the correct mime type, and for some stupid reason, it wont work otherwise here's one that will. Just pop the script in the directory containing your wasm/html files are and it should serve them with the correct type, meaning you can access everything on http://127.0.0.1:8000/
import http.server import socketserver PORT = 8000 Handler = http.server.SimpleHTTPRequestHandler Handler.extensions_map.update({ '.wasm': 'application/wasm', }) socketserver.TCPServer.allow_reuse_address = True with socketserver.TCPServer(("", PORT), Handler) as httpd: httpd.allow_reuse_address = True print("serving at port", PORT) httpd.serve_forever()
Well, for now anyways. I've got some more stupid things to try when I have the free time.