Skip to content

Update to .NET 10 SDK with workload version set pinning#3514

Merged
mattleibow merged 95 commits into
mainfrom
update/dotnet-10
Mar 13, 2026
Merged

Update to .NET 10 SDK with workload version set pinning#3514
mattleibow merged 95 commits into
mainfrom
update/dotnet-10

Conversation

@mattleibow

@mattleibow mattleibow commented Feb 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Upgrade SkiaSharp from .NET 8 SDK to .NET 10 SDK. Updates the build system, CI pipelines, TFM architecture, workload management, samples, and test infrastructure.

89 files changed, 606 insertions, 367 deletions

TFM Architecture Change

Restructured from Previous/Current/Next to Base/Previous/Current:

Property Before (net8) After (net10) Purpose
TFMBase (did not exist) net6.0 Class libraries only (netstandard replacement)
TFMPrevious net6.0 net9.0 Previous platform-supported TFM
TFMCurrent net8.0 net10.0 Current platform-supported TFM
TFMNext (conditionally net9) (removed) No longer needed

Platform TFMs only support two versions (current + previous), so Next was eliminated. Base was added for class library TFMs (net6.0) that aren't tied to platform workloads.

Third-Party Platform Versions (TPVs)

Platform Previous Current
Android 35.0 36.0
iOS 18.0 26.2
Mac Catalyst 18.0 26.2
tvOS 18.0 26.2
macOS 15.0 26.2
Tizen 8.0 10.0
Windows 10.0.19041.0 10.0.19041.0

Workload Management — Workload Version Sets

Replaced ad-hoc manifest mode and --skip-manifest-update workarounds with deterministic workload version set pinning.

Key changes in scripts/install-dotnet-workloads.ps1:

  • WorkloadSetVersion is now a mandatory parameter
  • Official workloads install with dotnet workload install --version <version> for deterministic resolution
  • Tizen installs separately — it's a Samsung third-party workload not included in any official workload set
  • DOTNET_WORKLOAD_VERSION pipeline variable (10.0.104) centralizes the version
  • No global.json workloadVersion — only CI is pinned, developers use whatever they have installed

SDK Pinning

global.json updated:

  • SDK 8.0.10010.0.100
  • rollForward: latestMinorlatestFeature
  • latestFeature allows any 10.0.xxx feature band (e.g., 10.0.102, 10.0.201), which is necessary because CI environments have different SDK versions (Docker images use 10.0.201, Windows agents install 10.0.103)

CI Pipeline Changes

SDK & Tooling

  • .NET SDK: 8.0.30410.0.103 (via DOTNET_VERSION variable)
  • Xcode: 15.426.2 (managed builds), 15.416.2 (native builds)
  • Docker images: dotnet/sdk:8.0dotnet/sdk:10.0
  • xharness CLI: 9.0.0-prerelease.24317.311.0.0-prerelease.26107.1
  • Emscripten: 3.1.343.1.56
  • Android test API level: 3436
  • iOS simulator: 17.226.2
  • macOS build agents: macos-14macos-15
  • Android tests: moved from macOS to Linux agents (better emulator support)

Removed / Cleaned Up

  • DOTNET_VERSION_PREVIEW variable and conditional preview SDK install step
  • DOTNET_WORKLOAD_SOURCE manifest URL — replaced by workload version sets
  • installPreviewVs parameter and the conditional Visual Studio install block
  • Old NuGet feeds (dotnet6, dotnet7, dotnet8, test-device-runners) from nuget.config
  • Manifest mode workarounds (--skip-manifest-update, dotnet workload config --update-mode manifests)

Android Emulator (Linux)

  • Set ANDROID_AVD_HOME and ANDROID_EMULATOR_HOME via ##vso[task.setvariable] in YAML to fix XDG path mismatch (~/.config/.android/avd/ vs ~/.android/avd/)

Package Updates

Build & Test

  • xunit/xunit.extensibility.core/xunit.runner.utility: 2.4.2 → 2.9.3
  • xunit.runner.visualstudio: 2.4.5 → 2.8.2
  • Microsoft.TypeScript.MSBuild: 5.7.1 → 5.9.3
  • DeviceRunners.*: 0.1.0-preview.1 → 0.1.0-preview.6
  • Uno.Sdk: 5.2.175 → 6.5.31

TypeScript Build Fix (Blazor)

Replaced TypeScriptCompileBlocked with per-TFM TypeScriptOutDir:

<TypeScriptOutDir>$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/ts</TypeScriptOutDir>

Root cause: multi-TFM parallel builds would delete/rewrite shared wwwroot/*.js files via TypeScriptDeleteOutputFromOtherConfigs while another TFM's StaticWebAssets.Compression was reading them. Redirecting TypeScript output to a per-TFM intermediate directory + <Content> items resolves the race.

Workarounds Required for .NET 10

  1. TypeScriptOutDir per-TFM — Blazor multi-TFM build race condition (see above)
  2. SKColorSpaceStructsTest precision — Assert.Equal(expected, actual, 5) → 4 decimal places for float rounding differences
  3. WASM P/Invoke return type — changed uintint to match binding declaration
  4. Apple TPV numbering — iOS/macOS/tvOS jumped from 18.x to 26.x (aligned with Xcode version numbers in Xcode 26)

Samples

  • MAUI: Removed Platforms/Tizen/ folder (Tizen MAUI no longer supported), removed UseMauiCompatibility
  • Uno Platform: Updated to Uno 6.5, migrated SkiaHostBuilderUnoPlatformHostBuilder, added solution filters
  • iOS/macOS/tvOS: Updated SupportedOSPlatformVersion minimums to match new TPVs
  • All samples: TFM updates from net8 → net10/net9 as appropriate

Documentation

  • New: documentation/updating-dotnet-version.md — step-by-step guide for future .NET version upgrades

Known Issues

  • SKBitmapThreadingTest.ImageScalingMultipleThreadsTest(100, 1000) — pre-existing flaky OOM on CI (also fails on main). The test intentionally avoids disposal to stress-test GC finalization across 100 threads × 1000 iterations, which exhausts memory on constrained CI agents.

- Pin SDK to 10.0.103 with workload sets in global.json
- Restructure TFMs: TFMBase=net6.0, TFMPrevious=net9.0, TFMCurrent=net10.0
- Remove TFMNext and all associated conditional blocks
- Remove MAUI TPV workaround (dotnet/maui#24263 fixed in .NET 9+)
- Update all 14 NativeAssets csproj files to TFMPrevious+TFMCurrent pattern
- Update platform TPVs for .NET 9 (Previous) and .NET 10 (Current)
- Replace workload install script with dotnet workload restore + Tizen
- Remove DOTNET_VERSION_PREVIEW and preview SDK install step
- Update pipeline variables: SDK 10.0.103, Xcode 16.2, Emscripten 3.1.56
- Update Blazor csproj with net10.0 PackageReference
- Update all sample, test, utility, and cake files
- Clean up NuGet.config (remove old preview feeds)
- Add documentation/updating-dotnet-version.md upgrade checklist
- global.json: Use 10.0.100 with latestPatch so any 10.0.1xx SDK satisfies
  the constraint (CI agents have 10.0.102, not 10.0.103)
- All Dockerfiles: Update from .NET 8 to .NET 10 SDK
  - WASM: mcr.microsoft.com/dotnet/sdk:8.0 → 10.0
  - Linux/Alpine: DOTNET_SDK_VERSION=8.0 → 10.0
The workloadVersion field causes native builds (WinUI, etc.) to fail when
the pre-installed SDK version doesn't match the pinned workload version.
Native builds skip the SDK/workload install step but still need dotnet.

Managed builds get workloads via 'dotnet workload restore' which uses
the SDK's bundled manifests — no global.json pin needed.
dotnet workload restore requires a project/solution file but there is
none in the repo root. Revert to explicit dotnet workload install with
the specific workload IDs needed by the repo.
- Add DOTNET_WORKLOAD_VERSION variable (10.0.103) to azure-templates-variables.yml
- Pass to install-dotnet-workloads.ps1 via -WorkloadVersion parameter
- Script uses 'dotnet workload install --version' for reproducible workload sets
- Keep global.json clean (no workloadVersion) so native builds aren't affected
- Update documentation to reflect new approach
- Update DOTNET_WORKLOAD_TIZEN to 10.0.123 (latest available for 10.0.100 band)
- Pass --dotnet-target-version-band 10.0.100 to Samsung's install scripts
  since their LatestVersionMap doesn't have .NET 10 entries yet
.NET 10 Apple workloads use Xcode 26 unified SDK versioning:
- iOS/MacCatalyst/tvOS/macOS TPV: 18.0/15.0 → 26.0

SupportedOSPlatformVersion minimums bumped in .NET 9/10 workloads:
- iOS/tvOS: 10.0 → 12.2
- MacCatalyst: 13.1 → 15.0
- macOS: 10.14 → 12.0
The Samsung Tizen workload must be installed before 'dotnet workload install
--version' locks the SDK into workload-set mode. Reorder to install Tizen
first via Samsung scripts, then official workloads with version pinning.
…or device tests

- Remove --version from dotnet workload install to avoid workload-set mode
  which makes the SDK ignore Samsung Tizen manifests installed separately
- Update WindowsSdkPackageVersion from 10.0.19041.27 to 10.0.19041.38
  (required by WindowsAppSDK 1.7)
- Add explicit TPVs to MauiTargetFrameworksApp* (26.0 for Apple, 36.0 for
  Android) to avoid resolving to default TPV 26.2 which requires Xcode 26.2
- Update build.cake device test TFMs to match TPV-qualified forms
- Remove unused DOTNET_WORKLOAD_VERSION pipeline variable
- Force manifest update mode with 'dotnet workload config --update-mode
  manifests' before installing workloads. .NET 10 SDK auto-switches to
  workload-set mode which ignores Samsung Tizen manifests.
- Use --skip-manifest-update to prevent official workload install from
  downloading a workload set and overriding manifest mode.
- Install Tizen AFTER official workloads (order doesn't matter in manifest mode).
- Use net9.0 TFMs for iOS/MacCatalyst device tests because net10.0 Apple
  SDK packs (both 26.0 and 26.2) require Xcode 26.0+ which CI doesn't have.
- Add Previous TFMs to device test project so net9.0 builds are available.
Debug Tizen install: show manifest directory contents and dotnet
workload list before and after official workload install to understand
why Samsung.Tizen FrameworkReference is not recognized.
- Set buildExternals default to 155857 to skip native rebuilds
- SkiaSharp.Tests: Add TFMPrevious so device tests can reference it
  from net9.0 TFMs (NU1201: not compatible)
- SkiaSharp.Tests.Devices: Bump MacCatalyst min to 15.0 (workload minimum)
Tizen SDK 10.0.123 only defines KnownFrameworkReference for TPV 8.0+.
TPV 7.0 is listed as supported but has no Samsung.Tizen framework ref,
causing NETSDK1073 'Samsung.Tizen was not recognized'.
- Remove --skip-manifest-update from official workload install:
  The flag prevented downloading manifests, so workloads had nothing
  to install (empty 'Successfully installed workload(s) .' output).
- Fix WASM AOT P/Invoke type conflict: Test used int/int signature
  for hb_script_get_horizontal_direction but binding uses uint/Direction.
  .NET 10 WASM AOT compiler flags this as a C-level type conflict.
The HarfBuzzSharp binding declares Direction as int-backed enum with
uint32_t parameter. The test must match: int32_t return, uint32_t param.
Previous fix incorrectly used uint32_t for both.
MAUI 10.0.0 dropped Tizen support entirely - the NuGet package has no
net10.0-tizen* assemblies. Samsung Tizen 10.0.123 workload removed
KnownFrameworkReference for TPV 7.0 (needed by MAUI 9.0), making
net9.0-tizen7.0 MAUI builds impossible too.

Non-MAUI Tizen support (NativeAssets, bindings) still works with
net9.0-tizen8.0 and net10.0-tizen10.0.
- Remove Microsoft.Maui.Controls.Compatibility.Hosting from MAUI sample
  (namespace removed in MAUI 10.0)
- Remove Tizen from MAUI sample TargetFrameworks (MAUI 10 dropped Tizen)
- Update Tizen sample tizen-manifest.xml api-version to 13 (matches
  TPV 10.0 → API level 13 in Samsung SDK 10.0.123)
- Update Apple ref package names in UpdateDocs.cake for TPV 26.0
…e sample TFMs

- Block TypeScript recompilation in Blazor csproj to fix .NET 10 static web
  assets compression race condition (TypeScriptCompileBlocked=true)
- Update VERSIONS.txt: Apple ref pack names from net8.0_17.0 to net10.0_26.0,
  MAUI versions from 8.0.3 to 10.0.31, tvOS ref pack name updated
- Switch Apple sample apps (iOS, MacCatalyst, MAUI, Uno) to net9.0 TFMs since
  net10.0 Apple TFMs require Xcode 26.0+ (CI has Xcode 16.2)
With the .NET 10 SDK, bare net9.0-ios resolves to TPV 26.0 (not 18.0),
which requires Xcode 26.0. Explicit TPVs (net9.0-ios18.0, net9.0-maccatalyst18.0)
are needed to match the Xcode 16.2 available on CI.
iOS SDK 18.0 requires minimum SupportedOSPlatformVersion of 12.2.
The truncation-based comparison with (int)(v * pow) / pow doesn't
handle negative values correctly near precision boundaries.
For example, -4.9999995 truncates to -4.9999 (not -5.0), causing
false test failures.

This became apparent with .NET 9+ which changed Matrix4x4.CreateFromAxisAngle
to go through Quaternion, producing slightly different floating-point results.

Using Math.Round() is the correct approach for floating-point similarity
comparison.
- Add Apple TPV 26.0 unified SDK versioning note
- Add SupportedOSPlatformVersion section
- Add global.json rollForward and workloadVersion warnings
- Add Docker images section
- Add Known Issues section (floating-point precision, Apple TPVs, MAUI breaking changes)
- Add CI Troubleshooting section (artifact reuse, SDK mismatch, workload install)
- Update workload pinning explanation
- nuget.org is disallowed in CI, must be removed before merging
- buildExternals must be reset to 'latest' before merging
- Add note about temporarily adding nuget.org during development
mattleibow and others added 6 commits March 11, 2026 20:11
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move ANDROID_AVD_HOME/EMULATOR_HOME setup from cake to YAML pipeline
  (fixes XDG path mismatch on Linux CI agents)
- Remove nuget.org from nuget.config (was temporary workaround)
- Remove manifest mode override from workload install script
  (use default workload version sets now that .NET 10 packages are published)
- Simplify config.ini partition size code to use ANDROID_AVD_HOME env var

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread scripts/azure-pipelines-complete.yml Outdated
displayName: 'The Build ID containing the specific native artifacts to use:'
type: string
default: 'latest'
default: '155848'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to change this to be hard coded?

mattleibow and others added 8 commits March 11, 2026 21:12
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Workload-set mode resolves to 10.0.104 which requires packages
(e.g. microsoft.macos.sdk.net9.0_26.2 v26.2.9000) not yet mirrored
to the dnceng feeds. Manifest mode uses the SDK's bundled manifests
which only reference packages available at SDK release time.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Even in manifest mode, dotnet workload install tries to update manifests
which resolves to packages (e.g. microsoft.ios.windows.sdk.net9.0_26.2
v26.2.9000) not available in the dnceng feeds. --skip-manifest-update
forces use of the SDK's bundled manifests only.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The missing packages just need mirroring to dnceng, not a workaround.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pass --version to dotnet workload install on CI to pin all agents to the
same workload set. This keeps developer machines unaffected (no global.json
workloadVersion) while ensuring CI builds are deterministic.

- Add -WorkloadSetVersion parameter to install-dotnet-workloads.ps1
- Add DOTNET_WORKLOAD_VERSION variable in azure-templates-variables.yml
- Pass the version through azure-templates-jobs-bootstrapper.yml

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
XHarness already disables the package verifier internally before
installing APKs. The 'android adb' subcommand doesn't exist in the
current dotnet-android tool, causing 'Unknown command' errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The test creates 4 native Skia objects per iteration (bitmap,
scaledBitmap, image, data) across 100 threads × 1000 iterations
(400K allocations) but never disposed them, relying solely on
GC finalization every 500ms. On CI agents with limited memory,
the GC couldn't keep up, causing 'Unable to allocate pixels'.

Add using declarations to all native objects so memory is released
deterministically. The test still validates threading correctness
(concurrent decode/scale/encode) while the GC background task
remains as additional stress.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mattleibow mattleibow changed the title Update to .NET 10 SDK and restructure TFMs Update to .NET 10 SDK with workload version set pinning Mar 12, 2026
mattleibow and others added 6 commits March 12, 2026 11:38
Remove the TypeScriptCompileBlocked workaround in the Blazor project and
instead redirect TypeScript output to per-TFM intermediate directories
using TypeScriptOutDir. This eliminates the multi-TFM race condition
where parallel builds would delete/rewrite shared wwwroot/*.js files
while another TFM's static web asset compression reads them.

The compiled JS still goes to obj/<Config>/<TFM>/ts/ per-TFM while the
checked-in wwwroot/*.js files remain the source-of-truth for static web
assets. TypeScript compilation now validates the .ts source on every
build instead of being blocked entirely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The --partition-size flag alone doesn't override the system image's
default userdata partition size. API 36 requires 7373 MB by default,
but CI agents only have ~6.5 GB free after build artifacts download.
The emulator starts in a degraded state (FATAL: not enough space) and
crashes during APK install with 'device offline'.

Restore the config.ini approach (disk.dataPartition.size=2048M) in
addition to the --partition-size flag, and log the full config.ini
contents for debugging.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The pinned build ID 155848 was used during development to speed up
CI iterations. Now that native builds are passing, revert to 'latest'
so the pipeline always uses the most recent native artifacts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Local testing confirmed that:
- `--partition-size` acts as a floor: max(flag, system_image_default)
- API 36 system images already default to 6+ GB data partitions
- Setting config.ini disk.dataPartition.size is overwritten by the emulator
- Both the config.ini hack and --partition-size 2048 were no-ops

The INSTALL_FAILED_INSUFFICIENT_STORAGE issue was likely caused by the
emulator being offline, not by partition size.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Docker images for Linux/WASM builds have SDK 10.0.201 (feature band 2).
The previous pin to 10.0.100 with latestPatch only allowed 10.0.1xx,
causing all Linux and WASM native builds to fail with SDK not found.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Windows ANGLE agents have 10.0.102, Linux Docker images have 10.0.201.
Using 10.0.100 as the base version with latestFeature allows any 10.0.xxx
feature band to satisfy the requirement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mattleibow
mattleibow merged commit 58a1a73 into main Mar 13, 2026
1 of 2 checks passed
@mattleibow
mattleibow deleted the update/dotnet-10 branch March 13, 2026 14:34
mattleibow added a commit that referenced this pull request Apr 29, 2026
Restores the original intent of MauiTargetFrameworksApp from commit
40b0f57 — app TFMs should have no TPV so they use whatever workload
is installed. The TPVs were accidentally added in 58a1a73 (#3514).

Windows keeps the TPV since it's a Windows SDK version, not a workload.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mattleibow added a commit that referenced this pull request Apr 30, 2026
…#3798)

Fix Apple platform TFMs: use 26.0 for libraries, unversioned for apps (#3798)

Fixes: #3514 (regression)

The .NET 10 upgrade in #3514 set the Apple Target Platform Versions to
26.2 (matching the CI's Xcode version) instead of 26.0 (the base Xcode 26
unified SDK version). This caused library NuGet packages to ship with
TFMs like `net10.0-ios26.2`, forcing consumers to install Xcode 26.2
rather than accepting any 26.x workload.

The same PR also accidentally added explicit TPVs to the
`MauiTargetFrameworksApp` properties, which were originally introduced
in 40b0f57 with no TPV so that apps pick up whatever workload is
installed on the build machine.

The fix splits the versioning strategy:

  * Libraries pin to the `.0` TPV (`net10.0-ios26.0`) for maximum
    compatibility — consumers need only the base workload.
  * Apps (test devices, samples) use unversioned TFMs (`net10.0-ios`)
    so they build against whatever Xcode is on the CI agent or dev
    machine, avoiding SDK/Xcode version mismatches.

Files changed:

  * `source/SkiaSharp.Build.props` — Apple TPVs 26.2 → 26.0;
    `MauiTargetFrameworksApp` restored to unversioned
  * `build.cake` — test task TFMs to unversioned
  * `scripts/VERSIONS.txt` — ref pack names and versions to 26.0
  * `scripts/cake/UpdateDocs.cake` — ref pack package names to 26.0

Verified: all 15 Apple-platform NuGet packages contain `26.0` TFMs.
iOS and Mac Catalyst CI tests pass with Xcode 26.2 installed.

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mattleibow added a commit that referenced this pull request May 29, 2026
Fix WinUI Projection DLL not resolved for .NET 9 consumers on Windows (#4084)

Fixes: #4082

When TFMCurrent moved from net8.0 to net10.0 (in #3514), the
`NativeAssetPackageFile` entries in `SkiaSharp.NativeAssets.WinUI.csproj`
placed `SkiaSharp.Views.WinUI.Native.Projection.dll` only into:

    runtimes/win-{arch}/lib/net10.0-windows10.0.19041.0/

NuGet's TFM resolution algorithm won't serve a net10.0 runtime asset to a
net9.0 consumer — higher TFMs are not backward-compatible. .NET 9 apps hit
a `FileNotFoundException` at startup:

    Could not load file or assembly
    'SkiaSharp.Views.WinUI.Native.Projection, ...'

In v3.119.2 (TFMCurrent=net8.0) this worked because the DLL landed in
`lib/net8.0-windows.../`, which both net8 and net9 consumers could resolve.

Include the Projection DLL in both `$(WindowsTargetFrameworksCurrent)` and
`$(WindowsTargetFrameworksPrevious)` folders so NuGet serves it regardless
of whether the consuming app targets net9 or net10. The DLL itself is built
targeting net9.0-windows and is binary-compatible with both. Size overhead
is ~25 KB × 3 RIDs — negligible against the ~450 MB package.

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants