LinkError: WebAssembly.instantiate(): Import #16 "wasi_snapshot_preview1" "fd_prestat_get": function import requires a callable
I am implementing a simple wrapper of cel-go that can run in browser. First I was using go, which worked just fine in terms of logic. However as soon as I moved from go to tinygo in order to optimise the file size of wasm. I ran into this issue that I do not understand
LinkError: WebAssembly.instantiate(): Import #16 "wasi_snapshot_preview1" "fd_prestat_get": function import requires a callable
An example reproducible function for v0.39.0
import (
celgo "github.com/google/cel-go/cel"
)
func CanRun(expression string) bool {
// Create a basic CEL environment for syntax checking
env, err := celgo.NewEnv()
if err != nil {
return false
}
// Try to parse and check the expression
_, issues := env.Parse(expression)
if issues != nil && issues.Err() != nil {
return false // Invalid syntax, but not an internal error
}
return true
}
I would like to know is this a problem with tinygo, a limitation or is there something missing in worker_exec.js . Is there any workaround?
What is the command you used to compile this code?
tinygo build -o main.wasm -target wasm ./cmd/wasm/main.go
Huh, interesting. We don't call this function in TinyGo itself, but we do support CGo and use wasi-libc as a C library. My guess is that this dependency uses CGo somewhere which then requires that import.
Not sure whether this is something we need to fix in TinyGo, or whether the answer is "don't use CGo".
Hi, we just ran into this. Is there a way I can avoid using CGo (if I don't control the third-party code) given https://github.com/tinygo-org/tinygo/pull/4136?
I tried changing this line in the TinyGo source to set CGO_ENABLED=0 but I still get the same fd_prestat_get error when I instantiate the compiled module. Is there something else I would need to do to work around the issue?
I was just playing around with this, and I think that the problem is that the package you are trying to compile to WASM has calls that it makes that bring in functions that end up trying to connect to WASI interfaces.
As a result, even though you are using -target=wasm, since we are using wasi-libc you are running into something like this: https://github.com/WebAssembly/wasi-libc/issues/248
I tried making a non-operative polyfill, but was able to load the WASM module. The module of course did not actually work, since it probably needs some of those features to operate.
So I am not sure this is something that is possible to get to work in every case at least without some kind of functioning browser polyfill.
This was my non-functioning one just to get the module to load:
const wasi_snapshot_preview1_emulator = {
fd_pread: input => {
return 0;
},
fd_write: input => {
return 0;
},
fd_close: input => {
return 0;
},
fd_fdstat_get: input => {
return 0;
},
fd_prestat_get: input => {
return 0;
},
fd_prestat_dir_name: input => {
return 0;
},
fd_read: input => {
return 0;
},
fd_seek: input => {
return 0;
},
path_open: input => {
return 0;
},
random_get: input => {
return 0;
},
proc_exit: input => {
return 0;
},
}
Thanks, yeah, I tried something similar with our module and got past the missing import errors, but now it seems to hang on WebAssembly.instantiate 🤔
What would be the best way to try to figure out which functions in my Go program use these WASI interfaces?
One thing you can try is to put throw "called fd_prestat_get"; in the fd_prestat_get implementation to get a backtrace.