Skip to content

Latest commit

 

History

History
172 lines (127 loc) · 6.83 KB

File metadata and controls

172 lines (127 loc) · 6.83 KB

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

Make sure you've prepared your environment and installed all the requirements for your platform. If not, follow this link 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:

./build.sh -os browser -c Debug -subset clr+libs

Windows:

.\build.cmd -os browser -c Debug -subset clr+libs

This command will:

  • Install the Emscripten SDK (emsdk) automatically
  • 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:

dotnet tool install --global dotnet-serve

Linux/macOS:

dotnet-serve --directory "artifacts/bin/coreclr/browser.wasm.Debug"

Windows:

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).

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 ./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:

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 ./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:

  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):

  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).

 {
     "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=1000"
             ],
             "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).

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

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

  3. 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.

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