Stream: beginners

Topic: Golang plattform using webassembly


view this post on Zulip Oskar Hahn (Jun 18 2023 at 15:50):

I would like to use roc with a go platform.

I read this comment, that it is probably not possible to use go as a platform directly: https://roc.zulipchat.com/#narrow/stream/231634-beginners/topic/webserver.20platform/near/296018502

But there is a webassembly runtime written in go: https://wazero.io/

It was easy to create a wasm-file from the plattform-switching example. To make it a bit more interesting, I used this roc program: https://github.com/lukewilliamboswell/roc-things/blob/main/aoc-2022/12/main.roc

I just changed it, so main returns a string instead of a task, so it was compatible with the web-assembly-platform.

Then I run the wasm-file with this go program: https://gist.github.com/ostcar/17c7cc0257734128a4b29c060d09887f

This works, but it is much slower then a native build. When I run the code with the c-platform, i takes around one minute. With the go-wasm platform, it takes around three minutes.

But I don't now how to go further.

I would like to change the web-assembly-platform, so the main function has the signature "Str -> Str". I have no idea how to do this.

I am also very excited about this idea about wasm without a host: https://roc.zulipchat.com/#narrow/stream/304902-show-and-tell/topic/wasm.20without.20a.20host

Is it currently even possible to build a wasm file without zig?

view this post on Zulip Brendan Hansknecht (Jun 18 2023 at 17:20):

I think our wasm is currently tied to zig. Something we definitely need to change in the future.

view this post on Zulip Oskar Hahn (Jun 18 2023 at 18:46):

When I build roc from source, it works. But If a use a nightly build, I get an error, that wasi-libc.a can not be found

🔨 Rebuilding platform...
An internal compiler expectation was broken.
This is definitely a compiler bug.
Please file an issue here: https://github.com/roc-lang/roc/issues/new/choose
thread 'main' panicked at 'cannot find `wasi-libc.a`', crates/compiler/build/src/link.rs:126:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Do I have to copy the wasi-libc.a file somewhere? Or is the nightly build different from the source build?

view this post on Zulip Brian Carroll (Jun 19 2023 at 07:21):

Thanks, I think you've found a bug in the nightly build!
When we build the compiler from source, wasi-libc.a is created somewhere inside Cargo's target directory, and we set an environment variable equal to that path. The path is then compiled into some of the other crates in the compiler. (There's also a second file called compiler-rt.o.)
Later when we run the compiler with --target=wasm32, it will try to find those files to link them with the user's Roc code.
My guess is that our nightly build does not copy wasi-libc.a and compiler-rt.o into the bundle.
So basically right now Wasm targets won't work with nightly builds... unless you happen to have these files at the exact same directory paths as the machine where the nightly build was run!

view this post on Zulip Brian Carroll (Jun 19 2023 at 07:23):

However this is solvable and we have solved it in other places. For example we have object files for builtin functions that we also link with user code. So maybe there's a similar approach we can take in this case.

view this post on Zulip Anton (Jun 19 2023 at 09:26):

I've made issue #5573 for this

view this post on Zulip Oskar Hahn (Jun 19 2023 at 14:28):

Thank you. This will make it easier.

After a lot of try and error I succeeded to build a wasm file with the main signature main : Str -> Str

The zig function signature is:

extern fn roc__mainForHost_1_exposed(*RocStr, *RocStr) void;

But the first *RocStr is the return value and the second is the first argument. I had guest it the other way around.

The zig function to call it can look like this:

export fn run_roc() void {
    var callresult = RocStr.empty();
    roc__mainForHost_1_exposed(&callresult, &RocStr.init("foobar\n",7));
    print_roc_string(callresult.asU8ptrMut(), callresult.len());
    callresult.decref();
}

A strange thing was, that the roc mainForHost function had to be

mainForHost = \s -> main s

I would have guest, that

mainForHost = main

should also work, but it gets defined in wasm as () -> void

Another thing is, that the zig-cache folder has to be removed before building. In other case, the wasm file does not contain the zig-function.

view this post on Zulip Oskar Hahn (Jun 20 2023 at 16:26):

Oskar Hahn said:

Another thing is, that the zig-cache folder has to be removed before building. In other case, the wasm file does not contain the zig-function.

Ahh, this is a bug in zig 0.9.1 that was fixed in zig 0.10: https://github.com/ziglang/zig/issues/12864


Last updated: Jul 05 2025 at 12:14 UTC