Skip to content

Commit

Permalink
[msbuild/dotnet] Add support for compressed xcframeworks in binding p…
Browse files Browse the repository at this point in the history
…rojects and as NativeReference items. Fixes #21294.

Now it's possible to reference a compressed xcframework like this:

```xml
<NativeReference Include="path/to/myframework.xcframework.zip" />
```

This makes it easier to work with xcframeworks on Windows, because
xcframeworks can contain symlinks, and by zipping them up the whole symlink
problem is avoided.

Turns out there's already a NuGet that adds a .xcframework.zip file as a
NativeReference (Microsoft.ML.OnnxRuntime), so this makes that NuGet work.

Fixes #21294.
Fixes #21450.
  • Loading branch information
rolfbjarne committed Oct 22, 2024
1 parent 99250b6 commit 2d5829a
Show file tree
Hide file tree
Showing 42 changed files with 455 additions and 20 deletions.
36 changes: 21 additions & 15 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/ResolveNativeReferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,10 @@ static bool TryGetSidecarManifest (TaskLoggingHelper log, string resources, [Not
/// <returns>True if the Info.plist was found and successfully parsed.</returns>
static bool TryGetInfoPlist (TaskLoggingHelper log, string resourcePath, string xcframework, [NotNullWhen (true)] out PDictionary? plist)
{
var manifestPath = Path.Combine (xcframework, "Info.plist");
using var stream = CompressionHelper.TryGetPotentiallyCompressedFile (log, resourcePath, manifestPath);
var isCompressedXcframework = CompressionHelper.IsCompressed (xcframework);
var potentiallyCompressedFile = isCompressedXcframework ? Path.Combine (resourcePath, xcframework) : resourcePath;
var manifestPath = Path.Combine (isCompressedXcframework ? Path.GetFileNameWithoutExtension (xcframework) : xcframework, "Info.plist");
using var stream = CompressionHelper.TryGetPotentiallyCompressedFile (log, potentiallyCompressedFile, manifestPath);
if (stream is null) {
plist = null;
return false;
Expand Down Expand Up @@ -305,14 +307,11 @@ void ProcessSidecar (ITaskItem r, string resources, List<ITaskItem> native_frame
foreach (XmlNode referenceNode in document.GetElementsByTagName ("NativeReference")) {
ITaskItem t = new TaskItem (r);
var name = referenceNode.Attributes ["Name"].Value.Trim ('\\', '/');
switch (Path.GetExtension (name)) {
case ".xcframework": {
if (name.EndsWith (".xcframework", StringComparison.Ordinal) || name.EndsWith (".xcframework.zip", StringComparison.Ordinal)) {
if (!TryResolveXCFramework (Log, TargetFrameworkMoniker, SdkIsSimulator, Architectures, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out var nativeLibraryPath))
continue;
SetMetadataNativeLibrary (t, nativeLibraryPath);
break;
}
case ".framework": {
} else if (name.EndsWith (".framework", StringComparison.Ordinal)) {
string? frameworkPath;
if (!isCompressed) {
frameworkPath = Path.Combine (resources, name);
Expand All @@ -323,9 +322,8 @@ void ProcessSidecar (ITaskItem r, string resources, List<ITaskItem> native_frame
t.SetMetadata ("Kind", "Framework");
t.SetMetadata ("PublishFolderType", "AppleFramework");
t.SetMetadata ("RelativePath", Path.Combine (FrameworksDirectory, Path.GetFileName (Path.GetDirectoryName (t.ItemSpec))));
break;
}
case ".dylib": // macOS
} else if (name.EndsWith (".dylib", StringComparison.Ordinal)) {
// macOS
string? dylibPath;
if (!isCompressed) {
dylibPath = Path.Combine (resources, name);
Expand All @@ -335,8 +333,8 @@ void ProcessSidecar (ITaskItem r, string resources, List<ITaskItem> native_frame
t.ItemSpec = dylibPath;
t.SetMetadata ("Kind", "Dynamic");
t.SetMetadata ("PublishFolderType", "DynamicLibrary");
break;
case ".a": // static library
} else if (name.EndsWith (".a", StringComparison.Ordinal)) {
// static library
string? aPath;
if (!isCompressed) {
aPath = Path.Combine (resources, name);
Expand All @@ -346,11 +344,9 @@ void ProcessSidecar (ITaskItem r, string resources, List<ITaskItem> native_frame
t.ItemSpec = aPath;
t.SetMetadata ("Kind", "Static");
t.SetMetadata ("PublishFolderType", "StaticLibrary");
break;
default:
} else {
Log.LogWarning (MSBStrings.W7105 /* Unexpected extension '{0}' for native reference '{1}' in binding resource package '{2}'. */, Path.GetExtension (name), name, r.ItemSpec);
t = r;
break;
}

// defaults
Expand Down Expand Up @@ -419,6 +415,16 @@ public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFr
if (!TryResolveXCFramework (log, plist, xcframeworkPath, targetFrameworkMoniker, isSimulator, architectures!, cancellationToken, out var nativeLibraryRelativePath))
return false;

if (!isCompressed && CompressionHelper.IsCompressed (xcframework)) {
var zipPath = Path.Combine (resourcePath, xcframework);
var xcframeworkName = Path.GetFileNameWithoutExtension (xcframework);
if (!CompressionHelper.TryDecompress (log, zipPath, xcframeworkName, intermediateDecompressionDir, createdFiles, cancellationToken, out var decompressedXcframeworkPath))
return false;

nativeLibraryPath = Path.Combine (intermediateDecompressionDir, xcframeworkName, nativeLibraryRelativePath);
return true;
}

if (!isCompressed) {
nativeLibraryPath = Path.Combine (resourcePath, xcframework, nativeLibraryRelativePath);
return true;
Expand Down
4 changes: 2 additions & 2 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ Copyright (C) 2018 Microsoft. All rights reserved.
-->
<Target Name="_ExpandNativeReferences" Condition="'$(DesignTimeBuild)' != 'true'" DependsOnTargets="_DetectSdkLocations;_ComputeTargetArchitectures;_GenerateBundleName;_SanitizeNativeReferences">
<ItemGroup>
<_XCFrameworkNativeReference Include="@(NativeReference -> '%(Identity)/.')" Condition="'%(Extension)' == '.xcframework'" />
<_XCFrameworkNativeReference Include="@(NativeReference -> '%(Identity)/.')" Condition="'%(Extension)' == '.xcframework' Or $([MSBuild]::ValueOrDefault('%(FileName)%(Extension)', '').EndsWith('.xcframework.zip'))" />
<_FrameworkNativeReference Include="@(NativeReference -> '%(Identity)/%(Filename)')" Condition="'%(Extension)' == '.framework'" />
<_FileNativeReference Include="@(NativeReference)" Condition="'%(Extension)' != '.framework' And '%(Extension)' != '.xcframework'" />
<_FileNativeReference Include="@(NativeReference)" Condition="'%(Extension)' != '.framework' And '%(Extension)' != '.xcframework' And '%(Extension)' != '.zip'" />
</ItemGroup>
<ResolveNativeReferences
SessionId="$(BuildSessionId)"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
using Foundation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
8 changes: 8 additions & 0 deletions tests/dotnet/BindingWithCompressedXCFramework/MyClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;
namespace BindingWithCompressedXCFramework {
public class MyClass {
public MyClass ()
{
}
}
}
16 changes: 16 additions & 0 deletions tests/dotnet/BindingWithCompressedXCFramework/StructsAndEnums.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Runtime.InteropServices;

namespace BindingWithCompressedXCFramework {
public static class CFunctions {
[DllImport ("XTest.framework/XTest")]
static extern int theUltimateAnswer ();

// This comes from XStaticArTest.framework
[DllImport ("__Internal")]
static extern int ar_theUltimateAnswer ();

// This comes from XStaticObjectTest.framework
[DllImport ("__Internal", EntryPoint = "theUltimateAnswer")]
static extern int object_theUltimateAnswer ();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

1 change: 1 addition & 0 deletions tests/dotnet/BindingWithCompressedXCFramework/iOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
16 changes: 16 additions & 0 deletions tests/dotnet/BindingWithCompressedXCFramework/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<IsBindingProject>true</IsBindingProject>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<ObjcBindingApiDefinition Include="../ApiDefinition.cs" />
<ObjcBindingCoreSource Include="../StructsAndEnums.cs" />
<NativeReference Include="../../../test-libraries/.libs/XTest.xcframework.zip" Kind="Framework" />
<NativeReference Include="../../../test-libraries/.libs/XStaticArTest.xcframework.zip" Kind="Static" />
<NativeReference Include="../../../test-libraries/.libs/XStaticObjectTest.xcframework.zip" Kind="Static" />
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/BindingWithCompressedXCFramework/shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../../..
include $(TOP)/tests/common/shared-dotnet.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Runtime.InteropServices;

using Foundation;

namespace NativeFrameworkReferencesApp {
public class Program {
[DllImport ("XTest.framework/XTest")]
static extern int theUltimateAnswer ();

// This comes from XStaticArTest.framework
[DllImport ("__Internal")]
static extern int ar_theUltimateAnswer ();

// This comes from XStaticObjectTest.framework
[DllImport ("__Internal", EntryPoint = "theUltimateAnswer")]
static extern int object_theUltimateAnswer ();

static int Main (string [] args)
{
Console.WriteLine ($"XCFramework: {theUltimateAnswer ()}");
Console.WriteLine ($"XCFramework with ar files: {ar_theUltimateAnswer ()}");
Console.WriteLine ($"XCFramework with object files: {object_theUltimateAnswer ()}");

GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly

Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));

return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>CompressedNativeXCFrameworkReferencesApp</ApplicationTitle>
<ApplicationId>com.xamarin.compressednativexcframeworkreferencesapp</ApplicationId>
<ApplicationVersion>1.0</ApplicationVersion>

<UseIntepreter>true</UseIntepreter> <!-- speed up the test -->
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<NativeReference Include="..\..\..\test-libraries\.libs\XTest.xcframework.zip" Kind="Framework" />
<NativeReference Include="..\..\..\test-libraries\.libs\XStaticArTest.xcframework.zip" Kind="Static" />
<NativeReference Include="..\..\..\test-libraries\.libs\XStaticObjectTest.xcframework.zip" Kind="Static" />
</ItemGroup>

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TOP=../../../..
TESTNAME=CompressedNativeXCFrameworkReferencesApp
include $(TOP)/tests/common/shared-dotnet.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Runtime.InteropServices;

using Foundation;

namespace NativeFrameworkReferencesApp {
public class Program {
[DllImport ("XTest.framework/XTest")]
static extern int theUltimateAnswer ();

// This comes from XStaticArTest.framework
[DllImport ("__Internal")]
static extern int ar_theUltimateAnswer ();

// This comes from XStaticObjectTest.framework
[DllImport ("__Internal", EntryPoint = "theUltimateAnswer")]
static extern int object_theUltimateAnswer ();

static int Main (string [] args)
{
Console.WriteLine ($"XCFramework: {theUltimateAnswer ()}");
Console.WriteLine ($"XCFramework with ar files: {ar_theUltimateAnswer ()}");
Console.WriteLine ($"XCFramework with object files: {object_theUltimateAnswer ()}");

GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly

Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));

return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>CompressedXCFrameworkInBindingProjectApp</ApplicationTitle>
<ApplicationId>com.xamarin.compressedxcframeworkinbindingprojectapp</ApplicationId>
<ApplicationVersion>1.0</ApplicationVersion>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<ProjectReference Include="..\..\BindingWithCompressedXCFramework\$(_PlatformName)\BindingWithCompressedXCFramework.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TOP=../../../..
TESTNAME=CompressedXCFrameworkInBindingProjectApp
include $(TOP)/tests/common/shared-dotnet.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Loading

0 comments on commit 2d5829a

Please sign in to comment.