Skip to content

Commit

Permalink
[dotnet] Point app extensions to any frameworks in the root app bundle.
Browse files Browse the repository at this point in the history
Fixes xamarin#17876.

Put any frameworks in app extensions in the Frameworks directory in the
containing app bundle. This saves a lot of space if the same framework is used
in both an app extension and the containing project (or multiple app
extensions).

Fixes xamarin#17876.
Fixes xamarin#17679.
  • Loading branch information
rolfbjarne committed Sep 1, 2023
1 parent a400d2f commit ab6e20a
Show file tree
Hide file tree
Showing 43 changed files with 827 additions and 1 deletion.
51 changes: 50 additions & 1 deletion dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<UsingTask TaskName="Xamarin.MacDev.Tasks.CompileNativeCode" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.FilterStaticFrameworks" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.FindAotCompiler" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.GetFullPaths" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.InstallNameTool" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.LinkNativeCode" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.MergeAppBundles" AssemblyFile="$(_XamarinTaskAssembly)" />
Expand Down Expand Up @@ -696,8 +697,49 @@
<Output TaskParameter="FrameworkToPublish" ItemName="_FilteredFrameworkToPublish" />
</FilterStaticFrameworks>

<!--
We need to use the full path to the framework for frameworks that
come from app extensions (since any relative paths from the app
extension projects won't be correct once loaded into the
containing project), so compute that. However, also do this for
app projects, so that we can properly deduplicate frameworks that
come from both extensions and the main app project.
-->
<GetFullPaths
Condition="'$(IsMacEnabled)' == 'true'"
SessionId="$(BuildSessionId)"
Items="@(_FilteredFrameworkToPublish)"
Metadata="Identity;SourceDirectory"
>
<Output TaskParameter="Output" ItemName="_FilteredFrameworkToPublishWithFullPath" />
</GetFullPaths>

<!-- If we're an app extension, store the list of all the frameworks to disk (and don't publish any of them to the appex) -->
<!-- Note that app extensions may be nested, so we first check if we have any app extensions with frameworks, read those, then store the full list to disk if we're an app extension, so the containing app project sees everything -->
<ReadItemsFromFile File="@(_ResolvedAppExtensionReferences->'%(Identity)\..\native-frameworks.items')" Condition="Exists('%(Identity)\..\native-frameworks.items')">
<Output TaskParameter="Items" ItemName="_FrameworksFromAppExtensions" />
</ReadItemsFromFile>

<WriteItemsToFile
Condition="'$(IsAppExtension)' == 'true'"
Items="@(_FilteredFrameworkToPublishWithFullPath);@(_FrameworksFromAppExtensions)"
ItemName="_FrameworksFromAppExtensions"
File="$(DeviceSpecificOutputPath)\native-frameworks.items"
IncludeMetadata="true"
Overwrite="true"
/>

<ItemGroup>
<_FrameworksFromAppExtensions Update="@(_FrameworksFromAppExtensions)">
<TargetDirectory>$(_RelativePublishDir)$(_AppBundleFrameworksDir)\%(Filename)%(Extension).framework</TargetDirectory>
</_FrameworksFromAppExtensions>
</ItemGroup>

<ItemGroup>
<_DirectoriesToPublish Include="@(_FilteredFrameworkToPublish)" />
<_DirectoriesToPublish Include="@(_FrameworksFromAppExtensions)" Condition="'$(IsAppExtension)' != 'true'" />
<_DirectoriesToPublish Include="@(_FilteredFrameworkToPublishWithFullPath)" Condition="'$(IsAppExtension)' != 'true'" />
</ItemGroup>
</Target>

Expand Down Expand Up @@ -967,6 +1009,13 @@
<_RuntimeConfigurationFile>runtimeconfig.bin</_RuntimeConfigurationFile>
</PropertyGroup>

<!-- Not sure about how to handle nested app extensions here, but if it ever becomes a problem we can look into it (I believe only watch extensions can have embedded extensions at this point, and we don't support watchOS on .NET anyways) -->
<ItemGroup Condition="'$(IsAppExtension)' == 'true'">
<_CustomLinkFlags Include="-rpath" />
<_CustomLinkFlags Include="@executable_path/../../Frameworks" Condition="'$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS'" />
<_CustomLinkFlags Include="@executable_path/../../../../Frameworks" Condition="'$(_PlatformName)' == 'macOS' Or '$(_PlatformName)' == 'MacCatalyst'" />
</ItemGroup>

<ItemGroup>
<!-- Select the native libraries from mono we need to link with and potentially copy into the app -->
<_MonoLibrary
Expand Down
62 changes: 62 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/GetFullPaths.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

using Xamarin.MacDev.Tasks;
using Xamarin.Messaging.Build.Client;

#nullable enable

namespace Xamarin.MacDev.Tasks {
public class GetFullPaths : XamarinTask, ICancelableTask {
[Required]
public ITaskItem[] Items { get; set; } = Array.Empty<ITaskItem> ();

public string[] Metadata { get; set; } = Array.Empty<string> ();

[Output]
public ITaskItem[] Output { get; set; } = Array.Empty<ITaskItem> ();

public override bool Execute ()
{
if (ShouldExecuteRemotely ())
return new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;

return ExecuteLocally ();
}

public void Cancel ()
{
if (ShouldExecuteRemotely ())
BuildConnection.CancelAsync (BuildEngine4).Wait ();
}

bool ExecuteLocally ()
{
var rv = new List<ITaskItem> ();

foreach (var item in Items) {
var identity = item.ItemSpec;
if (Metadata.Length == 0 || Array.IndexOf (Metadata, "Identity") >= 0)
identity = Path.GetFullPath (identity);
var newItem = new TaskItem (identity);
item.CopyMetadataTo (newItem);
foreach (var md in Metadata) {
if (string.IsNullOrEmpty (md))
continue;
if (md == "Identity")
continue;
newItem.SetMetadata (md, Path.GetFullPath (newItem.GetMetadata (md)));
}
rv.Add (newItem);
}

Output = rv.ToArray ();

return !Log.HasLoggedErrors;
}
}
}
1 change: 1 addition & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.

<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign-bundle.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)native-frameworks.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="@(_IpaPackageFile)" />
</Target>

Expand Down
24 changes: 24 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Runtime.InteropServices;

using Foundation;

namespace MySimpleApp {
public class Program {
[DllImport ("__Internal")]
static extern int getUnknownE ();
[DllImport ("__Internal")]
static extern int getSomewhatUnknownD ();

static int Main (string [] args)
{
GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly

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

return args.Length;
}
}
}
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySimpleApp", "MySimpleApp.csproj", "{23664512-6B06-4135-9A94-C012BDA93CB1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "..\..\ExtensionProject\iOS\ExtensionProject.csproj", "{8A72DB8F-4C30-4462-9F7A-6095E41D5D46}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{23664512-6B06-4135-9A94-C012BDA93CB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23664512-6B06-4135-9A94-C012BDA93CB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23664512-6B06-4135-9A94-C012BDA93CB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23664512-6B06-4135-9A94-C012BDA93CB1}.Release|Any CPU.Build.0 = Release|Any CPU
{8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
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>
1 change: 1 addition & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/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,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySimpleApp", "MySimpleApp.csproj", "{B7C29D40-0079-416C-8507-FE9EE82FBD4F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "..\..\ExtensionProject\macOS\ExtensionProject.csproj", "{C32EB68F-1FF7-42DE-ABD8-C0151497595A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Release|Any CPU.Build.0 = Release|Any CPU
{C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
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
27 changes: 27 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>ExtensionConsumerWithFramework</ApplicationTitle>
<ApplicationId>com.xamarin.extensionconsumerwithframework</ApplicationId>
<RootTestsDirectory Condition="'$(RootTestsDirectory)' == ''">$(MSBuildThisFileDirectory)/../..</RootTestsDirectory>
</PropertyGroup>

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

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\ExtensionProjectWithFrameworks\$(_PlatformName)\ExtensionProjectWithFrameworks.csproj">
<IsAppExtension>true</IsAppExtension>
</ProjectReference>

<!-- Both the extension and the consumer references UnknownE.framework -->
<None Include="$(RootTestsDirectory)/test-libraries/frameworks/.libs/$(RuntimeIdentifier)/UnknownE.framework" CopyToPublishDirectory="PreserveNewest" PublishFolderType="AppleFramework" />
<!-- Only the consumer references SomewhatUnknownD.framework -->
<None Include="$(RootTestsDirectory)/test-libraries/frameworks/.libs/$(RuntimeIdentifier)/SomewhatUnknownD.framework.zip" CopyToPublishDirectory="PreserveNewest" Link="Subfolder/SomewhatUnknownD.bin" PublishFolderType="CompressedAppleFramework" />
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/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,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySimpleApp", "MySimpleApp.csproj", "{D8448FDC-1002-432B-A3A7-CCFCB833F292}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "..\..\ExtensionProject\tvOS\ExtensionProject.csproj", "{CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D8448FDC-1002-432B-A3A7-CCFCB833F292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8448FDC-1002-432B-A3A7-CCFCB833F292}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8448FDC-1002-432B-A3A7-CCFCB833F292}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8448FDC-1002-432B-A3A7-CCFCB833F292}.Release|Any CPU.Build.0 = Release|Any CPU
{CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
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>
1 change: 1 addition & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "ExtensionProject.csproj", "{6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
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>
Loading

0 comments on commit ab6e20a

Please sign in to comment.