Skip to content

Instantly share code, notes, and snippets.

@sortofsleepy
Last active February 28, 2024 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sortofsleepy/603e70468f0b33c56e220df698451ce6 to your computer and use it in GitHub Desktop.
Save sortofsleepy/603e70468f0b33c56e220df698451ce6 to your computer and use it in GitHub Desktop.
Odin language simple WebAsembly setup
(async function(){
// will hold callbacks we can call from Odin.
const env = {
// this is required given how Odin is structured.
// you may have to add additional functions depending on Odin structures used; for example you'll need to add
// implementations of things like sine and cosine functions.
// (should throw an error in the console if something is missing, just add the function/property mentioned)
odin_env:{
write(){},
cos:Math.cos
},
// this is a foreign interface that can be refernced in Odin
dom_interface:{
getWindowWidth(){
return window.innerWidth
}
}
}
// load module
// TODO maybe shift to `await` to make it simpler.
WebAssembly.instantiateStreaming(fetch("./odin.wasm"),env)
.then(results => {
let instance = results.instance;
let funcs = instance.exports;
// call the setup function in main.odin
console.log(funcs.setup());
}).catch(e => {
console.error(e);
})
})()// end async
package main
import "core:fmt"
// These are functions from the JS side you may want to interface with.
// "dom_interface" is essentially a namespace for these functions in this instance.
foreign import "dom_interface"
foreign dom_interface {
getWindowWidth :: proc "contextless" () -> int ---
// you can pass values to the JS side too.
log :: proc "contextless" (val: string) ---
// you can pass arrays/slices as well
// Not sure if it should be an pointer instead like in Zig but this seems to work - make sure to translate on
// the JS side as you'll get a memory address and not your actual array(TypedArray constructors can take a memory object + address + length
// which should give you the values in the slice)
arrayTest :: proc "contextless" (val:[]f32) ---
}
// there is a flag to forgo use of a main proc so this might not be needed, have not tested.
main :: proc(){}
// This is a function that gets sent to JS side
@export
setup :: proc() -> int{
return getWindowWidth();
}

Have some free time on my hands so I thought I'd try out Odin, an interesting language I came across a few weeks ago. I haven't dived too far into it but so far from what I understand, it's another language in a similar vain of Rust and Zig(both also very good)

Since as far as I can tell, though Odin does support WebAssembly, how specifically to build for it is not well documented so I thought I should post a very basic setup for WebAssembly.

All the Odin app does is

  • export a function that called setup that calls an imported JS function getWindowWidth
  • In the JS, it calls setup and logs the result.

When building the Odin code, the command is roughly odin build <app location> -target="js_wasm32" -out="<output location>"

If you add custom packages, don't forget to add the -collection flag to the command.

Note there are multiple flavors of Wasm you can build for but js_wasm32 is likely gonna be what you want if you intend to interface with JS. At the time of this writing(2/13/2024), the targets include

  • freestanding_wasm32
  • wasi_wasm32
  • js_wasm32
  • freestanding_wasm64p32
  • js_wasm64p32
  • wasi_wasm64p32

There's still a lot I don't understand of course, especially how the foreign keyword works in this context so take this with a grain of salt.

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