Split Avalonia Native package workflow

This commit is contained in:
geruipu committed 2026-07-20 01:47:12 +08:00
1 parent 06f3b17b8f
commit 229c0dc767
8 files changed
+315 -100

No files matched your search

+278
View File
@@ -0,0 +1,278 @@
name: staticlink-avalonia-native
on:
schedule:
- cron: "17 3 * * *"
workflow_dispatch:
inputs:
avalonia_version:
description: Avalonia version to build; empty uses the latest stable NuGet version
required: false
type: string
force_build:
description: Build even when this StaticLink.Avalonia.Native version already exists
required: true
default: false
type: boolean
publish_to_nuget:
description: Publish with NuGet Trusted Publishing after smoke tests
required: true
default: true
type: boolean
concurrency:
group: staticlink-avalonia-native
cancel-in-progress: false
jobs:
detect:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
avalonia_version: ${{ steps.version.outputs.avalonia_version }}
package_version: ${{ steps.version.outputs.package_version }}
should_build: ${{ steps.version.outputs.should_build }}
steps:
- name: Detect unpublished Avalonia version
id: version
shell: bash
env:
REQUESTED_VERSION: ${{ inputs.avalonia_version }}
FORCE_BUILD: ${{ inputs.force_build }}
run: |
set -euo pipefail
avalonia_version="$REQUESTED_VERSION"
if [ -z "$avalonia_version" ]; then
avalonia_version="$(curl --fail --silent --show-error --location \
https://api.nuget.org/v3-flatcontainer/avalonia/index.json \
| jq -r '[.versions[] | select(contains("-") | not)] | last')"
fi
if [ -z "$avalonia_version" ] || [ "$avalonia_version" = "null" ]; then
echo "Could not determine the latest stable Avalonia version." >&2
exit 1
fi
package_version="$avalonia_version.1"
package_url="https://api.nuget.org/v3-flatcontainer/staticlink.avalonia.native/$package_version/staticlink.avalonia.native.$package_version.nupkg"
should_build=true
if [ "$FORCE_BUILD" != "true" ] && curl --fail --silent --location --output /dev/null "$package_url"; then
should_build=false
fi
echo "Avalonia version: $avalonia_version"
echo "StaticLink.Avalonia.Native version: $package_version"
echo "Build required: $should_build"
echo "avalonia_version=$avalonia_version" >> "$GITHUB_OUTPUT"
echo "package_version=$package_version" >> "$GITHUB_OUTPUT"
echo "should_build=$should_build" >> "$GITHUB_OUTPUT"
build:
needs: detect
if: ${{ needs.detect.outputs.should_build == 'true' }}
strategy:
fail-fast: false
matrix:
include:
- rid: osx-x64
runner: macos-14
- rid: osx-arm64
runner: macos-15
runs-on: ${{ matrix.runner }}
permissions:
contents: read
env:
RID: ${{ matrix.rid }}
AVALONIA_VERSION: ${{ needs.detect.outputs.avalonia_version }}
WORK_DIR: ${{ github.workspace }}/External/AvaloniaNative/.work
OUTPUT_DIR: ${{ github.workspace }}/External/AvaloniaNative/${{ matrix.rid }}/native
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.rid }}
path: |
External/AvaloniaNative/${{ matrix.rid }}/native/libAvaloniaNative.a
External/AvaloniaNative/${{ matrix.rid }}/native/macos_font_preinit.o
if-no-files-found: error
pack:
needs:
- detect
- build
if: ${{ needs.detect.outputs.should_build == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"
- name: Download static AvaloniaNative archives
uses: actions/download-artifact@v4
with:
pattern: native-avalonia-*
path: artifacts/native
merge-multiple: false
- name: Prepare package inputs
shell: bash
run: |
set -euo pipefail
for rid in osx-x64 osx-arm64; do
mkdir -p "External/AvaloniaNative/$rid/native"
cp "artifacts/native/native-avalonia-$rid/libAvaloniaNative.a" "External/AvaloniaNative/$rid/native/"
cp "artifacts/native/native-avalonia-$rid/macos_font_preinit.o" "External/AvaloniaNative/$rid/native/"
done
- name: Pack StaticLink.Avalonia.Native
run: |
dotnet pack NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj \
-c Release \
-o artifacts/nuget \
/p:PackageVersion=${{ needs.detect.outputs.package_version }} \
/p:Version=${{ needs.detect.outputs.package_version }}
- name: Upload NuGet package
uses: actions/upload-artifact@v4
with:
name: staticlink-avalonia-native-${{ needs.detect.outputs.package_version }}
path: artifacts/nuget/*.nupkg
if-no-files-found: error
smoke:
needs:
- detect
- pack
if: ${{ needs.detect.outputs.should_build == 'true' }}
strategy:
fail-fast: false
matrix:
include:
- rid: osx-x64
runner: macos-14
- rid: osx-arm64
runner: macos-15
runs-on: ${{ matrix.runner }}
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"
- name: Download NuGet package
uses: actions/download-artifact@v4
with:
name: staticlink-avalonia-native-${{ needs.detect.outputs.package_version }}
path: artifacts/nuget
- name: Publish Avalonia NativeAOT smoke app
shell: pwsh
run: |
$projectDir = Join-Path $PWD "artifacts/avalonia-native-smoke-src"
pwsh ./scripts/create-avalonia-smoke.ps1 `
-ProjectDir $projectDir `
-NuGetSource (Resolve-Path "artifacts/nuget") `
-AvaloniaVersion "${{ needs.detect.outputs.avalonia_version }}" `
-StaticLinkNativeVersion "${{ needs.detect.outputs.package_version }}"
dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") `
-c Release `
-r "${{ matrix.rid }}" `
--configfile (Join-Path $projectDir "NuGet.config") `
/p:PublishDir="$PWD/artifacts/smoke-${{ matrix.rid }}/"
- name: Verify AvaloniaNative is statically linked
shell: bash
run: |
set -euo pipefail
test ! -f "artifacts/smoke-${{ matrix.rid }}/libAvaloniaNative.dylib"
test -x "artifacts/smoke-${{ matrix.rid }}/AvaloniaStaticLinkSmoke"
- name: Run Avalonia smoke app
shell: bash
run: |
set -euo pipefail
cd "artifacts/smoke-${{ matrix.rid }}"
python3 - <<'PY'
import subprocess
import sys
proc = subprocess.Popen(
["./AvaloniaStaticLinkSmoke"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
try:
output, _ = proc.communicate(timeout=15)
except subprocess.TimeoutExpired:
proc.kill()
output, _ = proc.communicate()
print(output or "")
print("Avalonia smoke app stayed alive for 15 seconds.")
sys.exit(0)
print(output or "")
if proc.returncode == 0:
sys.exit(0)
sys.exit(proc.returncode if proc.returncode > 0 else 1)
PY
publish:
needs:
- detect
- smoke
if: ${{ needs.detect.outputs.should_build == 'true' && (github.event_name == 'schedule' || inputs.publish_to_nuget == true) }}
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Download NuGet package
uses: actions/download-artifact@v4
with:
name: staticlink-avalonia-native-${{ needs.detect.outputs.package_version }}
path: artifacts/nuget
- name: Validate Trusted Publishing configuration
env:
NUGET_USER: ${{ vars.NUGET_USER }}
run: test -n "$NUGET_USER"
- name: NuGet login
id: login
uses: NuGet/login@v1
with:
user: ${{ vars.NUGET_USER }}
- name: Publish to nuget.org
run: |
dotnet nuget push artifacts/nuget/*.nupkg \
--source https://www.nuget.org/api/v2/package \
--api-key "${{ steps.login.outputs.NUGET_API_KEY }}" \
--skip-duplicate
+3 -88
View File
@@ -194,9 +194,6 @@ jobs:
- name: Build macOS static graphics libraries
run: bash ./scripts/build-macos-static-graphics.sh all
- name: Build macOS font preinit object
run: bash scripts/build-macos-font-preinit.sh
- name: Upload macOS static archives
uses: actions/upload-artifact@v4
with:
@@ -204,61 +201,12 @@ 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-15
avalonia_version: 11.3.14
- rid: osx-x64
runner: macos-14
avalonia_version: 12.0.3
- rid: osx-arm64
runner: macos-15
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:
@@ -276,13 +224,6 @@ 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-x86 win-arm64 linux-x64 linux-arm64 linux-musl-x64 linux-musl-arm64 osx-x64 osx-arm64; do
@@ -315,18 +256,7 @@ jobs:
test -f External/NativeStatic/win-x86/native/skia_x86_stdcall_thunks.lib
- name: Pack NuGet package
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
run: dotnet pack NuGet/StaticGraphics/StaticLink.Avalonia.csproj -c Release -o artifacts/nuget
- name: Upload NuGet artifact
uses: actions/upload-artifact@v4
@@ -380,19 +310,9 @@ jobs:
- rid: osx-x64
runner: macos-14
avalonia_version: 11.3.14
native_version: 11.3.14.1
- rid: osx-arm64
runner: macos-15
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-15
avalonia_version: 12.0.3
native_version: 12.0.3.1
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
@@ -429,15 +349,10 @@ jobs:
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 -AvaloniaVersion $avaloniaVersion -StaticLinkNativeVersion $nativeVersion
pwsh ./scripts/create-avalonia-smoke.ps1 -ProjectDir $projectDir -NuGetSource (Resolve-Path "artifacts/nuget") -StaticLinkVersion $version -AvaloniaVersion $avaloniaVersion
dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") `
-c Release `
-r "${{ matrix.rid }}" `
@@ -470,7 +385,7 @@ jobs:
run: |
$publishDir = "artifacts/smoke-${{ matrix.rid }}"
$blocked = Get-ChildItem -Path $publishDir -Recurse -File | Where-Object {
$_.Name -in @("libSkiaSharp.dll", "libHarfBuzzSharp.dll", "av_libglesv2.dll", "libSkiaSharp.so", "libHarfBuzzSharp.so", "libAvaloniaNative.dylib", "libSkiaSharp.dylib", "libHarfBuzzSharp.dylib")
$_.Name -in @("libSkiaSharp.dll", "libHarfBuzzSharp.dll", "av_libglesv2.dll", "libSkiaSharp.so", "libHarfBuzzSharp.so", "libSkiaSharp.dylib", "libHarfBuzzSharp.dylib")
}
if ($blocked) {
$blocked | ForEach-Object { Write-Error "Unexpected dynamic graphics library: $($_.FullName)" }
+1
View File
@@ -4,3 +4,4 @@ artifacts/
*.nupkg
*.snupkg
External/NativeStatic/.work/
External/AvaloniaNative/.work/
+12
View File
@@ -0,0 +1,12 @@
# StaticLink.Avalonia.Native
Static `AvaloniaNative` libraries for macOS Avalonia NativeAOT publishing.
The package version matches the Avalonia version with a `.1` suffix. For example, use `StaticLink.Avalonia.Native` version `12.1.0.1` with Avalonia `12.1.0`.
```xml
<PackageReference Include="Avalonia" Version="12.1.0" />
<PackageReference Include="StaticLink.Avalonia.Native" Version="12.1.0.1" />
```
The package supports `osx-x64` and `osx-arm64` NativeAOT publishing.
@@ -6,7 +6,7 @@
<IncludeBuildOutput>false</IncludeBuildOutput>
<SuppressDependenciesWhenPacking>false</SuppressDependenciesWhenPacking>
<PackageId>StaticLink.Avalonia.Native</PackageId>
<Version>11.3.14.1</Version>
<Version>0.0.0</Version>
<Authors>greepar</Authors>
<Company>greepar</Company>
<Description>Static AvaloniaNative library for macOS Avalonia NativeAOT publishing.</Description>
@@ -19,14 +19,14 @@
</PropertyGroup>
<ItemGroup>
<None Include="../StaticGraphics/README.md" Pack="true" PackagePath="README.md" />
<None Include="README.md" Pack="true" PackagePath="README.md" />
<None Include="lib/net8.0/_._" Pack="true" PackagePath="lib/net8.0/_._" />
<None Include="buildTransitive/StaticLink.Avalonia.Native.props" Pack="true" PackagePath="buildTransitive/$(PackageId).props" />
<None Include="buildTransitive/StaticLink.Avalonia.Native.targets" Pack="true" PackagePath="buildTransitive/$(PackageId).targets" />
<None Include="buildTransitive/StaticLink.Avalonia.Native.MacOSFontWarmup.cs" Pack="true" PackagePath="buildTransitive/StaticLink.Avalonia.Native.MacOSFontWarmup.cs" />
<None Include="../../External/NativeStatic/osx-x64/native/libAvaloniaNative.a" Condition="Exists('../../External/NativeStatic/osx-x64/native/libAvaloniaNative.a')" Pack="true" PackagePath="static/osx-x64/native/libAvaloniaNative.a" />
<None Include="../../External/NativeStatic/osx-x64/native/macos_font_preinit.o" Condition="Exists('../../External/NativeStatic/osx-x64/native/macos_font_preinit.o')" Pack="true" PackagePath="static/osx-x64/native/macos_font_preinit.o" />
<None Include="../../External/NativeStatic/osx-arm64/native/libAvaloniaNative.a" Condition="Exists('../../External/NativeStatic/osx-arm64/native/libAvaloniaNative.a')" Pack="true" PackagePath="static/osx-arm64/native/libAvaloniaNative.a" />
<None Include="../../External/NativeStatic/osx-arm64/native/macos_font_preinit.o" Condition="Exists('../../External/NativeStatic/osx-arm64/native/macos_font_preinit.o')" Pack="true" PackagePath="static/osx-arm64/native/macos_font_preinit.o" />
<None Include="../../External/AvaloniaNative/osx-x64/native/libAvaloniaNative.a" Pack="true" PackagePath="static/osx-x64/native/libAvaloniaNative.a" />
<None Include="../../External/AvaloniaNative/osx-x64/native/macos_font_preinit.o" Pack="true" PackagePath="static/osx-x64/native/macos_font_preinit.o" />
<None Include="../../External/AvaloniaNative/osx-arm64/native/libAvaloniaNative.a" Pack="true" PackagePath="static/osx-arm64/native/libAvaloniaNative.a" />
<None Include="../../External/AvaloniaNative/osx-arm64/native/macos_font_preinit.o" Pack="true" PackagePath="static/osx-arm64/native/macos_font_preinit.o" />
</ItemGroup>
</Project>
+6
View File
@@ -41,3 +41,9 @@ dotnet publish -c Release -r win-x64 \
Use the RID you need, such as `win-x86`, `linux-x64`, `linux-arm64`, `osx-arm64`, or `osx-x64`.
For macOS, avoid the Metal renderer for fully static output. Use OpenGL or Software.
## Native Package Automation
`.github/workflows/nuget-avalonia-native.yml` runs daily and checks the latest stable `Avalonia` version on NuGet.org. If `StaticLink.Avalonia.Native.<AvaloniaVersion>.1` does not exist, it builds both macOS architectures from the matching Avalonia source tag, runs NativeAOT smoke tests, and publishes the package with NuGet Trusted Publishing.
Configure NuGet.org Trusted Publishing for this repository and the `nuget-avalonia-native.yml` workflow, then add the NuGet.org account name as the repository variable `NUGET_USER`. No long-lived NuGet API key is used by this workflow.
@@ -3,8 +3,8 @@ set -euo pipefail
RID="${RID:-osx-arm64}"
AVALONIA_VERSION="${AVALONIA_VERSION:-11.3.14}"
WORK_DIR="${WORK_DIR:-$PWD/External/NativeStatic/.work}"
OUTPUT_DIR="${OUTPUT_DIR:-$PWD/External/NativeStatic/$RID/native}"
WORK_DIR="${WORK_DIR:-$PWD/External/AvaloniaNative/.work}"
OUTPUT_DIR="${OUTPUT_DIR:-$PWD/External/AvaloniaNative/$RID/native}"
BUILD_JOBS="${BUILD_JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
case "$RID" in
+7 -4
View File
@@ -5,8 +5,7 @@ param(
[Parameter(Mandatory = $true)]
[string]$NuGetSource,
[Parameter(Mandatory = $true)]
[string]$StaticLinkVersion,
[string]$StaticLinkVersion = "",
[string]$AvaloniaVersion = "11.3.14",
@@ -22,6 +21,11 @@ if ($StaticLinkNativeVersion) {
$nativeReference = "`n <PackageReference Include=`"StaticLink.Avalonia.Native`" Version=`"$StaticLinkNativeVersion`" />"
}
$staticLinkReference = ""
if ($StaticLinkVersion) {
$staticLinkReference = "`n <PackageReference Include=`"StaticLink.Avalonia`" Version=`"$StaticLinkVersion`" />"
}
@"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
@@ -52,8 +56,7 @@ if ($StaticLinkNativeVersion) {
<ItemGroup>
<PackageReference Include="Avalonia" Version="$AvaloniaVersion" />
<PackageReference Include="Avalonia.Desktop" Version="$AvaloniaVersion" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="$AvaloniaVersion" />
<PackageReference Include="StaticLink.Avalonia" Version="$StaticLinkVersion" />$nativeReference
<PackageReference Include="Avalonia.Themes.Fluent" Version="$AvaloniaVersion" />$staticLinkReference$nativeReference
</ItemGroup>
</Project>
"@ | Set-Content -Path (Join-Path $ProjectDir "AvaloniaStaticLinkSmoke.csproj") -Encoding UTF8