From 7373933f8aef892455a93c0d9e758176a48269b4 Mon Sep 17 00:00:00 2001 From: Timmy Silesmo Date: Tue, 31 Mar 2026 20:23:12 +0200 Subject: [PATCH] C# MacOS support --- .github/workflows/main.yml | 66 ++++++++++++++++++++++++++++++++++--- crates/csharp/src/csproj.rs | 28 ++++++++++++---- crates/test/src/csharp.rs | 1 + 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 71828f1e3..1f11d52b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,11 +80,9 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] # moonbit removed from language matrix for now - causing CI failures lang: [c, rust, csharp, cpp, go] - exclude: - # For now csharp doesn't work on macos, so exclude it from testing. - - os: macos-latest - lang: csharp runs-on: ${{ matrix.os }} + env: + RUNTIMELAB_COMMIT: '4cac3ab5c8e97fda69c23dfca41ace964babc05e' steps: - uses: actions/checkout@v4 with: @@ -103,7 +101,14 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: '9.x' - if: matrix.lang == 'csharp' + if: matrix.lang == 'csharp' && runner.os != 'macOS' + + - name: Setup .NET 10 (macOS) + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.x' + dotnet-quality: 'preview' + if: matrix.lang == 'csharp' && runner.os == 'macOS' - name: Setup Go uses: actions/setup-go@v5 @@ -125,6 +130,57 @@ jobs: shell: powershell if: matrix.os == 'windows-latest' && matrix.lang == 'moonbit' + # macOS C# requires locally-built ILC packages since no osx-arm64 + # packages are published on NuGet. + - name: Cache runtimelab ILC packages + id: cache-runtimelab + uses: actions/cache@v4 + with: + path: runtimelab-packages + key: runtimelab-macos-arm64-${{ env.RUNTIMELAB_COMMIT }} + if: runner.os == 'macOS' && matrix.lang == 'csharp' + + - name: Install LLVM 18 for runtimelab build + if: runner.os == 'macOS' && matrix.lang == 'csharp' && steps.cache-runtimelab.outputs.cache-hit != 'true' + run: brew install llvm@18 + + - name: Checkout runtimelab + uses: actions/checkout@v4 + with: + repository: dotnet/runtimelab + ref: ${{ env.RUNTIMELAB_COMMIT }} + path: runtimelab + if: runner.os == 'macOS' && matrix.lang == 'csharp' && steps.cache-runtimelab.outputs.cache-hit != 'true' + + - name: Build runtimelab ILC packages + if: runner.os == 'macOS' && matrix.lang == 'csharp' && steps.cache-runtimelab.outputs.cache-hit != 'true' + run: | + cd runtimelab + ln -sf $WASI_SDK_PATH src/mono/wasi/wasi-sdk + mkdir -p src/mono/wasi/include + + # Build wasi libs and packages + ./build.sh clr.aot+libs -c Release -a wasm -os wasi /p:NuGetAudit=false + ./build.sh nativeaot.packages -c Release -a wasm -os wasi /p:NuGetAudit=false + + # Build host compiler, libs, WASM JIT, and packages + ./build.sh clr.aot -c Release /p:NuGetAudit=false + ./build.sh libs -c Release /p:NuGetAudit=false + LLVM_CMAKE_CONFIG_RELEASE=$(brew --prefix llvm@18)/lib/cmake/llvm \ + src/coreclr/build-runtime.sh -arm64 -release -os osx -outputrid osx-arm64 -component llvmjit + cp artifacts/bin/coreclr/osx.arm64.Release/libclrjit_universal_llvm32_arm64.dylib artifacts/bin/coreclr/osx.arm64.Release/ilc-published/ + cp artifacts/bin/coreclr/osx.arm64.Release/libjitinterface_arm64.dylib artifacts/bin/coreclr/osx.arm64.Release/ilc-published/ + ./build.sh nativeaot.packages -c Release /p:NuGetAudit=false + + mkdir -p ../runtimelab-packages + cp artifacts/packages/Release/Shipping/*.nupkg ../runtimelab-packages/ + + - name: Set ILC env vars for macOS C# + if: runner.os == 'macOS' && matrix.lang == 'csharp' + run: | + echo "ILC_VERSION=10.0.0-dev" >> $GITHUB_ENV + echo "ILC_PACKAGES_PATH=${{ github.workspace }}/runtimelab-packages" >> $GITHUB_ENV + # Run all codegen tests for this language - run: | cargo run test --languages ${{ matrix.lang }} tests/codegen \ diff --git a/crates/csharp/src/csproj.rs b/crates/csharp/src/csproj.rs index 1d9d86aaa..c94b39064 100644 --- a/crates/csharp/src/csproj.rs +++ b/crates/csharp/src/csproj.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use std::{fs, path::PathBuf}; +use std::{env, fs, path::PathBuf}; use heck::ToUpperCamelCase; @@ -103,21 +103,36 @@ impl CSProjectLLVMBuilder { let os = match std::env::consts::OS { "windows" => "win", "linux" => std::env::consts::OS, + "macos" => "osx", other => todo!("OS {} not supported", other), }; + let arch = match std::env::consts::ARCH { + "aarch64" => "arm64", + "x86_64" => "x64", + other => todo!("ARCH {} not supported", other), + }; + + let ilc_version = env::var("ILC_VERSION").unwrap_or_else(|_| "10.0.0-*".to_string()); + csproj.push_str( &format!( r#" - - + + "#), ); + let local_source = match env::var("ILC_PACKAGES_PATH") { + Ok(path) => format!(r#""#), + Err(_) => String::new(), + }; + fs::write( self.dir.join("nuget.config"), - r#" + format!( + r#" @@ -126,11 +141,12 @@ impl CSProjectLLVMBuilder { + {local_source} - - "#, + "# + ), )?; } diff --git a/crates/test/src/csharp.rs b/crates/test/src/csharp.rs index 8e11ca7f7..692221e02 100644 --- a/crates/test/src/csharp.rs +++ b/crates/test/src/csharp.rs @@ -99,6 +99,7 @@ impl LanguageMethods for Csharp { let os = match std::env::consts::OS { "windows" => "win", "linux" => std::env::consts::OS, + "macos" => "osx", other => todo!("OS {} not supported", other), };