983 строки
36 KiB
C#
983 строки
36 KiB
C#
|
// Copyright 2013--2014 Xamarin Inc. All rights reserved.
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.IO;
|
|||
|
using System.Text;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
using MonoTouch.Tuner;
|
|||
|
|
|||
|
using Mono.Cecil;
|
|||
|
using Mono.Tuner;
|
|||
|
using Mono.Linker;
|
|||
|
using Xamarin.Linker;
|
|||
|
|
|||
|
using Xamarin.Utils;
|
|||
|
|
|||
|
namespace Xamarin.Bundler
|
|||
|
{
|
|||
|
public partial class Target {
|
|||
|
public string TargetDirectory;
|
|||
|
public string AppTargetDirectory;
|
|||
|
|
|||
|
public MonoTouchManifestResolver ManifestResolver = new MonoTouchManifestResolver ();
|
|||
|
public AssemblyDefinition ProductAssembly;
|
|||
|
|
|||
|
// directories used during the build process
|
|||
|
public string ArchDirectory;
|
|||
|
public string PreBuildDirectory;
|
|||
|
public string BuildDirectory;
|
|||
|
public string LinkDirectory;
|
|||
|
public string NoResDirectory;
|
|||
|
|
|||
|
// Note that each 'Target' can have multiple abis: armv7+armv7s for instance.
|
|||
|
public List<Abi> Abis;
|
|||
|
|
|||
|
// This is a list of native libraries to into the final executable.
|
|||
|
// All the native libraries are included here (this means all the libraries
|
|||
|
// that were AOTed from managed code, main, registrar, extra static libraries, etc).
|
|||
|
List<string> link_with = new List<string> ();
|
|||
|
|
|||
|
// If we didn't link because the existing (cached) assemblyes are up-to-date.
|
|||
|
bool cached_link;
|
|||
|
|
|||
|
// If any assemblies were updated (only set to false if the linker is disabled and no assemblies were modified).
|
|||
|
bool any_assembly_updated = true;
|
|||
|
|
|||
|
// If we didn't link the final executable because the existing binary is up-to-date.
|
|||
|
public bool cached_executable;
|
|||
|
|
|||
|
// If the assemblies were symlinked.
|
|||
|
public bool Symlinked;
|
|||
|
|
|||
|
public bool Is32Build { get { return Application.IsArchEnabled (Abis, Abi.Arch32Mask); } } // If we're targetting a 32 bit arch for this target.
|
|||
|
public bool Is64Build { get { return Application.IsArchEnabled (Abis, Abi.Arch64Mask); } } // If we're targetting a 64 bit arch for this target.
|
|||
|
|
|||
|
public string Executable {
|
|||
|
get {
|
|||
|
return Path.Combine (TargetDirectory, App.ExecutableName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Initialize (bool show_warnings)
|
|||
|
{
|
|||
|
// we want to load our own mscorlib[-runtime].dll, not something else we're being feeded
|
|||
|
// (e.g. bug #6612) since it might not match the libmono[-sgen].a library we'll link with,
|
|||
|
// so load the corlib we want first.
|
|||
|
|
|||
|
var corlib_path = Path.Combine (Resolver.FrameworkDirectory, "mscorlib.dll");
|
|||
|
var corlib = ManifestResolver.Load (corlib_path);
|
|||
|
if (corlib == null)
|
|||
|
throw new MonoTouchException (2006, true, "Can not load mscorlib.dll from: '{0}'. Please reinstall Xamarin.iOS.", corlib_path);
|
|||
|
|
|||
|
foreach (var reference in App.References) {
|
|||
|
var ad = ManifestResolver.Load (reference);
|
|||
|
if (ad == null)
|
|||
|
throw new MonoTouchException (2002, true, "Can not resolve reference: {0}", reference);
|
|||
|
if (ad.MainModule.Runtime > TargetRuntime.Net_4_0)
|
|||
|
ErrorHelper.Show (new MonoTouchException (11, false, "{0} was built against a more recent runtime ({1}) than Xamarin.iOS supports.", Path.GetFileName (reference), ad.MainModule.Runtime));
|
|||
|
|
|||
|
// Figure out if we're referencing Xamarin.iOS or monotouch.dll
|
|||
|
if (Path.GetFileNameWithoutExtension (ad.MainModule.FullyQualifiedName) == Driver.ProductAssembly)
|
|||
|
ProductAssembly = ad;
|
|||
|
}
|
|||
|
|
|||
|
ComputeListOfAssemblies ();
|
|||
|
|
|||
|
if (App.LinkMode == LinkMode.None && App.I18n != I18nAssemblies.None)
|
|||
|
AddI18nAssemblies ();
|
|||
|
|
|||
|
// an extension is a .dll and it would match itself
|
|||
|
if (App.IsExtension)
|
|||
|
return;
|
|||
|
|
|||
|
var root_wo_ext = Path.GetFileNameWithoutExtension (App.RootAssembly);
|
|||
|
foreach (var assembly in Assemblies) {
|
|||
|
if (!assembly.FullPath.EndsWith (".exe", StringComparison.OrdinalIgnoreCase)) {
|
|||
|
if (root_wo_ext == Path.GetFileNameWithoutExtension (assembly.FullPath))
|
|||
|
throw new MonoTouchException (23, true, "Application name '{0}.exe' conflicts with another user assembly.", root_wo_ext);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// This is to load the symbols for all assemblies, so that we can give better error messages
|
|||
|
// (with file name / line number information).
|
|||
|
public void LoadSymbols ()
|
|||
|
{
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.LoadSymbols ();
|
|||
|
}
|
|||
|
|
|||
|
IEnumerable<AssemblyDefinition> GetAssemblies ()
|
|||
|
{
|
|||
|
if (App.LinkMode == LinkMode.None)
|
|||
|
return Resolver.GetAssemblies ();
|
|||
|
|
|||
|
List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
|
|||
|
if (LinkContext == null) {
|
|||
|
// use data from cache
|
|||
|
foreach (var assembly in Assemblies)
|
|||
|
assemblies.Add (assembly.AssemblyDefinition);
|
|||
|
} else {
|
|||
|
foreach (var assembly in LinkContext.GetAssemblies ()) {
|
|||
|
if (LinkContext.Annotations.GetAction (assembly) == AssemblyAction.Delete)
|
|||
|
continue;
|
|||
|
|
|||
|
assemblies.Add (assembly);
|
|||
|
}
|
|||
|
}
|
|||
|
return assemblies;
|
|||
|
}
|
|||
|
|
|||
|
public void ComputeLinkerFlags ()
|
|||
|
{
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.ComputeLinkerFlags ();
|
|||
|
|
|||
|
if (App.Platform != ApplePlatform.WatchOS && App.Platform != ApplePlatform.TVOS)
|
|||
|
Frameworks.Add ("CFNetwork"); // required by xamarin_start_wwan
|
|||
|
}
|
|||
|
|
|||
|
Dictionary<string, MemberReference> entry_points;
|
|||
|
public IDictionary<string, MemberReference> GetEntryPoints ()
|
|||
|
{
|
|||
|
if (entry_points == null)
|
|||
|
GetRequiredSymbols ();
|
|||
|
return entry_points;
|
|||
|
}
|
|||
|
|
|||
|
public IEnumerable<string> GetRequiredSymbols ()
|
|||
|
{
|
|||
|
if (entry_points != null)
|
|||
|
return entry_points.Keys;
|
|||
|
|
|||
|
var cache_location = Path.Combine (Cache.Location, "entry-points.txt");
|
|||
|
if (cached_link || !any_assembly_updated) {
|
|||
|
entry_points = new Dictionary<string, MemberReference> ();
|
|||
|
foreach (var ep in File.ReadAllLines (cache_location))
|
|||
|
entry_points.Add (ep, null);
|
|||
|
} else {
|
|||
|
if (LinkContext == null) {
|
|||
|
// This happens when using the simlauncher and the msbuild tasks asked for a list
|
|||
|
// of symbols (--symbollist). In that case just produce an empty list, since the
|
|||
|
// binary shouldn't end up stripped anyway.
|
|||
|
entry_points = new Dictionary<string, MemberReference> ();
|
|||
|
} else {
|
|||
|
entry_points = LinkContext.RequiredSymbols;
|
|||
|
}
|
|||
|
|
|||
|
// keep the debugging helper in debugging binaries only
|
|||
|
if (App.EnableDebug && !App.EnableBitCode)
|
|||
|
entry_points.Add ("mono_pmip", null);
|
|||
|
|
|||
|
File.WriteAllText (cache_location, string.Join ("\n", entry_points.Keys.ToArray ()));
|
|||
|
}
|
|||
|
return entry_points.Keys;
|
|||
|
}
|
|||
|
|
|||
|
public MemberReference GetMemberForSymbol (string symbol)
|
|||
|
{
|
|||
|
MemberReference rv = null;
|
|||
|
entry_points?.TryGetValue (symbol, out rv);
|
|||
|
return rv;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Gets a flattened list of all the assemblies pulled by the root assembly
|
|||
|
//
|
|||
|
public void ComputeListOfAssemblies ()
|
|||
|
{
|
|||
|
var exceptions = new List<Exception> ();
|
|||
|
var assemblies = new HashSet<string> ();
|
|||
|
|
|||
|
try {
|
|||
|
var assembly = ManifestResolver.Load (App.RootAssembly);
|
|||
|
ComputeListOfAssemblies (assemblies, assembly, exceptions);
|
|||
|
} catch (MonoTouchException mte) {
|
|||
|
exceptions.Add (mte);
|
|||
|
} catch (Exception e) {
|
|||
|
exceptions.Add (new MonoTouchException (9, true, "Error while loading assemblies: {0}", e.Message));
|
|||
|
}
|
|||
|
|
|||
|
if (App.LinkMode == LinkMode.None)
|
|||
|
exceptions.AddRange (ManifestResolver.list);
|
|||
|
|
|||
|
if (exceptions.Count > 0)
|
|||
|
throw new AggregateException (exceptions);
|
|||
|
}
|
|||
|
|
|||
|
void ComputeListOfAssemblies (HashSet<string> assemblies, AssemblyDefinition assembly, List<Exception> exceptions)
|
|||
|
{
|
|||
|
if (assembly == null)
|
|||
|
return;
|
|||
|
|
|||
|
var fqname = assembly.MainModule.FullyQualifiedName;
|
|||
|
if (assemblies.Contains (fqname))
|
|||
|
return;
|
|||
|
|
|||
|
assemblies.Add (fqname);
|
|||
|
|
|||
|
var asm = new Assembly (this, assembly);
|
|||
|
asm.ComputeSatellites ();
|
|||
|
this.Assemblies.Add (asm);
|
|||
|
|
|||
|
var main = assembly.MainModule;
|
|||
|
foreach (AssemblyNameReference reference in main.AssemblyReferences) {
|
|||
|
// Verify that none of the references references an incorrect platform assembly.
|
|||
|
switch (reference.Name) {
|
|||
|
case "monotouch":
|
|||
|
case "Xamarin.iOS":
|
|||
|
case "Xamarin.TVOS":
|
|||
|
case "Xamarin.WatchOS":
|
|||
|
if (reference.Name != Driver.ProductAssembly)
|
|||
|
exceptions.Add (ErrorHelper.CreateError (34, "Cannot reference '{0}.dll' in a {1} project - it is implicitly referenced by '{2}'.", reference.Name, Driver.TargetFramework.Identifier, assembly.FullName));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
var reference_assembly = ManifestResolver.Resolve (reference);
|
|||
|
ComputeListOfAssemblies (assemblies, reference_assembly, exceptions);
|
|||
|
}
|
|||
|
|
|||
|
// Custom Attribute metadata can include references to other assemblies, e.g. [X (typeof (Y)],
|
|||
|
// but it is not reflected in AssemblyReferences :-( ref: #37611
|
|||
|
// so we must scan every custom attribute to look for System.Type
|
|||
|
GetCustomAttributeReferences (assembly, assemblies, exceptions);
|
|||
|
GetCustomAttributeReferences (main, assemblies, exceptions);
|
|||
|
if (main.HasTypes) {
|
|||
|
foreach (var t in main.Types) {
|
|||
|
GetTypeReferences (t, assemblies, exceptions);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void GetTypeReferences (TypeDefinition type, HashSet<string> assemblies, List<Exception> exceptions)
|
|||
|
{
|
|||
|
GetCustomAttributeReferences (type, assemblies, exceptions);
|
|||
|
if (type.HasEvents) {
|
|||
|
foreach (var e in type.Events)
|
|||
|
GetCustomAttributeReferences (e, assemblies, exceptions);
|
|||
|
}
|
|||
|
if (type.HasFields) {
|
|||
|
foreach (var f in type.Fields)
|
|||
|
GetCustomAttributeReferences (f, assemblies, exceptions);
|
|||
|
}
|
|||
|
if (type.HasMethods) {
|
|||
|
foreach (var m in type.Methods)
|
|||
|
GetCustomAttributeReferences (m, assemblies, exceptions);
|
|||
|
}
|
|||
|
if (type.HasProperties) {
|
|||
|
foreach (var p in type.Properties)
|
|||
|
GetCustomAttributeReferences (p, assemblies, exceptions);
|
|||
|
}
|
|||
|
if (type.HasNestedTypes) {
|
|||
|
foreach (var nt in type.NestedTypes)
|
|||
|
GetTypeReferences (nt, assemblies, exceptions);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void GetCustomAttributeReferences (ICustomAttributeProvider cap, HashSet<string> assemblies, List<Exception> exceptions)
|
|||
|
{
|
|||
|
if (!cap.HasCustomAttributes)
|
|||
|
return;
|
|||
|
foreach (var ca in cap.CustomAttributes) {
|
|||
|
if (ca.HasConstructorArguments) {
|
|||
|
foreach (var arg in ca.ConstructorArguments)
|
|||
|
GetCustomAttributeArgumentReference (arg, assemblies, exceptions);
|
|||
|
}
|
|||
|
if (ca.HasFields) {
|
|||
|
foreach (var arg in ca.Fields)
|
|||
|
GetCustomAttributeArgumentReference (arg.Argument, assemblies, exceptions);
|
|||
|
}
|
|||
|
if (ca.HasProperties) {
|
|||
|
foreach (var arg in ca.Properties)
|
|||
|
GetCustomAttributeArgumentReference (arg.Argument, assemblies, exceptions);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void GetCustomAttributeArgumentReference (CustomAttributeArgument arg, HashSet<string> assemblies, List<Exception> exceptions)
|
|||
|
{
|
|||
|
if (!arg.Type.Is ("System", "Type"))
|
|||
|
return;
|
|||
|
var ar = (arg.Value as TypeReference)?.Scope as AssemblyNameReference;
|
|||
|
if (ar == null)
|
|||
|
return;
|
|||
|
var reference_assembly = ManifestResolver.Resolve (ar);
|
|||
|
ComputeListOfAssemblies (assemblies, reference_assembly, exceptions);
|
|||
|
}
|
|||
|
|
|||
|
bool IncludeI18nAssembly (Mono.Linker.I18nAssemblies assembly)
|
|||
|
{
|
|||
|
return (App.I18n & assembly) != 0;
|
|||
|
}
|
|||
|
|
|||
|
public void AddI18nAssemblies ()
|
|||
|
{
|
|||
|
Assemblies.Add (LoadI18nAssembly ("I18N"));
|
|||
|
|
|||
|
if (IncludeI18nAssembly (Mono.Linker.I18nAssemblies.CJK))
|
|||
|
Assemblies.Add (LoadI18nAssembly ("I18N.CJK"));
|
|||
|
|
|||
|
if (IncludeI18nAssembly (Mono.Linker.I18nAssemblies.MidEast))
|
|||
|
Assemblies.Add (LoadI18nAssembly ("I18N.MidEast"));
|
|||
|
|
|||
|
if (IncludeI18nAssembly (Mono.Linker.I18nAssemblies.Other))
|
|||
|
Assemblies.Add (LoadI18nAssembly ("I18N.Other"));
|
|||
|
|
|||
|
if (IncludeI18nAssembly (Mono.Linker.I18nAssemblies.Rare))
|
|||
|
Assemblies.Add (LoadI18nAssembly ("I18N.Rare"));
|
|||
|
|
|||
|
if (IncludeI18nAssembly (Mono.Linker.I18nAssemblies.West))
|
|||
|
Assemblies.Add (LoadI18nAssembly ("I18N.West"));
|
|||
|
}
|
|||
|
|
|||
|
Assembly LoadI18nAssembly (string name)
|
|||
|
{
|
|||
|
var assembly = ManifestResolver.Resolve (AssemblyNameReference.Parse (name));
|
|||
|
return new Assembly (this, assembly);
|
|||
|
}
|
|||
|
|
|||
|
public void LinkAssemblies (string main, ref List<string> assemblies, string output_dir, out MonoTouchLinkContext link_context)
|
|||
|
{
|
|||
|
if (Driver.Verbosity > 0)
|
|||
|
Console.WriteLine ("Linking {0} into {1} using mode '{2}'", main, output_dir, App.LinkMode);
|
|||
|
|
|||
|
var cache = Resolver.ToResolverCache ();
|
|||
|
var resolver = cache != null
|
|||
|
? new AssemblyResolver (cache)
|
|||
|
: new AssemblyResolver ();
|
|||
|
|
|||
|
resolver.AddSearchDirectory (Resolver.RootDirectory);
|
|||
|
resolver.AddSearchDirectory (Resolver.FrameworkDirectory);
|
|||
|
|
|||
|
var options = new LinkerOptions {
|
|||
|
MainAssembly = Resolver.Load (main),
|
|||
|
OutputDirectory = output_dir,
|
|||
|
LinkMode = App.LinkMode,
|
|||
|
Resolver = resolver,
|
|||
|
SkippedAssemblies = App.LinkSkipped,
|
|||
|
I18nAssemblies = App.I18n,
|
|||
|
LinkSymbols = true,
|
|||
|
LinkAway = App.LinkAway,
|
|||
|
ExtraDefinitions = App.Definitions,
|
|||
|
Device = App.IsDeviceBuild,
|
|||
|
// by default we keep the code to ensure we're executing on the UI thread (for UI code) for debug builds
|
|||
|
// but this can be overridden to either (a) remove it from debug builds or (b) keep it in release builds
|
|||
|
EnsureUIThread = App.ThreadCheck.HasValue ? App.ThreadCheck.Value : App.EnableDebug,
|
|||
|
OldRegistrar = (App.Registrar == RegistrarMode.LegacyDynamic || App.Registrar == RegistrarMode.LegacyStatic),
|
|||
|
DebugBuild = App.EnableDebug,
|
|||
|
Arch = Is64Build ? 8 : 4,
|
|||
|
IsDualBuild = App.IsDualBuild,
|
|||
|
Unified = App.IsUnified,
|
|||
|
DumpDependencies = App.LinkerDumpDependencies,
|
|||
|
RuntimeOptions = App.RuntimeOptions
|
|||
|
};
|
|||
|
|
|||
|
MonoTouch.Tuner.Linker.Process (options, out link_context, out assemblies);
|
|||
|
|
|||
|
// reset resolver
|
|||
|
foreach (var file in assemblies) {
|
|||
|
/* var assembly = */Resolver.Load (file);
|
|||
|
// FIXME assembly.MainModule.AssemblyResolver = Resolver;
|
|||
|
}
|
|||
|
Driver.Watch ("Link Assemblies", 1);
|
|||
|
}
|
|||
|
|
|||
|
public void ManagedLink ()
|
|||
|
{
|
|||
|
var cache_path = Path.Combine (ArchDirectory, "linked-assemblies.txt");
|
|||
|
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.CopyToDirectory (LinkDirectory, false, check_case: true);
|
|||
|
|
|||
|
// Check if we can use a previous link result.
|
|||
|
if (!Driver.Force) {
|
|||
|
var input = new List<string> ();
|
|||
|
var output = new List<string> ();
|
|||
|
var cached_output = new List<string> ();
|
|||
|
|
|||
|
if (File.Exists (cache_path)) {
|
|||
|
cached_output.AddRange (File.ReadAllLines (cache_path));
|
|||
|
|
|||
|
var cached_loaded = new HashSet<string> ();
|
|||
|
// Only add the previously linked assemblies (and their satellites) as the input/output assemblies.
|
|||
|
// Do not add assemblies which the linker process removed.
|
|||
|
foreach (var a in Assemblies) {
|
|||
|
if (!cached_output.Contains (a.FullPath))
|
|||
|
continue;
|
|||
|
cached_loaded.Add (a.FullPath);
|
|||
|
input.Add (a.FullPath);
|
|||
|
output.Add (Path.Combine (PreBuildDirectory, a.FileName));
|
|||
|
if (a.Satellites != null) {
|
|||
|
foreach (var s in a.Satellites) {
|
|||
|
input.Add (s);
|
|||
|
output.Add (Path.Combine (PreBuildDirectory, Path.GetFileName (Path.GetDirectoryName (s)), Path.GetFileName (s)));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// The linker might have added assemblies that weren't specified/reachable
|
|||
|
// from the command line arguments (such as I18N assemblies). Those are not
|
|||
|
// in the Assemblies list at this point (since we haven't run the linker yet)
|
|||
|
// so make sure we take those into account as well.
|
|||
|
var not_loaded = cached_output.Except (cached_loaded);
|
|||
|
foreach (var path in not_loaded) {
|
|||
|
input.Add (path);
|
|||
|
output.Add (Path.Combine (PreBuildDirectory, Path.GetFileName (path)));
|
|||
|
}
|
|||
|
|
|||
|
// Include mtouch here too?
|
|||
|
// input.Add (Path.Combine (MTouch.MonoTouchDirectory, "usr", "bin", "mtouch"));
|
|||
|
|
|||
|
if (Application.IsUptodate (input, output)) {
|
|||
|
cached_link = true;
|
|||
|
for (int i = Assemblies.Count - 1; i >= 0; i--) {
|
|||
|
var a = Assemblies [i];
|
|||
|
if (!cached_output.Contains (a.FullPath)) {
|
|||
|
Assemblies.RemoveAt (i);
|
|||
|
continue;
|
|||
|
}
|
|||
|
// Load the cached assembly
|
|||
|
a.LoadAssembly (Path.Combine (PreBuildDirectory, a.FileName));
|
|||
|
Driver.Log (3, "Target '{0}' is up-to-date.", a.FullPath);
|
|||
|
}
|
|||
|
|
|||
|
foreach (var path in not_loaded) {
|
|||
|
var a = new Assembly (this, path);
|
|||
|
a.LoadAssembly (Path.Combine (PreBuildDirectory, a.FileName));
|
|||
|
Assemblies.Add (a);
|
|||
|
}
|
|||
|
|
|||
|
Driver.Watch ("Cached assemblies reloaded", 1);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Load the assemblies into memory.
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.LoadAssembly (a.FullPath);
|
|||
|
|
|||
|
var assemblies = new List<string> ();
|
|||
|
foreach (var a in Assemblies)
|
|||
|
assemblies.Add (a.FullPath);
|
|||
|
var linked_assemblies = new List<string> (assemblies);
|
|||
|
|
|||
|
LinkAssemblies (App.RootAssembly, ref linked_assemblies, PreBuildDirectory, out LinkContext);
|
|||
|
|
|||
|
// Remove assemblies that were linked away
|
|||
|
var removed = new HashSet<string> (assemblies);
|
|||
|
removed.ExceptWith (linked_assemblies);
|
|||
|
|
|||
|
foreach (var assembly in removed) {
|
|||
|
for (int i = Assemblies.Count - 1; i >= 0; i--) {
|
|||
|
var ad = Assemblies [i];
|
|||
|
if (assembly != ad.FullPath)
|
|||
|
continue;
|
|||
|
|
|||
|
Assemblies.RemoveAt (i);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// anything added by the linker will have it's original path
|
|||
|
var added = new HashSet<string> ();
|
|||
|
foreach (var assembly in linked_assemblies)
|
|||
|
added.Add (Path.GetFileName (assembly));
|
|||
|
var original = new HashSet<string> ();
|
|||
|
foreach (var assembly in assemblies)
|
|||
|
original.Add (Path.GetFileName (assembly));
|
|||
|
added.ExceptWith (original);
|
|||
|
|
|||
|
foreach (var assembly in added) {
|
|||
|
// the linker already copied the assemblies (linked or not) into the output directory
|
|||
|
// and we must NOT overwrite the linker work with an original (unlinked) assembly
|
|||
|
string path = Path.Combine (PreBuildDirectory, assembly);
|
|||
|
var ad = ManifestResolver.Load (path);
|
|||
|
var a = new Assembly (this, ad);
|
|||
|
a.CopyToDirectory (PreBuildDirectory);
|
|||
|
Assemblies.Add (a);
|
|||
|
}
|
|||
|
|
|||
|
assemblies = linked_assemblies;
|
|||
|
|
|||
|
// Make the assemblies point to the right path.
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.FullPath = Path.Combine (PreBuildDirectory, a.FileName);
|
|||
|
|
|||
|
File.WriteAllText (cache_path, string.Join ("\n", linked_assemblies));
|
|||
|
}
|
|||
|
|
|||
|
public void ProcessAssemblies ()
|
|||
|
{
|
|||
|
//
|
|||
|
// * Linking
|
|||
|
// Copy assemblies to LinkDirectory
|
|||
|
// Link and save to PreBuildDirectory
|
|||
|
// * Has resourced to be removed:
|
|||
|
// Remove resource and save to NoResDirectory
|
|||
|
// Copy to BuildDirectory. [Why not save directly to BuildDirectory? Because otherwise if we're rebuilding
|
|||
|
// and the only thing that changed is the resources we're removing in this step,
|
|||
|
// we won't be able to detect that the remaining parts of the assembly
|
|||
|
// haven't changed.]
|
|||
|
// * No resources to be removed:
|
|||
|
// Copy to BuildDirectory.
|
|||
|
// [AOT assemblies in BuildDirectory]
|
|||
|
// Strip managed code save to TargetDirectory (or just copy the file if stripping is disabled).
|
|||
|
//
|
|||
|
// * No linking
|
|||
|
// Copy assembly to PreBuildDirectory.
|
|||
|
// * Has resourced to be removed:
|
|||
|
// Remove resource and save to NoResDirectory
|
|||
|
// Copy to BuildDirectory.
|
|||
|
// * No resources to be removed:
|
|||
|
// Copy to BuildDirectory.
|
|||
|
// [AOT assemblies in BuildDirectory]
|
|||
|
// Strip managed code save to TargetDirectory (or just copy the file if stripping is disabled).
|
|||
|
//
|
|||
|
// Note that we end up copying assemblies around quite much,
|
|||
|
// this is because we we're comparing contents instead of
|
|||
|
// filestamps, so we need the previous file around to be
|
|||
|
// able to do the actual comparison. For instance: in the
|
|||
|
// 'No linking' case above, we copy the assembly to PreBuild
|
|||
|
// before removing the resources and saving that result to Build.
|
|||
|
// The copy in PreBuild is required for the next build iteration,
|
|||
|
// to see if the original assembly has been modified or not (the
|
|||
|
// file in the Build directory might be different due to resource
|
|||
|
// removal even if the original assembly didn't change).
|
|||
|
//
|
|||
|
// This can probably be improved by storing digests/hashes instead
|
|||
|
// of the entire files, but this turned out a bit messy when
|
|||
|
// trying to make it work with the linker, so I decided to go for
|
|||
|
// simple file copying for now.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Other notes:
|
|||
|
//
|
|||
|
// * We need all assemblies in the same directory when doing AOT-compilation.
|
|||
|
// * We cannot overwrite in-place, because it will mess up dependency tracking
|
|||
|
// and besides if we overwrite in place we might not be able to ignore
|
|||
|
// insignificant changes (such as only a GUID change - the code is identical,
|
|||
|
// but we still need the original assembly since the AOT-ed image also stores
|
|||
|
// the GUID, and we fail at runtime if the GUIDs in the assembly and the AOT-ed
|
|||
|
// image don't match - if we overwrite in-place we lose the original assembly and
|
|||
|
// its GUID).
|
|||
|
//
|
|||
|
|
|||
|
LinkDirectory = Path.Combine (ArchDirectory, "Link");
|
|||
|
if (!Directory.Exists (LinkDirectory))
|
|||
|
Directory.CreateDirectory (LinkDirectory);
|
|||
|
|
|||
|
PreBuildDirectory = Path.Combine (ArchDirectory, "PreBuild");
|
|||
|
if (!Directory.Exists (PreBuildDirectory))
|
|||
|
Directory.CreateDirectory (PreBuildDirectory);
|
|||
|
|
|||
|
BuildDirectory = Path.Combine (ArchDirectory, "Build");
|
|||
|
if (!Directory.Exists (BuildDirectory))
|
|||
|
Directory.CreateDirectory (BuildDirectory);
|
|||
|
|
|||
|
NoResDirectory = Path.Combine (ArchDirectory, "NoRes");
|
|||
|
if (!Directory.Exists (NoResDirectory))
|
|||
|
Directory.CreateDirectory (NoResDirectory);
|
|||
|
|
|||
|
if (!Directory.Exists (TargetDirectory))
|
|||
|
Directory.CreateDirectory (TargetDirectory);
|
|||
|
|
|||
|
ManagedLink ();
|
|||
|
|
|||
|
// Now the assemblies are in PreBuildDirectory.
|
|||
|
|
|||
|
//
|
|||
|
// PreBuildDirectory -> BuildDirectory [resource removal]
|
|||
|
//
|
|||
|
// Resource removal
|
|||
|
// * Remove any __monotouch_content_* or __monotouch_page_* resources
|
|||
|
// - This is already done in the linker, so there is no need to do it here if the linker is enabled (for user assemblies).
|
|||
|
// - It is only done for device-builds. Xamarin Studio requires the resources to be present (to extract
|
|||
|
// them) - which is not a problem for device-builds since we operate on a copied assembly, not the
|
|||
|
// original like Xamarin Studio does).
|
|||
|
// * Remove any LinkWith-related resources
|
|||
|
//
|
|||
|
|
|||
|
var remove_res = App.IsDeviceBuild && App.LinkMode != LinkMode.All;
|
|||
|
foreach (var a in Assemblies) {
|
|||
|
var target = Path.Combine (BuildDirectory, a.FileName);
|
|||
|
if (!Application.IsUptodate (a.FullPath, target)) {
|
|||
|
a.RemoveResources (remove_res, BuildDirectory, NoResDirectory);
|
|||
|
} else {
|
|||
|
a.FullPath = target;
|
|||
|
Driver.Log (3, "Target '{0}' is up-to-date.", target);
|
|||
|
}
|
|||
|
}
|
|||
|
Driver.Watch ("Removing Resources", 1);
|
|||
|
|
|||
|
Driver.GatherFrameworks (this, Frameworks, WeakFrameworks);
|
|||
|
|
|||
|
// Make sure there are no duplicates between frameworks and weak frameworks.
|
|||
|
// Keep the weak ones.
|
|||
|
Frameworks.ExceptWith (WeakFrameworks);
|
|||
|
}
|
|||
|
|
|||
|
public void Compile ()
|
|||
|
{
|
|||
|
var tasks = new List<BuildTask> ();
|
|||
|
|
|||
|
// Compile the managed assemblies into object files or shared libraries
|
|||
|
if (App.IsDeviceBuild) {
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.CreateCompilationTasks (tasks, BuildDirectory, Abis);
|
|||
|
}
|
|||
|
|
|||
|
// The static registrar.
|
|||
|
List<string> registration_methods = null;
|
|||
|
if (App.Registrar == RegistrarMode.Static || App.Registrar == RegistrarMode.LegacyStatic) {
|
|||
|
var registrar_m = Path.Combine (ArchDirectory, "registrar.m");
|
|||
|
if (!Application.IsUptodate (Assemblies.Select (v => v.FullPath), new string[] { registrar_m })) {
|
|||
|
registrar_m = Driver.RunRegistrar (this, Assemblies, BuildDirectory, BuildDirectory, App.Registrar == RegistrarMode.LegacyStatic, Is64Build, registrar_m);
|
|||
|
registration_methods = new List<string> ();
|
|||
|
registration_methods.Add ("xamarin_create_classes");
|
|||
|
Driver.Watch ("Registrar", 1);
|
|||
|
} else {
|
|||
|
Driver.Log (3, "Target '{0}' is up-to-date.", registrar_m);
|
|||
|
}
|
|||
|
|
|||
|
foreach (var abi in Abis)
|
|||
|
RegistrarTask.Create (tasks, abi, this, registrar_m);
|
|||
|
}
|
|||
|
|
|||
|
if (App.Registrar == RegistrarMode.Dynamic && App.IsSimulatorBuild && App.LinkMode == LinkMode.None && App.IsUnified) {
|
|||
|
if (registration_methods == null)
|
|||
|
registration_methods = new List<string> ();
|
|||
|
|
|||
|
string method;
|
|||
|
string library;
|
|||
|
switch (App.Platform) {
|
|||
|
case ApplePlatform.iOS:
|
|||
|
method = "xamarin_create_classes_Xamarin_iOS";
|
|||
|
library = "Xamarin.iOS.registrar.a";
|
|||
|
break;
|
|||
|
case ApplePlatform.WatchOS:
|
|||
|
method = "xamarin_create_classes_Xamarin_WatchOS";
|
|||
|
library = "Xamarin.WatchOS.registrar.a";
|
|||
|
break;
|
|||
|
case ApplePlatform.TVOS:
|
|||
|
method = "xamarin_create_classes_Xamarin_TVOS";
|
|||
|
library = "Xamarin.TVOS.registrar.a";
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw ErrorHelper.CreateError (71, "Unknown platform: {0}. This usually indicates a bug in Xamarin.iOS; please file a bug report at http://bugzilla.xamarin.com with a test case.", App.Platform);
|
|||
|
}
|
|||
|
|
|||
|
registration_methods.Add (method);
|
|||
|
link_with.Add (Path.Combine (Driver.ProductSdkDirectory, "usr", "lib", library));
|
|||
|
|
|||
|
if (App.Platform == ApplePlatform.iOS) {
|
|||
|
foreach (var assembly in Assemblies) {
|
|||
|
if (!assembly.IsFrameworkAssembly)
|
|||
|
continue;
|
|||
|
|
|||
|
switch (Path.GetFileNameWithoutExtension (assembly.FileName)) {
|
|||
|
case "MonoTouch.Dialog-1":
|
|||
|
registration_methods.Add ("xamarin_create_classes_MonoTouch_Dialog_1");
|
|||
|
link_with.Add (Path.Combine (Driver.ProductSdkDirectory, "usr", "lib", "MonoTouch.Dialog-1.registrar.a"));
|
|||
|
break;
|
|||
|
// MonoTouch.NUnitLite doesn't quite work yet, because its generated registrar code uses types
|
|||
|
// from the generated registrar code for MonoTouch.Dialog-1 (and there is no header file (yet)
|
|||
|
// for those types).
|
|||
|
// case "MonoTouch.NUnitLite":
|
|||
|
// registration_methods.Add ("xamarin_create_classes_MonoTouch_NUnitLite");
|
|||
|
// link_with.Add (Path.Combine (MTouch.MonoTouchIPhoneSimulatorDirectory, "usr", "lib", "MonoTouch.NUnitLite.registrar.a"));
|
|||
|
// break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// The main method.
|
|||
|
foreach (var abi in Abis)
|
|||
|
MainTask.Create (tasks, this, abi, Assemblies, App.AssemblyName, registration_methods);
|
|||
|
|
|||
|
// Start compiling.
|
|||
|
if (tasks.Count > 0) {
|
|||
|
Action<BuildTask> action = null;
|
|||
|
action = (v) => {
|
|||
|
var next = v.Execute ();
|
|||
|
if (next != null)
|
|||
|
Parallel.ForEach (next, new ParallelOptions () { MaxDegreeOfParallelism = Environment.ProcessorCount }, action);
|
|||
|
};
|
|||
|
|
|||
|
Parallel.ForEach (tasks, new ParallelOptions () { MaxDegreeOfParallelism = Environment.ProcessorCount }, action);
|
|||
|
}
|
|||
|
|
|||
|
if (App.FastDev) {
|
|||
|
foreach (var a in Assemblies) {
|
|||
|
if (a.Dylibs == null)
|
|||
|
continue;
|
|||
|
foreach (var dylib in a.Dylibs)
|
|||
|
LinkWith (dylib);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Driver.Watch ("Compile", 1);
|
|||
|
}
|
|||
|
|
|||
|
public void NativeLink ()
|
|||
|
{
|
|||
|
if (!string.IsNullOrEmpty (App.UserGccFlags))
|
|||
|
App.DeadStrip = false;
|
|||
|
if (App.EnableLLVMOnlyBitCode)
|
|||
|
App.DeadStrip = false;
|
|||
|
|
|||
|
var compiler_flags = new CompilerFlags () { Target = this };
|
|||
|
|
|||
|
// Get global frameworks
|
|||
|
compiler_flags.AddFrameworks (App.Frameworks, App.WeakFrameworks);
|
|||
|
compiler_flags.AddFrameworks (Frameworks, WeakFrameworks);
|
|||
|
|
|||
|
// Collect all LinkWith flags and frameworks from all assemblies.
|
|||
|
foreach (var a in Assemblies) {
|
|||
|
compiler_flags.AddFrameworks (a.Frameworks, a.WeakFrameworks);
|
|||
|
compiler_flags.AddLinkWith (a.LinkWith, a.ForceLoad);
|
|||
|
compiler_flags.AddOtherFlags (a.LinkerFlags);
|
|||
|
}
|
|||
|
|
|||
|
var bitcode = App.EnableBitCode;
|
|||
|
if (bitcode)
|
|||
|
compiler_flags.AddOtherFlag (App.EnableMarkerOnlyBitCode ? "-fembed-bitcode-marker" : "-fembed-bitcode");
|
|||
|
|
|||
|
if (App.EnablePie.HasValue && App.EnablePie.Value && (App.DeploymentTarget < new Version (4, 2)))
|
|||
|
ErrorHelper.Error (28, "Cannot enable PIE (-pie) when targeting iOS 4.1 or earlier. Please disable PIE (-pie:false) or set the deployment target to at least iOS 4.2");
|
|||
|
|
|||
|
if (!App.EnablePie.HasValue)
|
|||
|
App.EnablePie = true;
|
|||
|
|
|||
|
if (App.Platform == ApplePlatform.iOS) {
|
|||
|
if (App.EnablePie.Value && (App.DeploymentTarget >= new Version (4, 2))) {
|
|||
|
compiler_flags.AddOtherFlag ("-Wl,-pie");
|
|||
|
} else {
|
|||
|
compiler_flags.AddOtherFlag ("-Wl,-no_pie");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CompileTask.GetArchFlags (compiler_flags, Abis);
|
|||
|
if (App.IsDeviceBuild) {
|
|||
|
compiler_flags.AddOtherFlag ($"-m{Driver.TargetMinSdkName}-version-min={App.DeploymentTarget}");
|
|||
|
compiler_flags.AddOtherFlag ($"-isysroot {Driver.Quote (Driver.FrameworkDirectory)}");
|
|||
|
} else {
|
|||
|
CompileTask.GetSimulatorCompilerFlags (compiler_flags, null, App);
|
|||
|
}
|
|||
|
compiler_flags.LinkWithMono ();
|
|||
|
compiler_flags.LinkWithXamarin ();
|
|||
|
|
|||
|
compiler_flags.AddLinkWith (link_with);
|
|||
|
compiler_flags.AddOtherFlag ($"-o {Driver.Quote (Executable)}");
|
|||
|
|
|||
|
compiler_flags.AddOtherFlag ("-lz");
|
|||
|
compiler_flags.AddOtherFlag ("-liconv");
|
|||
|
|
|||
|
if (App.EnableBitCode)
|
|||
|
compiler_flags.AddOtherFlag ("-lc++");
|
|||
|
|
|||
|
// allow the native linker to remove unused symbols (if the caller was removed by the managed linker)
|
|||
|
if (!bitcode) {
|
|||
|
foreach (var entry in GetRequiredSymbols ()) {
|
|||
|
// Note that we include *all* (__Internal) p/invoked symbols here
|
|||
|
// We also include any fields from [Field] attributes.
|
|||
|
compiler_flags.ReferenceSymbol (entry);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
string mainlib;
|
|||
|
if (App.IsWatchExtension) {
|
|||
|
mainlib = "libwatchextension.a";
|
|||
|
compiler_flags.AddOtherFlag (" -e _xamarin_watchextension_main");
|
|||
|
} else if (App.IsExtension) {
|
|||
|
mainlib = "libextension.a";
|
|||
|
} else {
|
|||
|
mainlib = "libapp.a";
|
|||
|
}
|
|||
|
var libdir = Path.Combine (Driver.ProductSdkDirectory, "usr", "lib");
|
|||
|
var libmain = Path.Combine (libdir, mainlib);
|
|||
|
compiler_flags.AddLinkWith (libmain, true);
|
|||
|
|
|||
|
if (App.EnableProfiling) {
|
|||
|
string libprofiler;
|
|||
|
if (App.FastDev) {
|
|||
|
libprofiler = Path.Combine (libdir, "libmono-profiler-log.dylib");
|
|||
|
compiler_flags.AddLinkWith (libprofiler);
|
|||
|
} else {
|
|||
|
libprofiler = Path.Combine (libdir, "libmono-profiler-log.a");
|
|||
|
compiler_flags.AddLinkWith (libprofiler);
|
|||
|
if (!App.EnableBitCode)
|
|||
|
compiler_flags.ReferenceSymbol ("mono_profiler_startup_log");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!string.IsNullOrEmpty (App.UserGccFlags))
|
|||
|
compiler_flags.AddOtherFlag (App.UserGccFlags);
|
|||
|
|
|||
|
if (App.DeadStrip)
|
|||
|
compiler_flags.AddOtherFlag ("-dead_strip");
|
|||
|
|
|||
|
if (App.IsExtension) {
|
|||
|
if (App.Platform == ApplePlatform.iOS && Driver.XcodeVersion.Major < 7) {
|
|||
|
compiler_flags.AddOtherFlag ("-lpkstart");
|
|||
|
compiler_flags.AddOtherFlag ($"-F {Driver.Quote (Path.Combine (Driver.FrameworkDirectory, "System/Library/PrivateFrameworks"))} -framework PlugInKit");
|
|||
|
}
|
|||
|
compiler_flags.AddOtherFlag ("-fapplication-extension");
|
|||
|
}
|
|||
|
|
|||
|
compiler_flags.Inputs = new List<string> ();
|
|||
|
var flags = compiler_flags.ToString (); // This will populate Inputs.
|
|||
|
|
|||
|
if (!Application.IsUptodate (compiler_flags.Inputs, new string [] { Executable } )) {
|
|||
|
// always show the native linker warnings since many of them turn out to be very important
|
|||
|
// and very hard to diagnose otherwise when hidden from the build output. Ref: bug #2430
|
|||
|
var linker_errors = new List<Exception> ();
|
|||
|
var output = new StringBuilder ();
|
|||
|
var code = Driver.RunCommand (Driver.CompilerPath, flags, null, output);
|
|||
|
|
|||
|
Application.ProcessNativeLinkerOutput (this, output.ToString (), link_with, linker_errors, code != 0);
|
|||
|
|
|||
|
if (code != 0) {
|
|||
|
// if the build failed - it could be because of missing frameworks / libraries we identified earlier
|
|||
|
foreach (var assembly in Assemblies) {
|
|||
|
if (assembly.UnresolvedModuleReferences == null)
|
|||
|
continue;
|
|||
|
|
|||
|
foreach (var mr in assembly.UnresolvedModuleReferences) {
|
|||
|
// TODO: add more diagnose information on the warnings
|
|||
|
var name = Path.GetFileNameWithoutExtension (mr.Name);
|
|||
|
linker_errors.Add (new MonoTouchException (5215, false, "References to '{0}' might require additional -framework=XXX or -lXXX instructions to the native linker", name));
|
|||
|
}
|
|||
|
}
|
|||
|
// mtouch does not validate extra parameters given to GCC when linking (--gcc_flags)
|
|||
|
if (!String.IsNullOrEmpty (App.UserGccFlags))
|
|||
|
linker_errors.Add (new MonoTouchException (5201, true, "Native linking failed. Please review the build log and the user flags provided to gcc: {0}", App.UserGccFlags));
|
|||
|
linker_errors.Add (new MonoTouchException (5202, true, "Native linking failed. Please review the build log.", App.UserGccFlags));
|
|||
|
}
|
|||
|
ErrorHelper.Show (linker_errors);
|
|||
|
} else {
|
|||
|
cached_executable = true;
|
|||
|
Driver.Log (3, "Target '{0}' is up-to-date.", Executable);
|
|||
|
}
|
|||
|
// the native linker can prefer private (and existing) over public (but non-existing) framework when weak_framework are used
|
|||
|
// on an iOS target version where the framework does not exists, e.g. targeting iOS6 for JavaScriptCore added in iOS7 results in
|
|||
|
// /System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore instead of
|
|||
|
// /System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
|
|||
|
// more details in https://bugzilla.xamarin.com/show_bug.cgi?id=31036
|
|||
|
if (WeakFrameworks.Count > 0)
|
|||
|
AdjustDylibs ();
|
|||
|
Driver.Watch ("Native Link", 1);
|
|||
|
}
|
|||
|
|
|||
|
void AdjustDylibs ()
|
|||
|
{
|
|||
|
var sb = new StringBuilder ();
|
|||
|
foreach (var dependency in Xamarin.MachO.GetNativeDependencies (Executable)) {
|
|||
|
if (!dependency.StartsWith ("/System/Library/PrivateFrameworks/", StringComparison.Ordinal))
|
|||
|
continue;
|
|||
|
var fixed_dep = dependency.Replace ("/PrivateFrameworks/", "/Frameworks/");
|
|||
|
sb.Append (" -change ").Append (dependency).Append (' ').Append (fixed_dep);
|
|||
|
}
|
|||
|
if (sb.Length > 0) {
|
|||
|
var quoted_name = Driver.Quote (Executable);
|
|||
|
sb.Append (' ').Append (quoted_name);
|
|||
|
Driver.XcodeRun ("install_name_tool", sb.ToString ());
|
|||
|
sb.Clear ();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool CanWeSymlinkTheApplication ()
|
|||
|
{
|
|||
|
if (!Driver.CanWeSymlinkTheApplication ())
|
|||
|
return false;
|
|||
|
|
|||
|
foreach (var a in Assemblies)
|
|||
|
if (!a.CanSymLinkForApplication ())
|
|||
|
return false;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
public void Symlink ()
|
|||
|
{
|
|||
|
foreach (var a in Assemblies)
|
|||
|
a.Symlink ();
|
|||
|
|
|||
|
var targetExecutable = Executable;
|
|||
|
|
|||
|
Application.TryDelete (targetExecutable);
|
|||
|
|
|||
|
try {
|
|||
|
var launcher = new StringBuilder ();
|
|||
|
launcher.Append (Path.Combine (Driver.MonoTouchDirectory, "bin", "simlauncher"));
|
|||
|
if (App.IsUnified) {
|
|||
|
if (Is32Build)
|
|||
|
launcher.Append ("32");
|
|||
|
else if (Is64Build)
|
|||
|
launcher.Append ("64");
|
|||
|
}
|
|||
|
launcher.Append ("-sgen");
|
|||
|
File.Copy (launcher.ToString (), Executable);
|
|||
|
} catch (MonoTouchException) {
|
|||
|
throw;
|
|||
|
} catch (Exception ex) {
|
|||
|
throw new MonoTouchException (1015, true, ex, "Failed to create the executable '{0}': {1}", targetExecutable, ex.Message);
|
|||
|
}
|
|||
|
|
|||
|
Symlinked = true;
|
|||
|
|
|||
|
if (Driver.Verbosity > 0)
|
|||
|
Console.WriteLine ("Application ({0}) was built using fast-path for simulator.", string.Join (", ", Abis.ToArray ()));
|
|||
|
}
|
|||
|
|
|||
|
// Thread-safe
|
|||
|
public void LinkWith (string native_library)
|
|||
|
{
|
|||
|
lock (link_with)
|
|||
|
link_with.Add (native_library);
|
|||
|
}
|
|||
|
|
|||
|
public void StripManagedCode ()
|
|||
|
{
|
|||
|
var strip = false;
|
|||
|
|
|||
|
strip = App.ManagedStrip && App.IsDeviceBuild && !App.EnableDebug && !App.PackageMdb;
|
|||
|
|
|||
|
if (!Directory.Exists (AppTargetDirectory))
|
|||
|
Directory.CreateDirectory (AppTargetDirectory);
|
|||
|
|
|||
|
if (strip) {
|
|||
|
// note: this is much slower when Parallel.ForEach is used
|
|||
|
Parallel.ForEach (Assemblies, new ParallelOptions () { MaxDegreeOfParallelism = Environment.ProcessorCount }, (assembly) =>
|
|||
|
{
|
|||
|
var file = assembly.FullPath;
|
|||
|
var output = Path.Combine (AppTargetDirectory, Path.GetFileName (assembly.FullPath));
|
|||
|
if (Application.IsUptodate (file, output)) {
|
|||
|
Driver.Log (3, "Target '{0}' is up-to-date", output);
|
|||
|
} else {
|
|||
|
Driver.Log (1, "Stripping assembly {0}", file);
|
|||
|
Driver.FileDelete (output);
|
|||
|
Stripper.Process (file, output);
|
|||
|
}
|
|||
|
// The stripper will only copy the main assembly.
|
|||
|
// We need to copy .config files and satellite assemblies too
|
|||
|
if (App.PackageMdb)
|
|||
|
assembly.CopyMdbToDirectory (AppTargetDirectory);
|
|||
|
assembly.CopyConfigToDirectory (AppTargetDirectory);
|
|||
|
assembly.CopySatellitesToDirectory (AppTargetDirectory);
|
|||
|
});
|
|||
|
|
|||
|
Driver.Watch ("Strip Assemblies", 1);
|
|||
|
} else if (!Symlinked) {
|
|||
|
foreach (var assembly in Assemblies)
|
|||
|
assembly.CopyToDirectory (AppTargetDirectory, reload: false, copy_mdb: App.PackageMdb);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|