static void LogLinkWithAttribute(LinkWithAttribute linkWith) { Driver.Log(3, " ForceLoad: {0}", linkWith.ForceLoad); Driver.Log(3, " Frameworks: {0}", linkWith.Frameworks); Driver.Log(3, " IsCxx: {0}", linkWith.IsCxx); Driver.Log(3, " LinkerFlags: {0}", linkWith.LinkerFlags); Driver.Log(3, " LinkTarget: {0}", linkWith.LinkTarget); Driver.Log(3, " NeedsGccExceptionHandling: {0}", linkWith.NeedsGccExceptionHandling); Driver.Log(3, " SmartLink: {0}", linkWith.SmartLink); Driver.Log(3, " WeakFrameworks: {0}", linkWith.WeakFrameworks); }
public NativeReferenceMetadata(LinkWithAttribute attribute) { ForceLoad = attribute.ForceLoad; Frameworks = attribute.Frameworks; WeakFrameworks = attribute.WeakFrameworks; LibraryName = attribute.LibraryName; LinkerFlags = attribute.LinkerFlags; LinkTarget = attribute.LinkTarget; NeedsGccExceptionHandling = attribute.NeedsGccExceptionHandling; IsCxx = attribute.IsCxx; SmartLink = attribute.SmartLink; Dlsym = attribute.Dlsym; Attribute = attribute; }
void ProcessLinkWithAttributes(AssemblyDefinition assembly) { // // 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; } // Let the linker remove it the attribute from the assembly HasLinkWithAttributes = true; LinkWithAttribute linkWith = GetLinkWithAttribute(attr); NativeReferenceMetadata metadata = new NativeReferenceMetadata(linkWith); // If we've already processed this native library, skip it if (LinkWith.Any(x => Path.GetFileName(x) == metadata.LibraryName) || Frameworks.Any(x => Path.GetFileName(x) == metadata.LibraryName)) { continue; } // Remove the resource from the assembly at a later stage. if (!string.IsNullOrEmpty(metadata.LibraryName)) { AddResourceToBeRemoved(metadata.LibraryName); } ProcessNativeReferenceOptions(metadata); if (!string.IsNullOrEmpty(linkWith.LibraryName)) { if (linkWith.LibraryName.EndsWith(".framework", StringComparison.OrdinalIgnoreCase)) { AssertiOSVersionSupportsUserFrameworks(linkWith.LibraryName); Frameworks.Add(ExtractFramework(assembly, metadata)); } else { LinkWith.Add(ExtractNativeLibrary(assembly, metadata)); } } } }
static int Main2(string [] args) { bool show_help = false; bool zero_copy = false; bool alpha = false; string basedir = null; string tmpdir = null; string ns = null; string outfile = null; bool delete_temp = true, debug = false; bool verbose = false; bool unsafef = true; bool external = false; bool pmode = true; bool nostdlib = false; bool clean_mono_path = false; bool inline_selectors = false; List <string> sources; var resources = new List <string> (); #if !MONOMAC var linkwith = new List <string> (); #endif var references = new List <string> (); var libs = new List <string> (); var core_sources = new List <string> (); var extra_sources = new List <string> (); var defines = new List <string> (); bool binding_third_party = true; string generate_file_list = null; var os = new OptionSet() { { "h|?|help", "Displays the help", v => show_help = true }, { "a", "Include alpha bindings", v => alpha = true }, { "outdir=", "Sets the output directory for the temporary binding files", v => { basedir = v; } }, { "o|out=", "Sets the name of the output library", v => outfile = v }, { "tmpdir=", "Sets the working directory for temp files", v => { tmpdir = v; delete_temp = false; } }, { "debug", "Generates a debugging build of the binding", v => debug = true }, { "sourceonly=", "Only generates the source", v => generate_file_list = v }, { "ns=", "Sets the namespace for storing helper classes", v => ns = v }, { "unsafe", "Sets the unsafe flag for the build", v => unsafef = true }, #if MONOMAC { "core", "Use this to build monomac.dll", v => binding_third_party = false }, #else { "core", "Use this to build monotouch.dll", v => binding_third_party = false }, #endif { "r=", "Adds a reference", v => references.Add(v) }, { "lib=", "Adds the directory to the search path for the compiler", v => libs.Add(v) }, { "compiler=", "Sets the compiler to use", v => compiler = v }, { "d=", "Defines a symbol", v => defines.Add(v) }, { "s=", "Adds a source file required to build the API", v => core_sources.Add(v) }, { "v", "Sets verbose mode", v => verbose = true }, { "x=", "Adds the specified file to the build, used after the core files are compiled", v => extra_sources.Add(v) }, { "e", "Generates smaller classes that can not be subclassed (previously called 'external mode')", v => external = true }, { "p", "Sets private mode", v => pmode = false }, { "baselib=", "Sets the base library", v => baselibdll = v }, { "use-zero-copy", v => zero_copy = true }, { "nostdlib", "Does not reference mscorlib.dll library", l => nostdlib = true }, { "no-mono-path", "Launches compiler with empty MONO_PATH", l => clean_mono_path = true }, { "inline-selectors:", "If Selector.GetHandle is inlined and does not need to be cached (default: false)", v => inline_selectors = string.Equals("true", v, StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(v) }, #if !MONOMAC { "link-with=,", "Link with a native library {0:FILE} to the binding, embedded as a resource named {1:ID}", (path, id) => { if (path == null || path.Length == 0) { throw new Exception("-link-with=FILE,ID requires a filename."); } if (id == null || id.Length == 0) { id = Path.GetFileName(path); } if (linkwith.Contains(id)) { throw new Exception("-link-with=FILE,ID cannot assign the same resource id to multiple libraries."); } resources.Add(string.Format("-res:{0},{1}", path, id)); linkwith.Add(id); } }, #endif }; try { sources = os.Parse(args); } catch (Exception e) { Console.Error.WriteLine("{0}: {1}", tool_name, e.Message); Console.Error.WriteLine("see {0} --help for more information", tool_name); return(1); } if (show_help || sources.Count == 0) { Console.WriteLine("Error: no api file provided"); ShowHelp(os); return(0); } if (alpha) { defines.Add("ALPHA"); } if (tmpdir == null) { tmpdir = GetWorkDir(); } if (outfile == null) { outfile = Path.GetFileNameWithoutExtension(sources [0]) + ".dll"; } string refs = (references.Count > 0 ? "-r:" + String.Join(" -r:", references.ToArray()) : ""); string paths = (libs.Count > 0 ? "-lib:" + String.Join(" -lib:", libs.ToArray()) : ""); try { var api_file = sources [0]; var tmpass = Path.Combine(tmpdir, "temp.dll"); // -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources var cargs = String.Format("-unsafe -target:library {0} -nowarn:436 -out:{1} -r:{2} {3} {4} {5} -r:{6} {7} {8} {9}", string.Join(" ", sources.ToArray()), tmpass, Environment.GetCommandLineArgs()[0], string.Join(" ", core_sources.ToArray()), refs, unsafef ? "-unsafe" : "", baselibdll, string.Join(" ", defines.Select(x => "-define:" + x).ToArray()), paths, nostdlib ? "-nostdlib" : null); var si = new ProcessStartInfo(compiler, cargs) { UseShellExecute = false, }; if (clean_mono_path) { // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler si.EnvironmentVariables.Remove("MONO_PATH"); } if (verbose) { Console.WriteLine("{0} {1}", si.FileName, si.Arguments); } var p = Process.Start(si); p.WaitForExit(); if (p.ExitCode != 0) { Console.WriteLine("{0}: API binding contains errors.", tool_name); return(1); } Assembly api; try { api = Assembly.LoadFrom(tmpass); } catch (Exception e) { if (verbose) { Console.WriteLine(e); } Console.Error.WriteLine("Error loading API definition from {0}", tmpass); return(1); } Assembly baselib; try { baselib = Assembly.LoadFrom(baselibdll); } catch (Exception e) { if (verbose) { Console.WriteLine(e); } Console.Error.WriteLine("Error loading base library {0}", baselibdll); return(1); } #if !MONOMAC foreach (object attr in api.GetCustomAttributes(typeof(LinkWithAttribute), true)) { LinkWithAttribute linkWith = (LinkWithAttribute)attr; if (!linkwith.Contains(linkWith.LibraryName)) { Console.Error.WriteLine("Missing native library {0}, please use `--link-with' to specify the path to this library.", linkWith.LibraryName); return(1); } } #endif var types = new List <Type> (); foreach (var t in api.GetTypes()) { if (t.GetCustomAttributes(typeof(BaseTypeAttribute), true).Length > 0 || t.GetCustomAttributes(typeof(StaticAttribute), true).Length > 0) { types.Add(t); } } var g = new Generator(pmode, external, debug, types.ToArray()) { MessagingNS = ns == null?Path.GetFileNameWithoutExtension(api_file) : ns, CoreMessagingNS = RootNS + ".ObjCRuntime", BindThirdPartyLibrary = binding_third_party, CoreNSObject = CoreObject, BaseDir = basedir != null ? basedir : tmpdir, ZeroCopyStrings = zero_copy, #if MONOMAC OnlyX86 = true, #endif Alpha = alpha, InlineSelectors = inline_selectors, }; foreach (var mi in baselib.GetType(RootNS + ".ObjCRuntime.Messaging").GetMethods()) { if (mi.Name.IndexOf("_objc_msgSend") != -1) { g.RegisterMethodName(mi.Name); } } g.Go(); if (generate_file_list != null) { using (var f = File.CreateText(generate_file_list)){ g.GeneratedFiles.ForEach(x => f.WriteLine(x)); } return(0); } cargs = String.Format("{0} -target:library -out:{1} {2} {3} {4} {5} {6} {7} -r:{8} {9} {10}", unsafef ? "-unsafe" : "", /* 0 */ outfile, /* 1 */ string.Join(" ", defines.Select(x => "-define:" + x).ToArray()), /* 2 */ String.Join(" ", g.GeneratedFiles.ToArray()), /* 3 */ String.Join(" ", core_sources.ToArray()), /* 4 */ String.Join(" ", sources.Skip(1).ToArray()), /* 5 */ String.Join(" ", extra_sources.ToArray()), /* 6 */ refs, /* 7 */ baselibdll, /* 8 */ String.Join(" ", resources.ToArray()), /* 9 */ nostdlib ? "-nostdlib" : null ); si = new ProcessStartInfo(compiler, cargs) { UseShellExecute = false, }; if (verbose) { Console.WriteLine("{0} {1}", si.FileName, si.Arguments); } p = Process.Start(si); p.WaitForExit(); if (p.ExitCode != 0) { Console.WriteLine("{0}: API binding contains errors.", tool_name); return(1); } } finally { if (delete_temp) { Directory.Delete(tmpdir, true); } } return(0); }
public static LinkWithAttribute GetLinkWithAttribute(CustomAttribute attr) { LinkWithAttribute linkWith; var cargs = attr.ConstructorArguments; switch (cargs.Count) { case 3: linkWith = new LinkWithAttribute((string)cargs [0].Value, (LinkTarget)cargs [1].Value, (string)cargs [2].Value); break; case 2: linkWith = new LinkWithAttribute((string)cargs [0].Value, (LinkTarget)cargs [1].Value); break; default: case 1: linkWith = new LinkWithAttribute((string)cargs [0].Value); break; } foreach (var property in attr.Properties) { switch (property.Name) { case "NeedsGccExceptionHandling": linkWith.NeedsGccExceptionHandling = (bool)property.Argument.Value; break; case "WeakFrameworks": linkWith.WeakFrameworks = (string)property.Argument.Value; break; case "Frameworks": linkWith.Frameworks = (string)property.Argument.Value; break; case "LinkerFlags": linkWith.LinkerFlags = (string)property.Argument.Value; break; case "LinkTarget": linkWith.LinkTarget = (LinkTarget)property.Argument.Value; break; case "ForceLoad": linkWith.ForceLoad = (bool)property.Argument.Value; break; case "IsCxx": linkWith.IsCxx = (bool)property.Argument.Value; break; case "SmartLink": linkWith.SmartLink = (bool)property.Argument.Value; break; default: break; } } return(linkWith); }
// 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"); } }
void ProcessLinkWithAttributes(AssemblyDefinition assembly) { // // 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.Is("ObjCRuntime", "LinkWithAttribute")) { continue; } // Let the linker remove it the attribute from the assembly HasLinkWithAttributes = true; LinkWithAttribute linkWith = GetLinkWithAttribute(attr); NativeReferenceMetadata metadata = new NativeReferenceMetadata(linkWith); // If we've already processed this native library, skip it if (LinkWith.Any(x => Path.GetFileName(x) == metadata.LibraryName) || Frameworks.Any(x => Path.GetFileName(x) == metadata.LibraryName)) { continue; } // Remove the resource from the assembly at a later stage. if (!string.IsNullOrEmpty(metadata.LibraryName)) { AddResourceToBeRemoved(metadata.LibraryName); } ProcessNativeReferenceOptions(metadata); if (!string.IsNullOrEmpty(linkWith.LibraryName)) { switch (Path.GetExtension(linkWith.LibraryName).ToLowerInvariant()) { case ".framework": AssertiOSVersionSupportsUserFrameworks(linkWith.LibraryName); Frameworks.Add(ExtractFramework(assembly, metadata)); break; case ".xcframework": // this is resolved, at msbuild time, into a framework // but we must ignore it here (can't be the `default` case) break; default: LinkWith.Add(ExtractNativeLibrary(assembly, metadata)); break; } } } }
static int Main2(string [] args) { bool show_help = false; bool zero_copy = false; string basedir = null; string tmpdir = null; string ns = null; string outfile = null; bool delete_temp = true, debug = false; bool verbose = false; bool unsafef = true; bool external = false; bool public_mode = true; bool nostdlib = false; bool inline_selectors = Unified && CurrentPlatform != PlatformName.MacOSX; List <string> sources; var resources = new List <string> (); var linkwith = new List <string> (); var references = new List <string> (); var libs = new List <string> (); var api_sources = new List <string> (); var core_sources = new List <string> (); var extra_sources = new List <string> (); var defines = new List <string> (); bool binding_third_party = true; string generate_file_list = null; bool process_enums = false; // .NET treats ' as part of the command name when running an app so we must use " on Windows PlatformID pid = Environment.OSVersion.Platform; if (((int)pid != 128 && pid != PlatformID.Unix && pid != PlatformID.MacOSX)) { shellQuoteChar = '"'; // Windows } else { shellQuoteChar = '\''; // !Windows } var os = new OptionSet() { { "h|?|help", "Displays the help", v => show_help = true }, { "a", "Include alpha bindings (Obsolete).", v => {}, true }, { "outdir=", "Sets the output directory for the temporary binding files", v => { basedir = v; } }, { "o|out=", "Sets the name of the output library", v => outfile = v }, { "tmpdir=", "Sets the working directory for temp files", v => { tmpdir = v; delete_temp = false; } }, { "debug", "Generates a debugging build of the binding", v => debug = true }, { "sourceonly=", "Only generates the source", v => generate_file_list = v }, { "ns=", "Sets the namespace for storing helper classes", v => ns = v }, { "unsafe", "Sets the unsafe flag for the build", v => unsafef = true }, { "core", "Use this to build product assemblies", v => binding_third_party = false }, { "r=", "Adds a reference", v => references.Add(v) }, { "lib=", "Adds the directory to the search path for the compiler", v => libs.Add(Quote(v)) }, { "compiler=", "Sets the compiler to use", v => compiler = v }, { "sdk=", "Sets the .NET SDK to use", v => net_sdk = v }, { "new-style", "Build for Unified (Obsolete).", v => { Console.WriteLine("The --new-style option is obsolete and ignored."); }, true }, { "d=", "Defines a symbol", v => defines.Add(v) }, { "api=", "Adds a API definition source file", v => api_sources.Add(Quote(v)) }, { "s=", "Adds a source file required to build the API", v => core_sources.Add(Quote(v)) }, { "v", "Sets verbose mode", v => verbose = true }, { "x=", "Adds the specified file to the build, used after the core files are compiled", v => extra_sources.Add(Quote(v)) }, { "e", "Generates smaller classes that can not be subclassed (previously called 'external mode')", v => external = true }, { "p", "Sets private mode", v => public_mode = false }, { "baselib=", "Sets the base library", v => baselibdll = v }, { "use-zero-copy", v => zero_copy = true }, { "nostdlib", "Does not reference mscorlib.dll library", l => nostdlib = true }, { "no-mono-path", "Launches compiler with empty MONO_PATH", l => { } }, { "native-exception-marshalling", "Enable the marshalling support for Objective-C exceptions", (v) => { /* no-op */ } }, { "inline-selectors:", "If Selector.GetHandle is inlined and does not need to be cached (enabled by default in Xamarin.iOS, disabled in Xamarin.Mac)", v => inline_selectors = string.Equals("true", v, StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(v) }, { "process-enums", "Process enums as bindings, not external, types.", v => process_enums = true }, { "link-with=,", "Link with a native library {0:FILE} to the binding, embedded as a resource named {1:ID}", (path, id) => { if (path == null || path.Length == 0) { throw new Exception("-link-with=FILE,ID requires a filename."); } if (id == null || id.Length == 0) { id = Path.GetFileName(path); } if (linkwith.Contains(id)) { throw new Exception("-link-with=FILE,ID cannot assign the same resource id to multiple libraries."); } resources.Add(string.Format("-res:{0},{1}", path, id)); linkwith.Add(id); } }, { "unified-full-profile", "Launches compiler pointing to XM Full Profile", l => { /* no-op*/ }, true }, { "unified-mobile-profile", "Launches compiler pointing to XM Mobile Profile", l => { /* no-op*/ }, true }, }; try { sources = os.Parse(args); } catch (Exception e) { Console.Error.WriteLine("{0}: {1}", tool_name, e.Message); Console.Error.WriteLine("see {0} --help for more information", tool_name); return(1); } if (show_help) { ShowHelp(os); return(0); } if (sources.Count > 0) { api_sources.Insert(0, Quote(sources [0])); for (int i = 1; i < sources.Count; i++) { core_sources.Insert(i - 1, Quote(sources [i])); } } if (api_sources.Count == 0) { Console.WriteLine("Error: no api file provided"); ShowHelp(os); return(1); } if (tmpdir == null) { tmpdir = GetWorkDir(); } string firstApiDefinitionName = Path.GetFileNameWithoutExtension(Unquote(api_sources [0])); firstApiDefinitionName = firstApiDefinitionName.Replace('-', '_'); // This is not exhaustive, but common. if (outfile == null) { outfile = firstApiDefinitionName + ".dll"; } string refs = string.Empty; foreach (var r in references) { if (refs != string.Empty) { refs += " "; } refs += "-r:" + Quote(r); } string paths = (libs.Count > 0 ? "-lib:" + String.Join(" -lib:", libs.ToArray()) : ""); try { var tmpass = Path.Combine(tmpdir, "temp.dll"); // -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources // Keep source files at the end of the command line - csc will create TWO assemblies if any sources preceed the -out parameter var cargs = new StringBuilder(); if (CurrentPlatform == PlatformName.MacOSX) { if (!string.IsNullOrEmpty(net_sdk) && net_sdk != "mobile") { cargs.Append("-sdk:").Append(net_sdk).Append(' '); } } else { if (!string.IsNullOrEmpty(net_sdk)) { cargs.Append("-sdk:").Append(net_sdk).Append(' '); } } cargs.Append("-debug -unsafe -target:library -nowarn:436").Append(' '); cargs.Append("-out:").Append(Quote(tmpass)).Append(' '); cargs.Append("-r:").Append(Environment.GetCommandLineArgs()[0]).Append(' '); cargs.Append(refs).Append(' '); if (unsafef) { cargs.Append("-unsafe "); } cargs.Append("-r:").Append(Quote(baselibdll)).Append(' '); foreach (var def in defines) { cargs.Append("-define:").Append(def).Append(' '); } cargs.Append(paths).Append(' '); if (nostdlib) { cargs.Append("-nostdlib "); } foreach (var qs in api_sources) { cargs.Append(qs).Append(' '); } foreach (var cs in core_sources) { cargs.Append(cs).Append(' '); } if (!string.IsNullOrEmpty(Path.GetDirectoryName(baselibdll))) { cargs.Append("-lib:").Append(Path.GetDirectoryName(baselibdll)).Append(' '); } var si = new ProcessStartInfo(compiler, cargs.ToString()) { UseShellExecute = false, }; // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler si.EnvironmentVariables.Remove("MONO_PATH"); if (verbose) { Console.WriteLine("{0} {1}", si.FileName, si.Arguments); } var p = Process.Start(si); p.WaitForExit(); if (p.ExitCode != 0) { Console.WriteLine("{0}: API binding contains errors.", tool_name); return(1); } Assembly api; try { api = Assembly.LoadFrom(tmpass); } catch (Exception e) { if (verbose) { Console.WriteLine(e); } Console.Error.WriteLine("Error loading API definition from {0}", tmpass); return(1); } Assembly baselib; try { baselib = Assembly.LoadFrom(baselibdll); } catch (Exception e) { if (verbose) { Console.WriteLine(e); } Console.Error.WriteLine("Error loading base library {0}", baselibdll); return(1); } GC.KeepAlive(baselib); // Fixes a compiler warning (unused variable). foreach (object attr in api.GetCustomAttributes(typeof(LinkWithAttribute), true)) { LinkWithAttribute linkWith = (LinkWithAttribute)attr; if (!linkwith.Contains(linkWith.LibraryName)) { Console.Error.WriteLine("Missing native library {0}, please use `--link-with' to specify the path to this library.", linkWith.LibraryName); return(1); } } foreach (var r in references) { if (File.Exists(r)) { try { Assembly.LoadFrom(r); } catch (Exception ex) { ErrorHelper.Show(new BindingException(1104, false, "Could not load the referenced library '{0}': {1}.", r, ex.Message)); } } } var types = new List <Type> (); var strong_dictionaries = new List <Type> (); foreach (var t in api.GetTypes()) { if ((process_enums && t.IsEnum) || t.GetCustomAttributes(typeof(BaseTypeAttribute), true).Length > 0 || t.GetCustomAttributes(typeof(ProtocolAttribute), true).Length > 0 || t.GetCustomAttributes(typeof(StaticAttribute), true).Length > 0 || t.GetCustomAttributes(typeof(PartialAttribute), true).Length > 0) { types.Add(t); } if (t.GetCustomAttributes(typeof(StrongDictionaryAttribute), true).Length > 0) { strong_dictionaries.Add(t); } } bool addSystemDrawingReferences = #if NO_SYSTEM_DRAWING true; #else false; #endif string nsManagerPrefix; switch (CurrentPlatform) { case PlatformName.MacOSX: nsManagerPrefix = Unified ? null : "MonoMac"; break; case PlatformName.iOS: nsManagerPrefix = Unified ? null : "MonoTouch"; break; default: nsManagerPrefix = null; break; } var nsManager = new NamespaceManager( nsManagerPrefix, ns == null ? firstApiDefinitionName : ns, addSystemDrawingReferences ); Generator.CurrentPlatform = CurrentPlatform; var g = new Generator(nsManager, public_mode, external, debug, types.ToArray(), strong_dictionaries.ToArray()) { BindThirdPartyLibrary = binding_third_party, CoreNSObject = CoreObject, BaseDir = basedir != null ? basedir : tmpdir, ZeroCopyStrings = zero_copy, Compat = !Unified, InlineSelectors = inline_selectors, SkipSystemDrawing = addSystemDrawingReferences }; if (!Unified && !binding_third_party) { foreach (var mi in baselib.GetType(nsManager.CoreObjCRuntime + ".Messaging").GetMethods()) { if (mi.Name.IndexOf("_objc_msgSend") != -1) { g.RegisterMethodName(mi.Name); } } } g.Go(); if (generate_file_list != null) { using (var f = File.CreateText(generate_file_list)){ foreach (var x in g.GeneratedFiles.OrderBy((v) => v)) { f.WriteLine(x); } } return(0); } cargs.Clear(); if (unsafef) { cargs.Append("-unsafe "); } cargs.Append("-target:library "); cargs.Append("-out:").Append(Quote(outfile)).Append(' '); foreach (var def in defines) { cargs.Append("-define:").Append(def).Append(' '); } foreach (var gf in g.GeneratedFiles) { cargs.Append(gf).Append(' '); } foreach (var cs in core_sources) { cargs.Append(cs).Append(' '); } foreach (var es in extra_sources) { cargs.Append(es).Append(' '); } cargs.Append(refs).Append(' '); cargs.Append("-r:").Append(Quote(baselibdll)).Append(' '); foreach (var res in resources) { cargs.Append(res).Append(' '); } if (nostdlib) { cargs.Append("-nostdlib "); } if (!string.IsNullOrEmpty(Path.GetDirectoryName(baselibdll))) { cargs.Append("-lib:").Append(Path.GetDirectoryName(baselibdll)).Append(' '); } si = new ProcessStartInfo(compiler, cargs.ToString()) { UseShellExecute = false, }; // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler si.EnvironmentVariables.Remove("MONO_PATH"); if (verbose) { Console.WriteLine("{0} {1}", si.FileName, si.Arguments); } p = Process.Start(si); p.WaitForExit(); if (p.ExitCode != 0) { Console.WriteLine("{0}: API binding contains errors.", tool_name); return(1); } } finally { if (delete_temp) { Directory.Delete(tmpdir, true); } } return(0); }