# Building CoreCLR for WebAssembly

This guide provides instructions for building, running, and debugging CoreCLR on WebAssembly (WASM). This is experimental support and is currently under active development.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Building CoreCLR for WebAssembly](#building-coreclr-for-webassembly)
- [Testing the Runtime](#testing-the-runtime)
- [Debugging](#debugging)
  - [Chrome DevTools with DWARF Support](#chrome-devtools-with-dwarf-support)
  - [VS Code WebAssembly Debugging](#vs-code-webassembly-debugging)

## Prerequisites

Make sure you've prepared your environment and installed all the requirements for your platform. If not, follow this [link](/docs/workflow/README.md#introduction) for the corresponding instructions.

## Building CoreCLR for WebAssembly

To build the CoreCLR runtime for WebAssembly, use the following command from the repository root:

**Linux/macOS:**
```bash
./build.sh -os browser -c Debug -subset clr+libs
```

**Windows:**
```cmd
.\build.cmd -os browser -c Debug -subset clr+libs
```

This command will:
- Install the Emscripten SDK (emsdk) automatically, into a shared cache under the main checkout
- Build the CoreCLR runtime for WebAssembly
- Build the required libraries

**Note:** The first build may take longer as it downloads and sets up the Emscripten toolchain.

## Testing the Runtime

### Browser Testing (Recommended)

To enable the browser workflow, edit `src/coreclr/hosts/corerun/CMakeLists.txt` and set the `CORERUN_IN_BROWSER` variable to 1.

You will also need to ensure the `WASM_PRELOAD_DIR` (see `src/coreclr/hosts/corerun/CMakeLists.txt`) is populated during a build of `corerun` so the virtual file system is created. This will require the copying of the libraries (see Console Testing details below) and `HelloWorld.dll` into `./artifacts/bin/coreclr/browser.wasm.Debug/IL` and then the corerun project will then need to be rebuilt.

If you don't have `dotnet-serve` installed, you can install it as a global .NET tool with:

```bash
dotnet tool install --global dotnet-serve
```

**Linux/macOS:**
```bash
dotnet-serve --directory "artifacts/bin/coreclr/browser.wasm.Debug"
```

**Windows:**
```cmd
dotnet-serve --directory "artifacts\bin\coreclr\browser.wasm.Debug"
```

This will start a local HTTP server and you can open the provided URL in your browser. The entry point is the corerun.html file. If you don't see corerun.html, you didn't set the `CORERUN_IN_BROWSER` variable when building the `clr` subset.

### Console Testing

You can also run the runtime directly in Node.js:
In script below please replace `/path/to/runtime/` by a **absolute unix path** to the actual runtime repo (even on Windows).

```bash
cp ./artifacts/bin/microsoft.netcore.app.runtime.browser-wasm/Debug/runtimes/browser-wasm/lib/net11.0/*.dll ./artifacts/bin/coreclr/browser.wasm.Debug/IL
cp helloworld.dll ./artifacts/bin/coreclr/browser.wasm.Debug/IL
cd ./artifacts/bin/coreclr/browser.wasm.Debug/
node --experimental-wasm-exnref ./corerun.js -c /path/to/runtime/artifacts/bin/coreclr/browser.wasm.Debug/IL /path/to/runtime/artifacts/bin/coreclr/browser.wasm.Debug/IL/helloworld.dll
```

### Console Testing with corehost

You can also run the corehost directly in Node.js:

```bash
cp ./artifacts/bin/microsoft.netcore.app.runtime.browser-wasm/Debug/runtimes/browser-wasm/lib/net11.0/*.dll ./artifacts/bin/coreclr/browser.wasm.Debug/corehost
cp helloworld.dll ./artifacts/bin/coreclr/browser.wasm.Debug/corehost
cd ./artifacts/bin/coreclr/browser.wasm.Debug/corehost
node --experimental-wasm-exnref ./main.mjs
```

## Debugging

### Chrome DevTools with DWARF Support

For debugging CoreCLR WebAssembly code, the recommended approach is using Chrome browser with the **C/C++ DevTools Support (DWARF)** extension:

1. **Install the Chrome extension:**
   - [C/C++ DevTools Support (DWARF)](https://goo.gle/wasm-debugging-extension)

2. **Open Chrome DevTools** (F12) while running your WebAssembly application

3. **Set breakpoints** in the Sources tab:
   - Navigate to the WebAssembly modules
   - You can step through C code, set breakpoints, and inspect WebAssembly linear memory
   - The extension provides source-level debugging with DWARF debug information

**Note:** The debugging experience is not perfect but works most of the time. You can step through C code, set breakpoints, and inspect the WebAssembly linear memory.

### VS Code WebAssembly Debugging

VS Code, through Node.js, provides a good debugging option for WebAssembly CoreCLR:

1. **Install the VS Code extension (Optional):**
   - [WebAssembly Dwarf Debugging](https://marketplace.visualstudio.com/items?itemName=ms-vscode.wasm-dwarf-debugging)

2. **Create a launch.json configuration:**

In config below please replace `/path/to/runtime/` by a **absolute unix path** to the actual runtime repo (even on Windows).

   ```json
    {
        "version": "0.2.0",
        "configurations": [
            {
                "type": "node",
                "request": "launch",
                "name": "corerun",
                "skipFiles": [
                    "<node_internals>/**"
                ],
                "outputCapture": "std",
                "program": "corerun.js",
                "env": {
                    "CORE_ROOT":"/path/to/runtime/artifacts/bin/coreclr/browser.wasm.Debug/IL/"
                },
                "runtimeArgs": [
                    "--stack-trace-limit=1000"
                ],
                "args": [
                    "/path/to/runtime/artifacts/bin/coreclr/browser.wasm.Debug/IL/helloworld.dll"
                ],
                "cwd": "${workspaceFolder}/artifacts/bin/coreclr/browser.wasm.Debug/"
            },
            {
                "name": "browserhost",
                "type": "node",
                "request": "launch",
                "skipFiles": [
                    "<node_internals>/**"
                ],
                "runtimeArgs": [
                    "--stack-trace-limit=10000"
                ],
                "args": [
                    "HelloWorld.dll"
                ],
                "outputCapture": "std",
                "cwd": "${workspaceFolder}/artifacts/bin/coreclr/browser.wasm.Debug/corehost",
                "program": "main.mjs",
            }
        ]
    }
   ```

Note that for `corerun` path in the `args` and `CORE_ROOT` need to be **absolute path** on your host file system in **unix format** (even on Windows).

3. **Copy managed DLLs** `System.Runtime.dll` and `helloworld.dll` into `artifacts/bin/coreclr/browser.wasm.Debug/IL/`.

4. **Set breakpoints** in `corerun.js` in one of the `put_char` functions (the `stdout`/`stderr` implementation)

5. **Start debugging** and step through the WebAssembly code using the call stack

This approach allows you to debug the JavaScript host and step into WebAssembly code or into the C/C++ code if the Dwarf Debugging extension was installed.

6. to display `WCHAR *` strings in debugger watch window, cast it to `char16_t*` like `(char16_t*)pLoaderModule->m_fileName`
