Skip to content

[Feature] Support WASI via --platform option #36

Description

@katsujukou

[Feature] Support WASI via --platform option (#36)

Summary

Add wasi as a fourth value for --platform, producing a self-contained wasm that runs
directly under a WASI runtime (wasmtime run index.wasm, Node's --experimental-wasi, edge
runtimes, …) with no JavaScript loader. Together with -E/--executable, the emitted module
runs the entry module's main on start, so a PureScript program becomes a standalone wasm
executable.

Today --platform accepts node | browser | standalone (and -E is wired for node/browser
only — it errors on standalone). wasi is the intended home for "make a runnable wasm that
calls main itself, without JS".

Motivation

  • Run PureScript-compiled wasm without a JS host — CLI tools, serverless/edge (WASI),
    containers (wasmtime/wasmer), and embedding in non-JS hosts.
  • standalone is a library artifact (exports only, no run mechanism); wasi is the
    executable counterpart. This is why standalone + -E is an error and wasi + -E is the
    way to get a self-running command.
  • The -E machinery (main :: Effect Unit, the run-on-load semantics) and the
    main(cliRoot)(binaryenBinDir) build wiring already exist; this extends them to a wasm-native
    entry point.

Design sketch

  • --platform=wasi — a single self-contained wasm targeting the WASI ABI
    (wasi_snapshot_preview1 to start). Like standalone, every foreign import must be provided
    in wasm (no JS loader to fall back to) — see the foreign/IO question below.
  • -E under wasi — instead of a JS loader calling main, emit a _start export (the
    WASI command convention wasmtime invokes) whose body performs main and proc_exit(0).
    main stays restricted to main :: Effect Unit for now (same validation as node/browser -E).
  • wasi without -E — a reactor-style module that exports its values but does not auto-run
    (or: wasi implies -E; to be decided).

Open questions

  1. Foreign / IO story (the crux). With no JS loader, host effects have no provider. Two
    options, not mutually exclusive:
    • Strict: require every foreign to be wasm-provided (like standalone). Pure effects
      (Effect.Ref, arithmetic) run; console.log does not (no stdout) unless wasm-provided.
    • WASI provider layer: map common effects to WASI syscalls — most importantly
      Effect.Console.log → fd_write on stdout (fd 1) — so a real "hello world" prints under
      wasmtime. Likely needed for wasi to be useful.
  2. WASI version — preview1 (broadly supported: wasmtime, Node, browser polyfills) first;
    preview2 / the component model later?
  3. _start export vs the wasm start section — _start matches the WASI command
    convention runtimes invoke; the start section runs at instantiation (reactor-ish). Pick per
    the executable vs reactor distinction.
  4. CLI args / env / exit code — main :: Array String -> Effect Unit via args_get /
    args_sizes_get, environ_*, and a non-zero proc_exit on failure are natural follow-ups
    (depends on closing closure-direction-2 / argv marshalling).

Tasks

  • Add Wasi to the Platform ADT + --platform parser (PursWasm.CLI.Options*).
  • Build/codegen: emit the WASI entry (_start performing main) for --platform=wasi -E;
    keep the main :: Effect Unit validation.
  • Foreign resolution under wasi (strict all-wasm, or a minimal WASI provider — at least
    fd_write for stdout so console.log works).
  • e2e: build a fixture with --platform=wasi -E, run it under wasmtime, assert stdout.
  • Docs: --platform table in Overview, and the wasi notes in Performance and Limitations.

Related

  • -E/--executable (node/browser) and the --platform design — ADR 0025, ADR 0011.
  • Deferred from v0.1 (the build-options work landed node/browser/standalone + -E).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions