Wasi_snapshot_preview1 equivalent?

Greetings folks,

Perhaps you have seen my earlier post here about getting rails running on ICP.

Well according to the output of wasi2ic, the first set of imports I need to replace all come from a single component called wasi_snapshot_preview1 which can be found here

Would I be lucky enough to learn that IC has an equivalent module (complete or under development) that also provides these target specific low-level filesystem, etc calls?

Here is a list of functions that it provides.

Module imports:
import “wasi_snapshot_preview1” “args_get”
import “wasi_snapshot_preview1” “args_sizes_get”
import “wasi_snapshot_preview1” “environ_get”
import “wasi_snapshot_preview1” “environ_sizes_get”
import “wasi_snapshot_preview1” “clock_res_get”
import “wasi_snapshot_preview1” “clock_time_get”
import “wasi_snapshot_preview1” “fd_advise”
import “wasi_snapshot_preview1” “fd_close”
import “wasi_snapshot_preview1” “fd_datasync”
import “wasi_snapshot_preview1” “fd_fdstat_get”
import “wasi_snapshot_preview1” “fd_fdstat_set_flags”
import “wasi_snapshot_preview1” “fd_filestat_get”
import “wasi_snapshot_preview1” “fd_filestat_set_size”
import “wasi_snapshot_preview1” “fd_pread”
import “wasi_snapshot_preview1” “fd_prestat_get”
import “wasi_snapshot_preview1” “fd_prestat_dir_name”
import “wasi_snapshot_preview1” “fd_pwrite”
import “wasi_snapshot_preview1” “fd_read”
import “wasi_snapshot_preview1” “fd_readdir”
import “wasi_snapshot_preview1” “fd_renumber”
import “wasi_snapshot_preview1” “fd_seek”
import “wasi_snapshot_preview1” “fd_sync”
import “wasi_snapshot_preview1” “fd_tell”
import “wasi_snapshot_preview1” “fd_write”
import “wasi_snapshot_preview1” “path_create_directory”
import “wasi_snapshot_preview1” “path_filestat_get”
import “wasi_snapshot_preview1” “path_filestat_set_times”
import “wasi_snapshot_preview1” “path_link”
import “wasi_snapshot_preview1” “path_open”
import “wasi_snapshot_preview1” “path_readlink”
import “wasi_snapshot_preview1” “path_remove_directory”
import “wasi_snapshot_preview1” “path_rename”
import “wasi_snapshot_preview1” “path_symlink”
import “wasi_snapshot_preview1” “path_unlink_file”
import “wasi_snapshot_preview1” “poll_oneoff”
import “wasi_snapshot_preview1” “proc_exit”
import “wasi_snapshot_preview1” “random_get”
Error: There are imports remaining that are not compatible with the Internet Computer.

Cheers

As I mentioned in the other thread, the IC does not natively support these system calls. However, there is a community project that translates some of these to syscalls that the IC does support:

You can see there which syscalls are supported. If your program needs to make syscalls that are unsupported (like socket stuff), it won’t run on the IC. But if you can avoid them, there is a good chance you can make this work.

You might have to compile this Rust library to an object file (.so) and link it with your binary.

Also if you keep the topic in a single thread it will be easier for me to see your questions.

This might be interesting to you: Bytecode Alliance — Making JavaScript run fast on WebAssembly

Hey mate,

Thanks for the feedback, I’ll be away from this project for another week or two. But will be picking it up again.

I’ll make sure to pass a link if I start a new thread. I normally do that If I clear a major step and am into new territory with my question.

Cheers

Greetings @michael-weigelt

I’m having a go at this now https://github.com/wasm-forge/ic-wasi-polyfill

If i try:

cargo build -p ic-wasi-polyfill --target wasm32-wasip1 --release

i end up with these artifacts

  • ibic_wasi_polyfill.a
  • libic_wasi_polyfill.rlib
  • libic_wasi_polyfill.d

The drop-in replacement for wasi_snapshot_preview1 is a .wasm module.

I was able to generate a wasm module by adding “cdylib” to [lib] crate-type. Does that make sense for your codebase?

Cheers

These are two separate wasm

So I guess it’s not a static library like what your module builds.

I’ve opened an issue to ask how they generated them. I don’t see anything about a command/reactor separation in other docs about snapshot_preview

https://github.com/ruby/ruby.wasm/tree/main/lib/ruby_wasm/packager/component_adapter

Looks like it comes from here, I’ll see if I can mess you your lib to get it to also generate command and reactor wasms

https://github.com/bytecodealliance/wasmtime/blob/main/crates/wasi-preview1-component-adapter/Cargo.toml

You need these files for the next step: When you compile your Ruby code, there should be a linking phase. These files (or just one of them) need to be passed as an argument there. What tool are you using to compile Ruby to Wasm? Hopefully you can follow the docs to find the right argument…

The result should be a .wasm file with the polyfill library included.

The component-adapter is related to the component model and therefore wasip2. But I would not target that now, because ic-wasi-polyfill targets wasip1. So this seems irrelevant here and now.

Edit: Actually, it depends on how ruby.wasm is built. Not sure.

Reading https://github.com/ruby/ruby.wasm/blob/main/README.md it seems to me like you don’t have to compile your app to Wasm. Instead, the linked project has already compiled the Ruby runtime to Wasm. I think they expect the users to “pack” their Ruby app into the pre-built runtime Wasm (probably by writing the user app to a custom section in the Wasm binary) and then deploy that pre-built, edited Wasm artifact on their host (browser, Wasmtime, or in our case, the IC).

The problem is that the pre-built Wasm is compiled to a target we do not support, wasm32-unknown-wasip1. So what you should try to make this all work is to figure out how to build that ruby.wasm yourself. If you can do that, you can build this artifact with the polyfill library object files (you listed them above) linked in, and then follow the steps as normally.

Does that make sense?

I was targeting here under the hope that I could apply the polyfills at the snapshot level, sort of stub out the system calls with what IC responds to.

Perhaps that was naive because I was just chasing the function names shown in the error haha.

Agree, you may recall of my original posts, I was suggesting that y’all might want to define a target triplet to facilitate this kind of conversation. Something like wasm32-unknown-icp

I did find the spot in the code where I can fork and customize this. Also read up a bit on FFI like you mentioned. I’ll dig deeper into the code generating the pre-builts now.

Cheers

@michael-weigelt

I’ve created an ICP handler.

https://github.com/graial/ruby.wasm/blob/80153aa2f6df7b73d81e3e28387db5d251d91025/lib/ruby_wasm/build/toolchain.rb#L291

Is emcc a viable toolchain for compiling to ICP?

It compiles successfully if I:

  • pass --host wasm32
  • remove this from LDFLAGS -Xlinker\ stack-size=16777216

Alternatively, I could try to adapt the wasi handler (starting at line 62). But I rememer you said wasi isn’t supported, so I suspect i gain nothing from the extra complexity that one contains

Cheers