diff --git a/.github/workflows/macos-static-avalonia-native.yml b/.github/workflows/macos-static-avalonia-native.yml index 3a06d02..10abc25 100644 --- a/.github/workflows/macos-static-avalonia-native.yml +++ b/.github/workflows/macos-static-avalonia-native.yml @@ -98,6 +98,11 @@ jobs: -o artifacts/nuget \ /p:PackageVersion=${{ steps.version.outputs.package_version }} \ /p:Version=${{ steps.version.outputs.package_version }} + dotnet pack NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj \ + -c Release \ + -o artifacts/nuget \ + /p:PackageVersion=11.3.14-macavn.${{ github.run_number }} \ + /p:Version=11.3.14-macavn.${{ github.run_number }} - name: Upload experimental NuGet package uses: actions/upload-artifact@v4 @@ -136,10 +141,15 @@ jobs: run: | $ErrorActionPreference = "Stop" $projectDir = Join-Path $PWD "artifacts/avalonia-smoke-src" + $nativePackage = Get-ChildItem -Path "artifacts/nuget" -Filter "StaticLink.Avalonia.Native.*.nupkg" | Select-Object -First 1 + if (-not $nativePackage) { throw "StaticLink AvaloniaNative NuGet package was not downloaded." } + if ($nativePackage.BaseName -notmatch '^StaticLink\.Avalonia\.Native\.(.+)$') { throw "Unexpected native package name: $($nativePackage.Name)" } + $nativeVersion = $Matches[1] pwsh ./scripts/create-avalonia-smoke.ps1 ` -ProjectDir $projectDir ` -NuGetSource (Resolve-Path "artifacts/nuget") ` - -StaticLinkVersion "${{ needs.pack-experimental.outputs.package_version }}" + -StaticLinkVersion "${{ needs.pack-experimental.outputs.package_version }}" ` + -StaticLinkNativeVersion $nativeVersion dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") ` -c Release ` -r "${{ matrix.rid }}" ` diff --git a/.github/workflows/nuget-static-graphics.yml b/.github/workflows/nuget-static-graphics.yml index c332ab5..352540a 100644 --- a/.github/workflows/nuget-static-graphics.yml +++ b/.github/workflows/nuget-static-graphics.yml @@ -131,21 +131,12 @@ jobs: TARGET_CPU: ${{ matrix.target_cpu }} WORK_DIR: ${{ github.workspace }}/External/NativeStatic/.work OUTPUT_DIR: ${{ github.workspace }}/External/NativeStatic/${{ matrix.rid }}/native - AVALONIA_VERSION: 11.3.14 steps: - uses: actions/checkout@v4 - - name: Setup .NET for Avalonia header generation - uses: actions/setup-dotnet@v4 - with: - dotnet-version: "8.0.x" - - name: Install native build dependencies run: brew install ninja - - name: Build static AvaloniaNative - run: bash ./scripts/build-macos-avalonia-native-static.sh - - name: Build macOS static graphics libraries run: bash ./scripts/build-macos-static-graphics.sh all @@ -159,12 +150,61 @@ jobs: path: External/NativeStatic/${{ matrix.rid }}/* if-no-files-found: error + build-macos-avalonia-native: + strategy: + fail-fast: false + matrix: + include: + - rid: osx-x64 + runner: macos-14 + avalonia_version: 11.3.14 + - rid: osx-arm64 + runner: macos-latest + avalonia_version: 11.3.14 + - rid: osx-x64 + runner: macos-14 + avalonia_version: 12.0.3 + - rid: osx-arm64 + runner: macos-latest + avalonia_version: 12.0.3 + runs-on: ${{ matrix.runner }} + env: + RID: ${{ matrix.rid }} + WORK_DIR: ${{ github.workspace }}/External/NativeStatic/.work + OUTPUT_DIR: ${{ github.workspace }}/External/NativeStatic/${{ matrix.rid }}/native + AVALONIA_VERSION: ${{ matrix.avalonia_version }} + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET for Avalonia header generation + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + 10.0.x + + - name: Build static AvaloniaNative + run: bash ./scripts/build-macos-avalonia-native-static.sh + + - name: Build macOS font preinit object + run: bash scripts/build-macos-font-preinit.sh + + - name: Upload static AvaloniaNative + uses: actions/upload-artifact@v4 + with: + name: native-avalonia-${{ matrix.avalonia_version }}-${{ matrix.rid }} + path: | + External/NativeStatic/${{ matrix.rid }}/native/libAvaloniaNative.a + External/NativeStatic/${{ matrix.rid }}/native/macos_font_preinit.o + if-no-files-found: error + pack: runs-on: ubuntu-latest needs: - build-linux - build-windows - build-macos + - build-macos-avalonia-native permissions: contents: read steps: @@ -182,6 +222,13 @@ jobs: path: External/NativeStatic merge-multiple: false + - name: Download static AvaloniaNative archives + uses: actions/download-artifact@v4 + with: + pattern: native-avalonia-* + path: External/AvaloniaNative + merge-multiple: false + - name: Move static archives into RID directories run: | for rid in win-x64 win-arm64 linux-x64 linux-arm64 osx-x64 osx-arm64; do @@ -200,11 +247,6 @@ jobs: test -f External/NativeStatic/$rid/native/libGLESv2_static.a done - for rid in osx-x64 osx-arm64; do - test -f External/NativeStatic/$rid/native/libAvaloniaNative.a - test -f External/NativeStatic/$rid/native/macos_font_preinit.o - done - for rid in win-x64 win-arm64; do test -f External/NativeStatic/$rid/native/skia.lib test -f External/NativeStatic/$rid/native/SkiaSharp.lib @@ -214,7 +256,18 @@ jobs: done - name: Pack NuGet package - run: dotnet pack NuGet/StaticGraphics/StaticLink.Avalonia.csproj -c Release -o artifacts/nuget + run: | + dotnet pack NuGet/StaticGraphics/StaticLink.Avalonia.csproj -c Release -o artifacts/nuget + for version in 11.3.14 12.0.3; do + mkdir -p External/NativeStatic/osx-x64/native External/NativeStatic/osx-arm64/native + cp External/AvaloniaNative/native-avalonia-$version-osx-x64/* External/NativeStatic/osx-x64/native/ + cp External/AvaloniaNative/native-avalonia-$version-osx-arm64/* External/NativeStatic/osx-arm64/native/ + dotnet pack NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj \ + -c Release \ + -o artifacts/nuget \ + /p:PackageVersion=$version.1 \ + /p:Version=$version.1 + done - name: Upload NuGet artifact uses: actions/upload-artifact@v4 @@ -260,8 +313,20 @@ jobs: runner: ubuntu-24.04-arm - rid: osx-x64 runner: macos-14 + avalonia_version: 11.3.14 + native_version: 11.3.14.1 - rid: osx-arm64 runner: macos-latest + avalonia_version: 11.3.14 + native_version: 11.3.14.1 + - rid: osx-x64 + runner: macos-14 + avalonia_version: 12.0.3 + native_version: 12.0.3.1 + - rid: osx-arm64 + runner: macos-latest + avalonia_version: 12.0.3 + native_version: 12.0.3.1 runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v4 @@ -293,12 +358,19 @@ jobs: shell: pwsh run: | $ErrorActionPreference = "Stop" - $package = Get-ChildItem -Path "artifacts/nuget" -Filter "StaticLink.Avalonia.*.nupkg" | Select-Object -First 1 + $package = Get-ChildItem -Path "artifacts/nuget" -Filter "StaticLink.Avalonia.*.nupkg" | Where-Object { $_.Name -notlike "StaticLink.Avalonia.Native.*" } | Select-Object -First 1 if (-not $package) { throw "StaticLink NuGet package was not downloaded." } if ($package.BaseName -notmatch '^StaticLink\.Avalonia\.(.+)$') { throw "Unexpected package name: $($package.Name)" } $version = $Matches[1] + $nativeVersion = "${{ matrix.native_version }}" + $avaloniaVersion = "${{ matrix.avalonia_version }}" + if (-not $avaloniaVersion) { $avaloniaVersion = "11.3.14" } + if ($nativeVersion) { + $nativePackage = Get-ChildItem -Path "artifacts/nuget" -Filter "StaticLink.Avalonia.Native.$nativeVersion.nupkg" | Select-Object -First 1 + if (-not $nativePackage) { throw "StaticLink AvaloniaNative NuGet package $nativeVersion was not downloaded." } + } $projectDir = Join-Path $PWD "artifacts/avalonia-smoke-src" - pwsh ./scripts/create-avalonia-smoke.ps1 -ProjectDir $projectDir -NuGetSource (Resolve-Path "artifacts/nuget") -StaticLinkVersion $version + pwsh ./scripts/create-avalonia-smoke.ps1 -ProjectDir $projectDir -NuGetSource (Resolve-Path "artifacts/nuget") -StaticLinkVersion $version -AvaloniaVersion $avaloniaVersion -StaticLinkNativeVersion $nativeVersion dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") ` -c Release ` -r "${{ matrix.rid }}" ` diff --git a/NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj b/NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj new file mode 100644 index 0000000..06aef8c --- /dev/null +++ b/NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj @@ -0,0 +1,32 @@ + + + net10.0 + true + true + false + false + StaticLink.Avalonia.Native + 11.3.14.1 + greepar + greepar + Static AvaloniaNative library for macOS Avalonia NativeAOT publishing. + Avalonia;AvaloniaNative;NativeAOT;macOS;Static + MIT + README.md + git + https://github.com/greepar/StaticLink.Avalonia + https://github.com/greepar/StaticLink.Avalonia + + + + + + + + + + + + + + diff --git a/NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.MacOSFontWarmup.cs b/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.MacOSFontWarmup.cs similarity index 93% rename from NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.MacOSFontWarmup.cs rename to NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.MacOSFontWarmup.cs index 28ed6b7..1b6b382 100644 --- a/NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.MacOSFontWarmup.cs +++ b/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.MacOSFontWarmup.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace StaticLink.Avalonia; +namespace StaticLink.Avalonia.Native; internal static class MacOSFontWarmup { @@ -29,7 +29,7 @@ internal static class MacOSFontWarmup } catch { - // Never fail application startup from the defensive macOS font-cache warmup. + // Defensive AppKit font-cache warmup must never fail application startup. } } diff --git a/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.props b/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.props new file mode 100644 index 0000000..6026106 --- /dev/null +++ b/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.props @@ -0,0 +1,5 @@ + + + $(MSBuildThisFileDirectory)../static/ + + diff --git a/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.targets b/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.targets new file mode 100644 index 0000000..6d8cd17 --- /dev/null +++ b/NuGet/AvaloniaNative/buildTransitive/StaticLink.Avalonia.Native.targets @@ -0,0 +1,41 @@ + + + <_StaticLinkAvaloniaNativeRid Condition="'$(RuntimeIdentifier)' == 'osx-x64'">osx-x64 + <_StaticLinkAvaloniaNativeRid Condition="'$(RuntimeIdentifier)' == 'osx-arm64'">osx-arm64 + <_StaticLinkAvaloniaNativeRoot Condition="'$(_StaticLinkAvaloniaNativeRid)' != ''">$(StaticLinkAvaloniaNativeRoot)$(_StaticLinkAvaloniaNativeRid)/native + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_StaticLinkAvaloniaNativeFilesToDelete Include="$(PublishDir)libAvaloniaNative.dylib" /> + + + + diff --git a/NuGet/AvaloniaNative/lib/net10.0/_._ b/NuGet/AvaloniaNative/lib/net10.0/_._ new file mode 100644 index 0000000..e69de29 diff --git a/NuGet/StaticGraphics/README.md b/NuGet/StaticGraphics/README.md index e4e5da2..17b9e40 100644 --- a/NuGet/StaticGraphics/README.md +++ b/NuGet/StaticGraphics/README.md @@ -21,6 +21,12 @@ Repository: dotnet add package StaticLink.Avalonia ``` +For fully static macOS output, also reference the AvaloniaNative package that matches your Avalonia version: + +```bash +dotnet add package StaticLink.Avalonia.Native --version 11.3.14.1 +``` + ## Publish ```bash @@ -56,6 +62,7 @@ For macOS, avoid the Metal renderer for fully static output. Use OpenGL or Softw ## Notes - The package is intended for Avalonia `11.3.x` NativeAOT apps. +- `StaticLink.Avalonia.Native` is version-specific because `libAvaloniaNative.a` must match Avalonia's native ABI. - The CI builds and smoke-publishes all six supported RIDs. - macOS smoke tests run the published app on GitHub Actions and require it to stay alive for 15 seconds. - Other native dependencies used by your app, such as SQLite or audio libraries, are outside this package's scope. diff --git a/NuGet/StaticGraphics/StaticLink.Avalonia.csproj b/NuGet/StaticGraphics/StaticLink.Avalonia.csproj index f389e75..3edc064 100644 --- a/NuGet/StaticGraphics/StaticLink.Avalonia.csproj +++ b/NuGet/StaticGraphics/StaticLink.Avalonia.csproj @@ -27,12 +27,11 @@ - - - + + diff --git a/NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.targets b/NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.targets index 85cb909..5024f27 100644 --- a/NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.targets +++ b/NuGet/StaticGraphics/buildTransitive/StaticLink.Avalonia.targets @@ -49,12 +49,8 @@ - - - - @@ -96,8 +92,6 @@ BeforeTargets="WriteIlcRspFileForCompilation" Condition="'$(PublishAot)' == 'true' and ('$(RuntimeIdentifier)' == 'osx-x64' or '$(RuntimeIdentifier)' == 'osx-arm64') and '$(_StaticLinkAvaloniaNativeRoot)' != ''"> - - @@ -118,7 +112,6 @@ <_StaticLinkAvaloniaFilesToDelete Include="$(PublishDir)libSkiaSharp.so" /> <_StaticLinkAvaloniaFilesToDelete Include="$(PublishDir)libHarfBuzzSharp.dylib" /> <_StaticLinkAvaloniaFilesToDelete Include="$(PublishDir)libSkiaSharp.dylib" /> - <_StaticLinkAvaloniaFilesToDelete Include="$(PublishDir)libAvaloniaNative.dylib" /> diff --git a/README.md b/README.md index e4e5da2..17b9e40 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,12 @@ Repository: dotnet add package StaticLink.Avalonia ``` +For fully static macOS output, also reference the AvaloniaNative package that matches your Avalonia version: + +```bash +dotnet add package StaticLink.Avalonia.Native --version 11.3.14.1 +``` + ## Publish ```bash @@ -56,6 +62,7 @@ For macOS, avoid the Metal renderer for fully static output. Use OpenGL or Softw ## Notes - The package is intended for Avalonia `11.3.x` NativeAOT apps. +- `StaticLink.Avalonia.Native` is version-specific because `libAvaloniaNative.a` must match Avalonia's native ABI. - The CI builds and smoke-publishes all six supported RIDs. - macOS smoke tests run the published app on GitHub Actions and require it to stay alive for 15 seconds. - Other native dependencies used by your app, such as SQLite or audio libraries, are outside this package's scope. diff --git a/scripts/create-avalonia-smoke.ps1 b/scripts/create-avalonia-smoke.ps1 index 3d2fff6..e9eb5f8 100644 --- a/scripts/create-avalonia-smoke.ps1 +++ b/scripts/create-avalonia-smoke.ps1 @@ -6,13 +6,22 @@ param( [string]$NuGetSource, [Parameter(Mandatory = $true)] - [string]$StaticLinkVersion + [string]$StaticLinkVersion, + + [string]$AvaloniaVersion = "11.3.14", + + [string]$StaticLinkNativeVersion = "" ) $ErrorActionPreference = "Stop" New-Item -ItemType Directory -Path $ProjectDir -Force | Out-Null +$nativeReference = "" +if ($StaticLinkNativeVersion) { + $nativeReference = "`n " +} + @" @@ -41,10 +50,10 @@ New-Item -ItemType Directory -Path $ProjectDir -Force | Out-Null - - - - + + + + $nativeReference "@ | Set-Content -Path (Join-Path $ProjectDir "AvaloniaStaticLinkSmoke.csproj") -Encoding UTF8 @@ -137,7 +146,7 @@ public sealed partial class MainWindow : Window Title="Avalonia StaticLink Smoke"> - +