[dotnet] Add support for consuming binding projects. (#9376)

* Port the interdependent-binding-projects test to .NET (it's the simplest
  test project we have with binding projects).
* Add a lot of the shared source code for mtouch/mmp to dotnet-linker, and
  make it compile. Most issues were fixed by adding a few stubbed out classes,
  since there are large chunks of the mtouch/mmp code we're not using yet, so
  stubbing out while things are being implemented works fine.
* Add a step in dotnet-linker for loading the linker output (the linked
  assemblies) into our bundler code.
* Add another step in dotnet-linker to extract native resources from binding
  libraries.
* Augment the build process to take into account the native resources we found
  in any binding libraries.
This commit is contained in:
Rolf Bjarne Kvinge 2020-08-20 08:35:12 +02:00
Родитель f8637d780a a8291e4351
Коммит 558af9612a
52 изменённых файлов: 844 добавлений и 103 удалений

Просмотреть файл

@ -137,6 +137,7 @@
PlatformAssembly=$(_PlatformAssemblyName).dll
SdkVersion=$(_SdkVersion)
TargetArchitectures=$(TargetArchitectures)
TargetFramework=$(_ComputedTargetFrameworkMoniker)
Verbosity=$(_BundlerVerbosity)
</_CustomLinkerOptions>
<_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --custom-data "LinkerOptionsFile=$(_CustomLinkerOptionsFile)"</_ExtraTrimmerArgs>
@ -181,6 +182,18 @@
<ReadItemsFromFile File="$(_LinkerItemsDirectory)/_LinkerFrameworks.items" Condition="Exists('$(_LinkerItemsDirectory)/_LinkerFrameworks.items')">
<Output TaskParameter="Items" ItemName="_LinkerFrameworks" />
</ReadItemsFromFile>
<!-- Load _BindingLibraryLinkWith -->
<ReadItemsFromFile File="$(_LinkerItemsDirectory)/_BindingLibraryLinkWith.items" Condition="Exists('$(_LinkerItemsDirectory)/_BindingLibraryLinkWith.items')">
<Output TaskParameter="Items" ItemName="_BindingLibraryLinkWith" />
</ReadItemsFromFile>
<!-- Load _BindingLibraryLinkerFlags -->
<ReadItemsFromFile File="$(_LinkerItemsDirectory)/_BindingLibraryLinkerFlags.items" Condition="Exists('$(_LinkerItemsDirectory)/_BindingLibraryLinkerFlags.items')">
<Output TaskParameter="Items" ItemName="_BindingLibraryLinkerFlags" />
</ReadItemsFromFile>
<!-- Load _BindingLibraryFrameworks -->
<ReadItemsFromFile File="$(_LinkerItemsDirectory)/_BindingLibraryFrameworks.items" Condition="Exists('$(_LinkerItemsDirectory)/_BindingLibraryFrameworks.items')">
<Output TaskParameter="Items" ItemName="_BindingLibraryFrameworks" />
</ReadItemsFromFile>
</Target>
<!-- Native code -->
@ -315,8 +328,9 @@
<LinkNativeCode
SessionId="$(BuildSessionId)"
Frameworks="@(_NativeExecutableFrameworks)"
LinkWithLibraries="@(_XamarinMainLibraries)"
Frameworks="@(_NativeExecutableFrameworks);@(_BindingLibraryFrameworks)"
LinkerFlags="@(_BindingLibraryLinkerFlags)"
LinkWithLibraries="@(_XamarinMainLibraries);@(_BindingLibraryLinkWith)"
MinimumOSVersion="$(_MinimumOSVersion)"
ObjectFiles="@(_NativeExecutableObjectFiles)"
OutputFile="$(_IntermediateNativeLibraryDir)$(_NativeExecutableName)"

Просмотреть файл

@ -8,6 +8,8 @@ namespace Xamarin.MacDev.Tasks {
public abstract class LinkNativeCodeTaskBase : XamarinTask {
#region Inputs
public ITaskItem[] LinkerFlags { get; set; }
public ITaskItem[] LinkWithLibraries { get; set; }
[Required]
@ -48,6 +50,9 @@ namespace Xamarin.MacDev.Tasks {
var libExtension = Path.GetExtension (lib).ToLowerInvariant ();
switch (libExtension) {
case ".a":
var forceLoad = string.Equals (libSpec.GetMetadata ("ForceLoad"), "true", StringComparison.OrdinalIgnoreCase);
if (forceLoad)
arguments.Add ("-force_load");
arguments.Add (lib);
break;
case ".dylib":
@ -90,6 +95,11 @@ namespace Xamarin.MacDev.Tasks {
arguments.Add ("-o");
arguments.Add (Path.GetFullPath (OutputFile));
if (LinkerFlags != null) {
foreach (var flag in LinkerFlags)
arguments.Add (flag.ItemSpec);
}
ExecuteAsync ("xcrun", arguments, sdkDevPath: SdkDevPath).Wait ();
return !Log.HasLoggedErrors;

Просмотреть файл

@ -25,7 +25,7 @@ using ObjCRuntime;
using Xamarin.Utils;
using Xamarin.Bundler;
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
using TAssembly=Mono.Cecil.AssemblyDefinition;
using TType=Mono.Cecil.TypeReference;
using TMethod=Mono.Cecil.MethodDefinition;
@ -41,11 +41,11 @@ using TField=System.Reflection.FieldInfo;
using R=ObjCRuntime.Runtime;
#endif
#if !(MTOUCH || MMP)
#if !(MTOUCH || MMP || BUNDLER)
using ProductException=ObjCRuntime.RuntimeException;
#endif
#if !MTOUCH && !MMP
#if !MTOUCH && !MMP && !BUNDLER
// static registrar needs them but they might not be marked (e.g. if System.Console is not used)
[assembly: Preserve (typeof (System.Action))]
[assembly: Preserve (typeof (System.Action<string>))]
@ -84,7 +84,7 @@ namespace Registrar {
}
abstract partial class Registrar {
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
public Application App { get; protected set; }
#endif
@ -124,7 +124,7 @@ namespace Registrar {
public bool IsInformalProtocol;
public bool IsWrapper;
public bool IsGeneric;
#if !MTOUCH && !MMP
#if !MTOUCH && !MMP && !BUNDLER
public IntPtr Handle;
#else
public TType ProtocolWrapperType;
@ -140,7 +140,7 @@ namespace Registrar {
public bool IsCategory { get { return CategoryAttribute != null; } }
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
HashSet<ObjCType> all_protocols;
// This contains all protocols in the type hierarchy.
// Given a type T that implements a protocol with super protocols:
@ -585,7 +585,7 @@ namespace Registrar {
}
}
#if !MMP && !MTOUCH
#if !MMP && !MTOUCH && !BUNDLER
// The ArgumentSemantic enum is public, and
// I don't want to add another enum value there which
// is just an internal implementation detail, so just
@ -832,7 +832,7 @@ namespace Registrar {
if (trampoline != Trampoline.None)
return trampoline;
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
throw ErrorHelper.CreateError (8018, Errors.MT8018);
#else
var mi = (System.Reflection.MethodInfo) Method;
@ -1001,7 +1001,7 @@ namespace Registrar {
}
internal class ObjCField : ObjCMember {
#if !MTOUCH && !MMP
#if !MTOUCH && !MMP && !BUNDLER
public int Size;
public byte Alignment;
#else
@ -1259,7 +1259,7 @@ namespace Registrar {
#if MONOMAC
internal const string AssemblyName = "Xamarin.Mac";
#else
#if MTOUCH
#if MTOUCH || BUNDLER
internal string AssemblyName
{
get {
@ -1305,7 +1305,7 @@ namespace Registrar {
}
}
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
// "#if MTOUCH" code does not need locking when accessing 'types', because mtouch is single-threaded.
public Dictionary<TType, ObjCType> Types {
get { return types; }
@ -1884,7 +1884,7 @@ namespace Registrar {
protected bool SupportsModernObjectiveC {
get {
#if MTOUCH || MONOTOUCH
#if MTOUCH || MONOTOUCH || BUNDLER
return true;
#elif MMP
return App.Is64Build;
@ -1935,7 +1935,7 @@ namespace Registrar {
isInformalProtocol = pAttr.IsInformal;
isProtocol = true;
#if MMP || MTOUCH
#if MMP || MTOUCH || BUNDLER
if (pAttr.FormalSinceVersion != null && pAttr.FormalSinceVersion > App.SdkVersion)
isInformalProtocol = !isInformalProtocol;
#endif
@ -1969,7 +1969,7 @@ namespace Registrar {
objcType.VerifyAdoptedProtocolsNames (ref exceptions);
objcType.BaseType = isProtocol ? null : (baseObjCType ?? objcType);
objcType.Protocols = GetProtocols (objcType, ref exceptions);
#if MMP || MTOUCH
#if MMP || MTOUCH || BUNDLER
objcType.ProtocolWrapperType = (isProtocol && !isInformalProtocol) ? GetProtocolAttributeWrapperType (objcType.Type) : null;
#endif
objcType.IsWrapper = (isProtocol && !isInformalProtocol) ? (GetProtocolAttributeWrapperType (objcType.Type) != null) : (objcType.RegisterAttribute != null && objcType.RegisterAttribute.IsWrapper);
@ -2064,7 +2064,7 @@ namespace Registrar {
}
}
#if MMP || MTOUCH
#if MMP || MTOUCH || BUNDLER
// Special fields
if (is_first_nonWrapper) {
// static registrar
@ -2131,7 +2131,7 @@ namespace Registrar {
}
} else {
TMethod method = null;
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
method = attrib.Method;
#endif
var objcMethod = new ObjCMethod (this, objcType, method) {
@ -2180,7 +2180,7 @@ namespace Registrar {
objcType.Add (new ObjCField () {
DeclaringType = objcType,
Name = ca.Name ?? GetPropertyName (property),
#if !MTOUCH && !MMP
#if !MTOUCH && !MMP && !BUNDLER
Size = Is64Bits ? 8 : 4,
Alignment = (byte) (Is64Bits ? 3 : 2),
#endif
@ -2460,7 +2460,7 @@ namespace Registrar {
if (exceptions.Count > 0) {
Exception ae = exceptions.Count == 1 ? exceptions [0] : new AggregateException (exceptions);
#if !MTOUCH && !MMP
#if !MTOUCH && !MMP && !BUNDLER
Runtime.NSLog (ae.ToString ());
#endif
throw ae;
@ -2689,7 +2689,7 @@ namespace Registrar {
System.Threading.Monitor.Exit (types);
}
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
internal static void NSLog (string format, params object [] args)
{
Console.WriteLine (format, args);

Просмотреть файл

@ -2,7 +2,7 @@ using System;
using System.IO;
using System.Text;
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
using Mono.Cecil;
using Xamarin.Linker;
#else
@ -11,7 +11,7 @@ using Foundation;
using ObjCRuntime;
#endif
#if MMP || MMP_TEST || MTOUCH
#if MMP || MMP_TEST || MTOUCH || BUNDLER
namespace Xamarin.Bundler {
#else
namespace ObjCRuntime {
@ -24,7 +24,7 @@ namespace ObjCRuntime {
string http_message_handler;
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
/*
* This section is only used by the tools
*/

Просмотреть файл

@ -45,7 +45,7 @@
<Compile Include="$(RootTestsDirectory)\api-shared\ObjCRuntime\Registrar.cs">
<Link>Registrar.cs</Link>
</Compile>
<Compile Include="..\..\RegistrarBindingTest.cs" />
<Compile Include="$(BindingsTestDirectory)\RegistrarBindingTest.cs" />
<Compile Include="$(RootTestsDirectory)\common\TestRuntime.cs">
<Link>TestRuntime.cs</Link>
</Compile>

Просмотреть файл

@ -3,6 +3,11 @@
<PropertyGroup>
<NativeLibName>ios-fat</NativeLibName>
<PlatformName>iOS</PlatformName>
<RootTestsDirectory>..\..\..</RootTestsDirectory>
</PropertyGroup>
<Import Project="..\shared.targets" />
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\iOS\bindings-test.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -3,6 +3,11 @@
<PropertyGroup>
<NativeLibName>macos</NativeLibName>
<PlatformName>macOS</PlatformName>
<RootTestsDirectory>..\..\..</RootTestsDirectory>
</PropertyGroup>
<Import Project="..\shared.targets" />
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\macOS\bindings-test.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -8,17 +8,10 @@
<LangVersion>latest</LangVersion>
<IsBindingProject>true</IsBindingProject>
<RootTestsDirectory>$(MSBuildThisFileDirectory)\..\..</RootTestsDirectory>
<BindingsTest2Directory>$(RootTestsDirectory)\bindings-test2</BindingsTest2Directory>
<TestLibrariesDirectory>$(RootTestsDirectory)\test-libraries</TestLibrariesDirectory>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\$(PlatformName)\bindings-test.csproj" />
</ItemGroup>
<ItemGroup>
<ObjcBindingApiDefinition Include="$(BindingsTest2Directory)\ApiDefinition.cs" />
<ObjcBindingApiDefinition Include="$(BindingsTest2Directory)\ApiProtocol.cs" />

Просмотреть файл

@ -3,6 +3,11 @@
<PropertyGroup>
<NativeLibName>tvos-fat</NativeLibName>
<PlatformName>tvOS</PlatformName>
<RootTestsDirectory>..\..\..</RootTestsDirectory>
</PropertyGroup>
<Import Project="..\shared.targets" />
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\tvOS\bindings-test.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -3,6 +3,11 @@
<PropertyGroup>
<NativeLibName>watchos-fat</NativeLibName>
<PlatformName>watchOS</PlatformName>
<RootTestsDirectory>..\..\..</RootTestsDirectory>
</PropertyGroup>
<Import Project="..\shared.targets" />
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\iOS\bindings-test.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -258,11 +258,77 @@ namespace Xamarin.Tests {
Assert.That (ad.MainModule.Resources [0].Name, Is.EqualTo ("libtest2.a"), "libtest2.a");
}
void CopyDotNetSupportingFiles (string targetDirectory)
[TestCase ("iOS")]
[TestCase ("tvOS")]
// [TestCase ("watchOS")] // No watchOS Touch.Client project for .NET yet
// [TestCase ("macOS")] // No macOS Touch.Client project for .NET yet
public void BuildInterdependentBindingProjects (string platform)
{
var assemblyName = "interdependent-binding-projects";
var dotnet_bindings_dir = Path.Combine (Configuration.SourceRoot, "tests", assemblyName, "dotnet");
var project_dir = Path.Combine (dotnet_bindings_dir, platform);
var project_path = Path.Combine (project_dir, $"{assemblyName}.csproj");
Clean (project_path);
CopyDotNetSupportingFiles (dotnet_bindings_dir);
CopyDotNetSupportingFiles (dotnet_bindings_dir.Replace (assemblyName, "bindings-test"));
CopyDotNetSupportingFiles (dotnet_bindings_dir.Replace (assemblyName, "bindings-test2"));
var cleanupSupportFiles = CopyDotNetSupportingFiles (Path.Combine (Configuration.SourceRoot, "external", "Touch.Unit", "Touch.Client/dotnet"));
try {
var result = DotNet.AssertBuild (project_path, verbosity);
var lines = result.StandardOutput.ToString ().Split ('\n');
// Find the resulting binding assembly from the build log
var assemblies = lines.
Select (v => v.Trim ()).
Where (v => {
if (v.Length < 10)
return false;
if (v [0] != '/')
return false;
if (!v.EndsWith ($"{assemblyName}.dll", StringComparison.Ordinal))
return false;
if (!v.Contains ("/bin/", StringComparison.Ordinal))
return false;
if (!v.Contains ($"{assemblyName}.app", StringComparison.Ordinal))
return false;
return true;
});
Assert.That (assemblies, Is.Not.Empty, "Assemblies");
// Make sure there's no other assembly confusing our logic
assemblies = assemblies.Distinct ();
Assert.That (assemblies.Count (), Is.EqualTo (1), $"Unique assemblies: {string.Join (", ", assemblies)}");
var asm = assemblies.First ();
Assert.That (asm, Does.Exist, "Assembly existence");
// Verify that the resources
var asmDir = Path.GetDirectoryName (asm);
var ad = AssemblyDefinition.ReadAssembly (asm, new ReaderParameters { ReadingMode = ReadingMode.Deferred });
Assert.That (ad.MainModule.Resources.Count, Is.EqualTo (0), "0 resources for interdependent-binding-projects.dll");
var ad1 = AssemblyDefinition.ReadAssembly (Path.Combine (asmDir, "bindings-test.dll"), new ReaderParameters { ReadingMode = ReadingMode.Deferred });
Assert.That (ad1.MainModule.Resources.Count, Is.EqualTo (1), "1 resource for bindings-test.dll");
Assert.That (ad1.MainModule.Resources [0].Name, Is.EqualTo ("libtest.a"), "libtest.a - bindings-test.dll");
var ad2 = AssemblyDefinition.ReadAssembly (Path.Combine (asmDir, "bindings-test2.dll"), new ReaderParameters { ReadingMode = ReadingMode.Deferred });
Assert.That (ad2.MainModule.Resources.Count, Is.EqualTo (1), "1 resource for bindings-test2.dll");
Assert.That (ad2.MainModule.Resources [0].Name, Is.EqualTo ("libtest2.a"), "libtest2.a - bindings-test2.dll");
} finally {
foreach (var file in cleanupSupportFiles)
File.Delete (file);
}
}
string[] CopyDotNetSupportingFiles (string targetDirectory)
{
var srcDirectory = Path.Combine (Configuration.SourceRoot, "tests", "dotnet");
foreach (var fn in new string [] { "global.json", "NuGet.config" })
File.Copy (Path.Combine (srcDirectory, fn), Path.Combine (targetDirectory, fn), true);
var files = new string [] { "global.json", "NuGet.config" };
var targets = new string [files.Length];
for (var i = 0; i < files.Length; i++) {
var fn = files [i];
targets [i] = Path.Combine (targetDirectory, fn);
File.Copy (Path.Combine (srcDirectory, fn), targets [i], true);
}
return targets;
}
void AssertThatLinkerExecuted (ExecutionResult result)

3
tests/interdependent-binding-projects/dotnet/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
global.json
NuGet.config

Просмотреть файл

@ -0,0 +1,19 @@
<?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>
<key>CFBundleDisplayName</key>
<string>InterdependentBindingProject</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.dotnet.interdependentbindingprojects</string>
<key>CFBundleName</key>
<string>InterdependentBindingProject</string>
<key>MinimumOSVersion</key>
<string>7.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.iOS.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<SignAssembly>true</SignAssembly>
<LangVersion>latest</LangVersion>
<RuntimeIdentifier>ios-x64</RuntimeIdentifier>
<AssetTargetFallback>xamarinios10;$(AssetTargetFallback)</AssetTargetFallback>
<RootTestsDirectory>..\..\..\</RootTestsDirectory>
<!-- This is needed because the packages/ directory might be in the same folder as this project file, and some some packages might have C# files, which would then automatically be included -->
<DefaultItemExcludes>$(DefaultItemExcludes);packages/**;</DefaultItemExcludes>
<AssemblyOriginatorKeyFile>$(RootTestsDirectory)\..\product.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<PackageReference Include="MonoTouch.Dialog" Version="2.0.0-pre1" />
<!-- MonoTouch.Dialog references System.Json, which isn't shipped with .NET5, so reference the NuGet instead -->
<PackageReference Include="System.Json" Version="4.7.1" />
<ProjectReference Include="$(RootTestsDirectory)\..\external\Touch.Unit\Touch.Client\dotnet\iOS\Touch.Client-iOS.dotnet.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\iOS\bindings-test.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test2\dotnet\iOS\bindings-test2.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<Compile Include="$(RootTestsDirectory)\interdependent-binding-projects\Main.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,14 @@
<?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>
<key>CFBundleDisplayName</key>
<string>InterdependentBindingProject</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.dotnet.interdependentbindingprojects</string>
<key>CFBundleName</key>
<string>CFBundleIdentifier</string>
<key>LSMinimumSystemVersion</key>
<string>10.9</string>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.macOS.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<SignAssembly>true</SignAssembly>
<LangVersion>latest</LangVersion>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<RootTestsDirectory>..\..\..\</RootTestsDirectory>
<!-- This is needed because the packages/ directory might be in the same folder as this project file, and some some packages might have C# files, which would then automatically be included -->
<DefaultItemExcludes>$(DefaultItemExcludes);packages/**;</DefaultItemExcludes>
<AssemblyOriginatorKeyFile>$(RootTestsDirectory)\..\product.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\..\external\Touch.Unit\Touch.Client\dotnet\macOS\Touch.Client-macOS.dotnet.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\macOS\bindings-test.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test2\dotnet\macOS\bindings-test2.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<Compile Include="$(RootTestsDirectory)\interdependent-binding-projects\Main.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,18 @@
<?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>
<key>CFBundleDisplayName</key>
<string>InterdependentBindingProject</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.dotnet.interdependentbindingprojects</string>
<key>CFBundleName</key>
<string>InterdependentBindingProject</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>3</integer>
</array>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.tvOS.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<SignAssembly>true</SignAssembly>
<LangVersion>latest</LangVersion>
<RuntimeIdentifier>tvos-x64</RuntimeIdentifier>
<AssetTargetFallback>xamarintvos10;$(AssetTargetFallback)</AssetTargetFallback>
<RootTestsDirectory>..\..\..\</RootTestsDirectory>
<!-- This is needed because the packages/ directory might be in the same folder as this project file, and some some packages might have C# files, which would then automatically be included -->
<DefaultItemExcludes>$(DefaultItemExcludes);packages/**;</DefaultItemExcludes>
<AssemblyOriginatorKeyFile>$(RootTestsDirectory)\..\product.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<PackageReference Include="MonoTouch.Dialog" Version="2.0.0-pre1" />
<!-- MonoTouch.Dialog references System.Json, which isn't shipped with .NET5, so reference the NuGet instead -->
<PackageReference Include="System.Json" Version="4.7.1" />
<ProjectReference Include="$(RootTestsDirectory)\..\external\Touch.Unit\Touch.Client\dotnet\tvOS\Touch.Client-tvOS.dotnet.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\tvOS\bindings-test.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test2\dotnet\tvOS\bindings-test2.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<Compile Include="$(RootTestsDirectory)\interdependent-binding-projects\Main.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,35 @@
<?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>
<key>CFBundleDisplayName</key>
<string>InterdependentBindingProject</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.dotnet.interdependentbindingprojects_watch.watchkitapp.watchkitextension</string>
<key>CFBundleName</key>
<string>InterdependentBindingProject</string>
<key>MinimumOSVersion</key>
<string>2.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>4</integer>
</array>
<key>RemoteInterfacePrincipleClass</key>
<string>InterfaceController</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>WKAppBundleIdentifier</key>
<string>com.xamarin.dotnet.interdependentbindingprojects_watch.watchkitapp</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.watchkit</string>
</dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true />
</dict>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.watchOS.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<SignAssembly>true</SignAssembly>
<LangVersion>latest</LangVersion>
<RuntimeIdentifier>watchos-x86</RuntimeIdentifier>
<RootTestsDirectory>..\..\..\</RootTestsDirectory>
<!-- This is needed because the packages/ directory might be in the same folder as this project file, and some some packages might have C# files, which would then automatically be included -->
<DefaultItemExcludes>$(DefaultItemExcludes);packages/**;</DefaultItemExcludes>
<AssemblyOriginatorKeyFile>$(RootTestsDirectory)\..\product.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnitLite" Version="3.12.0" />
<ProjectReference Include="$(RootTestsDirectory)\..\external\Touch.Unit\Touch.Client\dotnet\watchOS\Touch.Client-watchOS.dotnet.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test\dotnet\watchOS\bindings-test.csproj" />
<ProjectReference Include="$(RootTestsDirectory)\bindings-test2\dotnet\watchOS\bindings-test2.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<Compile Include="$(RootTestsDirectory)\interdependent-binding-projects\Main.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -371,7 +371,7 @@ namespace Xharness {
void AutoConfigureIOS ()
{
var test_suites = new string [] { "monotouch-test", "framework-test", "interdependent-binding-projects" };
var test_suites = new string [] { "monotouch-test", "framework-test" };
var library_projects = new string [] { "BundledResources", "EmbeddedResources", "bindings-test2", "bindings-framework-test" };
var fsharp_test_suites = new string [] { "fsharp" };
var fsharp_library_projects = new string [] { "fsharplibrary" };
@ -387,6 +387,8 @@ namespace Xharness {
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "bindings-test", "iOS", "bindings-test.csproj")), false) { Name = "bindings-test" });
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "interdependent-binding-projects", "interdependent-binding-projects.csproj"))) { Name = "interdependent-binding-projects" });
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "interdependent-binding-projects", "dotnet", "iOS", "interdependent-binding-projects.csproj"))) { Name = "interdependent-binding-projects", IsDotNetProject = true, SkipiOSVariation = false, SkiptvOSVariation = true, SkipwatchOSVariation = true, SkipTodayExtensionVariation = true, SkipDeviceVariations = true, SkipiOS32Variation = true, });
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "iOS", "introspection-ios.csproj"))) { Name = "introspection" });
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "iOS", "introspection-ios-dotnet.csproj"))) { Name = "introspection", IsDotNetProject = true, SkipiOSVariation = false, SkiptvOSVariation = false, SkipwatchOSVariation = true, SkipTodayExtensionVariation = true, SkipDeviceVariations = true, SkipiOS32Variation = true, });
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "linker", "ios", "dont link", "dont link.csproj"))) { Configurations = new string [] { "Debug", "Release" } });

Просмотреть файл

@ -223,7 +223,7 @@ namespace Xharness.Jenkins {
TestProject = buildDotNetTestsProject,
Platform = TestPlatform.All,
TestName = "DotNet tests",
Timeout = TimeSpan.FromMinutes (5),
Timeout = TimeSpan.FromMinutes (15),
Ignored = !IncludeDotNet,
};
Tasks.Add (runDotNetTests);

Просмотреть файл

@ -81,7 +81,7 @@ namespace Xharness.Jenkins {
foreach (var config in configurations) {
MSBuildTask build = new MSBuildTask (jenkins: jenkins, testProject: project, processManager: processManager);
build.Platform = platform;
build.CloneTestProject (jenkins.MainLog, processManager, project);
build.CloneTestProject (jenkins.MainLog, processManager, project, HarnessConfiguration.RootDirectory);
build.ProjectConfiguration = config;
build.ProjectPlatform = project.Platform;
build.SpecifyPlatform = false;

Просмотреть файл

@ -52,7 +52,7 @@ namespace Xharness.Jenkins {
Platform = TestPlatform.iOS_Unified64,
TestName = project.Name,
};
build64.CloneTestProject (jenkins.MainLog, processManager, project);
build64.CloneTestProject (jenkins.MainLog, processManager, project, HarnessConfiguration.RootDirectory);
projectTasks.Add (new RunDeviceTask (
jenkins: jenkins,
devices: jenkins.Devices,
@ -69,7 +69,7 @@ namespace Xharness.Jenkins {
Platform = TestPlatform.iOS_Unified32,
TestName = project.Name,
};
build32.CloneTestProject (jenkins.MainLog, processManager, project);
build32.CloneTestProject (jenkins.MainLog, processManager, project, HarnessConfiguration.RootDirectory);
projectTasks.Add (new RunDeviceTask (
jenkins: jenkins,
devices: jenkins.Devices,
@ -88,7 +88,7 @@ namespace Xharness.Jenkins {
Platform = TestPlatform.iOS_TodayExtension64,
TestName = project.Name,
};
buildToday.CloneTestProject (jenkins.MainLog, processManager, todayProject);
buildToday.CloneTestProject (jenkins.MainLog, processManager, todayProject, HarnessConfiguration.RootDirectory);
projectTasks.Add (new RunDeviceTask (
jenkins: jenkins,
devices: jenkins.Devices,
@ -109,7 +109,7 @@ namespace Xharness.Jenkins {
Platform = TestPlatform.tvOS,
TestName = project.Name,
};
buildTV.CloneTestProject (jenkins.MainLog, processManager, tvOSProject);
buildTV.CloneTestProject (jenkins.MainLog, processManager, tvOSProject, HarnessConfiguration.RootDirectory);
projectTasks.Add (new RunDeviceTask (
jenkins: jenkins,
devices: jenkins.Devices,
@ -130,7 +130,7 @@ namespace Xharness.Jenkins {
Platform = TestPlatform.watchOS_32,
TestName = project.Name,
};
buildWatch32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject);
buildWatch32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject, HarnessConfiguration.RootDirectory);
projectTasks.Add (new RunDeviceTask (
jenkins: jenkins,
devices: jenkins.Devices,
@ -149,7 +149,7 @@ namespace Xharness.Jenkins {
Platform = TestPlatform.watchOS_64_32,
TestName = project.Name,
};
buildWatch64_32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject);
buildWatch64_32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject, HarnessConfiguration.RootDirectory);
projectTasks.Add (new RunDeviceTask (
jenkins: jenkins,
devices: jenkins.Devices,

Просмотреть файл

@ -74,7 +74,7 @@ namespace Xharness.Jenkins {
derived.Ignored = configIgnored;
derived.TestName = project.Name;
derived.Dependency = project.Dependency;
derived.CloneTestProject (jenkins.MainLog, processManager, pair.Item1);
derived.CloneTestProject (jenkins.MainLog, processManager, pair.Item1, HarnessConfiguration.RootDirectory);
var simTasks = CreateAsync (jenkins, processManager, derived);
runSimulatorTasks.AddRange (simTasks);
foreach (var task in simTasks) {

Просмотреть файл

@ -160,7 +160,7 @@ namespace Xharness.Jenkins {
var clone = task.TestProject.Clone ();
var clone_task = Task.Run (async () => {
await task.BuildTask.InitialTask; // this is the project cloning above
await clone.CreateCopyAsync (jenkins.MainLog, processManager, task);
await clone.CreateCopyAsync (jenkins.MainLog, processManager, task, HarnessConfiguration.RootDirectory);
var isMac = task.Platform.IsMac ();
var canSymlink = task.Platform.CanSymlink();

Просмотреть файл

@ -242,7 +242,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Tasks {
return Task.CompletedTask;
}
public void CloneTestProject (ILog log, IProcessManager processManager, TestProject project)
public void CloneTestProject (ILog log, IProcessManager processManager, TestProject project, string rootDirectory)
{
// Don't build in the original project directory
// We can build multiple projects in parallel, and if some of those
@ -252,7 +252,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Tasks {
// So we clone the project file to a separate directory and build there instead.
// This is done asynchronously to speed to the initial test load.
TestProject = project.Clone ();
InitialTask = TestProject.CreateCopyAsync (log, processManager, this);
InitialTask = TestProject.CreateCopyAsync (log, processManager, this, rootDirectory);
}
protected Stopwatch waitingDuration = new Stopwatch ();

Просмотреть файл

@ -69,14 +69,20 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared {
return rv;
}
internal async Task<TestProject> CreateCloneAsync (ILog log, IProcessManager processManager, ITestTask test)
internal async Task<TestProject> CreateCloneAsync (ILog log, IProcessManager processManager, ITestTask test, string rootDirectory)
{
var rv = Clone ();
await rv.CreateCopyAsync (log, processManager, test);
await rv.CreateCopyAsync (log, processManager, test, rootDirectory);
return rv;
}
public async Task CreateCopyAsync (ILog log, IProcessManager processManager, ITestTask test)
public Task CreateCopyAsync (ILog log, IProcessManager processManager, ITestTask test, string rootDirectory)
{
var pr = new Dictionary<string, TestProject> ();
return CreateCopyAsync (log, processManager, test, rootDirectory, pr);
}
async Task CreateCopyAsync (ILog log, IProcessManager processManager, ITestTask test, string rootDirectory, Dictionary<string, TestProject> allProjectReferences)
{
var directory = DirectoryUtilities.CreateTemporaryDirectory (test?.TestName ?? System.IO.Path.GetFileNameWithoutExtension (Path));
Directory.CreateDirectory (directory);
@ -89,7 +95,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared {
doc = new XmlDocument ();
doc.LoadWithoutNetworkAccess (original_path);
var original_name = System.IO.Path.GetFileName (original_path);
doc.ResolveAllPaths (original_path);
doc.ResolveAllPaths (original_path, rootDirectory);
if (doc.IsDotNetProject ()) {
if (doc.GetEnableDefaultItems () != false) {
@ -154,8 +160,12 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared {
var projectReferences = new List<TestProject> ();
foreach (var pr in doc.GetProjectReferences ()) {
var tp = new TestProject (pr.Replace ('\\', '/'));
await tp.CreateCopyAsync (log, processManager, test);
var prPath = pr.Replace ('\\', '/');
if (!allProjectReferences.TryGetValue (prPath, out var tp)) {
tp = new TestProject (pr.Replace ('\\', '/'));
await tp.CreateCopyAsync (log, processManager, test, rootDirectory, allProjectReferences);
allProjectReferences.Add (prPath, tp);
}
doc.SetProjectReferenceInclude (pr, tp.Path.Replace ('/', '\\'));
projectReferences.Add (tp);
}

Просмотреть файл

@ -912,7 +912,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities {
}
}
public static void ResolveAllPaths (this XmlDocument csproj, string project_path)
public static void ResolveAllPaths (this XmlDocument csproj, string project_path, string rootDirectory = null)
{
var dir = System.IO.Path.GetDirectoryName (project_path);
var nodes_with_paths = new string []
@ -942,7 +942,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities {
new string [] { "ObjcBindingCoreSource", "Include" },
new string [] { "ObjcBindingNativeLibrary", "Include" },
new string [] { "ObjcBindingNativeFramework", "Include" },
new string [] { "Import", "Project", "CustomBuildActions.targets" },
new string [] { "Import", "Project", "CustomBuildActions.targets", "..\\shared.targets" },
new string [] { "FilesToCopy", "Include" },
new string [] { "FilesToCopyFoo", "Include" },
new string [] { "FilesToCopyFooBar", "Include" },
@ -967,6 +967,10 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities {
if (input.StartsWith ("$(MSBuildBinPath)", StringComparison.Ordinal))
return input; // This is already a full path.
input = input.Replace ('\\', '/'); // make unix-style
if (rootDirectory != null)
input = input.Replace ("$(RootTestsDirectory)", rootDirectory);
input = System.IO.Path.GetFullPath (System.IO.Path.Combine (dir, input));
input = input.Replace ('/', '\\'); // make windows-style again
return input;
@ -1064,9 +1068,12 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities {
foreach (var prop in properties)
args.Add ($"/p:{prop.Key}={prop.Value}");
args.Add (inspector);
var env = new Dictionary<string, string> {
{ "MSBUILD_EXE_PATH", null },
};
proc.StartInfo.Arguments = StringUtils.FormatArguments (args);
proc.StartInfo.WorkingDirectory = dir;
var rv = await processManager.RunAsync (proc, log, timeout: TimeSpan.FromSeconds (15));
var rv = await processManager.RunAsync (proc, log, environment_variables: env, timeout: TimeSpan.FromSeconds (15));
if (!rv.Succeeded)
throw new Exception ($"Unable to evaluate the property {evaluateProperty}.");
return File.ReadAllText (output).Trim ();

Просмотреть файл

@ -199,6 +199,7 @@ namespace Xharness.Targets
protected void CreateLibraryProject ()
{
ProcessProject ();
inputProject.ResolveAllPaths (TemplateProjectPath);
inputProject.Save (ProjectPath, (l, m) => Harness.Log (l,m));
ProjectGuid = inputProject.GetProjectGuid ();

Просмотреть файл

@ -51,6 +51,7 @@ namespace Xharness.Targets {
TodayContainerGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
ProjectGuid = TodayContainerGuid;
csproj.SetProjectGuid (TodayContainerGuid);
csproj.ResolveAllPaths (Harness.TodayContainerTemplate);
csproj.Save(TodayContainerProjectPath, (l, m) => Harness.Log (l,m));
XmlDocument info_plist = new XmlDocument ();
@ -79,7 +80,7 @@ namespace Xharness.Targets {
csproj.AddInterfaceDefinition (Path.Combine (Harness.TodayExtensionTemplate, "TodayView.storyboard").Replace ('/', '\\'));
csproj.SetExtraLinkerDefs ("extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml");
csproj.FixProjectReferences (Path.Combine (ProjectsDir, GetTargetSpecificDir ()), "-today", FixProjectReference);
csproj.ResolveAllPaths (TemplateProjectPath);
csproj.Save (TodayExtensionProjectPath, (l,m) => Harness.Log (l,m));
TodayExtensionGuid = csproj.GetProjectGuid ();

Просмотреть файл

@ -16,8 +16,12 @@ using ObjCRuntime;
#if MONOTOUCH
using PlatformResolver = MonoTouch.Tuner.MonoTouchResolver;
#else
#elif MMP
using PlatformResolver = Xamarin.Bundler.MonoMacResolver;
#elif NET
using PlatformResolver = Xamarin.Linker.DotNetResolver;
#else
#error Invalid defines
#endif
namespace Xamarin.Bundler {

Просмотреть файл

@ -55,25 +55,31 @@ namespace Xamarin.Bundler {
public AssemblyDefinition AssemblyDefinition;
public Target Target;
public bool IsFrameworkAssembly { get { return is_framework_assembly.Value; } }
public bool? IsFrameworkAssembly { get { return is_framework_assembly; } }
public string FullPath {
get {
return full_path;
}
set {
full_path = value;
if (!is_framework_assembly.HasValue) {
if (!is_framework_assembly.HasValue && !string.IsNullOrEmpty (full_path)) {
var real_full_path = Target.GetRealPath (full_path);
#if NET
// TODO: Figure out how to determine whether an assembly is a framework assembly or not (but it's not urgent to implement, it's just a performance improvement)
#else
is_framework_assembly = real_full_path.StartsWith (Path.GetDirectoryName (Path.GetDirectoryName (Target.Resolver.FrameworkDirectory)), StringComparison.Ordinal);
#endif
}
}
}
public string FileName { get { return Path.GetFileName (FullPath); } }
public string Identity { get { return GetIdentity (FullPath); } }
public string Identity { get { return GetIdentity (AssemblyDefinition); } }
public static string GetIdentity (AssemblyDefinition ad)
{
return Path.GetFileNameWithoutExtension (ad.MainModule.FileName);
if (!string.IsNullOrEmpty (ad.MainModule.FileName))
return Path.GetFileNameWithoutExtension (ad.MainModule.FileName);
return ad.Name.Name;
}
public static string GetIdentity (string path)
@ -143,7 +149,7 @@ namespace Xamarin.Bundler {
public void ExtractNativeLinkInfo ()
{
// ignore framework assemblies, they won't have any LinkWith attributes
if (IsFrameworkAssembly)
if (IsFrameworkAssembly == true)
return;
var assembly = AssemblyDefinition;

Просмотреть файл

@ -9,6 +9,10 @@ using Registrar;
using Mono.Tuner;
using Xamarin.Bundler;
#if NET
using LinkContext = Xamarin.Bundler.DotNetLinkContext;
#endif
namespace Xamarin.Tuner
{
public class DerivedLinkContext : LinkContext

Просмотреть файл

@ -28,6 +28,7 @@ namespace Xamarin.Bundler {
public static bool Force { get; set; }
static Version min_xcode_version = new Version (6, 0);
#if !NET
public static int Main (string [] args)
{
try {
@ -327,6 +328,7 @@ namespace Xamarin.Bundler {
return false;
}
#endif // !NET
static int Jobs;
public static int Concurrency {

Просмотреть файл

@ -139,7 +139,7 @@ namespace Xamarin.Bundler {
return Task.Run (() => RunCommand (path, args, env, output, output, suppressPrintOnErrors, verbosity ?? Verbosity));
}
#if !MTOUCH && !MMP
#if !MTOUCH && !MMP && !BUNDLER
internal static int Verbosity;
#endif
}

Просмотреть файл

@ -1,6 +1,6 @@
using System;
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
using Xamarin.Bundler;
using Xamarin.Utils;
#endif
@ -62,7 +62,7 @@ namespace Xamarin {
public static Version XcodeVersion { get { return new Version (Xcode); }}
#if MTOUCH || MMP
#if MTOUCH || MMP || BUNDLER
public static Version GetVersion (Application app)
{
switch (app.Platform) {

Просмотреть файл

@ -20,6 +20,7 @@ using Registrar;
using Foundation;
using ObjCRuntime;
using Mono.Cecil;
using Mono.Linker;
using Mono.Tuner;
namespace Registrar {

Просмотреть файл

@ -26,10 +26,16 @@ using MonoTouch;
using MonoTouch.Tuner;
using PlatformResolver = MonoTouch.Tuner.MonoTouchResolver;
using PlatformLinkContext = MonoTouch.Tuner.MonoTouchLinkContext;
#else
#elif MMP
using MonoMac.Tuner;
using PlatformResolver = Xamarin.Bundler.MonoMacResolver;
using PlatformLinkContext = MonoMac.Tuner.MonoMacLinkContext;
#elif NET
using LinkerOptions = Xamarin.Linker.LinkerConfiguration;
using PlatformLinkContext = Xamarin.Tuner.DerivedLinkContext;
using PlatformResolver = Xamarin.Linker.DotNetResolver;
#else
#error Invalid defines
#endif
namespace Xamarin.Bundler {
@ -80,6 +86,13 @@ namespace Xamarin.Bundler {
this.StaticRegistrar = new StaticRegistrar (this);
}
public Assembly AddAssembly (AssemblyDefinition assembly)
{
var asm = new Assembly (this, assembly);
Assemblies.Add (asm);
return asm;
}
// This will find the link context, possibly looking in container targets.
public PlatformLinkContext GetLinkContext ()
{

Просмотреть файл

@ -13,6 +13,8 @@ public class Cache {
const string NAME = "mmp";
#elif MTOUCH
const string NAME = "mtouch";
#elif BUNDLER
const string NAME = "dotnet-linker";
#else
#error Wrong defines
#endif

Просмотреть файл

@ -1,51 +1,109 @@
// Compat.cs: might not be ideal but it eases code sharing with existing code during the initial implementation.
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Linker;
using Mono.Linker.Steps;
using Xamarin.Linker;
using Xamarin.Utils;
namespace Xamarin.Bundler {
public class Application {
public partial class Application {
public LinkerConfiguration Configuration { get; private set; }
public Application (LinkerConfiguration configuration)
public Application (LinkerConfiguration configuration, string[] arguments)
: this (arguments)
{
this.Configuration = configuration;
}
// This method is needed for ErrorHelper.tools.cs to compile.
public void LoadSymbols ()
{
}
public string GetProductName ()
{
switch (Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
case ApplePlatform.WatchOS:
return "Xamarin.iOS";
case ApplePlatform.MacOSX:
return "Xamarin.Mac";
default:
throw ErrorHelper.CreateError (177, Errors.MX0177 /* "Unknown platform: {0}. This usually indicates a bug; please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new with a test case." */, Platform);
public string ProductName {
get {
switch (Platform) {
case ApplePlatform.iOS:
return "Microsoft.iOS";
case ApplePlatform.TVOS:
return "Microsoft.tvOS";
case ApplePlatform.WatchOS:
return "Microsoft.watchOS";
case ApplePlatform.MacOSX:
return "Microsoft.macOS";
default:
throw ErrorHelper.CreateError (177, Errors.MX0177 /* "Unknown platform: {0}. This usually indicates a bug; please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new with a test case." */, Platform);
}
}
}
public Version SdkVersion {
get { return Configuration.SdkVersion; }
public void SelectRegistrar ()
{
throw new NotImplementedException ();
}
}
public partial class Driver {
public static string NAME {
get { return "xamarin-bundler"; }
}
public Version DeploymentTarget {
get { return Configuration.DeploymentTarget; }
public static string GetArch32Directory (Application app)
{
throw new NotImplementedException ();
}
public bool IsSimulatorBuild {
get { return Configuration.IsSimulatorBuild; }
public static string GetArch64Directory (Application app)
{
throw new NotImplementedException ();
}
}
public class DotNetLinkContext {
public DotNetLinkContext ()
{
throw new NotImplementedException ();
}
public ApplePlatform Platform {
get { return Configuration.Platform; }
public DotNetLinkContext (Pipeline pipeline, AssemblyResolver resolver)
{
throw new NotImplementedException ();
}
public AssemblyAction UserAction {
get { throw new NotImplementedException (); }
set { throw new NotImplementedException (); }
}
public AnnotationStore Annotations {
get {
throw new NotImplementedException ();
}
}
public AssemblyDefinition GetAssembly (string name)
{
throw new NotImplementedException ();
}
}
public class Pipeline {
}
}
namespace Mono.Linker {
public static class LinkContextExtensions {
public static void LogMessage (this LinkContext context, string messsage)
{
throw new NotImplementedException ();
}
public static IEnumerable<AssemblyDefinition> GetAssemblies (this LinkContext context)
{
throw new NotImplementedException ();
}
public static Dictionary<IMetadataTokenProvider, object> GetCustomAnnotations (this AnnotationStore self, string name)
{
throw new NotImplementedException ();
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System;
namespace Xamarin.Bundler {
public static partial class Constants {
public static string Version {
get { throw new NotImplementedException (); }
}
internal static string Revision {
get { throw new NotImplementedException (); }
}
public static string SdkVersion {
get { throw new NotImplementedException (); }
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
using System;
using Mono.Cecil;
using Xamarin.Bundler;
namespace Xamarin.Linker {
public class DotNetResolver : CoreResolver {
public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters)
{
throw new NotImplementedException ();
}
}
}

Просмотреть файл

@ -5,11 +5,14 @@ using System.Linq;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using Mono.Cecil;
using Mono.Linker;
using Xamarin.Bundler;
using Xamarin.Utils;
using ObjCRuntime;
namespace Xamarin.Linker {
public class LinkerConfiguration {
public List<Abi> Abis;
@ -27,13 +30,19 @@ namespace Xamarin.Linker {
static ConditionalWeakTable<LinkContext, LinkerConfiguration> configurations = new ConditionalWeakTable<LinkContext, LinkerConfiguration> ();
public Application Application { get; private set; }
public Target Target { get; private set; }
public LinkContext Context { get; private set; }
public static LinkerConfiguration GetInstance (LinkContext context)
{
if (!configurations.TryGetValue (context, out var instance)) {
if (!context.TryGetCustomData ("LinkerOptionsFile", out var linker_options_file))
throw new Exception ($"No custom linker options file was passed to the linker (using --custom-data LinkerOptionsFile=...");
instance = new LinkerConfiguration (linker_options_file);
instance = new LinkerConfiguration (linker_options_file) {
Context = context,
};
configurations.Add (context, instance);
}
@ -46,6 +55,7 @@ namespace Xamarin.Linker {
throw new FileNotFoundException ($"The custom linker file {linker_file} does not exist.");
var lines = File.ReadAllLines (linker_file);
var significantLines = new List<string> (); // This is the input the cache uses to verify if the cache is still valid
for (var i = 0; i < lines.Length; i++) {
var line = lines [i].TrimStart ();
if (line.Length == 0 || line [0] == '#')
@ -55,6 +65,8 @@ namespace Xamarin.Linker {
if (eq == -1)
throw new InvalidOperationException ($"Invalid syntax for line {i + 1} in {linker_file}: No equals sign.");
significantLines.Add (line);
var key = line [..eq];
var value = line [(eq + 1)..];
@ -116,6 +128,11 @@ namespace Xamarin.Linker {
Abis.Add (a);
}
break;
case "TargetFramework":
if (!TargetFramework.TryParse (value, out var tf))
throw new InvalidOperationException ($"Invalid TargetFramework '{value}' in {linker_file}");
Driver.TargetFramework = TargetFramework.Parse (value);
break;
case "Verbosity":
if (!int.TryParse (value, out var verbosity))
throw new InvalidOperationException ($"Invalid Verbosity '{value}' in {linker_file}");
@ -128,7 +145,29 @@ namespace Xamarin.Linker {
ErrorHelper.Platform = Platform;
Application = new Application (this);
Application = new Application (this, significantLines.ToArray ());
Target = new Target (Application);
Application.Cache.Location = CacheDirectory;
Application.DeploymentTarget = DeploymentTarget;
Application.SdkVersion = SdkVersion;
switch (Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
case ApplePlatform.WatchOS:
Application.BuildTarget = IsSimulatorBuild ? BuildTarget.Simulator : BuildTarget.Device;
break;
case ApplePlatform.MacOSX:
default:
break;
}
if (Driver.TargetFramework.Platform != Platform)
throw ErrorHelper.CreateError (99, "Inconsistent platforms. TargetFramework={0}, Platform={1}", Driver.TargetFramework.Platform, Platform);
Driver.Verbosity = Verbosity;
ErrorHelper.Verbosity = Verbosity;
}
public void Write ()
@ -148,6 +187,15 @@ namespace Xamarin.Linker {
}
}
public string GetAssemblyFileName (AssemblyDefinition assembly)
{
// See: https://github.com/mono/linker/issues/1313
// Call LinkContext.Resolver.GetAssemblyFileName (https://github.com/mono/linker/blob/da2cc0fcd6c3a8e8e5d1b5d4a655f3653baa8980/src/linker/Linker/AssemblyResolver.cs#L88) using reflection.
var resolver = typeof (LinkContext).GetProperty ("Resolver").GetValue (Context);
var filename = (string) resolver.GetType ().GetMethod ("GetAssemblyFileName", new Type [] { typeof (AssemblyDefinition) }).Invoke (resolver, new object [] { assembly });
return filename;
}
public void WriteOutputForMSBuild (string itemName, List<MSBuildItem> items)
{
var xmlNs = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003");

Просмотреть файл

@ -29,6 +29,8 @@ namespace Xamarin {
// Don't use --custom-step to load each step, because this assembly
// is loaded into the current process once per --custom-step,
// which makes it very difficult to share state between steps.
Steps.Add (new LoadNonSkippedAssembliesStep ());
Steps.Add (new ExtractBindingLibrariesStep ());
Steps.Add (new GenerateMainStep ());
Steps.Add (new GatherFrameworksStep ());

Просмотреть файл

@ -1,9 +1,20 @@
using System;
using System.Collections.Generic;
using Mono.Linker.Steps;
using Xamarin.Bundler;
namespace Xamarin.Linker {
public abstract class ConfigurationAwareStep : BaseStep {
public LinkerConfiguration Configuration {
get { return LinkerConfiguration.GetInstance (Context); }
}
protected void Report (List<Exception> exceptions)
{
// Maybe there's a better way to show errors that integrates with the linker?
// We can't just throw an exception or exit here, since there might be only warnings in the list of exceptions.
ErrorHelper.Show (exceptions);
}
}
}

Просмотреть файл

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
namespace Xamarin.Linker {
public class ExtractBindingLibrariesStep : ConfigurationAwareStep {
protected override void EndProcess ()
{
base.EndProcess ();
// No attributes are currently linked away, which means we don't need to worry about linked away LinkWith attributes.
// Ref: https://github.com/mono/linker/issues/952 (still open as of this writing).
var exceptions = new List<Exception> ();
Configuration.Target.ExtractNativeLinkInfo (exceptions);
Report (exceptions);
// Tell MSBuild about the native libraries we found
var linkWith = new List<MSBuildItem> ();
foreach (var asm in Configuration.Target.Assemblies) {
foreach (var arg in asm.LinkWith) {
var item = new MSBuildItem {
Include = arg,
Metadata = new Dictionary<string, string> {
{ "ForceLoad", "true" },
{ "Assembly", asm.Identity },
},
};
linkWith.Add (item);
}
}
Configuration.WriteOutputForMSBuild ("_BindingLibraryLinkWith", linkWith);
// Tell MSBuild about the frameworks libraries we found
var frameworks = new List<MSBuildItem> ();
foreach (var asm in Configuration.Target.Assemblies) {
foreach (var fw in asm.Frameworks) {
var item = new MSBuildItem {
Include = fw,
Metadata = new Dictionary<string, string> {
{ "Assembly", asm.Identity },
},
};
frameworks.Add (item);
}
foreach (var fw in asm.WeakFrameworks) {
var item = new MSBuildItem {
Include = fw,
Metadata = new Dictionary<string, string> {
{ "IsWeak", "true " },
{ "Assembly", asm.Identity },
},
};
frameworks.Add (item);
}
}
Configuration.WriteOutputForMSBuild ("_BindingLibraryFrameworks", frameworks);
// Tell MSBuild about any additional linker flags we found
var linkerFlags = new List<MSBuildItem> ();
foreach (var asm in Configuration.Target.Assemblies) {
if (asm.LinkerFlags == null)
continue;
foreach (var arg in asm.LinkerFlags) {
var item = new MSBuildItem {
Include = arg,
Metadata = new Dictionary<string, string> {
{ "Assembly", asm.Identity },
},
};
linkerFlags.Add (item);
}
}
Configuration.WriteOutputForMSBuild ("_BindingLibraryLinkerFlags", linkerFlags);
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System;
using Mono.Cecil;
using Mono.Linker;
namespace Xamarin.Linker {
// List all the assemblies we care about (i.e. the ones that have not been linked away)
public class LoadNonSkippedAssembliesStep : ConfigurationAwareStep {
protected override void ProcessAssembly (AssemblyDefinition assembly)
{
base.ProcessAssembly (assembly);
// Figure out if an assembly is linked away or not
if (Context.Annotations.HasAction (assembly)) {
var action = Context.Annotations.GetAction (assembly);
switch (action) {
case AssemblyAction.Delete:
case AssemblyAction.Skip:
break;
case AssemblyAction.Copy:
case AssemblyAction.CopyUsed:
case AssemblyAction.Link:
case AssemblyAction.Save:
var ad = Configuration.Target.AddAssembly (assembly);
var assemblyFileName = Configuration.GetAssemblyFileName (assembly);
ad.FullPath = assemblyFileName;
break;
case AssemblyAction.AddBypassNGen: // This should be turned into Save or Delete
case AssemblyAction.AddBypassNGenUsed: // This should be turned into Save or Delete
// Log this?
break;
default:
// Log this?
break;
}
} else {
// Log this?
}
}
}
}

Просмотреть файл

@ -3,6 +3,7 @@
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>dotnet_linker</RootNamespace>
<DefineConstants>$(DefineConstants);BUNDLER</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="XliffTasks" Version="1.0.0-beta.20154.1" />
@ -18,6 +19,9 @@
<Compile Include="..\..\src\ObjCRuntime\ErrorHelper.cs">
<Link>src\ObjCRuntime\ErrorHelper.cs</Link>
</Compile>
<Compile Include="..\common\CoreResolver.cs">
<Link>external\tools\common\CoreResolver.cs</Link>
</Compile>
<Compile Include="..\common\error.cs">
<Link>tools\common\error.cs</Link>
</Compile>
@ -31,6 +35,123 @@
<Compile Include="..\common\Frameworks.cs">
<Link>tools\common\Frameworks.cs</Link>
</Compile>
<Compile Include="..\mtouch\Stripper.cs">
<Link>external\tools\mtouch\Stripper.cs</Link>
</Compile>
<Compile Include="..\common\Application.cs">
<Link>external\tools\common\Application.cs</Link>
</Compile>
<Compile Include="..\common\cache.cs">
<Link>external\tools\common\cache.cs</Link>
</Compile>
<Compile Include="..\common\Assembly.cs">
<Link>external\tools\common\Assembly.cs</Link>
</Compile>
<Compile Include="..\common\Driver.cs">
<Link>external\tools\common\Driver.cs</Link>
</Compile>
<Compile Include="..\common\Driver.execution.cs">
<Link>external\tools\common\Driver.execution.cs</Link>
</Compile>
<Compile Include="..\common\Execution.cs">
<Link>external\tools\common\Execution.cs</Link>
</Compile>
<Compile Include="..\common\FileCopier.cs">
<Link>external\tools\common\FileCopier.cs</Link>
</Compile>
<Compile Include="..\common\LinkMode.cs">
<Link>external\tools\common\LinkMode.cs</Link>
</Compile>
<Compile Include="..\common\SdkVersions.cs">
<Link>external\tools\common\SdkVersions.cs</Link>
</Compile>
<Compile Include="..\common\Symbols.cs">
<Link>external\tools\common\Symbols.cs</Link>
</Compile>
<Compile Include="..\common\Target.cs">
<Link>external\tools\common\Assembly.cs</Link>
</Compile>
<Compile Include="..\common\DerivedLinkContext.cs">
<Link>external\tools\common\DerivedLinkContext.cs</Link>
</Compile>
<Compile Include="..\common\Optimizations.cs">
<Link>external\tools\common\Optimizations.cs</Link>
</Compile>
<Compile Include="..\common\PInvokeWrapperGenerator.cs">
<Link>external\tools\common\PInvokeWrapperGenerator.cs</Link>
</Compile>
<Compile Include="..\common\PListExtensions.cs">
<Link>external\tools\common\PListExtensions.cs</Link>
</Compile>
<Compile Include="..\common\StaticRegistrar.cs">
<Link>external\tools\common\StaticRegistrar.cs</Link>
</Compile>
<Compile Include="..\common\StringUtils.cs">
<Link>external\tools\common\StringUtils.cs</Link>
</Compile>
<Compile Include="..\common\TargetFramework.cs">
<Link>external\tools\common\TargetFramework.cs</Link>
</Compile>
<Compile Include="..\linker\CustomSymbolWriter.cs">
<Link>external\tools\linker\CustomSymbolWriter.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\Registrar.cs">
<Link>external\src\ObjCRuntime\Registrar.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\Registrar.core.cs">
<Link>external\src\ObjCRuntime\Registrar.core.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\ArgumentSemantic.cs">
<Link>external\src\ObjCRuntime\ArgumentSemantic.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\BindingImplAttribute.cs">
<Link>external\src\ObjCRuntime\BindingImplAttribute.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\Constants.cs">
<Link>external\src\ObjCRuntime\Constants.cs</Link>
</Compile>
<Compile Include="..\..\src\Foundation\ExportAttribute.cs">
<Link>external\src\Foundation\ExportAttribute.cs</Link>
</Compile>
<Compile Include="..\..\src\Foundation\ConnectAttribute.cs">
<Link>external\src\Foundation\ConnectAttribute.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\ExceptionMode.cs">
<Link>external\src\ObjCRuntime\ExceptionMode.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\LinkWithAttribute.cs">
<Link>external\src\ObjCRuntime\LinkWithAttribute.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\PlatformAvailability2.cs">
<Link>external\src\ObjCRuntime\PlatformAvailability2.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\RuntimeOptions.cs">
<Link>external\src\ObjCRuntime\RuntimeOptions.cs</Link>
</Compile>
<Compile Include="..\linker\MonoTouch.Tuner\Extensions.cs">
<Link>external\tools\linker\MonoTouch.Tuner\Extensions.cs</Link>
</Compile>
<Compile Include="..\linker\MobileExtensions.cs">
<Link>external\tools\linker\MobileExtensions.cs</Link>
</Compile>
<Compile Include="..\linker\ObjCExtensions.cs">
<Link>external\tools\linker\ObjCExtensions.cs</Link>
</Compile>
<Compile Include="..\..\builds\mono-ios-sdk-destdir\ios-sources\external\linker\src\tuner\Mono.Tuner\Extensions.cs">
<Link>external\mono-archive\Mono.Tuner\Extensions.cs</Link>
</Compile>
<Compile Include="..\..\builds\mono-ios-sdk-destdir\ios-sources\external\linker\src\linker\Linker\AssemblyResolver.cs">
<Link>external\mono-archive\Linker\AssemblyResolver.cs</Link>
</Compile>
<Compile Include="..\..\builds\mono-ios-sdk-destdir\ios-sources\external\linker\src\linker\Linker\I18nAssemblies.cs">
<Link>external\mono-archive\Linker\I18nAssemblies.cs</Link>
</Compile>
<Compile Include="..\..\builds\mono-ios-sdk-destdir\ios-sources\external\linker\src\tuner\Mono.Tuner\CecilRocks.cs">
<Link>external\mono-archive\Mono.Tuner\CecilRocks.cs</Link>
</Compile>
<Compile Include="..\..\external\Xamarin.MacDev\Xamarin.MacDev\PListObject.cs">
<Link>external\Xamarin.MacDev\Xamarin.MacDev\PListObject.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\mtouch\Errors.resx">

Просмотреть файл

@ -1609,9 +1609,8 @@ namespace Xamarin.Bundler {
Target.PrintAssemblyReferences (assembly);
var asm = new Assembly (BuildTarget, assembly);
var asm = BuildTarget.AddAssembly (assembly);
asm.ComputeSatellites ();
BuildTarget.Assemblies.Add (asm);
resolved_assemblies.Add (fqname);

Просмотреть файл

@ -336,9 +336,8 @@ namespace Xamarin.Bundler
// Load all the assemblies in the cached list of assemblies
foreach (var assembly in assemblies) {
var ad = ManifestResolver.Load (assembly);
var asm = new Assembly (this, ad);
var asm = AddAssembly (ad);
asm.ComputeSatellites ();
this.Assemblies.Add (asm);
}
return;
}
@ -381,9 +380,8 @@ namespace Xamarin.Bundler
PrintAssemblyReferences (assembly);
assemblies.Add (fqname);
var asm = new Assembly (this, assembly);
var asm = AddAssembly (assembly);
asm.ComputeSatellites ();
this.Assemblies.Add (asm);
var main = assembly.MainModule;
foreach (AssemblyNameReference reference in main.AssemblyReferences) {

Просмотреть файл

@ -1154,7 +1154,7 @@ namespace Xamarin.Bundler
static bool IsBoundAssembly (Assembly s)
{
if (s.IsFrameworkAssembly)
if (s.IsFrameworkAssembly == true)
return false;
AssemblyDefinition ad = s.AssemblyDefinition;