Skip to content

Fix tvOS NativeReference targets to split device/simulator frameworks#3563

Merged
mattleibow merged 1 commit intomainfrom
dev/fix-tvos-simulator-native-assets
Mar 15, 2026
Merged

Fix tvOS NativeReference targets to split device/simulator frameworks#3563
mattleibow merged 1 commit intomainfrom
dev/fix-tvos-simulator-native-assets

Conversation

@mattleibow
Copy link
Contributor

Problem

tvOS builds targeting the tvOS Simulator fail at link time with architecture mismatch errors. The native framework included during build is the device framework (arm64 compiled for tvOS), but the simulator expects binaries compiled for the tvOS Simulator platform (x86_64 and/or arm64 with simulator platform tag).

Root Cause

Both IncludeNativeAssets.SkiaSharp.targets and IncludeNativeAssets.HarfBuzzSharp.targets had a single NativeReference for all tvOS builds:

<ItemGroup Condition="$(TargetFramework.Contains('-tvos'))">
  <NativeReference Include="...\output\native\tvos\libSkiaSharp.framework" Kind="Framework" />
</ItemGroup>

This means building for tvossimulator-arm64 or tvossimulator-x86_64 would link against the device framework, which has the wrong Mach-O platform load command (LC_BUILD_VERSION with platform=tvos instead of platform=tvossimulator). The linker rejects this with errors like:

ld: building for tvOS Simulator, but linking in object file built for tvOS

The Fix

Split the tvOS ItemGroup to conditionally select the correct framework based on RuntimeIdentifier, matching the existing iOS pattern exactly:

<ItemGroup Condition="$(TargetFramework.Contains('-tvos')) and '$(RuntimeIdentifier)' != ''">
  <NativeReference Include="...tvossimulator\libSkiaSharp.framework" Kind="Framework"
                   Condition="$(RuntimeIdentifier.StartsWith('tvossimulator'))" />
  <NativeReference Include="...tvos\libSkiaSharp.framework" Kind="Framework"
</ItemGroup>

Why the RuntimeIdentifier != '' guard?

MSBuild evaluates ItemGroup conditions during the outer build (before RID dispatch) when RuntimeIdentifier is empty. Without this guard, both NativeReference items would be evaluated with an empty RID —

This is the same guard used by the iOS targets.

Files Changed

File Change
binding/IncludeNativeAssets.SkiaSharp.targets Split tvOS NativeReference into simulator/device
binding/IncludeNativeAssets.HarfBuzzSharp.targets Same split for HarfBuzzSharp

Comparison with iOS (already correct)

The iOS targets already follow this pattern — this PR simply brings tvOS into alignment:

<ItemGroup Condition="$(TargetFramework.Contains('-ios')) and '$(RuntimeIdentifier)' != ''">
  <NativeReference Include="...iossimulator\libSkiaSharp.framework" Condition="$(RuntimeIdentifier.StartsWith('iossimulator'))" />
</ItemGroup>

Context

This is a companion fix to #3561 which added the tvOS simulator native build pipeline. That PR produces separate tvos/ and tvossimulator/ framework directories — this PR ensures MSBuild selects the right one at build time.

The tvOS ItemGroup in IncludeNativeAssets targets was using a single
NativeReference pointing to the device framework for all tvOS builds.
This caused linker failures when building for the tvOS Simulator
because the device framework contains arm64 binaries compiled for
tvOS, not the x86_64/arm64 binaries compiled for tvOS Simulator.

Split the tvOS NativeReference to match the existing iOS pattern:
- tvossimulator RID → tvossimulator/ framework
- tvos device RID → tvos/ framework
- Guard on RuntimeIdentifier != '' to avoid evaluation during
  outer builds where RID is not yet resolved

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mattleibow mattleibow merged commit 37ae520 into main Mar 15, 2026
1 of 2 checks passed
@mattleibow mattleibow deleted the dev/fix-tvos-simulator-native-assets branch March 15, 2026 19:52
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.

1 participant