2016-04-21 15:57:02 +03:00
|
|
|
using System;
|
2017-01-24 12:48:40 +03:00
|
|
|
using System.Collections;
|
2016-04-21 15:57:02 +03:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
2018-12-12 17:55:57 +03:00
|
|
|
using System.Xml;
|
2016-04-21 15:57:02 +03:00
|
|
|
using Mono.Cecil;
|
2020-08-27 21:02:30 +03:00
|
|
|
using Mono.Tuner;
|
2016-04-21 15:57:02 +03:00
|
|
|
using MonoTouch.Tuner;
|
2018-02-05 18:26:29 +03:00
|
|
|
using ObjCRuntime;
|
2018-12-12 17:55:57 +03:00
|
|
|
using Xamarin;
|
2017-06-06 23:32:25 +03:00
|
|
|
using Xamarin.Utils;
|
2016-04-21 15:57:02 +03:00
|
|
|
|
|
|
|
namespace Xamarin.Bundler {
|
2018-12-12 17:55:57 +03:00
|
|
|
|
|
|
|
struct NativeReferenceMetadata
|
|
|
|
{
|
|
|
|
public bool ForceLoad;
|
|
|
|
public string Frameworks;
|
|
|
|
public string WeakFrameworks;
|
|
|
|
public string LibraryName;
|
|
|
|
public string LinkerFlags;
|
|
|
|
public LinkTarget LinkTarget;
|
|
|
|
public bool NeedsGccExceptionHandling;
|
|
|
|
public bool IsCxx;
|
|
|
|
public bool SmartLink;
|
|
|
|
public DlsymOption Dlsym;
|
|
|
|
|
|
|
|
// Optional
|
|
|
|
public LinkWithAttribute Attribute;
|
|
|
|
|
|
|
|
public NativeReferenceMetadata (LinkWithAttribute attribute)
|
|
|
|
{
|
|
|
|
ForceLoad = attribute.ForceLoad;
|
|
|
|
Frameworks = attribute.Frameworks;
|
|
|
|
WeakFrameworks = attribute.WeakFrameworks;
|
|
|
|
LibraryName = attribute.LibraryName;
|
|
|
|
LinkerFlags = attribute.LinkerFlags;
|
|
|
|
LinkTarget = attribute.LinkTarget;
|
|
|
|
NeedsGccExceptionHandling = attribute.NeedsGccExceptionHandling;
|
|
|
|
IsCxx = attribute.IsCxx;
|
|
|
|
SmartLink = attribute.SmartLink;
|
|
|
|
Dlsym = attribute.Dlsym;
|
|
|
|
Attribute = attribute;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
public partial class Assembly
|
|
|
|
{
|
2020-10-22 22:05:58 +03:00
|
|
|
public AssemblyBuildTarget BuildTarget;
|
|
|
|
public string BuildTargetName;
|
|
|
|
public bool IsCodeShared;
|
2017-01-20 12:45:08 +03:00
|
|
|
public List<string> Satellites;
|
2016-04-21 15:57:02 +03:00
|
|
|
public Application App { get { return Target.App; } }
|
|
|
|
|
|
|
|
string full_path;
|
|
|
|
bool? is_framework_assembly;
|
|
|
|
|
|
|
|
public AssemblyDefinition AssemblyDefinition;
|
|
|
|
public Target Target;
|
2020-07-17 17:38:40 +03:00
|
|
|
public bool? IsFrameworkAssembly { get { return is_framework_assembly; } }
|
2016-04-21 15:57:02 +03:00
|
|
|
public string FullPath {
|
|
|
|
get {
|
|
|
|
return full_path;
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
full_path = value;
|
2020-07-17 17:38:40 +03:00
|
|
|
if (!is_framework_assembly.HasValue && !string.IsNullOrEmpty (full_path)) {
|
|
|
|
#if NET
|
2020-09-07 19:33:53 +03:00
|
|
|
is_framework_assembly = Target.App.Configuration.FrameworkAssemblies.Contains (GetIdentity (full_path));
|
2020-07-17 17:38:40 +03:00
|
|
|
#else
|
2020-09-07 19:33:53 +03:00
|
|
|
var real_full_path = Target.GetRealPath (full_path);
|
2016-10-14 21:14:27 +03:00
|
|
|
is_framework_assembly = real_full_path.StartsWith (Path.GetDirectoryName (Path.GetDirectoryName (Target.Resolver.FrameworkDirectory)), StringComparison.Ordinal);
|
2020-07-17 17:38:40 +03:00
|
|
|
#endif
|
2016-10-14 21:14:27 +03:00
|
|
|
}
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
public string FileName { get { return Path.GetFileName (FullPath); } }
|
2020-07-17 17:38:40 +03:00
|
|
|
public string Identity { get { return GetIdentity (AssemblyDefinition); } }
|
2017-01-24 12:48:40 +03:00
|
|
|
|
|
|
|
public static string GetIdentity (AssemblyDefinition ad)
|
|
|
|
{
|
2020-07-17 17:38:40 +03:00
|
|
|
if (!string.IsNullOrEmpty (ad.MainModule.FileName))
|
|
|
|
return Path.GetFileNameWithoutExtension (ad.MainModule.FileName);
|
|
|
|
return ad.Name.Name;
|
2017-01-24 12:48:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public static string GetIdentity (string path)
|
|
|
|
{
|
|
|
|
return Path.GetFileNameWithoutExtension (path);
|
|
|
|
}
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
public bool EnableCxx;
|
|
|
|
public bool NeedsGccExceptionHandling;
|
|
|
|
public bool ForceLoad;
|
2017-01-16 20:35:28 +03:00
|
|
|
public HashSet<string> Frameworks = new HashSet<string> ();
|
|
|
|
public HashSet<string> WeakFrameworks = new HashSet<string> ();
|
|
|
|
public List<string> LinkerFlags = new List<string> (); // list of extra linker flags
|
2017-01-18 12:25:58 +03:00
|
|
|
public List<string> LinkWith = new List<string> (); // list of paths to native libraries to link with, from LinkWith attributes
|
2016-04-21 15:57:02 +03:00
|
|
|
public HashSet<ModuleReference> UnresolvedModuleReferences;
|
2017-01-18 12:25:58 +03:00
|
|
|
public bool HasLinkWithAttributes { get; private set; }
|
2016-04-21 15:57:02 +03:00
|
|
|
|
|
|
|
bool? symbols_loaded;
|
|
|
|
|
|
|
|
List<string> link_with_resources; // a list of resources that must be removed from the app
|
|
|
|
|
|
|
|
public Assembly (Target target, string path)
|
|
|
|
{
|
|
|
|
this.Target = target;
|
|
|
|
this.FullPath = path;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Assembly (Target target, AssemblyDefinition definition)
|
|
|
|
{
|
|
|
|
this.Target = target;
|
|
|
|
this.AssemblyDefinition = definition;
|
2016-08-24 16:43:35 +03:00
|
|
|
this.FullPath = definition.MainModule.FileName;
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
|
|
|
|
2020-08-04 09:08:44 +03:00
|
|
|
public bool HasValidSymbols {
|
|
|
|
get {
|
|
|
|
return AssemblyDefinition.MainModule.HasSymbols;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
public void LoadSymbols ()
|
|
|
|
{
|
|
|
|
if (symbols_loaded.HasValue)
|
|
|
|
return;
|
|
|
|
|
|
|
|
symbols_loaded = false;
|
|
|
|
try {
|
2017-04-13 00:38:54 +03:00
|
|
|
var pdb = Path.ChangeExtension (FullPath, ".pdb");
|
|
|
|
if (File.Exists (pdb) || File.Exists (FullPath + ".mdb")) {
|
2016-04-21 15:57:02 +03:00
|
|
|
AssemblyDefinition.MainModule.ReadSymbols ();
|
|
|
|
symbols_loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch {
|
|
|
|
// do not let stale file crash us
|
|
|
|
Driver.Log (3, "Invalid debugging symbols for {0} ignored", FullPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddResourceToBeRemoved (string resource)
|
|
|
|
{
|
|
|
|
if (link_with_resources == null)
|
|
|
|
link_with_resources = new List<string> ();
|
|
|
|
link_with_resources.Add (resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ExtractNativeLinkInfo ()
|
|
|
|
{
|
|
|
|
// ignore framework assemblies, they won't have any LinkWith attributes
|
2020-07-17 17:38:40 +03:00
|
|
|
if (IsFrameworkAssembly == true)
|
2016-04-21 15:57:02 +03:00
|
|
|
return;
|
2018-12-12 17:55:57 +03:00
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
var assembly = AssemblyDefinition;
|
|
|
|
if (!assembly.HasCustomAttributes)
|
|
|
|
return;
|
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
string resourceBundlePath = Path.ChangeExtension (FullPath, ".resources");
|
|
|
|
string manifestPath = Path.Combine (resourceBundlePath, "manifest");
|
|
|
|
if (File.Exists (manifestPath)) {
|
|
|
|
foreach (NativeReferenceMetadata metadata in ReadManifest (manifestPath)) {
|
|
|
|
LogNativeReference (metadata);
|
|
|
|
ProcessNativeReferenceOptions (metadata);
|
|
|
|
|
|
|
|
if (metadata.LibraryName.EndsWith (".framework", StringComparison.OrdinalIgnoreCase)) {
|
|
|
|
AssertiOSVersionSupportsUserFrameworks (metadata.LibraryName);
|
|
|
|
Frameworks.Add (metadata.LibraryName);
|
|
|
|
#if MMP // HACK - MMP currently doesn't respect Frameworks on non-App - https://github.com/xamarin/xamarin-macios/issues/5203
|
|
|
|
App.Frameworks.Add (metadata.LibraryName);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} else {
|
|
|
|
#if MMP // HACK - MMP currently doesn't respect LinkWith - https://github.com/xamarin/xamarin-macios/issues/5203
|
|
|
|
Driver.native_references.Add (metadata.LibraryName);
|
|
|
|
#endif
|
|
|
|
LinkWith.Add (metadata.LibraryName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ProcessLinkWithAttributes (assembly);
|
|
|
|
|
|
|
|
// Make sure there are no duplicates between frameworks and weak frameworks.
|
|
|
|
// Keep the weak ones.
|
|
|
|
if (Frameworks != null && WeakFrameworks != null)
|
|
|
|
Frameworks.ExceptWith (WeakFrameworks);
|
|
|
|
|
|
|
|
if (NeedsGccExceptionHandling) {
|
|
|
|
if (LinkerFlags == null)
|
|
|
|
LinkerFlags = new List<string> ();
|
|
|
|
LinkerFlags.Add ("-lgcc_eh");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
IEnumerable <NativeReferenceMetadata> ReadManifest (string manifestPath)
|
|
|
|
{
|
|
|
|
XmlDocument document = new XmlDocument ();
|
|
|
|
document.LoadWithoutNetworkAccess (manifestPath);
|
|
|
|
|
|
|
|
foreach (XmlNode referenceNode in document.GetElementsByTagName ("NativeReference")) {
|
|
|
|
|
|
|
|
NativeReferenceMetadata metadata = new NativeReferenceMetadata ();
|
|
|
|
metadata.LibraryName = Path.Combine (Path.GetDirectoryName (manifestPath), referenceNode.Attributes ["Name"].Value);
|
|
|
|
|
|
|
|
var attributes = new Dictionary<string, string> ();
|
|
|
|
foreach (XmlNode attribute in referenceNode.ChildNodes)
|
|
|
|
attributes [attribute.Name] = attribute.InnerText;
|
|
|
|
|
|
|
|
metadata.ForceLoad = ParseAttributeWithDefault (attributes ["ForceLoad"], false);
|
|
|
|
metadata.Frameworks = attributes ["Frameworks"];
|
|
|
|
metadata.WeakFrameworks = attributes ["WeakFrameworks"];
|
|
|
|
metadata.LinkerFlags = attributes ["LinkerFlags"];
|
|
|
|
metadata.NeedsGccExceptionHandling = ParseAttributeWithDefault (attributes ["NeedsGccExceptionHandling"], false);
|
|
|
|
metadata.IsCxx = ParseAttributeWithDefault (attributes ["IsCxx"], false);
|
|
|
|
metadata.SmartLink = ParseAttributeWithDefault (attributes ["SmartLink"], true);
|
|
|
|
|
|
|
|
// TODO - The project attributes do not contain these bits, is that OK?
|
|
|
|
//metadata.LinkTarget = (LinkTarget) Enum.Parse (typeof (LinkTarget), attributes ["LinkTarget"]);
|
|
|
|
//metadata.Dlsym = (DlsymOption)Enum.Parse (typeof (DlsymOption), attributes ["Dlsym"]);
|
|
|
|
yield return metadata;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ParseAttributeWithDefault (string attribute, bool defaultValue) => string.IsNullOrEmpty (attribute) ? defaultValue : bool.Parse (attribute);
|
|
|
|
|
|
|
|
void ProcessLinkWithAttributes (AssemblyDefinition assembly)
|
|
|
|
{
|
2016-04-21 15:57:02 +03:00
|
|
|
//
|
|
|
|
// Tasks:
|
|
|
|
// * Remove LinkWith attribute: this is done in the linker.
|
|
|
|
// * Remove embedded resources related to LinkWith attribute from assembly: this is done at a later stage,
|
|
|
|
// here we just compile a list of resources to remove.
|
|
|
|
// * Extract embedded resources related to LinkWith attribute to a file
|
|
|
|
// * Modify the linker flags used to build/link the dylib (if fastdev) or the main binary (if !fastdev)
|
|
|
|
//
|
|
|
|
|
|
|
|
for (int i = 0; i < assembly.CustomAttributes.Count; i++) {
|
2018-12-12 17:55:57 +03:00
|
|
|
CustomAttribute attr = assembly.CustomAttributes [i];
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
if (attr.Constructor == null)
|
|
|
|
continue;
|
2018-12-12 17:55:57 +03:00
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
TypeReference type = attr.Constructor.DeclaringType;
|
2020-08-27 21:02:30 +03:00
|
|
|
if (!type.Is ("ObjCRuntime", "LinkWithAttribute"))
|
2016-04-21 15:57:02 +03:00
|
|
|
continue;
|
2018-12-12 17:55:57 +03:00
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
// Let the linker remove it the attribute from the assembly
|
2017-01-18 12:25:58 +03:00
|
|
|
HasLinkWithAttributes = true;
|
2018-12-12 17:55:57 +03:00
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
LinkWithAttribute linkWith = GetLinkWithAttribute (attr);
|
2018-12-12 17:55:57 +03:00
|
|
|
NativeReferenceMetadata metadata = new NativeReferenceMetadata (linkWith);
|
|
|
|
|
|
|
|
// If we've already processed this native library, skip it
|
|
|
|
if (LinkWith.Any (x => Path.GetFileName (x) == metadata.LibraryName) || Frameworks.Any (x => Path.GetFileName (x) == metadata.LibraryName))
|
|
|
|
continue;
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
// Remove the resource from the assembly at a later stage.
|
2018-12-12 17:55:57 +03:00
|
|
|
if (!string.IsNullOrEmpty (metadata.LibraryName))
|
|
|
|
AddResourceToBeRemoved (metadata.LibraryName);
|
|
|
|
|
|
|
|
ProcessNativeReferenceOptions (metadata);
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty (linkWith.LibraryName)) {
|
|
|
|
if (linkWith.LibraryName.EndsWith (".framework", StringComparison.OrdinalIgnoreCase)) {
|
|
|
|
AssertiOSVersionSupportsUserFrameworks (linkWith.LibraryName);
|
|
|
|
|
|
|
|
Frameworks.Add (ExtractFramework (assembly, metadata));
|
|
|
|
} else {
|
|
|
|
LinkWith.Add (ExtractNativeLibrary (assembly, metadata));
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
|
|
|
}
|
2018-12-12 17:55:57 +03:00
|
|
|
}
|
|
|
|
}
|
2016-04-21 15:57:02 +03:00
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
void AssertiOSVersionSupportsUserFrameworks (string path)
|
|
|
|
{
|
2020-09-28 09:36:47 +03:00
|
|
|
if (App.Platform == ApplePlatform.iOS && App.DeploymentTarget.Major < 8) {
|
2020-01-31 23:02:52 +03:00
|
|
|
throw ErrorHelper.CreateError (1305, Errors.MT1305,
|
2018-12-12 17:55:57 +03:00
|
|
|
FileName, Path.GetFileName (path), App.DeploymentTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProcessNativeReferenceOptions (NativeReferenceMetadata metadata)
|
|
|
|
{
|
|
|
|
// We can't add -dead_strip if there are any LinkWith attributes where smart linking is disabled.
|
|
|
|
if (!metadata.SmartLink)
|
|
|
|
App.DeadStrip = false;
|
|
|
|
|
|
|
|
// Don't add -force_load if the binding's SmartLink value is set and the static registrar is being used.
|
|
|
|
if (metadata.ForceLoad && !(metadata.SmartLink && App.Registrar == RegistrarMode.Static))
|
|
|
|
ForceLoad = true;
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty (metadata.LinkerFlags)) {
|
|
|
|
if (LinkerFlags == null)
|
|
|
|
LinkerFlags = new List<string> ();
|
2019-10-14 17:18:46 +03:00
|
|
|
if (!StringUtils.TryParseArguments (metadata.LinkerFlags, out string [] args, out var ex))
|
2020-01-31 23:02:52 +03:00
|
|
|
throw ErrorHelper.CreateError (148, ex, Errors.MX0148, metadata.LinkerFlags, metadata.LibraryName, FileName, ex.Message);
|
2019-10-14 17:18:46 +03:00
|
|
|
LinkerFlags.AddRange (args);
|
2018-12-12 17:55:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty (metadata.Frameworks)) {
|
|
|
|
foreach (var f in metadata.Frameworks.Split (new char [] { ' ' })) {
|
|
|
|
if (Frameworks == null)
|
|
|
|
Frameworks = new HashSet<string> ();
|
|
|
|
Frameworks.Add (f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty (metadata.WeakFrameworks)) {
|
|
|
|
foreach (var f in metadata.WeakFrameworks.Split (new char [] { ' ' })) {
|
|
|
|
if (WeakFrameworks == null)
|
|
|
|
WeakFrameworks = new HashSet<string> ();
|
|
|
|
WeakFrameworks.Add (f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (metadata.NeedsGccExceptionHandling)
|
|
|
|
NeedsGccExceptionHandling = true;
|
|
|
|
|
|
|
|
if (metadata.IsCxx)
|
|
|
|
EnableCxx = true;
|
2016-04-21 15:57:02 +03:00
|
|
|
|
2016-10-28 17:50:42 +03:00
|
|
|
#if MONOTOUCH
|
2018-12-12 17:55:57 +03:00
|
|
|
if (metadata.Dlsym != DlsymOption.Default)
|
|
|
|
App.SetDlsymOption (FullPath, metadata.Dlsym == DlsymOption.Required);
|
2016-10-28 17:50:42 +03:00
|
|
|
#endif
|
2018-12-12 17:55:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
string ExtractNativeLibrary (AssemblyDefinition assembly, NativeReferenceMetadata metadata)
|
|
|
|
{
|
|
|
|
string path = Path.Combine (App.Cache.Location, metadata.LibraryName);
|
|
|
|
|
|
|
|
if (!Application.IsUptodate (FullPath, path)) {
|
|
|
|
Application.ExtractResource (assembly.MainModule, metadata.LibraryName, path, false);
|
|
|
|
Driver.Log (3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", metadata.LibraryName, FullPath, path);
|
|
|
|
LogNativeReference (metadata);
|
|
|
|
} else {
|
|
|
|
Driver.Log (3, "Target '{0}' is up-to-date.", path);
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
if (!File.Exists (path))
|
2020-01-31 23:02:52 +03:00
|
|
|
ErrorHelper.Warning (1302, Errors.MT1302, metadata.LibraryName, path);
|
2016-04-21 15:57:02 +03:00
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
return path;
|
|
|
|
}
|
2016-04-21 15:57:02 +03:00
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
string ExtractFramework (AssemblyDefinition assembly, NativeReferenceMetadata metadata)
|
|
|
|
{
|
|
|
|
string path = Path.Combine (App.Cache.Location, metadata.LibraryName);
|
|
|
|
|
|
|
|
var zipPath = path + ".zip";
|
|
|
|
if (!Application.IsUptodate (FullPath, zipPath)) {
|
|
|
|
Application.ExtractResource (assembly.MainModule, metadata.LibraryName, zipPath, false);
|
|
|
|
Driver.Log (3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", metadata.LibraryName, FullPath, zipPath);
|
|
|
|
LogNativeReference (metadata);
|
|
|
|
} else {
|
|
|
|
Driver.Log (3, "Target '{0}' is up-to-date.", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!File.Exists (zipPath)) {
|
2020-01-31 23:02:52 +03:00
|
|
|
ErrorHelper.Warning (1302, Errors.MT1302, metadata.LibraryName, zipPath);
|
2018-12-12 17:55:57 +03:00
|
|
|
} else {
|
|
|
|
if (!Directory.Exists (path))
|
|
|
|
Directory.CreateDirectory (path);
|
|
|
|
|
2019-10-14 17:18:46 +03:00
|
|
|
if (Driver.RunCommand ("/usr/bin/unzip", "-u", "-o", "-d", path, zipPath) != 0)
|
2020-01-31 23:02:52 +03:00
|
|
|
throw ErrorHelper.CreateError (1303, Errors.MT1303, metadata.LibraryName, zipPath);
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
return path;
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
|
|
|
|
2018-12-12 17:55:57 +03:00
|
|
|
static void LogNativeReference (NativeReferenceMetadata metadata)
|
2016-09-26 17:23:28 +03:00
|
|
|
{
|
2018-12-12 17:55:57 +03:00
|
|
|
Driver.Log (3, " LibraryName: {0}", metadata.LibraryName);
|
|
|
|
Driver.Log (3, " From: {0}", metadata.Attribute != null ? "LinkWith" : "Binding Manifest");
|
|
|
|
Driver.Log (3, " ForceLoad: {0}", metadata.ForceLoad);
|
|
|
|
Driver.Log (3, " Frameworks: {0}", metadata.Frameworks);
|
|
|
|
Driver.Log (3, " IsCxx: {0}", metadata.IsCxx);
|
|
|
|
Driver.Log (3, " LinkerFlags: {0}", metadata.LinkerFlags);
|
|
|
|
Driver.Log (3, " LinkTarget: {0}", metadata.LinkTarget);
|
|
|
|
Driver.Log (3, " NeedsGccExceptionHandling: {0}", metadata.NeedsGccExceptionHandling);
|
|
|
|
Driver.Log (3, " SmartLink: {0}", metadata.SmartLink);
|
|
|
|
Driver.Log (3, " WeakFrameworks: {0}", metadata.WeakFrameworks);
|
2016-09-26 17:23:28 +03:00
|
|
|
}
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
public static LinkWithAttribute GetLinkWithAttribute (CustomAttribute attr)
|
|
|
|
{
|
|
|
|
LinkWithAttribute linkWith;
|
|
|
|
|
|
|
|
var cargs = attr.ConstructorArguments;
|
|
|
|
switch (cargs.Count) {
|
|
|
|
case 3:
|
|
|
|
linkWith = new LinkWithAttribute ((string) cargs [0].Value, (LinkTarget) cargs [1].Value, (string) cargs [2].Value);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
linkWith = new LinkWithAttribute ((string) cargs [0].Value, (LinkTarget) cargs [1].Value);
|
|
|
|
break;
|
2016-10-28 17:50:42 +03:00
|
|
|
case 0:
|
|
|
|
linkWith = new LinkWithAttribute ();
|
|
|
|
break;
|
2016-04-21 15:57:02 +03:00
|
|
|
default:
|
|
|
|
case 1:
|
|
|
|
linkWith = new LinkWithAttribute ((string) cargs [0].Value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (var property in attr.Properties) {
|
|
|
|
switch (property.Name) {
|
|
|
|
case "NeedsGccExceptionHandling":
|
|
|
|
linkWith.NeedsGccExceptionHandling = (bool) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "WeakFrameworks":
|
|
|
|
linkWith.WeakFrameworks = (string) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "Frameworks":
|
|
|
|
linkWith.Frameworks = (string) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "LinkerFlags":
|
|
|
|
linkWith.LinkerFlags = (string) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "LinkTarget":
|
|
|
|
linkWith.LinkTarget = (LinkTarget) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "ForceLoad":
|
|
|
|
linkWith.ForceLoad = (bool) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "IsCxx":
|
|
|
|
linkWith.IsCxx = (bool) property.Argument.Value;
|
|
|
|
break;
|
|
|
|
case "SmartLink":
|
|
|
|
linkWith.SmartLink = (bool) property.Argument.Value;
|
|
|
|
break;
|
2016-10-28 17:50:42 +03:00
|
|
|
case "Dlsym":
|
|
|
|
linkWith.Dlsym = (DlsymOption) property.Argument.Value;
|
|
|
|
break;
|
2016-04-21 15:57:02 +03:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return linkWith;
|
|
|
|
}
|
|
|
|
|
2018-03-20 17:26:25 +03:00
|
|
|
void AddFramework (string file)
|
|
|
|
{
|
|
|
|
if (Driver.GetFrameworks (App).TryGetValue (file, out var framework) && framework.Version > App.SdkVersion)
|
2020-01-31 23:02:52 +03:00
|
|
|
ErrorHelper.Warning (135, Errors.MX0135, file, FileName, App.PlatformName, framework.Version, App.SdkVersion);
|
2019-03-14 16:12:42 +03:00
|
|
|
else {
|
|
|
|
var strong = (framework == null) || (App.DeploymentTarget >= (App.IsSimulatorBuild ? framework.VersionAvailableInSimulator ?? framework.Version : framework.Version));
|
|
|
|
if (strong) {
|
|
|
|
if (Frameworks.Add (file))
|
|
|
|
Driver.Log (3, "Linking with the framework {0} because it's referenced by a module reference in {1}", file, FileName);
|
|
|
|
} else {
|
|
|
|
if (WeakFrameworks.Add (file))
|
|
|
|
Driver.Log (3, "Linking (weakly) with the framework {0} because it's referenced by a module reference in {1}", file, FileName);
|
|
|
|
}
|
|
|
|
}
|
2018-03-20 17:26:25 +03:00
|
|
|
}
|
|
|
|
|
2018-06-05 19:12:27 +03:00
|
|
|
public string GetCompressionLinkingFlag ()
|
|
|
|
{
|
|
|
|
switch(App.Platform) {
|
|
|
|
case ApplePlatform.MacOSX:
|
|
|
|
if (App.DeploymentTarget >= new Version (10, 11, 0))
|
|
|
|
return "-lcompression";
|
|
|
|
return "-weak-lcompression";
|
|
|
|
case ApplePlatform.iOS:
|
|
|
|
if (App.DeploymentTarget >= new Version (9,0))
|
|
|
|
return "-lcompression";
|
|
|
|
return "-weak-lcompression";
|
|
|
|
case ApplePlatform.TVOS:
|
|
|
|
case ApplePlatform.WatchOS:
|
|
|
|
return "-lcompression";
|
|
|
|
default:
|
2020-01-31 23:02:52 +03:00
|
|
|
throw ErrorHelper.CreateError (71, Errors.MX0071, App.Platform, App.SdkVersion);
|
2018-06-05 19:12:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
public void ComputeLinkerFlags ()
|
|
|
|
{
|
|
|
|
foreach (var m in AssemblyDefinition.Modules) {
|
|
|
|
if (!m.HasModuleReferences)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
foreach (var mr in m.ModuleReferences) {
|
|
|
|
string name = mr.Name;
|
2017-05-23 16:38:19 +03:00
|
|
|
if (string.IsNullOrEmpty (name))
|
|
|
|
continue; // obfuscated assemblies.
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
string file = Path.GetFileNameWithoutExtension (name);
|
2017-04-07 12:19:39 +03:00
|
|
|
|
2020-08-13 16:27:57 +03:00
|
|
|
if (App.IsSimulatorBuild && !App.IsFrameworkAvailableInSimulator (file)) {
|
2018-07-27 17:30:08 +03:00
|
|
|
Driver.Log (3, "Not linking with {0} (referenced by a module reference in {1}) because it's not available in the simulator.", file, FileName);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
switch (file) {
|
|
|
|
// special case
|
|
|
|
case "__Internal":
|
2018-11-14 21:20:48 +03:00
|
|
|
case "System.Native":
|
|
|
|
case "System.Security.Cryptography.Native.Apple":
|
|
|
|
case "System.Net.Security.Native":
|
2016-04-21 15:57:02 +03:00
|
|
|
// well known libs
|
|
|
|
case "libc":
|
|
|
|
case "libSystem":
|
|
|
|
case "libobjc":
|
|
|
|
case "libdyld":
|
|
|
|
case "libsystem_kernel":
|
|
|
|
break;
|
2016-10-14 13:34:51 +03:00
|
|
|
case "sqlite3":
|
2016-12-08 17:42:30 +03:00
|
|
|
LinkerFlags.Add ("-lsqlite3");
|
2016-10-14 13:34:51 +03:00
|
|
|
Driver.Log (3, "Linking with {0} because it's referenced by a module reference in {1}", file, FileName);
|
|
|
|
break;
|
2016-04-21 15:57:02 +03:00
|
|
|
case "libsqlite3":
|
|
|
|
// remove lib prefix
|
2016-12-08 17:42:30 +03:00
|
|
|
LinkerFlags.Add ("-l" + file.Substring (3));
|
2016-04-21 15:57:02 +03:00
|
|
|
Driver.Log (3, "Linking with {0} because it's referenced by a module reference in {1}", file, FileName);
|
2018-06-05 19:12:27 +03:00
|
|
|
break;
|
|
|
|
case "libcompression":
|
|
|
|
LinkerFlags.Add (GetCompressionLinkingFlag ());
|
|
|
|
break;
|
2016-04-21 15:57:02 +03:00
|
|
|
case "libGLES":
|
|
|
|
case "libGLESv2":
|
|
|
|
// special case for OpenGLES.framework
|
2017-01-16 20:35:28 +03:00
|
|
|
if (Frameworks.Add ("OpenGLES"))
|
2016-04-21 15:57:02 +03:00
|
|
|
Driver.Log (3, "Linking with the framework OpenGLES because {0} is referenced by a module reference in {1}", file, FileName);
|
|
|
|
break;
|
|
|
|
case "vImage":
|
|
|
|
case "vecLib":
|
|
|
|
// sub-frameworks
|
2017-01-16 20:35:28 +03:00
|
|
|
if (Frameworks.Add ("Accelerate"))
|
2016-04-21 15:57:02 +03:00
|
|
|
Driver.Log (3, "Linking with the framework Accelerate because {0} is referenced by a module reference in {1}", file, FileName);
|
|
|
|
break;
|
|
|
|
case "openal32":
|
2017-01-16 20:35:28 +03:00
|
|
|
if (Frameworks.Add ("OpenAL"))
|
|
|
|
Driver.Log (3, "Linking with the framework OpenAL because {0} is referenced by a module reference in {1}", file, FileName);
|
2016-04-21 15:57:02 +03:00
|
|
|
break;
|
|
|
|
default:
|
2020-09-28 09:36:47 +03:00
|
|
|
if (App.Platform == ApplePlatform.MacOSX) {
|
|
|
|
string path = Path.GetDirectoryName (name);
|
|
|
|
if (!path.StartsWith ("/System/Library/Frameworks", StringComparison.Ordinal))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// CoreServices has multiple sub-frameworks that can be used by customer code
|
|
|
|
if (path.StartsWith ("/System/Library/Frameworks/CoreServices.framework/", StringComparison.Ordinal)) {
|
|
|
|
if (Frameworks.Add ("CoreServices"))
|
|
|
|
Driver.Log (3, "Linking with the framework CoreServices because {0} is referenced by a module reference in {1}", file, FileName);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// ApplicationServices has multiple sub-frameworks that can be used by customer code
|
|
|
|
if (path.StartsWith ("/System/Library/Frameworks/ApplicationServices.framework/", StringComparison.Ordinal)) {
|
|
|
|
if (Frameworks.Add ("ApplicationServices"))
|
|
|
|
Driver.Log (3, "Linking with the framework ApplicationServices because {0} is referenced by a module reference in {1}", file, FileName);
|
|
|
|
break;
|
|
|
|
}
|
2017-07-31 18:54:09 +03:00
|
|
|
}
|
2017-04-14 18:45:14 +03:00
|
|
|
|
2016-04-21 15:57:02 +03:00
|
|
|
// detect frameworks
|
|
|
|
int f = name.IndexOf (".framework/", StringComparison.Ordinal);
|
|
|
|
if (f > 0) {
|
2018-03-20 17:26:25 +03:00
|
|
|
AddFramework (file);
|
2016-04-21 15:57:02 +03:00
|
|
|
} else {
|
|
|
|
if (UnresolvedModuleReferences == null)
|
|
|
|
UnresolvedModuleReferences = new HashSet<ModuleReference> ();
|
|
|
|
UnresolvedModuleReferences.Add (mr);
|
|
|
|
Driver.Log (3, "Could not resolve the module reference {0} in {1}", file, FileName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override string ToString ()
|
|
|
|
{
|
|
|
|
return FileName;
|
|
|
|
}
|
2017-01-20 12:45:08 +03:00
|
|
|
|
|
|
|
// This returns the path to all related files:
|
|
|
|
// * The assembly itself
|
|
|
|
// * Any debug files (mdb/pdb)
|
|
|
|
// * Any config files
|
|
|
|
// * Any satellite assemblies
|
|
|
|
public IEnumerable<string> GetRelatedFiles ()
|
|
|
|
{
|
|
|
|
yield return FullPath;
|
|
|
|
var mdb = FullPath + ".mdb";
|
|
|
|
if (File.Exists (mdb))
|
|
|
|
yield return mdb;
|
|
|
|
var pdb = Path.ChangeExtension (FullPath, ".pdb");
|
|
|
|
if (File.Exists (pdb))
|
|
|
|
yield return pdb;
|
|
|
|
var config = FullPath + ".config";
|
|
|
|
if (File.Exists (config))
|
|
|
|
yield return config;
|
|
|
|
if (Satellites != null) {
|
|
|
|
foreach (var satellite in Satellites)
|
|
|
|
yield return satellite;
|
|
|
|
}
|
|
|
|
}
|
2017-02-01 03:59:08 +03:00
|
|
|
|
|
|
|
public void ComputeSatellites ()
|
|
|
|
{
|
|
|
|
var satellite_name = Path.GetFileNameWithoutExtension (FullPath) + ".resources.dll";
|
2019-12-10 17:23:31 +03:00
|
|
|
var path = Path.GetDirectoryName (FullPath);
|
|
|
|
// first look if satellites are located in subdirectories of the current location of the assembly
|
|
|
|
ComputeSatellites (satellite_name, path);
|
|
|
|
if (Satellites == null) {
|
|
|
|
// 2nd chance: satellite assemblies can come from different nugets (as dependencies)
|
|
|
|
// they will be copied (at build time) into the destination directory (making them work at runtime)
|
|
|
|
// but they won't be side-by-side the original assembly (which breaks our build time assumptions)
|
|
|
|
path = Path.GetDirectoryName (App.RootAssemblies [0]);
|
2020-02-13 10:06:24 +03:00
|
|
|
if (string.IsNullOrEmpty (path))
|
|
|
|
path = Environment.CurrentDirectory;
|
2019-12-10 17:23:31 +03:00
|
|
|
ComputeSatellites (satellite_name, path);
|
|
|
|
}
|
|
|
|
}
|
2017-02-01 03:59:08 +03:00
|
|
|
|
2019-12-10 17:23:31 +03:00
|
|
|
void ComputeSatellites (string satellite_name, string path)
|
|
|
|
{
|
2017-02-01 03:59:08 +03:00
|
|
|
foreach (var subdir in Directory.GetDirectories (path)) {
|
|
|
|
var culture_name = Path.GetFileName (subdir);
|
|
|
|
CultureInfo ci;
|
|
|
|
|
|
|
|
if (culture_name.IndexOf ('.') >= 0)
|
|
|
|
continue; // cultures can't have dots. This way we don't check every *.app directory
|
|
|
|
|
2019-12-10 17:23:31 +03:00
|
|
|
// well-known subdirectories (that are not cultures) to avoid (slow) exceptions handling
|
2018-10-15 22:39:29 +03:00
|
|
|
switch (culture_name) {
|
|
|
|
case "Facades":
|
|
|
|
case "repl":
|
2019-12-10 17:23:31 +03:00
|
|
|
case "device-builds":
|
|
|
|
case "Design": // XF
|
2018-10-15 22:39:29 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-01 03:59:08 +03:00
|
|
|
try {
|
|
|
|
ci = CultureInfo.GetCultureInfo (culture_name);
|
|
|
|
} catch {
|
|
|
|
// nope, not a resource language
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ci == null)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var satellite = Path.Combine (subdir, satellite_name);
|
|
|
|
if (File.Exists (satellite)) {
|
|
|
|
if (Satellites == null)
|
|
|
|
Satellites = new List<string> ();
|
|
|
|
Satellites.Add (satellite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void CopySatellitesToDirectory (string directory)
|
|
|
|
{
|
|
|
|
if (Satellites == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
foreach (var a in Satellites) {
|
|
|
|
string target_dir = Path.Combine (directory, Path.GetFileName (Path.GetDirectoryName (a)));
|
|
|
|
string target_s = Path.Combine (target_dir, Path.GetFileName (a));
|
|
|
|
|
|
|
|
if (!Directory.Exists (target_dir))
|
|
|
|
Directory.CreateDirectory (target_dir);
|
|
|
|
|
|
|
|
CopyAssembly (a, target_s);
|
|
|
|
}
|
|
|
|
}
|
2020-08-07 09:24:09 +03:00
|
|
|
|
|
|
|
public delegate bool StripAssembly (string path);
|
|
|
|
|
|
|
|
// returns false if the assembly was not copied (because it was already up-to-date).
|
|
|
|
public bool CopyAssembly (string source, string target, bool copy_debug_symbols = true, StripAssembly strip = null)
|
|
|
|
{
|
|
|
|
var copied = false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
var strip_assembly = strip != null && strip (source);
|
|
|
|
if (!Application.IsUptodate (source, target) && (strip_assembly || !Cache.CompareAssemblies (source, target))) {
|
|
|
|
copied = true;
|
|
|
|
if (strip_assembly) {
|
|
|
|
Driver.FileDelete (target);
|
|
|
|
Directory.CreateDirectory (Path.GetDirectoryName (target));
|
|
|
|
MonoTouch.Tuner.Stripper.Process (source, target);
|
|
|
|
} else {
|
|
|
|
Application.CopyFile (source, target);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Driver.Log (3, "Target '{0}' is up-to-date.", target);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the debug symbols file even if the assembly didn't change.
|
|
|
|
if (copy_debug_symbols && HasValidSymbols) {
|
|
|
|
// Unfortunately Cecil won't tell us the path of the symbol file, so we have to try all we support (.pdb+.mdb)
|
|
|
|
if (File.Exists (source + ".mdb"))
|
|
|
|
Application.UpdateFile (source + ".mdb", target + ".mdb", true);
|
|
|
|
|
|
|
|
var spdb = Path.ChangeExtension (source, "pdb");
|
|
|
|
if (File.Exists (spdb))
|
|
|
|
Application.UpdateFile (spdb, Path.ChangeExtension (target, "pdb"), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyConfigToDirectory (Path.GetDirectoryName (target));
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new ProductException (1009, true, e, Errors.MX1009, source, target, e.Message);
|
|
|
|
}
|
|
|
|
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void CopyConfigToDirectory (string directory)
|
|
|
|
{
|
|
|
|
string config_src = FullPath + ".config";
|
|
|
|
if (File.Exists (config_src)) {
|
|
|
|
string config_target = Path.Combine (directory, FileName + ".config");
|
|
|
|
Application.UpdateFile (config_src, config_target, true);
|
|
|
|
}
|
|
|
|
}
|
2020-10-22 22:05:58 +03:00
|
|
|
|
|
|
|
public bool IsAOTCompiled {
|
|
|
|
get {
|
|
|
|
return App.IsAOTCompiled (Identity);
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|
2017-01-24 12:48:40 +03:00
|
|
|
|
2017-06-15 12:24:31 +03:00
|
|
|
public sealed class NormalizedStringComparer : IEqualityComparer<string>
|
|
|
|
{
|
|
|
|
public static readonly NormalizedStringComparer OrdinalIgnoreCase = new NormalizedStringComparer (StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
StringComparer comparer;
|
|
|
|
|
|
|
|
public NormalizedStringComparer (StringComparer comparer)
|
|
|
|
{
|
|
|
|
this.comparer = comparer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool Equals (string x, string y)
|
|
|
|
{
|
|
|
|
// From what I gather it doesn't matter which normalization form
|
|
|
|
// is used, but I chose Form D because HFS normalizes to Form D.
|
|
|
|
if (x != null)
|
|
|
|
x = x.Normalize (System.Text.NormalizationForm.FormD);
|
|
|
|
if (y != null)
|
|
|
|
y = y.Normalize (System.Text.NormalizationForm.FormD);
|
|
|
|
return comparer.Equals (x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int GetHashCode (string obj)
|
|
|
|
{
|
|
|
|
return comparer.GetHashCode (obj?.Normalize (System.Text.NormalizationForm.FormD));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-24 12:48:40 +03:00
|
|
|
public class AssemblyCollection : IEnumerable<Assembly>
|
|
|
|
{
|
2017-06-15 12:24:31 +03:00
|
|
|
Dictionary<string, Assembly> HashedAssemblies = new Dictionary<string, Assembly> (NormalizedStringComparer.OrdinalIgnoreCase);
|
2017-01-24 12:48:40 +03:00
|
|
|
|
|
|
|
public void Add (Assembly assembly)
|
|
|
|
{
|
|
|
|
Assembly other;
|
|
|
|
if (HashedAssemblies.TryGetValue (assembly.Identity, out other))
|
2020-01-31 23:02:52 +03:00
|
|
|
throw ErrorHelper.CreateError (2018, Errors.MT2018, assembly.Identity, other.FullPath, assembly.FullPath);
|
2017-01-24 12:48:40 +03:00
|
|
|
HashedAssemblies.Add (assembly.Identity, assembly);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void AddRange (AssemblyCollection assemblies)
|
|
|
|
{
|
2017-02-17 20:45:35 +03:00
|
|
|
foreach (var a in assemblies)
|
|
|
|
Add (a);
|
2017-01-24 12:48:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public int Count {
|
|
|
|
get {
|
|
|
|
return HashedAssemblies.Count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public IDictionary<string, Assembly> Hashed {
|
|
|
|
get { return HashedAssemblies; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool TryGetValue (string identity, out Assembly assembly)
|
|
|
|
{
|
|
|
|
return HashedAssemblies.TryGetValue (identity, out assembly);
|
|
|
|
}
|
|
|
|
|
[mtouch] Improve how we make sure native symbols aren't stripped away. Fixes #51710 and #54417. (#2162)
* [mtouch] Improve how we make sure native symbols aren't stripped away. Fixes #51710 and #54417.
* Refactor required symbol collection to store more information about each
symbol (field, function, Objective-C class), and in general make the code
more straight forward.
* Implement support for generating source code that references these symbols,
and do this whenever we can't ask the native linker to keep these symbols
(when using bitcode). Additionally make it possible to do this manually, so
that the source code can be generated for non-bitcode platforms too (which
is useful if the number of symbols is enormous, in which case we might
surpass the maximum command-line length).
* Also make it possible to completely ignore native symbols, or ignore them on
a per-symbol basis. This provides a fallback for users if we get something
right and we try to preserve something that shouldn't be preserved (for
instance if it doesn't exist), and the user ends up with unfixable linker
errors.
* Don't collect Objective-C classes unless they're in an assembly with
LinkWith attributes. We don't need to preserve Objective-C classes in any
other circumstances.
* Implement everything for both Xamarin.iOS and Xamarin.Mac, and share the
code between them.
* Remove previous workaround for bug #51710, since it's no longer needed.
* Add tests.
https://bugzilla.xamarin.com/show_bug.cgi?id=54417
https://bugzilla.xamarin.com/show_bug.cgi?id=51710
* [mtouch] Make sure to only keep symbols from the current app when code sharing.
This fixes a build problem with the interdependent-binding-projects test when
testing in Today Extension mode.
2017-06-02 19:29:19 +03:00
|
|
|
public bool TryGetValue (AssemblyDefinition asm, out Assembly assembly)
|
|
|
|
{
|
|
|
|
return HashedAssemblies.TryGetValue (Assembly.GetIdentity (asm), out assembly);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool Contains (AssemblyDefinition asm)
|
|
|
|
{
|
|
|
|
return HashedAssemblies.ContainsKey (Assembly.GetIdentity (asm));
|
|
|
|
}
|
|
|
|
|
2017-01-24 12:48:40 +03:00
|
|
|
public bool ContainsKey (string identity)
|
|
|
|
{
|
|
|
|
return HashedAssemblies.ContainsKey (identity);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Remove (string identity)
|
|
|
|
{
|
|
|
|
HashedAssemblies.Remove (identity);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Remove (Assembly assembly)
|
|
|
|
{
|
|
|
|
Remove (assembly.Identity);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Assembly this [string key] {
|
|
|
|
get { return HashedAssemblies [key]; }
|
|
|
|
set { HashedAssemblies [key] = value; }
|
|
|
|
}
|
|
|
|
|
2017-01-25 09:52:38 +03:00
|
|
|
public void Update (Target target, IEnumerable<AssemblyDefinition> assemblies)
|
|
|
|
{
|
|
|
|
// This function will remove any assemblies not in 'assemblies', and add any new assemblies.
|
2017-01-25 12:47:51 +03:00
|
|
|
var current = new HashSet<string> (HashedAssemblies.Keys, HashedAssemblies.Comparer);
|
2017-01-25 09:52:38 +03:00
|
|
|
foreach (var assembly in assemblies) {
|
|
|
|
var identity = Assembly.GetIdentity (assembly);
|
|
|
|
if (!current.Remove (identity)) {
|
|
|
|
// new assembly
|
|
|
|
var asm = new Assembly (target, assembly);
|
|
|
|
Add (asm);
|
2017-02-28 14:57:11 +03:00
|
|
|
Driver.Log (1, "The linker added the assembly '{0}' to '{1}' to satisfy a reference.", asm.Identity, target.App.Name);
|
2017-01-24 13:10:20 +03:00
|
|
|
} else {
|
|
|
|
this [identity].AssemblyDefinition = assembly;
|
2017-01-25 09:52:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (var removed in current) {
|
2017-02-28 14:57:11 +03:00
|
|
|
Driver.Log (1, "The linker removed the assembly '{0}' from '{1}' since there is no more reference to it.", this [removed].Identity, target.App.Name);
|
2017-01-25 09:52:38 +03:00
|
|
|
Remove (removed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-24 12:48:40 +03:00
|
|
|
#region Interface implementations
|
|
|
|
IEnumerator IEnumerable.GetEnumerator ()
|
|
|
|
{
|
|
|
|
return GetEnumerator ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public IEnumerator<Assembly> GetEnumerator ()
|
|
|
|
{
|
|
|
|
return HashedAssemblies.Values.GetEnumerator ();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
2016-04-21 15:57:02 +03:00
|
|
|
}
|