Skip to content

Commit

Permalink
Add wasm overlay, put hello-world-wasm-web under ci. (#772)
Browse files Browse the repository at this point in the history
- Pull in ghc-wasm-meta flake
- Create builder (in the spirit of .jsexe) for wasm compiler
- Create hello-world-wasm-web, put under CI
- Add wasm overlay for our own purposes
- Pulls in the latest version of node
  • Loading branch information
dmjio authored Feb 21, 2025
1 parent 647e139 commit 3d631d0
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ jobs:
- name: (x86) Miso sample app jsaddle
run: nix-build -A sample-app-jsaddle

- name: (WASM) GHC-WASM web build (not miso)
run: nix-build -A hello-world-wasm-web

- name: Diffing tests
run: cd tests && yarn && yarn test

Expand Down
9 changes: 9 additions & 0 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ in
miso-examples-ghc = pkgs.haskell.packages.ghc865.miso-examples;
inherit (pkgs.haskell.packages.ghc865) sample-app-jsaddle;

#wasm
inherit (pkgs) ghc-wasm ghc-wasm-meta;
hello-world-wasm-web = with pkgs;
wasmWebBuilder
{ name = "hello-world";
title = "Hello world Example";
src = wasmHelloWorld;
};

#hackage releases
inherit release release-examples;

Expand Down
6 changes: 6 additions & 0 deletions examples/wasm-hello-world/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Main where

foreign export javascript "hs_start" main :: IO ()

main :: IO ()
main = putStrLn "hello world"
4 changes: 3 additions & 1 deletion nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ let
};
config.allowUnfree = options.allowUnfree;
config.allowBroken = options.allowBroken;
overlays = [ (import ./overlay.nix options) ] ++ options.overlays;
overlays = [ (import ./wasm)
(import ./overlay.nix options)
] ++ options.overlays;
in
import nixpkgs
{ inherit overlays config;
Expand Down
104 changes: 104 additions & 0 deletions nix/wasm/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
self: super:
{

ghc-wasm-meta =
(builtins.getFlake "gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org")
.outputs.packages."${super.system}";

wasm-cabal =
self.ghc-wasm-meta.wasm32-wasi-cabal-9_12;

wasm-ghc =
self.ghc-wasm-meta.wasm32-wasi-ghc-9_12;

wasmWebBuilder = args: with self;
# dmj: note, only works for single files (no cabal / hackage support)
super.stdenv.mkDerivation {
inherit (args) src name;
buildInputs = [ ghc-wasm-meta.all_9_12 ];
buildCommand = with args; ''
mkdir -p $out/${name}.jsexe/
wasm32-wasi-ghc \
-no-hs-main -optl-mexec-model=reactor "-optl-Wl,--export=hs_start" \
${src} -o ${name}.wasm
$(wasm32-wasi-ghc --print-libdir)/post-link.mjs \
--input ${name}.wasm \
--output ghc_wasm_jsffi.js
cp -v ghc_wasm_jsffi.js $out/${name}.jsexe/
mv -v ${name}.wasm $out/${name}.jsexe/
cat ${wasmIndexJs name} > $out/${name}.jsexe/index.js
cat ${wasmIndexHtml title name} > $out/${name}.jsexe/index.html
'';
};

# dmj: ghc-wasm-meta already provides
nodeLatest =
super.stdenv.mkDerivation rec {
name = "nodejs";
src = builtins.fetchTarball
"https://nodejs.org/dist/v22.14.0/node-v22.14.0-linux-x64.tar.xz";
installPhase = ''
mkdir $out
cp -r $src/bin $out
cp -r $src/include $out
cp -r $src/lib $out
cp -r $src/share $out
'';
};

wasmHelloWorld = super.writeTextFile {
name = "Main.hs";
text = builtins.readFile ../../examples/wasm-hello-world/Main.hs;
};

wasmIndexHtml = title: name:
super.writeTextFile {
name = "index.html";
text = ''<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${title}</title>
</head>
<body>
<script>globalThis.example = "${name}";</script>
<script src="index.js" type="module"></script>
</body>
</html>
'';
};

wasmIndexJs = name:
super.writeTextFile {
name = "index.js";
text =
''
import { WASI, OpenFile, File, ConsoleStdout } from "https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/dist/index.js";
import ghc_wasm_jsffi from "./ghc_wasm_jsffi.js";
const args = [];
const env = ["GHCRTS=-H64m"];
const fds = [
new OpenFile(new File([])), // stdin
ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ''${msg}`)),
ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ''${msg}`)),
];
const options = { debug: false };
const wasi = new WASI(args, env, fds, options);
const instance_exports = {};
const { instance } = await WebAssembly.instantiateStreaming(fetch("${name}.wasm"), {
wasi_snapshot_preview1: wasi.wasiImport,
ghc_wasm_jsffi: ghc_wasm_jsffi(instance_exports),
});
Object.assign(instance_exports, instance.exports);
wasi.initialize(instance);
await instance.exports.hs_start(globalThis.example);
'';
};
}

0 comments on commit 3d631d0

Please sign in to comment.