tinygo-org / tinygo

Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM.
https://tinygo.org
Other
15.4k stars 909 forks source link

Wasi target command flag vs environment variables #4439

Open mattjohnsonpint opened 2 months ago

mattjohnsonpint commented 2 months ago

My understanding is that setting GOOS=wasip1 GOARCH=wasm should produce identical output as passing the -target wasi command line flag, but it doesn't. Rather, it seem to match -target wasm.

Repro:

package main

func main() {
    println("Hello, World!")
}

You'll need wasm2wat from The WebAssembly Binary Toolkit.

Then:

Open each wat file in a text editor. Imports are near the top, exports are near the bottom.

test1.wat

...
(import "wasi_snapshot_preview1" "fd_write" (func $runtime.fd_write (type 4)))
(import "wasi_snapshot_preview1" "poll_oneoff" (func $runtime.poll_oneoff (type 4)))
(import "wasi_snapshot_preview1" "clock_time_get" (func $runtime.clock_time_get (type 16)))
...
(export "memory" (memory 0))
(export "malloc" (func $malloc))
(export "free" (func $free))
(export "calloc" (func $calloc))
(export "realloc" (func $realloc))
(export "_start" (func $_start))
(export "asyncify_start_unwind" (func 168))
(export "asyncify_stop_unwind" (func 169))
(export "asyncify_start_rewind" (func 170))
(export "asyncify_stop_rewind" (func 171))
(export "asyncify_get_state" (func 172))
...

test2.wat / test3.wat

...
(import "gojs" "runtime.ticks" (func $runtime.ticks (type 15)))
(import "gojs" "runtime.sleepTicks" (func $runtime.sleepTicks (type 16)))
(import "wasi_snapshot_preview1" "fd_write" (func $runtime.fd_write (type 4)))
...
(export "memory" (memory 0))
(export "malloc" (func $malloc.command_export))
(export "free" (func $free.command_export))
(export "calloc" (func $calloc.command_export))
(export "realloc" (func $realloc.command_export))
(export "_start" (func $_start.command_export))
(export "resume" (func $resume.command_export))
(export "go_scheduler" (func $go_scheduler.command_export))
(export "asyncify_start_unwind" (func 175))
(export "asyncify_stop_unwind" (func 176))
(export "asyncify_start_rewind" (func 177))
(export "asyncify_stop_rewind" (func 178))
(export "asyncify_get_state" (func 179))
...

They should be identical, but test3 is importing from gojs, and is also exporting go_scheduler. It's identical to test2, whereas I would expect it to match test1.

dgryski commented 2 months ago

I think this will probably be solved by https://github.com/tinygo-org/tinygo/pull/4437

/cc @aykevl

aykevl commented 2 months ago

The problem here is the file extension, which apparently overrides the environment variables. That's a bug.

https://github.com/tinygo-org/tinygo/blob/ef4f46f1d1550beb62324d750c496b2b4a7f76d0/main.go#L1569-L1571

Maybe we should just remove this special case? It means that people that currently rely on the extension will have to provide some explicit flags or environment variables, but it's certainly more explicit and less "magic". (I think it was originally introduced when wasm was mostly a browser thing and WASI didn't really exist yet).