-
Notifications
You must be signed in to change notification settings - Fork 621
Description
Summary
The tvOS native build script (native/tvos/build.cake) creates a single fat framework combining device (arm64) and simulator (x86_64) slices into one output/native/tvos/ directory. This differs from the iOS build which correctly separates into ios/ (device) and iossimulator/ (simulator) directories. This causes two problems:
- Missing arm64 simulator build — Apple Silicon Macs run tvOS simulators natively as arm64, but the build only produces an x86_64 simulator slice
- Mixed device/simulator fat binary — Xcode 16+ linkers reject this:
ld: building for 'tvOS-simulator', but linking in dylib built for 'tvOS'
Current Behavior
tvOS build (native/tvos/build.cake)
// Only 2 builds — missing arm64 simulator
Build("appletvsimulator", "x86_64", "x64");
Build("appletvos", "arm64", "arm64");
// Single output directory — mixes device + simulator
DirectoryPath OUTPUT_PATH = MakeAbsolute(ROOT_PATH.Combine("output/native/tvos"));
CreateFatFramework(OUTPUT_PATH.Combine("libSkiaSharp"));Result: output/native/tvos/libSkiaSharp.framework — fat binary with x86_64 (simulator) + arm64 (device) combined, tagged with LC_VERSION_MIN_TVOS (ambiguous platform).
iOS build (native/ios/build.cake) — correct pattern
// 3 builds — includes arm64 simulator
Build("iphonesimulator", "x86_64", "x64");
Build("iphonesimulator", "arm64", "arm64");
Build("iphoneos", "arm64", "arm64");
// Separate output directories
CreateFatFramework(OUTPUT_PATH.Combine("ios/libSkiaSharp")); // device only
CreateFatFramework(OUTPUT_PATH.Combine("iossimulator/libSkiaSharp")); // simulator onlyResult: Two directories with properly tagged binaries.
IncludeNativeAssets.SkiaSharp.targets comparison
iOS correctly distinguishes simulator/device:
<ItemGroup Condition="$(TargetFramework.Contains('-ios')) and '$(RuntimeIdentifier)' != ''">
<NativeReference Include="...\iossimulator\libSkiaSharp.framework" Condition="$(RuntimeIdentifier.StartsWith('iossimulator'))" />
<NativeReference Include="...\ios\libSkiaSharp.framework" Condition="!$(RuntimeIdentifier.StartsWith('iossimulator'))" />
</ItemGroup>tvOS does not:
<ItemGroup Condition="$(TargetFramework.Contains('-tvos'))">
<NativeReference Include="...\tvos\libSkiaSharp.framework" />
</ItemGroup>Expected Behavior
The tvOS build should match the iOS pattern:
native/tvos/build.cake
DirectoryPath OUTPUT_PATH = MakeAbsolute(ROOT_PATH.Combine("output/native"));
Build("appletvsimulator", "x86_64", "x64"); // simulator x86_64 (Intel Macs)
Build("appletvsimulator", "arm64", "arm64"); // simulator arm64 (Apple Silicon Macs) — NEW
Build("appletvos", "arm64", "arm64"); // device arm64
CreateFatFramework(OUTPUT_PATH.Combine("tvos/libSkiaSharp")); // device only
CreateFatFramework(OUTPUT_PATH.Combine("tvossimulator/libSkiaSharp")); // simulator onlyIncludeNativeAssets.SkiaSharp.targets and IncludeNativeAssets.HarfBuzzSharp.targets
<ItemGroup Condition="$(TargetFramework.Contains('-tvos')) and '$(RuntimeIdentifier)' != ''">
<NativeReference Include="...\tvossimulator\..." Condition="$(RuntimeIdentifier.StartsWith('tvossimulator'))" />
<NativeReference Include="...\tvos\..." Condition="!$(RuntimeIdentifier.StartsWith('tvossimulator'))" />
</ItemGroup>Same changes needed for libHarfBuzzSharp in both files.
Reproduction
On an Apple Silicon Mac with Xcode 16+:
dotnet cake --target=externals-download
dotnet build samples/Basic/tvOS/SkiaSharpSample/SkiaSharpSample.csproj \
-f net8.0-tvos -p:IsNetTVOSSupported=trueError:
ld: building for 'tvOS-simulator', but linking in dylib (.../output/native/tvos/libSkiaSharp.framework/libSkiaSharp) built for 'tvOS'
clang++: error: linker command failed with exit code 1
Workaround
Re-tag the binary platform with vtool:
mkdir -p output/native/tvossimulator/libSkiaSharp.framework
lipo output/native/tvos/libSkiaSharp.framework/libSkiaSharp -thin arm64 -output /tmp/tvos_arm64.dylib
vtool -set-build-version 8 11.0 17.5 -replace -output /tmp/tvossim_arm64.dylib /tmp/tvos_arm64.dylib
# platform 8 = TVOSSIMULATOR
cp /tmp/tvossim_arm64.dylib output/native/tvossimulator/libSkiaSharp.framework/libSkiaSharp
codesign -f -s - output/native/tvossimulator/libSkiaSharp.framework/libSkiaSharpFiles to Change
native/tvos/build.cake— Add arm64 simulator build, split output intotvos/andtvossimulator/binding/IncludeNativeAssets.SkiaSharp.targets— Add RuntimeIdentifier-based tvos/tvossimulator splitbinding/IncludeNativeAssets.HarfBuzzSharp.targets— Same splitscripts/azure-templates-stages-native-macos.yml— May need updating if CI artifact paths change
Environment
- macOS on Apple Silicon (arm64)
- Xcode 16+ (strict linker platform checking)
- .NET 8 with tvOS workload
- Current: only x86_64 simulator + arm64 device in single fat binary
- Needed: x86_64 simulator + arm64 simulator + arm64 device in separate directories
Metadata
Metadata
Assignees
Labels
Type
Projects
Status