Skip to content

Instantly share code, notes, and snippets.

@bruxisma
Created April 22, 2019 21:14
Show Gist options
  • Save bruxisma/e0234741552d8ce3b42ab636936e1d05 to your computer and use it in GitHub Desktop.
Save bruxisma/e0234741552d8ce3b42ab636936e1d05 to your computer and use it in GitHub Desktop.
Minimal WASM C++ Test

Minimal WASM C++ Test

I spent a lot of hair tearing to figure out the minimal amount of work needed to get some C++ to output to HTML.

Simply clone this gist into a directory and everything should be good to go. You can run the build.sh file after a chmod +x, or just run the command manually. Anything goes, really.

This was written on April 22nd, 2019. Things are apparently changing enough that this might not be valid in the future. A lot of the work is handled by the wasm-ld tool, rather than by clang. It makes me wonder if something like CMake integration is even possible. That said, this code was run and tested on windows, in addition to linux and macOS. I used the 8.0 release of clang.

clang++ --target=wasm32 -Os .\test.cxx -nostdlib -o test.wasm -std=c++2a \
-Xlinker --entry=main \
-Xlinker --demangle \
-Xlinker --allow-undefined \
-Xlinker --initial-memory=16777216 \
-Xlinker --export=out \
-Xlinker --no-gc-sections \
-Xlinker --import-memory
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="module">
import {load} from './loader.js';
if (!('WebAssembly' in window)) {
console.error('WebAssembly not supported');
}
load('test.wasm').then(instance => {
const exports = instance.exports;
const main = exports.main;
main();
});
</script>
</head>
<body>
<div id="console"></div>
</body>
</html>
export function load (filename, imports) {
return fetch(filename)
.catch(reason => console.log(`Could not compile: ${reason}`))
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
let imports = {
env: {
__indirect_function_table: new WebAssembly.Table({
initial: 0,
element: 'anyfunc'
}),
memory: new WebAssembly.Memory({initial: 256}),
}
};
imports.env.out = function out (str, length) {
const bytes = new Uint8Array(imports.env.memory.buffer, str, length);
const string = new TextDecoder('utf-8').decode(bytes);
const content = document.createTextNode(string);
document.getElementById('console').appendChild(content);
};
return new WebAssembly.Instance(module, imports);
});
}
extern "C" void out (char const*, int len);
template <int N>
void print (char const (&str)[N]) {
out(str, N - 1);
}
void hello () {
print("Hello, World!");
}
int main () { hello(); }
@citUser88
Copy link

Great work! I'm going to see if it works on my Windows 10 PC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment