Beispiel #1
0
        public static void Create(List <BuildTask> tasks, Abi abi, Target target, string ifile)
        {
            var arch  = abi.AsArchString();
            var ext   = target.App.FastDev ? ".dylib" : ".o";
            var ofile = Path.Combine(target.App.Cache.Location, "lib" + Path.GetFileNameWithoutExtension(ifile) + "." + arch + ext);

            if (!Application.IsUptodate(ifile, ofile))
            {
                var task = new PinvokesTask()
                {
                    Target        = target,
                    Abi           = abi,
                    InputFile     = ifile,
                    OutputFile    = ofile,
                    SharedLibrary = target.App.FastDev,
                    Language      = "objective-c++",
                };
                if (target.App.FastDev)
                {
                    task.InstallName = "lib" + Path.GetFileNameWithoutExtension(ifile) + ext;
                    task.CompilerFlags.AddFramework("Foundation");
                    task.CompilerFlags.LinkWithXamarin();
                }
                tasks.Add(task);
            }
            else
            {
                Driver.Log(3, "Target '{0}' is up-to-date.", ofile);
            }

            target.LinkWith(ofile);
            target.LinkWithAndShip(ofile);
        }
Beispiel #2
0
        public static void Create(List <BuildTask> tasks, Abi abi, Target target, string ifile)
        {
            var app   = target.App;
            var arch  = abi.AsArchString();
            var ofile = Path.Combine(app.Cache.Location, Path.GetFileNameWithoutExtension(ifile) + "." + arch + ".o");

            if (!Application.IsUptodate(ifile, ofile))
            {
                tasks.Add(new RegistrarTask()
                {
                    Target        = target,
                    Abi           = abi,
                    InputFile     = ifile,
                    OutputFile    = ofile,
                    SharedLibrary = false,
                    Language      = "objective-c++",
                });
            }
            else
            {
                Driver.Log(3, "Target '{0}' is up-to-date.", ofile);
            }

            target.LinkWith(ofile);
        }
Beispiel #3
0
        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);
            }

            if (!File.Exists(path))
            {
                ErrorHelper.Warning(1302, "Could not extract the native library '{0}' from '{1}'. " +
                                    "Please ensure the native library was properly embedded in the managed assembly " +
                                    "(if the assembly was built using a binding project, the native library must be included in the project, and its Build Action must be 'ObjcBindingNativeLibrary').",
                                    metadata.LibraryName, path);
            }

            return(path);
        }
Beispiel #4
0
 public static void UpdateFile(string source, string target)
 {
     if (!Application.IsUptodate(source, target))
     {
         CopyFile(source, target);
     }
     else
     {
         Driver.Log(3, "Target '{0}' is up-to-date", target);
     }
 }
Beispiel #5
0
 public static void UpdateFile(string source, string target, bool check_contents = false)
 {
     if (!Application.IsUptodate(source, target, check_contents))
     {
         CopyFile(source, target);
     }
     else
     {
         Driver.Log(3, "Target '{0}' is up-to-date", target);
     }
 }
Beispiel #6
0
        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 = Driver.Concurrency
                }, (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);
                }
            }
        }
        // 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)
                {
                    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 MonoTouchException(1009, true, e, Errors.MX1009, source, target, e.Message);
            }

            return(copied);
        }
Beispiel #8
0
        // returns false if the assembly was not copied (because it was already up-to-date).
        bool CopyAssembly(string source, string target)
        {
            // TODO - We should move to mtouch's code, shared in common
            var copied = false;

            try {
                if (!Application.IsUptodate(source, target))
                {
                    copied = true;
                    Application.CopyFile(source, target);
                }
            } catch (Exception e) {
                throw new ProductException(1009, true, e, Errors.MX1009, source, target, e.Message);
            }

            return(copied);
        }
Beispiel #9
0
        // returns false if the assembly was not copied (because it was already up-to-date).
        bool CopyAssembly(string source, string target)
        {
            // TODO - We should move to mtouch's code, shared in common
            var copied = false;

            try {
                if (!Application.IsUptodate(source, target))
                {
                    copied = true;
                    Application.CopyFile(source, target);
                }
            } catch (Exception e) {
                throw new MonoMacException(1009, true, e, "Could not copy the assembly '{0}' to '{1}': {2}", source, target, e.Message);
            }

            return(copied);
        }
Beispiel #10
0
		// returns false if the assembly was not copied (because it was already up-to-date).
		public bool CopyAssembly (string source, string target, bool copy_mdb = true)
		{
			var copied = false;

			try {
				if (!Application.IsUptodate (source, target) && !Cache.CompareAssemblies (source, target)) {
					copied = true;
					Application.CopyFile (source, target);
				}

				// Update the mdb even if the assembly didn't change.
				if (copy_mdb && File.Exists (source + ".mdb"))
					Application.UpdateFile (source + ".mdb", target + ".mdb", true);

				CopyConfigToDirectory (Path.GetDirectoryName (target));
			} catch (Exception e) {
				throw new MonoTouchException (1009, true, e, "Could not copy the assembly '{0}' to '{1}': {2}", source, target, e.Message);
			}

			return copied;
		}
Beispiel #11
0
        public static void Create(List <BuildTask> tasks, Target target, Abi abi, IEnumerable <Assembly> assemblies, string assemblyName, IList <string> registration_methods)
        {
            var app   = target.App;
            var arch  = abi.AsArchString();
            var ofile = Path.Combine(app.Cache.Location, "main." + arch + ".o");
            var ifile = Path.Combine(app.Cache.Location, "main." + arch + ".m");

            var files = assemblies.Select(v => v.FullPath);

            if (!Application.IsUptodate(files, new string [] { ifile }))
            {
                Driver.GenerateMain(target.App, assemblies, assemblyName, abi, ifile, registration_methods);
            }
            else
            {
                Driver.Log(3, "Target '{0}' is up-to-date.", ifile);
            }

            if (!Application.IsUptodate(ifile, ofile))
            {
                var main = new MainTask()
                {
                    Target        = target,
                    Abi           = abi,
                    AssemblyName  = assemblyName,
                    InputFile     = ifile,
                    OutputFile    = ofile,
                    SharedLibrary = false,
                    Language      = "objective-c++",
                };
                main.CompilerFlags.AddDefine("MONOTOUCH");
                tasks.Add(main);
            }
            else
            {
                Driver.Log(3, "Target '{0}' is up-to-date.", ofile);
            }

            target.LinkWith(ofile);
        }
Beispiel #12
0
        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))
            {
                ErrorHelper.Warning(1302, "Could not extract the native framework '{0}' from '{1}'. " +
                                    "Please ensure the native framework was properly embedded in the managed assembly " +
                                    "(if the assembly was built using a binding project, the native framework must be included in the project, and its Build Action must be 'ObjcBindingNativeFramework').",
                                    metadata.LibraryName, zipPath);
            }
            else
            {
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                if (Driver.RunCommand("/usr/bin/unzip", string.Format("-u -o -d {0} {1}", StringUtils.Quote(path), StringUtils.Quote(zipPath))) != 0)
                {
                    throw ErrorHelper.CreateError(1303, "Could not decompress the native framework '{0}' from '{1}'. Please review the build log for more information from the native 'unzip' command.", metadata.LibraryName, zipPath);
                }
            }

            return(path);
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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);
                if (!App.FastDev || App.IsSimulatorBuild)
                {
                    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.GetTargetMinSdkName (App)}-version-min={App.DeploymentTarget}");
                compiler_flags.AddOtherFlag($"-isysroot {Driver.Quote (Driver.GetFrameworkDirectory (App))}");
            }
            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");

            bool need_libcpp = false;

            if (App.EnableBitCode)
            {
                need_libcpp = true;
            }
#if ENABLE_BITCODE_ON_IOS
            need_libcpp = true;
#endif
            if (need_libcpp)
            {
                compiler_flags.AddOtherFlag("-lc++");
            }

            // allow the native linker to remove unused symbols (if the caller was removed by the managed linker)
            if (!bitcode)
            {
                // Note that we include *all* (__Internal) p/invoked symbols here
                // We also include any fields from [Field] attributes.
                compiler_flags.ReferenceSymbols(GetRequiredSymbols());
            }

            string mainlib;
            if (App.IsWatchExtension)
            {
                mainlib = "libwatchextension.a";
                compiler_flags.AddOtherFlag(" -e _xamarin_watchextension_main");
            }
            else if (App.IsTVExtension)
            {
                mainlib = "libtvextension.a";
            }
            else if (App.IsExtension)
            {
                mainlib = "libextension.a";
            }
            else
            {
                mainlib = "libapp.a";
            }
            var libdir  = Path.Combine(Driver.GetProductSdkDirectory(App), "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.GetFrameworkDirectory (App), "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(App.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);
        }
Beispiel #15
0
        public void Compile()
        {
            // Compile the managed assemblies into object files or shared libraries
            if (App.IsDeviceBuild)
            {
                foreach (var a in Assemblies)
                {
                    a.CreateCompilationTasks(compile_tasks, BuildDirectory, Abis);
                }
            }

            // The static registrar.
            List <string> registration_methods = null;

            if (App.Registrar == RegistrarMode.Static)
            {
                var registrar_m = Path.Combine(ArchDirectory, "registrar.m");
                var registrar_h = Path.Combine(ArchDirectory, "registrar.h");
                if (!Application.IsUptodate(Assemblies.Select(v => v.FullPath), new string[] { registrar_m, registrar_h }))
                {
                    StaticRegistrar.Generate(Assemblies.Select((a) => a.AssemblyDefinition), registrar_h, 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);
                }

                RegistrarTask.Create(compile_tasks, Abis, this, registrar_m);
            }

            if (App.Registrar == RegistrarMode.Dynamic && App.IsSimulatorBuild && App.LinkMode == LinkMode.None)
            {
                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.GetProductSdkDirectory(App), "usr", "lib", library));
            }

            // The main method.
            foreach (var abi in Abis)
            {
                MainTask.Create(compile_tasks, this, abi, Assemblies, App.AssemblyName, registration_methods);
            }

            // Start compiling.
            compile_tasks.ExecuteInParallel();

            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);
        }
Beispiel #16
0
        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 (File.Exists(a.FullPath + ".mdb"))
                        {
                            // Debug files can change without the assemblies themselves changing
                            // This should also invalidate the cached linker results, since the non-linked mdbs can't be copied.
                            input.Add(a.FullPath + ".mdb");
                            output.Add(Path.Combine(PreBuildDirectory, a.FileName) + ".mdb");
                        }

                        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)));
                                // No need to copy satellite mdb files, satellites are resource-only assemblies.
                            }
                        }
                    }

                    // 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);
                        Driver.Log("Cached assemblies reloaded.");

                        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);
                // The linker can copy files (and not update timestamps), and then we run into this sequence:
                // * We run the linker, nothing changes, so the linker copies
                //   all files to the PreBuild directory, with timestamps intact.
                // * This means that for instance SDK assemblies will have the original
                //   timestamp from their installed location, and the exe will have the
                //   timestamp of when it was built.
                // * mtouch is executed again for some reason, and none of the input assemblies changed.
                //   We'll still re-execute the linker, because at least one of the input assemblies
                //   (the .exe) has a newer timestamp than some of the assemblies in the PreBuild directory.
                // So here we manually touch all the assemblies we have, to make sure their timestamps
                // change (this is us saying 'we know these files are up-to-date at this point in time').
                Driver.Touch(a.GetRelatedFiles());
            }

            File.WriteAllText(cache_path, string.Join("\n", linked_assemblies));
        }
Beispiel #17
0
        // Executed in parallel
        public void ExtractNativeLinkInfo()
        {
            // ignore framework assemblies, they won't have any LinkWith attributes
            if (IsFrameworkAssembly)
            {
                return;
            }

            var assembly = AssemblyDefinition;

            if (!assembly.HasCustomAttributes)
            {
                return;
            }

            var    exceptions = new List <Exception> ();
            string path;

            //
            // 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++)
            {
                CustomAttribute attr = assembly.CustomAttributes[i];

                if (attr.Constructor == null)
                {
                    continue;
                }

                TypeReference type = attr.Constructor.DeclaringType;
                if (!type.IsPlatformType("ObjCRuntime", "LinkWithAttribute"))
                {
                    continue;
                }

                // we know we'll modify this assembly, so load its symbols to keep them in sync
                LoadSymbols();

                // Let the linker remove it the attribute from the assembly

                LinkWithAttribute linkWith    = GetLinkWithAttribute(attr);
                string            libraryName = linkWith.LibraryName;

                // Remove the resource from the assembly at a later stage.
                AddResourceToBeRemoved(libraryName);

                // We can't add -dead_strip if there are any LinkWith attributes where smart linking is disabled.
                if (!linkWith.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 (linkWith.ForceLoad && !(linkWith.SmartLink && App.Registrar == RegistrarMode.Static))
                {
                    ForceLoad = true;
                }

                if (!string.IsNullOrEmpty(linkWith.LinkerFlags))
                {
                    if (LinkerFlags == null)
                    {
                        LinkerFlags = new List <string> ();
                    }
                    LinkerFlags.Add(linkWith.LinkerFlags);
                }

                if (!string.IsNullOrEmpty(linkWith.Frameworks))
                {
                    foreach (var f in linkWith.Frameworks.Split(new char[] { ' ' }))
                    {
                        if (Frameworks == null)
                        {
                            Frameworks = new HashSet <string> ();
                        }
                        Frameworks.Add(f);
                    }
                }

                if (!string.IsNullOrEmpty(linkWith.WeakFrameworks))
                {
                    foreach (var f in linkWith.WeakFrameworks.Split(new char[] { ' ' }))
                    {
                        if (WeakFrameworks == null)
                        {
                            WeakFrameworks = new HashSet <string> ();
                        }
                        WeakFrameworks.Add(f);
                    }
                }

                if (linkWith.NeedsGccExceptionHandling)
                {
                    NeedsGccExceptionHandling = true;
                }

                if (linkWith.IsCxx)
                {
                    EnableCxx = true;
                }

                path = Path.Combine(Cache.Location, libraryName);
                if (path.EndsWith(".framework"))
                {
#if MONOTOUCH
                    if (App.DeploymentTarget.Major < 8)
                    {
                        throw ErrorHelper.CreateError(1305, "The binding library '{0}' contains a user framework ({0}), but embedded user frameworks require iOS 8.0 (the deployment target is {1}). Please set the deployment target in the Info.plist file to at least 8.0.",
                                                      FileName, Path.GetFileName(path), App.DeploymentTarget);
                    }
#endif
                    var zipPath = path + ".zip";
                    if (!Application.IsUptodate(FullPath, zipPath))
                    {
                        Application.ExtractResource(assembly.MainModule, libraryName, zipPath, false);
                        Driver.Log(3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", libraryName, FullPath, zipPath);
                    }
                    else
                    {
                        Driver.Log(3, "Target '{0}' is up-to-date.", path);
                    }

                    if (!File.Exists(zipPath))
                    {
                        ErrorHelper.Warning(1302, "Could not extract the native framework '{0}' from '{1}'. " +
                                            "Please ensure the native framework was properly embedded in the managed assembly " +
                                            "(if the assembly was built using a binding project, the native framework must be included in the project, and its Build Action must be 'ObjcBindingNativeFramework').",
                                            libraryName, zipPath);
                    }
                    else
                    {
                        if (!Directory.Exists(path))
                        {
                            Directory.CreateDirectory(path);
                        }

                        if (Driver.RunCommand("/usr/bin/unzip", string.Format("-u -o -d {0} {1}", Driver.Quote(path), Driver.Quote(zipPath))) != 0)
                        {
                            throw ErrorHelper.CreateError(1303, "Could not decompress the native framework '{0}' from '{1}'. Please review the build log for more information from the native 'unzip' command.", libraryName, zipPath);
                        }
                    }

                    if (Frameworks == null)
                    {
                        Frameworks = new HashSet <string> ();
                    }
                    Frameworks.Add(path);
                }
                else
                {
                    if (!Application.IsUptodate(FullPath, path))
                    {
                        Application.ExtractResource(assembly.MainModule, libraryName, path, false);
                        Driver.Log(3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", libraryName, FullPath, path);
                    }
                    else
                    {
                        Driver.Log(3, "Target '{0}' is up-to-date.", path);
                    }

                    if (!File.Exists(path))
                    {
                        ErrorHelper.Warning(1302, "Could not extract the native library '{0}' from '{1}'. " +
                                            "Please ensure the native library was properly embedded in the managed assembly " +
                                            "(if the assembly was built using a binding project, the native library must be included in the project, and its Build Action must be 'ObjcBindingNativeLibrary').",
                                            libraryName, path);
                    }

                    if (LinkWith == null)
                    {
                        LinkWith = new List <string> ();
                    }
                    LinkWith.Add(path);
                }
            }

            if (exceptions != null && exceptions.Count > 0)
            {
                throw new AggregateException(exceptions);
            }

            // 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");
            }
        }
Beispiel #18
0
        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);
        }
        IEnumerable <BuildTask> CreateManagedToAssemblyTasks(string s, Abi abi, string build_dir)
        {
            var    arch = abi.AsArchString();
            var    asm_dir = Cache.Location;
            var    asm = Path.Combine(asm_dir, Path.GetFileName(s)) + "." + arch + ".s";
            var    llvm_asm = Path.Combine(asm_dir, Path.GetFileName(s)) + "." + arch + "-llvm.s";
            var    data = Path.Combine(asm_dir, Path.GetFileNameWithoutExtension(s)) + "." + arch + ".aotdata";
            string llvm_ofile, llvm_aot_ofile = "";
            var    is_llvm       = (abi & Abi.LLVM) == Abi.LLVM;
            bool   assemble_llvm = is_llvm && Driver.LLVMAsmWriter;

            if (!File.Exists(s))
            {
                throw new MonoTouchException(3004, true, "Could not AOT the assembly '{0}' because it doesn't exist.", s);
            }

            HashSet <string> dependencies = null;
            List <string>    deps         = null;
            List <string>    outputs      = new List <string> ();
            var warnings = new List <Exception> ();

            dependencies = ComputeDependencies(warnings);

            if (warnings.Count > 0)
            {
                ErrorHelper.Show(warnings);
                ErrorHelper.Warning(3006, "Could not compute a complete dependency map for the project. This will result in slower build times because Xamarin.iOS can't properly detect what needs to be rebuilt (and what does not need to be rebuilt). Please review previous warnings for more details.");
            }
            else
            {
                deps = new List <string> (dependencies.ToArray());
                deps.Add(s);
                deps.Add(Driver.GetAotCompiler(Target.Is64Build));
            }

            if (App.EnableLLVMOnlyBitCode)
            {
                //
                // In llvm-only mode, the AOT compiler emits a .bc file and no .s file for JITted code
                //
                llvm_ofile = Path.Combine(asm_dir, Path.GetFileName(s)) + "." + arch + ".bc";
                outputs.Add(llvm_ofile);
                llvm_aot_ofile = llvm_ofile;
            }
            else
            {
                llvm_ofile = Path.Combine(asm_dir, Path.GetFileName(s)) + "." + arch + "-llvm.o";
                outputs.Add(asm);

                if (is_llvm)
                {
                    if (assemble_llvm)
                    {
                        llvm_aot_ofile = llvm_asm;
                    }
                    else
                    {
                        llvm_aot_ofile = llvm_ofile;
                        Target.LinkWith(llvm_ofile);
                    }
                    outputs.Add(llvm_aot_ofile);
                }
            }

            if (deps != null && Application.IsUptodate(deps, outputs))
            {
                Driver.Log(3, "Target {0} is up-to-date.", asm);
                if (App.EnableLLVMOnlyBitCode)
                {
                    return(CreateCompileTasks(s, null, llvm_ofile, abi));
                }
                else
                {
                    return(CreateCompileTasks(s, asm, assemble_llvm ? llvm_asm : null, abi));
                }
            }
            else
            {
                Application.TryDelete(asm);                  // otherwise the next task might not detect that it will have to rebuild.
                Application.TryDelete(llvm_asm);
                Application.TryDelete(llvm_ofile);
                Driver.Log(3, "Target {0} needs to be rebuilt.", asm);
            }

            var aotCompiler = Driver.GetAotCompiler(Target.Is64Build);
            var aotArgs     = Driver.GetAotArguments(s, abi, build_dir, asm, llvm_aot_ofile, data);

            Driver.Log(3, "Aot compiler: {0} {1}", aotCompiler, aotArgs);

            AotDataFiles.Add(data);

            IEnumerable <BuildTask> nextTasks;

            if (App.EnableLLVMOnlyBitCode)
            {
                nextTasks = CreateCompileTasks(s, null, llvm_ofile, abi);
            }
            else
            {
                nextTasks = CreateCompileTasks(s, asm, assemble_llvm ? llvm_asm : null, abi);
            }

            return(new BuildTask [] { new AOTTask()
                                      {
                                          AssemblyName = s,
                                          ProcessStartInfo = Driver.CreateStartInfo(aotCompiler, aotArgs, Path.GetDirectoryName(s)),
                                          NextTasks = nextTasks
                                      } });
        }
        // The input file is either a .s or a .bc file
        BuildTask CreateCompileTask(string assembly_name, string infile_path, Abi abi)
        {
            var ext          = App.FastDev ? "dylib" : "o";
            var ofile        = Path.ChangeExtension(infile_path, ext);
            var install_name = string.Empty;

            if (App.FastDev)
            {
                if (dylibs == null)
                {
                    dylibs = new List <string> ();
                }
                dylibs.Add(ofile);
                install_name = "lib" + Path.GetFileName(assembly_name) + ".dylib";
            }
            else
            {
                Target.LinkWith(ofile);
            }

            if (Application.IsUptodate(new string [] { infile_path, Driver.CompilerPath }, new string [] { ofile }))
            {
                Driver.Log(3, "Target {0} is up-to-date.", ofile);
                return(null);
            }
            else
            {
                Application.TryDelete(ofile);                  // otherwise the next task might not detect that it will have to rebuild.
                Driver.Log(3, "Target {0} needs to be rebuilt.", ofile);
            }

            var compiler_flags = new CompilerFlags()
            {
                Target = Target
            };

            BuildTask bitcode_task = null;
            BuildTask link_task = null;
            string    link_task_input, link_language = "";

            if (App.EnableAsmOnlyBitCode)
            {
                link_task_input = infile_path + ".ll";
                link_language   = "";
                // linker_flags.Add (" -fembed-bitcode");

                bitcode_task = new BitCodeify()
                {
                    Input            = infile_path,
                    OutputFile       = link_task_input,
                    Platform         = App.Platform,
                    Abi              = abi,
                    DeploymentTarget = App.DeploymentTarget,
                };
            }
            else
            {
                link_task_input = infile_path;
                if (infile_path.EndsWith(".s"))
                {
                    link_language = "assembler";
                }
            }

            if (App.FastDev)
            {
                compiler_flags.AddFrameworks(Frameworks, WeakFrameworks);
                compiler_flags.AddLinkWith(LinkWith, ForceLoad);
                compiler_flags.LinkWithMono();
                compiler_flags.LinkWithXamarin();
                compiler_flags.AddOtherFlags(LinkerFlags);
                if (Target.GetEntryPoints().ContainsKey("UIApplicationMain"))
                {
                    compiler_flags.AddFramework("UIKit");
                }
            }

            link_task = new LinkTask()
            {
                Target        = Target,
                AssemblyName  = assembly_name,
                Abi           = abi,
                InputFile     = link_task_input,
                OutputFile    = ofile,
                InstallName   = install_name,
                CompilerFlags = compiler_flags,
                SharedLibrary = App.FastDev,
                Language      = link_language,
            };

            if (bitcode_task != null)
            {
                bitcode_task.NextTasks = new BuildTask[] { link_task };
                return(bitcode_task);
            }
            return(link_task);
        }
Beispiel #21
0
        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));
        }