From a8dac84587d84bd5d096fb117a304a2d77dec979 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 5 Mar 2026 14:59:40 -0800 Subject: [PATCH 01/16] Forcing LLVM packages to always be available as it seems dotnet restore won't pick up the chain of depedencies through the .nupkg --- crates/bindings-csharp/Runtime/Runtime.csproj | 8 ++++++++ .../Runtime/build/SpacetimeDB.Runtime.targets | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/bindings-csharp/Runtime/Runtime.csproj b/crates/bindings-csharp/Runtime/Runtime.csproj index 036167a1c45..fba955cb724 100644 --- a/crates/bindings-csharp/Runtime/Runtime.csproj +++ b/crates/bindings-csharp/Runtime/Runtime.csproj @@ -12,6 +12,7 @@ true SpacetimeDB true + https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json;$(RestoreAdditionalProjectSources) @@ -25,6 +26,13 @@ + + + + + + + diff --git a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets index aa412113b31..5f183e0e040 100644 --- a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets +++ b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets @@ -1,5 +1,9 @@ + + @@ -42,10 +46,6 @@ - - - - From adbcada46be79b0e5c08b7aadc7c7bb65bb52305 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 5 Mar 2026 19:48:28 -0800 Subject: [PATCH 02/16] Updating nuget config writer script with `NativeAOT-LLM` support --- sdks/csharp/tools~/write-nuget-config.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sdks/csharp/tools~/write-nuget-config.sh b/sdks/csharp/tools~/write-nuget-config.sh index 9997cd219ff..69286284ad8 100755 --- a/sdks/csharp/tools~/write-nuget-config.sh +++ b/sdks/csharp/tools~/write-nuget-config.sh @@ -15,6 +15,8 @@ cat >NuGet.Config < + + @@ -30,6 +32,11 @@ cat >NuGet.Config < + + + + + @@ -43,6 +50,8 @@ cat >"${SPACETIMEDB_REPO_PATH}/NuGet.Config" < + + @@ -58,6 +67,11 @@ cat >"${SPACETIMEDB_REPO_PATH}/NuGet.Config" < + + + + + From d5ef9fb1c0c441f4d4d812577a49847a3fa8f2a5 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 10 Mar 2026 13:18:41 -0700 Subject: [PATCH 03/16] Created conditional for `EXPERIMENTAL_WASM_AOT` specific packages in C# Runtime --- crates/bindings-csharp/Runtime/Runtime.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bindings-csharp/Runtime/Runtime.csproj b/crates/bindings-csharp/Runtime/Runtime.csproj index fba955cb724..eb7a4f05fde 100644 --- a/crates/bindings-csharp/Runtime/Runtime.csproj +++ b/crates/bindings-csharp/Runtime/Runtime.csproj @@ -12,7 +12,7 @@ true SpacetimeDB true - https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json;$(RestoreAdditionalProjectSources) + https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json;$(RestoreAdditionalProjectSources) @@ -27,7 +27,7 @@ - + From 6f5df9b317b8348b427a416c2d80aaa769c44464 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Wed, 11 Mar 2026 11:45:22 -0700 Subject: [PATCH 04/16] Create NATIVEAOT-LLVM instructions for C# modules --- crates/bindings-csharp/NATIVEAOT-LLVM.md | 118 +++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 crates/bindings-csharp/NATIVEAOT-LLVM.md diff --git a/crates/bindings-csharp/NATIVEAOT-LLVM.md b/crates/bindings-csharp/NATIVEAOT-LLVM.md new file mode 100644 index 00000000000..9fe5bb15c24 --- /dev/null +++ b/crates/bindings-csharp/NATIVEAOT-LLVM.md @@ -0,0 +1,118 @@ +# Converting a SpacetimeDB 2.0.x project to use NativeAOT-LLVM + +This guide provides instructions on taking an existing C# module that targets the public-released SpacetimeDB CLI, and guides you through the necessary steps to enable `NativeAOT-LLVM` use. + +## Overview +In order to use `NativeAOT-LLVM` on a C# module, we'll need to set the `EXPERIMENTAL_WASM_AOT` environment variable to `1` which SpacetimeDB will check during publishing of a module. +For the module to work, we'll also need the `NuGet.Config` and `.csproj` files with the required package sources and references. + +### Prerequisites: +- **.NET SDK 8.x** (same version used by SpacetimeDB) +- **Emscripten SDK (EMSDK)** installed (must contain `upstream/emscripten/emcc.bat`) +- **(Optional) Binaryen (wasm-opt)** installed and on `PATH` (recommended: `version_116`) + +## Steps + +1. **Install EMSDK** + - Download and extract the `https://github.com/emscripten-core/emsdk` release. + - Example path: `D:\Tools\emsdk` + +2. **Set environment variables** + + ```powershell + $env:EXPERIMENTAL_WASM_AOT=1 + $env:EMSDK="D:\Tools\emsdk" + ``` + +3. **Ensure NuGet feed is configured** + NativeAOT-LLVM packages currently come from **dotnet-experimental**: + - Add the `dotnet-experimental` feed to a project-local `NuGet.Config` + ```xml + + ``` + This should be a `NuGet.Config` placed in the root directory of your module folder (next to the `.csproj`). You can simply add the above line to the `packageSources` of your existing file, or if you need to create a minimal one, you can use: + + ```xml + + + + + + + + + ``` + +4. **Ensure NativeAOT emits a `.wasm` output** + - For LLVM AOT builds, the CLI currently accepts `dotnet.wasm` under `bin/Release/net8.0/wasi-wasm/publish/`. + - In the module `.csproj`, ensure the AOT package references include: + + ```xml + + + + + + ``` + + The contents of your `.csproj` should look something like this: + + ```xml + + + net8.0 + wasi-wasm + enable + enable + + + + + + + + + + + ``` + + - **NU1504 warning**: Because the runtime targets also add these LLVM packages, you may see a duplicate PackageReference warning. It is non-blocking. + +5. **(Optional) Install wasm-opt (Binaryen)** + This step is optional, but provides performance improvements, and therefore is recommended. + - Download Binaryen `https://github.com/WebAssembly/binaryen/releases/tag/version_116` for Windows and extract it, e.g. `D:\Tools\binaryen`. + - Add `D:\Tools\binaryen\bin` to `PATH`. + - Verify: + + ```powershell + wasm-opt --version + ``` + +6. **Publish module** + - Use the SpacetimeDB CLI to publish from the module directory. + - With `EXPERIMENTAL_WASM_AOT=1`, publish should attempt LLVM AOT. + - Ensure the local server is running if publishing to `local`. + +## Troubleshooting + +### Package source mapping enabled +If you have **package source mapping** enabled in `NuGet.Config`, you must add mappings for the LLVM packages or restores will fail. + +```xml + + + + + + + + + +``` + +### wasi-experimental workload install fails +If the CLI cannot install the `wasi-experimental` workload automatically, install it manually: + +```powershell +dotnet workload install wasi-experimental +``` From da2de3e9e6779ae7b443ea85b078ea411863f4c1 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 11 Mar 2026 12:02:08 -0700 Subject: [PATCH 05/16] Add AOT path for sdk-test-cs to allow the new CI test to work --- modules/sdk-test-cs/sdk-test-cs.csproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/sdk-test-cs/sdk-test-cs.csproj b/modules/sdk-test-cs/sdk-test-cs.csproj index d4caede5ffa..1d0fae78ccc 100644 --- a/modules/sdk-test-cs/sdk-test-cs.csproj +++ b/modules/sdk-test-cs/sdk-test-cs.csproj @@ -9,5 +9,9 @@ - + + + + + From e0221730b8c4e666abe20f828b528a13a94f0ff7 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 11 Mar 2026 13:46:18 -0700 Subject: [PATCH 06/16] Attempting to pin versions for CI test --- modules/sdk-test-cs/sdk-test-cs.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/sdk-test-cs/sdk-test-cs.csproj b/modules/sdk-test-cs/sdk-test-cs.csproj index 1d0fae78ccc..3f46858e7b7 100644 --- a/modules/sdk-test-cs/sdk-test-cs.csproj +++ b/modules/sdk-test-cs/sdk-test-cs.csproj @@ -10,8 +10,8 @@ - - - + + + From a0f68a6bf380e6444c930d2cde999e0f5b140648 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 11 Mar 2026 14:25:26 -0700 Subject: [PATCH 07/16] Runtime on Linux falling back to 9.* oddly trying to clear it up --- modules/sdk-test-cs/sdk-test-cs.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/sdk-test-cs/sdk-test-cs.csproj b/modules/sdk-test-cs/sdk-test-cs.csproj index 3f46858e7b7..5a8414638f3 100644 --- a/modules/sdk-test-cs/sdk-test-cs.csproj +++ b/modules/sdk-test-cs/sdk-test-cs.csproj @@ -12,6 +12,5 @@ - From 4734312f775de7d48225a4feee0f29153f7b79f5 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 11 Mar 2026 14:53:55 -0700 Subject: [PATCH 08/16] Minimal requirement for sdk-test-cs.csproj --- modules/sdk-test-cs/sdk-test-cs.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/sdk-test-cs/sdk-test-cs.csproj b/modules/sdk-test-cs/sdk-test-cs.csproj index 5a8414638f3..8f0bcce2076 100644 --- a/modules/sdk-test-cs/sdk-test-cs.csproj +++ b/modules/sdk-test-cs/sdk-test-cs.csproj @@ -10,7 +10,6 @@ - - + From 52f726be62767ee9fdf3aaf7b25aaa585dd31ade Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 10:03:12 -0700 Subject: [PATCH 09/16] Update `sdk-test-cs` project file with NativeAOT-LLVM packages --- modules/sdk-test-cs/sdk-test-cs.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sdk-test-cs/sdk-test-cs.csproj b/modules/sdk-test-cs/sdk-test-cs.csproj index 8f0bcce2076..1d0fae78ccc 100644 --- a/modules/sdk-test-cs/sdk-test-cs.csproj +++ b/modules/sdk-test-cs/sdk-test-cs.csproj @@ -11,5 +11,7 @@ + + From b37522fdbacd363028c5248fd7a93fdc49f871e1 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 13:34:06 -0700 Subject: [PATCH 10/16] Update `sdk-test-cs` project file to have `ILCompiler.LLMV` `GeneratePathProperty` --- modules/sdk-test-cs/sdk-test-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sdk-test-cs/sdk-test-cs.csproj b/modules/sdk-test-cs/sdk-test-cs.csproj index 1d0fae78ccc..09cf1192bb7 100644 --- a/modules/sdk-test-cs/sdk-test-cs.csproj +++ b/modules/sdk-test-cs/sdk-test-cs.csproj @@ -11,7 +11,7 @@ - + From 9c0a27ab7408742d7d859ea9803a3664d176c588 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 15:26:39 -0700 Subject: [PATCH 11/16] Update `modules/sdk-test-cs` CI job to run on Windows --- .github/workflows/ci.yml | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ae69a01cd3..57e05220743 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -869,11 +869,30 @@ jobs: exit 1 } + # NativeAOT-LLVM smoketest runs on Windows because runtime.linux-x64.Microsoft.DotNet.ILCompiler.LLVM + # does not have 8.0.0 versions available on the dotnet-experimental NuGet feed. + csharp-aot-smoketest: + needs: [lints] + runs-on: windows-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + - name: Smoketest C# AOT build (NativeAOT-LLVM) + shell: pwsh run: | - cd modules/sdk-test-cs - EXPERIMENTAL_WASM_AOT=1 dotnet publish -c Release - test -f bin/Release/net8.0/wasi-wasm/publish/StdbModule.wasm + $env:EXPERIMENTAL_WASM_AOT = "1" + dotnet publish -c Release modules/sdk-test-cs + if (-not (Test-Path "modules/sdk-test-cs/bin/Release/net8.0/wasi-wasm/publish/StdbModule.wasm")) { + Write-Error "StdbModule.wasm not found" + exit 1 + } internal-tests: name: Internal Tests From 90ff17c1f5248ebe440cfed418198af10bd3d204 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 15:48:18 -0700 Subject: [PATCH 12/16] Add Emscripten install step to `modules/sdk-test-cs` CI job --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57e05220743..c65e7e9be17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -884,6 +884,11 @@ jobs: with: global-json-file: global.json + - name: Setup Emscripten + uses: mymindstorm/setup-emsdk@v14 + with: + version: 3.1.56 + - name: Smoketest C# AOT build (NativeAOT-LLVM) shell: pwsh run: | From 107e6ed552f3a25537be780c4ecde80fe3507c6c Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 16:03:27 -0700 Subject: [PATCH 13/16] Updated Emscripten to NativeAOT-LLVM 8.0.0 compatible version --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c65e7e9be17..e4f9cdf6c3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -887,7 +887,9 @@ jobs: - name: Setup Emscripten uses: mymindstorm/setup-emsdk@v14 with: - version: 3.1.56 + # Use older Emscripten version compatible with NativeAOT-LLVM 8.0.0-preview.7 + # Newer versions (3.1.56+) have clang 19.0.0 which causes "absolute addressing not supported" errors + version: 3.1.47 - name: Smoketest C# AOT build (NativeAOT-LLVM) shell: pwsh From 69a0996ecaaa89d8bcf2276cec24106a71cd6b34 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 16:30:53 -0700 Subject: [PATCH 14/16] Using `wasi-sdk`'s clang for WASI targets --- .github/workflows/ci.yml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4f9cdf6c3c..40d7ac84ca2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -887,14 +887,30 @@ jobs: - name: Setup Emscripten uses: mymindstorm/setup-emsdk@v14 with: - # Use older Emscripten version compatible with NativeAOT-LLVM 8.0.0-preview.7 - # Newer versions (3.1.56+) have clang 19.0.0 which causes "absolute addressing not supported" errors - version: 3.1.47 + # Emscripten is required by NativeAOT-LLVM for the EMSDK env var + version: 3.1.24 - name: Smoketest C# AOT build (NativeAOT-LLVM) shell: pwsh run: | $env:EXPERIMENTAL_WASM_AOT = "1" + # Pre-download wasi-sdk so we can use its clang instead of Emscripten's + # NativeAOT-LLVM auto-downloads wasi-sdk but then uses EMSDK's clang which is incompatible + $wasiSdkVersion = "24" + $wasiSdkPath = "$env:USERPROFILE\.wasi-sdk\wasi-sdk-$wasiSdkVersion" + if (-not (Test-Path $wasiSdkPath)) { + Write-Host "Downloading wasi-sdk-$wasiSdkVersion..." + $wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$wasiSdkVersion/wasi-sdk-$wasiSdkVersion.0-x86_64-windows.tar.gz" + $wasiSdkTar = "$env:TEMP\wasi-sdk.tar.gz" + Invoke-WebRequest -Uri $wasiSdkUrl -OutFile $wasiSdkTar + New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.wasi-sdk" | Out-Null + tar -xzf $wasiSdkTar -C "$env:USERPROFILE\.wasi-sdk" + Move-Item "$env:USERPROFILE\.wasi-sdk\wasi-sdk-$wasiSdkVersion.0-x86_64-windows" $wasiSdkPath + } + # Override EMSDK clang path to use wasi-sdk's clang instead + # This prevents the "absolute addressing not supported" error from Emscripten's newer clang + $env:CC = "$wasiSdkPath\bin\clang.exe" + $env:CXX = "$wasiSdkPath\bin\clang++.exe" dotnet publish -c Release modules/sdk-test-cs if (-not (Test-Path "modules/sdk-test-cs/bin/Release/net8.0/wasi-wasm/publish/StdbModule.wasm")) { Write-Error "StdbModule.wasm not found" From 73d81b6c41658cc0507e571f5674b1f4c4d7b4e2 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 12 Mar 2026 17:58:21 -0700 Subject: [PATCH 15/16] Updating to newer version of Emscripten --- .github/workflows/ci.yml | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40d7ac84ca2..6968d8873d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -887,30 +887,12 @@ jobs: - name: Setup Emscripten uses: mymindstorm/setup-emsdk@v14 with: - # Emscripten is required by NativeAOT-LLVM for the EMSDK env var - version: 3.1.24 + version: 4.0.23 - name: Smoketest C# AOT build (NativeAOT-LLVM) shell: pwsh run: | $env:EXPERIMENTAL_WASM_AOT = "1" - # Pre-download wasi-sdk so we can use its clang instead of Emscripten's - # NativeAOT-LLVM auto-downloads wasi-sdk but then uses EMSDK's clang which is incompatible - $wasiSdkVersion = "24" - $wasiSdkPath = "$env:USERPROFILE\.wasi-sdk\wasi-sdk-$wasiSdkVersion" - if (-not (Test-Path $wasiSdkPath)) { - Write-Host "Downloading wasi-sdk-$wasiSdkVersion..." - $wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$wasiSdkVersion/wasi-sdk-$wasiSdkVersion.0-x86_64-windows.tar.gz" - $wasiSdkTar = "$env:TEMP\wasi-sdk.tar.gz" - Invoke-WebRequest -Uri $wasiSdkUrl -OutFile $wasiSdkTar - New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.wasi-sdk" | Out-Null - tar -xzf $wasiSdkTar -C "$env:USERPROFILE\.wasi-sdk" - Move-Item "$env:USERPROFILE\.wasi-sdk\wasi-sdk-$wasiSdkVersion.0-x86_64-windows" $wasiSdkPath - } - # Override EMSDK clang path to use wasi-sdk's clang instead - # This prevents the "absolute addressing not supported" error from Emscripten's newer clang - $env:CC = "$wasiSdkPath\bin\clang.exe" - $env:CXX = "$wasiSdkPath\bin\clang++.exe" dotnet publish -c Release modules/sdk-test-cs if (-not (Test-Path "modules/sdk-test-cs/bin/Release/net8.0/wasi-wasm/publish/StdbModule.wasm")) { Write-Error "StdbModule.wasm not found" From fcee060b09729cc63c42a74c7bcf24ef595fb682 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Fri, 13 Mar 2026 08:10:27 -0700 Subject: [PATCH 16/16] Minor `NATIVEAOT-LLVM.md` troubleshooting update --- crates/bindings-csharp/NATIVEAOT-LLVM.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/bindings-csharp/NATIVEAOT-LLVM.md b/crates/bindings-csharp/NATIVEAOT-LLVM.md index 9fe5bb15c24..362289af8b4 100644 --- a/crates/bindings-csharp/NATIVEAOT-LLVM.md +++ b/crates/bindings-csharp/NATIVEAOT-LLVM.md @@ -97,16 +97,22 @@ For the module to work, we'll also need the `NuGet.Config` and `.csproj` files w ### Package source mapping enabled If you have **package source mapping** enabled in `NuGet.Config`, you must add mappings for the LLVM packages or restores will fail. - +Place the following in `NuGet.Config` inside the `configuration` section: ```xml - - - - - - - + + + + + + + + + + + + + ```