{"id":21075073,"url":"https://github.com/hackworthltd/ghc-wasm-meta","last_synced_at":"2025-07-30T01:33:26.652Z","repository":{"id":243752969,"uuid":"813340520","full_name":"hackworthltd/ghc-wasm-meta","owner":"hackworthltd","description":"A temporary fork of `ghc-wasm-meta`","archived":false,"fork":false,"pushed_at":"2024-07-16T22:11:39.000Z","size":196,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-27T15:08:00.994Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hackworthltd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-06-10T22:34:47.000Z","updated_at":"2024-06-10T22:35:59.000Z","dependencies_parsed_at":"2025-06-16T02:08:01.398Z","dependency_job_id":"403aed2c-c777-42b8-aac7-1f03a26def70","html_url":"https://github.com/hackworthltd/ghc-wasm-meta","commit_stats":null,"previous_names":["hackworthltd/ghc-wasm-meta"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hackworthltd/ghc-wasm-meta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackworthltd%2Fghc-wasm-meta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackworthltd%2Fghc-wasm-meta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackworthltd%2Fghc-wasm-meta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackworthltd%2Fghc-wasm-meta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hackworthltd","download_url":"https://codeload.github.com/hackworthltd/ghc-wasm-meta/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackworthltd%2Fghc-wasm-meta/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267792658,"owners_count":24144929,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T19:19:27.513Z","updated_at":"2025-07-30T01:33:26.539Z","avatar_url":"https://github.com/hackworthltd.png","language":"Nix","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `ghc-wasm-meta`\n\n[![Chat on Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#haskell-wasm:matrix.terrorjack.com)\n\nThis repo provides convenient methods of using binary artifacts of\nGHC's wasm backend. It's also a staging area for the GHC wasm backend\ndocumentation.\n\n## Getting started as a nix flake\n\nThis repo is a nix flake. The default output is a derivation that\nbundles all provided tools:\n\n```sh\n$ nix shell https://gitlab.haskell.org/ghc/ghc-wasm-meta/-/archive/master/ghc-wasm-meta-master.tar.gz\n$ echo 'main = putStrLn \"hello world\"' \u003e hello.hs\n$ wasm32-wasi-ghc hello.hs -o hello.wasm\n[1 of 2] Compiling Main             ( hello.hs, hello.o )\n[2 of 2] Linking hello.wasm\n$ wasmtime ./hello.wasm\nhello world\n```\n\nFirst start will download a bunch of stuff, but won't take too long\nsince it just patches the binaries and performs no compilation. There\nis no need to set up a binary cache.\n\nNote that there are different GHC flavours available. The default\nflake output uses the `gmp` flavour, though you can also use the\n`all_native`, `all_unreg` and `all_9_6` flake outputs to get different\nflavours. See the next subsection for explanations of these flavours.\n\n## Getting started without nix\n\nThis repo also provides an installation script that installs the\nprovided tools to `~/.ghc-wasm`:\n\n```sh\n$ curl https://gitlab.haskell.org/ghc/ghc-wasm-meta/-/raw/master/bootstrap.sh | sh\n...\nEverything set up in /home/username/.ghc-wasm.\nRun 'source /home/username/.ghc-wasm/env' to add tools to your PATH.\n```\n\nAfter installing, `~/.ghc-wasm` will contain all the installed tools,\nplus:\n\n  - `~/.ghc-wasm/env` which can be sourced into the current shell to\n    add the tools to `PATH`, plus all the environment variables needed\n    to build `wasm32-wasi-ghc`\n  - `~/.ghc-wasm/add_to_github_path.sh` which can be run in GitHub\n    actions, so later steps in the same job can access the same\n    environment variables set by `env`\n\n`bootstrap.sh` is just a thin wrapper to download the `ghc-wasm-meta`\nrepo tarball and invoke `setup.sh`. These scripts can be configured\nvia these environment variables:\n\n  - `PREFIX`: installation destination, defaults to `~/.ghc-wasm`\n  - `FLAVOUR`: can be `gmp`, `native` or `unreg`.\n    - The `gmp` flavour uses the `gmp` bignum backend and the wasm\n      native codegen. It's the default flavour, offers good\n      compile-time and run-time performance.\n    - `native` uses the `native` bignum backend and the wasm native\n      codegen. Compared to the `gmp` flavour, the run-time performance\n      may be slightly worse if the workload involves big `Integer`\n      operations. May be useful if you are compiling proprietary\n      projects and have concerns about statically linking the\n      LGPL-licensed `gmp` library.\n    - The `unreg` flavour uses the `gmp` bignum backend and the\n      unregisterised C codegen. Compared to the default flavour,\n      compile-time performance is noticeably worse. May be useful for\n      debugging the native codegen, since there are less GHC test\n      suite failures in the unregisterised codegen at the moment.\n    - The `9.6`/`9.8`/`9.10` flavour tracks the\n      `ghc-9.6`/`ghc-9.8`/`ghc-9.10` release branch instead of the\n      `master` branch. It uses the `gmp` bignum backend and the wasm\n      native codegen.\n  - `SKIP_GHC`: set this to skip installing `cabal` and `ghc`\n\nNote that if you use the `9.6`/`9.8`/`9.10` flavour, the\n`wasm32-wasi-cabal` wrapper won't automatically set up `head.hackage`\nin the global config file. In the early days of `ghc-9.10`, this may\nresult in more packages being rejected at compile time. This is true\nfor both nix/non-nix installation methods.\n\n`setup.sh` requires `cc`, `curl`, `jq`, `unzip`, `zstd` to run.\n\n## What it emits when it emits a `.wasm` file?\n\nBesides wasm MVP, certain extensions are used. The feature flags are\nenabled globally in our\n[wasi-sdk](https://gitlab.haskell.org/ghc/wasi-sdk) build, passed at\nGHC configure time, and the wasm NCG may make use of the features. The\nrationale of post-MVP wasm feature inclusion:\n\n- Supported by default in latest versions of\nChrome/Firefox/Safari/wasmtime (check wasm\n[roadmap](https://webassembly.org/roadmap) for details)\n- LLVM support has been stable enough (doesn't get into our way when\nenabled globally)\n\nList of wasm extensions that we use:\n\n- [128-bit packed\n  SIMD](https://github.com/WebAssembly/spec/blob/master/proposals/simd/SIMD.md)\n- [Non-trapping Float-to-int\n  Conversions](https://github.com/WebAssembly/spec/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md)\n- [Sign-extension\n  operators](https://github.com/WebAssembly/spec/blob/master/proposals/sign-extension-ops/Overview.md)\n- [Bulk Memory\n  Operations](https://github.com/WebAssembly/spec/blob/master/proposals/bulk-memory-operations/Overview.md)\n- [Import/Export mutable\n  globals](https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md)\n- [Multi-value](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md)\n- [Reference\n  Types](https://github.com/WebAssembly/spec/blob/master/proposals/reference-types/Overview.md)\n\nThe target triple is `wasm32-wasi`, and it uses WASI snapshot 1 as\nused in `wasi-libc`.\n\nList of wasm extensions that we don't use yet but are keeping an eye\non:\n\n- [Tail\n  Call](https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md),\n  blocked by [webkit](https://bugs.webkit.org/show_bug.cgi?id=215275).\n  Note that we already support wasm tail calls, but it's an opt-in\n  feature for now.\n\n## What runtimes support those `.wasm` files?\n\nThe output `.wasm` modules are known to run on these runtimes:\n\n### Non-browser non-JavaScript runtimes\n\nThese tools are all packaged in this repo, available in both the nix\nflake \u0026 `setup.sh` installation. The recommended default runtime is\n`wasmtime`, other ones are included for testing purposes.\n\n- [`wasmtime`](https://wasmtime.dev)\n- [`wasmedge`](https://wasmedge.org)\n- [`wazero`](https://wazero.io)\n\n### Non-browser JavaScript runtimes\n\n- [`deno`](https://deno.land), using\n  https://deno.land/std/wasi/snapshot_preview1.ts as WASI\n  implementation\n- [`node`](https://nodejs.org), using the builtin\n  [`wasi`](https://nodejs.org/api/wasi.html) module to provide WASI\n  implementation\n- [`bun`](https://bun.sh), using the builtin WASI\n  [implementation](https://github.com/oven-sh/bun/blob/main/src/bun.js/wasi.exports.js)\n\n### Browsers\n\nLatest releases of Chrome/Firefox/Safari. A JavaScript library is\nneeded to provide the WASI implementation, the following are known to\nwork to some extent:\n\n- [`wasi-js`](https://github.com/sagemathinc/cowasm/tree/main/core/wasi-js)\n- [`browser_wasi_shim`](https://github.com/bjorn3/browser_wasi_shim)\n\n## Compiling to WASI reactor module with user-specified exports\n\nNote: if you are using the GHC wasm backend to target browsers, we\nalready support JSFFI in `master` as well as upcoming 9.10 releases.\nSee the relevant\n[section](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html#javascript-ffi-in-the-wasm-backend)\nin the GHC user's guide for details. The following content is archived\nhere for the time being, but eventually we'll move all documentation\nto the GHC user's guide.\n\nIf you want to embed the compiled wasm module into a host language,\nlike in JavaScript for running in a browser, then it's highly likely\nyou want to compile Haskell to a WASI reactor module.\n\n### What is a WASI reactor module?\n\nThe WASI spec includes certain\n[syscalls](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md)\nthat are provided as the `wasi_snapshot_preview1` wasm imports.\nAdditionally, the current WASI\n[ABI](https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md)\nspecifies two different kinds of WASI modules: commands and reactors.\n\nA WASI command module is what you get by default when using\n`wasm32-wasi-ghc` to compile \u0026 link a Haskell program. It's called\n\"command\" as in a conventional command-line program, with similar\nusage and lifecycle: run it with something like `wasmtime`, optionally\npassing some arguments and environment variables, it'll run to\ncompletion and probably causing some side effects using whatever\ncapabilities granted. After it runs to completion, the program state\nis finalized.\n\nA WASI reactor module is produced by special link-time flags. It's\ncalled \"reactor\" since it reacts to external calls of its exported\nfunctions. Once a reactor module is initialized, the program state is\npersisted, so if calling an export changes internal state (e.g. sets a\nglobal variable), subsequent calls will observe that change.\n\n### Why the distinction and why should you care?\n\nWhen linking a program for almost any platform out there, the linker\nneeds to handle ctors(constructors) \u0026 dtors(destructors). ctors and\ndtors are special functions that need to be invoked to correctly\ninitialize/finalize certain runtime state. Even if the user program\ndoesn't use ctors/dtors, as long as the program links to libc,\nctors/dtors will need to be handled.\n\nThe wasm spec does include a [start\nfunction](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-start).\nHowever, due to technical\n[reasons](https://github.com/WebAssembly/design/issues/1160), what a\nstart function can do is rather limited, and may not be sufficient to\nsupport ctors/dtors in libc and other places. So the WASI spec needs\nto address this fact, and the command/reactor distinction arises:\n\n- A WASI command module must export a `_start` function. You can see\n  how `_start` is defined in `wasi-libc`\n  [here](https://gitlab.haskell.org/ghc/wasi-libc/-/blob/master/libc-bottom-half/crt/crt1-command.c).\n  It'll call the ctors, then call the main function in user code, and\n  finally call the dtors. Since the dtors are called, the program\n  state is finalized, so attempting to call any export after this\n  point is undefined behavior!\n- A WASI reactor module may export an `_initialize` function, if it\n  exists, it must be called exactly once before any other exports are\n  called. See its definition\n  [here](https://gitlab.haskell.org/ghc/wasi-libc/-/blob/master/libc-bottom-half/crt/crt1-reactor.c),\n  it merely calls the ctors. So after `_initialize`, you can call the\n  exports freely, reusing the instance state. If you want to\n  \"finalize\", you're in charge of exporting and calling\n  `__wasm_call_dtors` yourself.\n\nThe command module works well for wasm modules that are intended to be\nused like a conventional CLI app. On the otherhand, for more advanced\nuse cases like running in a browser, you almost always want to create\na reactor module instead.\n\n### Creating a WASI reactor module from `wasm32-wasi-ghc`\n\nSuppose there's a `Hello.hs` that has a `fib :: Int -\u003e Int`. To invoke\nit from the JavaScript host, first you need to write down a `foreign\nexport` for it:\n\n```haskell\nforeign export ccall fib :: Int -\u003e Int\n```\n\nGHC will create a C function `HsInt fib(HsInt)` that calls into the\nactual `fib` Haskell function. Now you need to compile and link it\nwith special flags:\n\n```sh\n$ wasm32-wasi-ghc Hello.hs -o Hello.wasm -no-hs-main -optl-mexec-model=reactor -optl-Wl,--export=hs_init,--export=myMain\n```\n\nSome explainers:\n\n- `-no-hs-main`, since we only care about manually exported functions\n  and don't have a default `main :: IO ()`\n- `-optl-mexec-model=reactor` passes `-mexec-model=reactor` to `clang`\n  when linking, so it creates a WASI reactor instead of a WASI command\n- `-optl-Wl,--export=hs_init,--export=fib` passes the linker flags to\n  export `hs_init` and `fib`\n- `-o Hello.wasm` is necessary, otherwise the output name defaults to\n  `a.out` which can be confusing\n\nThe flags above also work in the `ghc-options` field of a cabal\nexecutable component, see\n[here](https://github.com/tweag/ormolu/blob/master/ormolu-live/ormolu-live.cabal)\nfor an example.\n\nNow, here's an example `deno` script to load and run `Hello.wasm`:\n\n```javascript\nimport WasiContext from \"https://deno.land/std@0.206.0/wasi/snapshot_preview1.ts\";\n\nconst context = new WasiContext({});\n\nconst instance = (\n  await WebAssembly.instantiate(await Deno.readFile(\"Hello.wasm\"), {\n    wasi_snapshot_preview1: context.exports,\n  })\n).instance;\n\n// The initialize() method will call the module's _initialize export\n// under the hood. This is only true for the wasi implementation used\n// in this example! If you're using another wasi implementation, do\n// read its source code to figure out whether you need to manually\n// call the module's _initialize export!\ncontext.initialize(instance);\n\n// This function is a part of GHC's RTS API. It must be called before\n// any other exported Haskell functions are called.\ninstance.exports.hs_init(0, 0);\n\nconsole.log(instance.exports.fib(10));\n```\n\nFor simplicity, we call `hs_init` with `argc` set to `0` and `argv`\nset to `NULL`, assuming we don't use things like\n`getArgs`/`getProgName` in the program. Now, we can call `fib`, or any\nfunction with `foreign export` and the correct `--export=` flag.\n\nBefore we add first-class JavaScript interop feature, it's only\npossible to use the `ccall` calling convention for foreign exports.\nIt's still possible to exchange large values between Haskell and\nJavaScript:\n\n- Add `--export` flag for `malloc`/`free`. You can now allocate and\n  free linear memory buffers that can be visible to the Haskell world,\n  since the entire linear memory is available as the `memory` export.\n- In the Haskell world, you can pass `Ptr` as foreign export\n  argument/return values.\n- You can also use `mallocBytes` in `Foreign.Marshal.Alloc` to\n  allocate buffers in the Haskell world. A buffer allocated by\n  `mallocBytes` in Haskell can be passed to JavaScript and be freed by\n  the exported `free`, and vice versa.\n\nIf you pass a buffer `malloc`ed in JavaScript into Haskell, before\n`free`ing that buffer after the exported Haskell function returns,\nlook into the Haskell code and double check if that buffer is indeed\nfully consumed in Haskell! Otherwise, use-after-free bugs await.\n\nWhich functions can be exported via the `--export` flag?\n\n- Any C function which symbol is externally visible. For libc, there\n  is a\n  [list](https://gitlab.haskell.org/ghc/wasi-libc/-/blob/master/expected/wasm32-wasip1/defined-symbols.txt)\n  of all externally visible symbols. For the GHC RTS, see\n  [`HsFFI.h`](https://gitlab.haskell.org/ghc/ghc/-/blob/master/rts/include/HsFFI.h)\n  and\n  [`RtsAPI.h`](https://gitlab.haskell.org/ghc/ghc/-/blob/master/rts/include/RtsAPI.h)\n  for the functions that you're likely interested in. For instance,\n  `hs_init` is in `HsFFI.h`, other variants of `hs_init*` is in\n  `RtsAPI.h`.\n- Any Haskell function that has been exported via a `foreign export`\n  declaration.\n\nFurther reading:\n\n- [Using the FFI with\n  GHC](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/ffi.html#using-the-ffi-with-ghc)\n- [WebAssembly lld port](https://lld.llvm.org/WebAssembly.html)\n\n### Custom imports\n\nIn addition to the standard `wasi_snapshot_preview1` import module,\nyou can add other import modules to import host JavaScript functions\nwhich can be called in C/Haskell. Of course, the resulting wasm module\nis not completely compliant to the WASI spec, and cannot be run in\nnon-browser runtimes that only supports WASI (like `wasmtime`), but\nit's not an issue if it's only intended to be run in browsers.\n\nHere's an example:\n\n```c\n#include \u003cstdint.h\u003e\n\nvoid _fill(void *buf, uint32_t len) __attribute__((\n  __import_module__(\"env\"),\n  __import_name__(\"foo\")\n));\n\nvoid fill(void *buf, uint32_t len) {\n  _fill(buf, len);\n}\n```\n\nThe above assembly source file can be saved as `fill.c`, and\ncompiled/linked with other C/Haskell sources. The `fill` function can\nbe called in C as long as you write down its prototype; it can also be\ncalled in Haskell just like any other normal C function.\n\nNow, when creating the instance, in addition to providing the\n`wasi_snapshot_preview1` import module, you also need to provide the\n`env` import module which has a `foo` function. Whatever `foo` can do\nis up to you, reader. It may take a buffer's pointer/length and fill\nin something interesting. Since the WASI module has a `memory` export,\n`foo` has access to the instance memory and can do whatever it wants.\n\nCustom imports is a powerful feature and provides more than one way to\ndo things. For instance, if your Haskell program needs to read a large\nblob, you may either put that blob in a memfs and read it as if\nreading a file; or you can just feed that blob via a custom import. In\nthis case, a custom import may be simpler, and it further lowers the\nrequirement on the WASI implementation, since not even a virtual memfs\nimplementation will be needed at run-time.\n\nIt's even possible for the imported function to invoke Haskell\ncomputation by calling exported Haskell functions! This kind of RTS\nre-entrance is permitted in GHC RTS, as long as the custom import is\nmarked with `foreign import ccall safe`.\n\n### Using `wizer` to pre-initialize a WASI reactor module\n\n[`wizer`](https://github.com/bytecodealliance/wizer) is a tool that\ntakes a wasm module, runs a user-specified initialization function,\nthen snapshots the wasm instance state into a new wasm module. Since\n`wizer` is based on `wasmtime`, it supports WASI modules out of the\nbox.\n\nI recommend using `wizer` to pre-initialize your WASI reactor module\ncompiled from Haskell. It's not just about avoiding the overhead of\n`_initialize`; the initialization function run by `wizer` is capable\nof much more tasks, including but not limited to:\n\n- Set up custom RTS flags and other command line arguments\n- Perform arbitrary Haskell computation\n- Perform Haskell garbage collection to re-arrange the heap in an\n  optimal way\n\nIt requires a bit of knowledge about GHC's RTS API to write this\ninitialization function, here's an example:\n\n```c\n// Including this since we need access to GHC's RTS API. And it\n// transitively includes pretty much all of libc headers that we need.\n#include \u003cRts.h\u003e\n\n// When GHC compiles the Test module with foreign export, it'll\n// generate Test_stub.h that declares the prototypes for C functions\n// that wrap the corresponding Haskell functions.\n#include \"Test_stub.h\"\n\n// The prototype of hs_init_with_rtsopts is \"void\n// hs_init_with_rtsopts(int *argc, char **argv[])\" which is a bit\n// cumbersome to work with, hence this convenience wrapper.\nSTATIC_INLINE void hs_init_with_rtsopts_(char *argv[]) {\n  int argc;\n  for (argc = 0; argv[argc] != NULL; ++argc) {\n  }\n  hs_init_with_rtsopts(\u0026argc, \u0026argv);\n}\n\nvoid malloc_inspect_all(void (*handler)(void *start, void *end,\n                                        size_t used_bytes, void *callback_arg),\n                        void *arg);\n\nstatic void malloc_inspect_all_handler(void *start, void *end,\n                                       size_t used_bytes, void *callback_arg) {\n  if (used_bytes == 0) {\n    memset(start, 0, (size_t)end - (size_t)start);\n  }\n}\n\nextern char __stack_low;\nextern char __stack_high;\n\n// Export this function as \"wizer.initialize\". wizer also accepts\n// \"--init-func \u003cinit-func\u003e\" if you dislike this export name, or\n// prefer to pass -Wl,--export=my_init at link-time.\n//\n// By the time this function is called, the WASI reactor _initialize\n// has already been called by wizer. The export entries of this\n// function and _initialize will both be stripped by wizer.\n__attribute__((export_name(\"wizer.initialize\"))) void __wizer_initialize(void) {\n  // The first argument is what you get in getProgName.\n  //\n  // -H64m sets the \"suggested heap size\" to 64MB and reserves so much\n  // memory when doing GC for the first time. It's not a hard limit,\n  // the RTS is perfectly capable of growing the heap beyond it, but\n  // it's still recommended to reserve a reasonably sized heap in the\n  // beginning. And it doesn't add 64MB to the wizer output, most of\n  // the grown memory will be zero anyway!\n  char *argv[] = {\"test.wasm\", \"+RTS\", \"-H64m\", \"-RTS\", NULL};\n\n  // The WASI reactor _initialize function only takes care of\n  // initializing the libc state. The GHC RTS needs to be initialized\n  // using one of hs_init* functions before doing any Haskell\n  // computation.\n  hs_init_with_rtsopts_(argv);\n\n  // Not interesting, I know. The point is you can perform any Haskell\n  // computation here! Or C/C++, whatever.\n  fib(10);\n\n  // Perform major GC to clean up the heap. The second run will invoke\n  // the C finalizers found during the first run.\n  hs_perform_gc();\n  hs_perform_gc();\n\n  // Zero out the unused RTS memory, to prevent the garbage bytes from\n  // being snapshotted into the final wasm module. Otherwise it\n  // wouldn't affect correctness, but the wasm module size would bloat\n  // significantly. It's only safe to call this after hs_perform_gc()\n  // has returned.\n  rts_clearMemory();\n\n  // Zero out the unused heap space. `malloc_inspect_all` is a\n  // dlmalloc internal function which traverses the heap space and can\n  // be used to zero out some space that's previously allocated and\n  // then freed. Upstream `wasi-libc` doesn't expose this function\n  // yet, we do since it's useful for this specific purpose.\n  malloc_inspect_all(malloc_inspect_all_handler, NULL);\n\n  // Zero out the entire stack region in the linear memory. This is\n  // only suitable to do after all other cleanup has been done and\n  // we're about to exit `__wizer_initialize`. `__stack_low` and\n  // `__stack_high` are linker generated symbols which resolve to the\n  // two ends of the stack region.\n  memset(\u0026__stack_low, 0, \u0026__stack_high - \u0026__stack_low);\n}\n```\n\nThen you can compile \u0026 link the C code above with a regular Haskell\nmodule, and pre-initialize using `wizer`:\n\n```sh\nwasm32-wasi-ghc test.hs test_c.c -o test.wasm -no-hs-main -optl-mexec-model=reactor -optl-Wl,--export=fib\nwizer --allow-wasi --wasm-bulk-memory true test.wasm -o test.wizer.wasm\n```\n\nNote that `test.wizer.wasm` will be slightly larger than `test.wasm`,\nwhich is expected behavior here, given some computation has already\nbeen run and the linear memory captures more runtime data.\n\nIf you run `wasm-opt` to minimize the `wasm` module, it's recommend to\nonly run it for the `wizer` output. `wasm-opt` will be able to strip\naway some unused initialization functions that are no longer reachable\nvia wasm exports or function table.\n\n## Accessing the host file system in non-browsers\n\nBy default, only stdin/stdout/stderr is supported. To access the host\nfile system, one needs to map the allowed root directory into `/` as a\nWASI preopen.\n\nThe initial working directoy is always `/`. If you'd like to specify\nanother working directory other than `/` in the virtual filesystem,\nuse the `PWD` environment variable. This is not a WASI standard, just\na workaround we implemented in the GHC RTS shall the need arises.\n\n## Building guide\n\nIf you intend to build the GHC's wasm backend, here's a building\nguide, assuming you already have some experience with building native\nGHC.\n\n### Install `wasi-sdk`\n\nTo build the wasm backend, the systemwide C/C++ toolchain won't work.\nYou need to install our `wasi-sdk`\n[fork](https://gitlab.haskell.org/ghc/wasi-sdk). Upstream `wasi-sdk`\nwon't work yet.\n\nIf your host system is one of `{x86_64,aarch64}-{linux,darwin}`, then\nyou can avoid building and simply download \u0026 extract the GitLab CI\nartifact from the latest `master` commit. The linux artifacts are\nstatically linked and work out of the box on all distros; the macos\nartifact contains universal binaries and works on either apple silicon\nor intel mac.\n\nIf your host system is `x86_64-linux`, you can use the `setup.sh`\nscript to install it, as documented in previous sections.\n\nFor simplicity, the following subsections all assume `wasi-sdk` is\ninstalled to `~/.ghc-wasm/wasi-sdk`, and\n`~/.ghc-wasm/wasi-sdk/bin/wasm32-wasi-clang` works.\n\n### Install `libffi-wasm`\n\nSkip this subsection if `wasi-sdk` is installed by `setup.sh` instead\nof extracting CI artifacts directly.\n\nExtract the CI artifact of\n[`libffi-wasm`](https://gitlab.haskell.org/ghc/libffi-wasm), and copy\nits contents:\n\n- `cp *.h ~/.ghc-wasm/wasi-sdk/share/wasi-sysroot/include/wasm32-wasi`\n- `cp *.a ~/.ghc-wasm/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi`\n\n### Set environment variables\n\nIf you used `setup.sh` to install `wasi-sdk`/`libffi-wasm`, then you\ncan `source ~/.ghc-wasm/env` into your current shell to set the\nfollowing environment variables required for building. Otherwise, you\ncan save this to somewhere else and source that script.\n\n```bash\nexport AR=~/.ghc-wasm/wasi-sdk/bin/llvm-ar\nexport CC=~/.ghc-wasm/wasi-sdk/bin/wasm32-wasi-clang\nexport CC_FOR_BUILD=cc\nexport CXX=~/.ghc-wasm/wasi-sdk/bin/wasm32-wasi-clang++\nexport LD=~/.ghc-wasm/wasi-sdk/bin/wasm-ld\nexport NM=~/.ghc-wasm/wasi-sdk/bin/llvm-nm\nexport OBJCOPY=~/.ghc-wasm/wasi-sdk/bin/llvm-objcopy\nexport OBJDUMP=~/.ghc-wasm/wasi-sdk/bin/llvm-objdump\nexport RANLIB=~/.ghc-wasm/wasi-sdk/bin/llvm-ranlib\nexport SIZE=~/.ghc-wasm/wasi-sdk/bin/llvm-size\nexport STRINGS=~/.ghc-wasm/wasi-sdk/bin/llvm-strings\nexport STRIP=~/.ghc-wasm/wasi-sdk/bin/llvm-strip\nexport CONF_CC_OPTS_STAGE2=\"-fno-strict-aliasing -Wno-error=implicit-function-declaration -Wno-error=int-conversion -O3 -msimd128 -mnontrapping-fptoint -msign-ext -mbulk-memory -mmutable-globals -mmultivalue -mreference-types\"\nexport CONF_CXX_OPTS_STAGE2=\"-fno-exceptions -fno-strict-aliasing -Wno-error=implicit-function-declaration -Wno-error=int-conversion -O3 -msimd128 -mnontrapping-fptoint -msign-ext -mbulk-memory -mmutable-globals -mmultivalue -mreference-types\"\nexport CONF_GCC_LINKER_OPTS_STAGE2=\"-Wl,--compress-relocations,--error-limit=0,--growable-table,--keep-section=ghc_wasm_jsffi,--stack-first,--strip-debug \"\nexport CONFIGURE_ARGS=\"--target=wasm32-wasi --with-intree-gmp --with-system-libffi\"\n```\n\n### Checkout GHC\n\nCheckout GHC.\n\n### Boot \u0026 configure \u0026 build GHC\n\nThe rest is the usual boot \u0026 configure \u0026 build process. You need to\nensure the environment variables described earlier are correctly set\nup; for `ghc.nix` users, it sets up a default `CONFIGURE_ARGS` in the\nnix-shell which is incompatible, and the `env` script set up by\n`setup.sh` respects existing `CONFIGURE_ARGS`, so don't forget to\nunset it first!\n\nConfigure with `./configure $CONFIGURE_ARGS`, then build with hadrian.\nAfter the build completes, you can compile stuff to wasm using\n`_build/stage1/bin/wasm32-wasi-ghc`.\n\nHappy hacking!\n\n## When something goes wrong\n\n### Reporting issues\n\nIf you suspect there's something wrong that needs fixing in the wasm\nbackend (e.g. runtime crashes), you're more than welcome to open a\nticket in the GHC issue tracker! The `wasm` tag will be added to the\nticket by one of the triagers, which ensures it ends up in my inbox.\n\nIt would be very nice to have a self-contained Haskell source file to\nreproduce the bug, but it's not a strict necessity to report the bug.\nIt's fine as long as the project source code and build instruction is\navailable.\n\nDo include the following info in the ticket:\n\n- Which `ghc-wasm-meta` revision is used to install `wasm32-wasi-ghc`?\n  Or if you're building it yourself, which GHC revision are you using?\n\n### Getting more insight on the bug\n\nTo get some more insight on the bug, there are a few things worth\nchecking, importance ranked from high to low:\n\n- Try a different runtime environment. If it is a WASI command module\n  (self-contained `.wasm` file), does it work in `wasmtime` or some\n  other runtime? If it is meant for the browser, try switching to a\n  different WASI implementation, does the same bug still occur? It's\n  known that all current JavaScript implementations of WASI are not\n  100% feature complete and may have bugs.\n- Try a different optimization level in GHC. If it's a cabal project,\n  you can configure the\n  [`optimization:`](https://cabal.readthedocs.io/en/latest/cabal-project.html#cfg-field-optimization)\n  field in `cabal.project`. In case of a code generation bug, it may\n  be the case that one of the passes during GHC optimization resulted\n  in buggy code.\n- Try enabling `-dlint` at compile-time to check consistency.\n- If it crashes, make it crash as early/verbose as possible. Use the\n  GHC `-debug` flag at link time to link with the debug RTS that\n  enables certain internal checks. On top of that, pass RTS flags to\n  enable certain checks, e.g. `+RTS -DS` for sanity checks, see\n  [here](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/runtime_control.html#rts-options-for-hackers-debuggers-and-over-interested-souls)\n  for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackworthltd%2Fghc-wasm-meta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhackworthltd%2Fghc-wasm-meta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackworthltd%2Fghc-wasm-meta/lists"}