How to compile WABT wasm2c output from Bytecode Alliance Javy (including wasi_snapshot_preview1) to a standalone executable?

17 views
Skip to first unread message

guest271314

unread,
Dec 1, 2024, 12:06:17 PM12/1/24
to emscripten-discuss
I compiled JavaScript to Web Assembly using Bytecode Alliance's Javy. I then compiled the `.wasm` to C using WABT's `wasm2c`. Now I am trying to compile the resulting C to a standalone executable.

```
./javy emit-plugin -o plugin.wasm
./javy build -C dynamic -C plugin=plugin.wasm -o javy-permutations.wasm permutations.js
```

The code can be run using

```
wasmtime run --preload javy_quickjs_provider_v3=plugin.wasm javy-permutations.wasm
```
Compiling WASM to C

```
./wabt/bin/wasm2c javy-permutations.wasm -n array_nth_permutation -o javy-permutations.c
```

```
./wabt/bin/wasm2c plugin.wasm -n w2c_javy__quickjs__provider__v3 -o plugin.c
```

which writes `plugin.c` and `plugin.h` to the filesystem. The Javy implementation of WebAssembly toolchain.

I also, in my attempts to replicate a working JavaScript implementation of this using Node.js https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-nodejs.md, compiled `wasi_snapshot_preview1.reactor.wasm` to C using `wasm2c`. I have not been able to reproduce what I do using JavaScript in C.

I was able to achieve the result for the factorial example in `wasm2c` https://github.com/WebAssembly/wabt/blob/main/wasm2c/README.md#tutorial-wat---wasm---c.

There's no examples in `wasm2c` for compiling WASI to a standalone executable.

Here's one version of the working JavaScript version that I'm trying to reproduce in C

```
import { readFile } from "node:fs/promises";
import { WASI } from "node:wasi";

try {
  const [embeddedModule, pluginModule] = await Promise.all([
    compileModule("./javy-permutations.wasm"),
    compileModule("./plugin.wasm"),
  ]);
  const result = await runJavy(pluginModule, embeddedModule);
  // console.log("Success!", JSON.stringify(result, null, 2));
} catch (e) {
  console.log(e);
}

async function compileModule(wasmPath) {
  const bytes = await readFile(new URL(wasmPath, import.meta.url));
  return WebAssembly.compile(bytes);
}

async function runJavy(pluginModule, embeddedModule) {
  /*
  // Use stdin/stdout/stderr to communicate with Wasm instance
  // See https://k33g.hashnode.dev/wasi-communication-between-nodejs-and-wasm-modules-another-way-with-stdin-and-stdout
  */
  try {
    const wasi = new WASI({
      version: "preview1",
      args: [],
      env: {},
      returnOnExit: true,
    });

    const pluginInstance = await WebAssembly.instantiate(
      pluginModule,
      { "wasi_snapshot_preview1": wasi.wasiImport },
    );
    const instance = await WebAssembly.instantiate(
      embeddedModule,
      { "javy_quickjs_provider_v3": pluginInstance.exports },
    );
    console.log(pluginInstance.exports);
    // Javy plugin is a WASI reactor see https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md?plain=1
    wasi.initialize(pluginInstance);
    instance.exports._start();
    return "Done";
  } catch (e) {
    console.log(e);
    if (e instanceof WebAssembly.RuntimeError) {
      if (errorMessage) {
        throw new Error(errorMessage);
      }
    }
    throw e;
  } finally {
    // console.log("Finally");
  }
}

```


Here's `javy-permutations.h`

```
/* Automatically generated by wasm2c */
#ifndef JAVY_PERMUTATIONS_H_GENERATED_
#define JAVY_PERMUTATIONS_H_GENERATED_

#include "wasm-rt.h"

#include <stdint.h>

#ifndef WASM_RT_CORE_TYPES_DEFINED
#define WASM_RT_CORE_TYPES_DEFINED
typedef uint8_t u8;
typedef int8_t s8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
typedef float f32;
typedef double f64;
#endif

#ifdef __cplusplus
extern "C" {//
#endif

struct w2c_javy__quickjs__provider__v3;
extern wasm_rt_memory_t* w2c_javy__quickjs__provider__v3_memory(struct w2c_javy__quickjs__provider__v3*);

typedef struct w2c_array__nth__permutation {
  struct w2c_javy__quickjs__provider__v3* w2c_javy__quickjs__provider__v3_instance;
  /* import: 'javy_quickjs_provider_v3' 'memory' */
  wasm_rt_memory_t *w2c_javy__quickjs__provider__v3_memory;
  bool data_segment_dropped_w2c_array__nth__permutation_d0 : 1;
} w2c_array__nth__permutation;

void wasm2c_array__nth__permutation_instantiate(w2c_array__nth__permutation*, struct w2c_javy__quickjs__provider__v3*);
void wasm2c_array__nth__permutation_free(w2c_array__nth__permutation*);
wasm_rt_func_type_t wasm2c_array__nth__permutation_get_func_type(uint32_t param_count, uint32_t result_count, ...);

/* import: 'javy_quickjs_provider_v3' 'canonical_abi_realloc' */
u32 w2c_javy__quickjs__provider__v3_canonical_abi_realloc(struct w2c_javy__quickjs__provider__v3*, u32, u32, u32, u32);

/* import: 'javy_quickjs_provider_v3' 'invoke' */
void w2c_javy__quickjs__provider__v3_invoke(struct w2c_javy__quickjs__provider__v3*, u32, u32, u32, u32);

extern const u64 wasm2c_array__nth__permutation_min_javy__quickjs__provider__v3_memory;
extern const u64 wasm2c_array__nth__permutation_max_javy__quickjs__provider__v3_memory;
extern const u8 wasm2c_array__nth__permutation_is64_javy__quickjs__provider__v3_memory;

/* export: '_start' */
void w2c_array__nth__permutation_0x5Fstart(w2c_array__nth__permutation*);

#ifdef __cplusplus
}
#endif

#endif  /* JAVY_PERMUTATIONS_H_GENERATED_ */
```

Here's what I tried so far in `main.javy.c`

```
#include <stdio.h>
#include <stdlib.h>

#include "javy-permutations.h"
#include "plugin.h"

int main(int argc, char** argv) {
  /* Make sure there is at least one command-line argument. */
  if (argc < 2) {
    printf("Invalid argument. Expected '%s NUMBER'\n", argv[0]);
    return 1;
  }

  /* Convert the argument from a string to an int. We'll implicitly cast the int
  to a `u32`, which is what `fac` expects. */
  // u32 x = atoi(argv[1]);

  /* Initialize the Wasm runtime. */
  wasm_rt_init();

  /* Declare an instance of the `fac` module. */
  w2c_array__nth__permutation array__nth__permutation;

  w2c_javy__quickjs__provider__v3 provider;

  /* Construct the module instance. */
  wasm2c_array__nth__permutation_instantiate(&array__nth__permutation, &provider);

  /* Call `fac`, using the mangled name. */
  // u32 result = w2c_fac_fac(&fac, x);

  /* Print the result. */
  // printf("fac(%u) -> %u\n", x, result);
  w2c_array__nth__permutation_0x5Fstart(array__nth__permutation*)
  /* Free the fac module. */
  w2c_w2c__javy__0x5Fquickjs__0x5Fprovider__0x5Fv3_canonical_abi_free(w2c_w2c__javy__0x5Fquickjs__0x5Fprovider__0x5Fv3*, u32, u32, u32);

  /* Free the Wasm runtime state. */
  wasm_rt_free();

  return 0;
}
```


which throws errors when trying to compile

```
cc -o javy-permutations main.javy.c javy-permutations.c wasm2c/wasm-rt-impl.c wasm2c/wasm-rt-mem-impl.c -Iwasm2c -lm
main.javy.c: In function ‘main’:
main.javy.c:24:3: error: unknown type name ‘w2c_javy__quickjs__provider__v3’; use ‘struct’ keyword to refer to the type
   24 |   w2c_javy__quickjs__provider__v3 provider;
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   struct
main.javy.c:27:72: warning: passing argument 2 of ‘wasm2c_array__nth__permutation_instantiate’ from incompatible pointer type [-Wincompatible-pointer-types]
   27 | ray__nth__permutation_instantiate(&array__nth__permutation, &provider);
      |                                                             ^~~~~~~~~
      |                                                             |
      |                                                             int *

In file included from main.javy.c:4:
javy-permutations.h:37:79: note: expected ‘struct w2c_javy__quickjs__provider__v3 *’ but argument is of type ‘int *’
   37 | _nth__permutation_instantiate(w2c_array__nth__permutation*, struct w2c_javy__quickjs__provider__v3*);
      |                                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

main.javy.c:34:65: error: expected expression before ‘)’ token
   34 |   w2c_array__nth__permutation_0x5Fstart(array__nth__permutation*)
      |                                          
```

I suspect I need to initialize import `wasi_snapshot_preview` into the plugin in C, though I am not sure how to do that.

Alon Zakai

unread,
Dec 2, 2024, 6:25:12 PM12/2/24
to emscripte...@googlegroups.com
I am not sure how much WASI support wabt's wasm2c has, but it does show up in tests and examples:


Asking in a wabt issue might be the best place to find people that know those details.


--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/emscripten-discuss/66e87783-4f35-482d-a6ae-c538477abf2an%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages