/src/btouch.cs
C# | 332 lines | 263 code | 41 blank | 28 comment | 38 complexity | a10dc43e3999412bcb76fbcb7c200dad MD5 | raw file
Possible License(s): Apache-2.0
- //
- // Authors:
- // Miguel de Icaza
- //
- // Copyright 2011 Xamarin Inc.
- // Copyright 2009-2010 Novell, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using System.Collections.Generic;
- using System.Diagnostics;
- using Mono.Options;
- #if !MONOMAC
- using MonoTouch.ObjCRuntime;
- #endif
- class BindingTouch {
- #if MONOMAC
- static string baselibdll = "MonoMac.dll";
- static string RootNS = "MonoMac";
- static Type CoreObject = typeof (MonoMac.Foundation.NSObject);
- static string tool_name = "bmac";
- static string compiler = "mcs";
- static string net_sdk = "4";
- #else
- static string baselibdll = "/Developer/MonoTouch/usr/lib/mono/2.1/monotouch.dll";
- static string RootNS = "MonoTouch";
- static Type CoreObject = typeof (MonoTouch.Foundation.NSObject);
- static string tool_name = "btouch";
- static string compiler = "/Developer/MonoTouch/usr/bin/smcs";
- static string net_sdk = null;
- #endif
- public static string ToolName {
- get { return tool_name; }
- }
- static void ShowHelp (OptionSet os)
- {
- Console.WriteLine ("{0} - Mono Objective-C API binder", tool_name);
- Console.WriteLine ("Usage is:\n {0} [options] apifile1.cs [apifileN] [-s=core1.cs [-s=core2.cs]] [-x=extra1.cs [-x=extra2.cs]]", tool_name);
-
- os.WriteOptionDescriptions (Console.Out);
- }
-
- static int Main (string [] args)
- {
- try {
- return Main2 (args);
- } catch (Exception ex) {
- ErrorHelper.Show (ex);
- return 1;
- }
- }
-
- 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 native_exception_marshalling = 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 },
- { "sdk=", "Sets the .NET SDK to use", v => net_sdk = 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 },
- { "native-exception-marshalling", "Enable the marshalling support for Objective-C exceptions", l => native_exception_marshalling = 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 ("{10} -debug -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,
- !String.IsNullOrEmpty (net_sdk) ? "-sdk:" + net_sdk : 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,
- NativeExceptionMarshalling = native_exception_marshalling,
- #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;
- }
- static string GetWorkDir ()
- {
- while (true){
- string p = Path.Combine (Path.GetTempPath(), Path.GetRandomFileName());
- if (Directory.Exists (p))
- continue;
-
- var di = Directory.CreateDirectory (p);
- return di.FullName;
- }
- }
- }