PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/btouch.cs

https://github.com/kjpou1/maccore
C# | 332 lines | 263 code | 41 blank | 28 comment | 38 complexity | a10dc43e3999412bcb76fbcb7c200dad MD5 | raw file
Possible License(s): Apache-2.0
  1. //
  2. // Authors:
  3. // Miguel de Icaza
  4. //
  5. // Copyright 2011 Xamarin Inc.
  6. // Copyright 2009-2010 Novell, Inc.
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining
  9. // a copy of this software and associated documentation files (the
  10. // "Software"), to deal in the Software without restriction, including
  11. // without limitation the rights to use, copy, modify, merge, publish,
  12. // distribute, sublicense, and/or sell copies of the Software, and to
  13. // permit persons to whom the Software is furnished to do so, subject to
  14. // the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be
  17. // included in all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  22. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  23. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  24. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  25. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26. //
  27. using System;
  28. using System.IO;
  29. using System.Linq;
  30. using System.Reflection;
  31. using System.Collections.Generic;
  32. using System.Diagnostics;
  33. using Mono.Options;
  34. #if !MONOMAC
  35. using MonoTouch.ObjCRuntime;
  36. #endif
  37. class BindingTouch {
  38. #if MONOMAC
  39. static string baselibdll = "MonoMac.dll";
  40. static string RootNS = "MonoMac";
  41. static Type CoreObject = typeof (MonoMac.Foundation.NSObject);
  42. static string tool_name = "bmac";
  43. static string compiler = "mcs";
  44. static string net_sdk = "4";
  45. #else
  46. static string baselibdll = "/Developer/MonoTouch/usr/lib/mono/2.1/monotouch.dll";
  47. static string RootNS = "MonoTouch";
  48. static Type CoreObject = typeof (MonoTouch.Foundation.NSObject);
  49. static string tool_name = "btouch";
  50. static string compiler = "/Developer/MonoTouch/usr/bin/smcs";
  51. static string net_sdk = null;
  52. #endif
  53. public static string ToolName {
  54. get { return tool_name; }
  55. }
  56. static void ShowHelp (OptionSet os)
  57. {
  58. Console.WriteLine ("{0} - Mono Objective-C API binder", tool_name);
  59. Console.WriteLine ("Usage is:\n {0} [options] apifile1.cs [apifileN] [-s=core1.cs [-s=core2.cs]] [-x=extra1.cs [-x=extra2.cs]]", tool_name);
  60. os.WriteOptionDescriptions (Console.Out);
  61. }
  62. static int Main (string [] args)
  63. {
  64. try {
  65. return Main2 (args);
  66. } catch (Exception ex) {
  67. ErrorHelper.Show (ex);
  68. return 1;
  69. }
  70. }
  71. static int Main2 (string [] args)
  72. {
  73. bool show_help = false;
  74. bool zero_copy = false;
  75. bool alpha = false;
  76. string basedir = null;
  77. string tmpdir = null;
  78. string ns = null;
  79. string outfile = null;
  80. bool delete_temp = true, debug = false;
  81. bool verbose = false;
  82. bool unsafef = true;
  83. bool external = false;
  84. bool pmode = true;
  85. bool nostdlib = false;
  86. bool clean_mono_path = false;
  87. bool native_exception_marshalling = false;
  88. bool inline_selectors = false;
  89. List<string> sources;
  90. var resources = new List<string> ();
  91. #if !MONOMAC
  92. var linkwith = new List<string> ();
  93. #endif
  94. var references = new List<string> ();
  95. var libs = new List<string> ();
  96. var core_sources = new List<string> ();
  97. var extra_sources = new List<string> ();
  98. var defines = new List<string> ();
  99. bool binding_third_party = true;
  100. string generate_file_list = null;
  101. var os = new OptionSet () {
  102. { "h|?|help", "Displays the help", v => show_help = true },
  103. { "a", "Include alpha bindings", v => alpha = true },
  104. { "outdir=", "Sets the output directory for the temporary binding files", v => { basedir = v; }},
  105. { "o|out=", "Sets the name of the output library", v => outfile = v },
  106. { "tmpdir=", "Sets the working directory for temp files", v => { tmpdir = v; delete_temp = false; }},
  107. { "debug", "Generates a debugging build of the binding", v => debug = true },
  108. { "sourceonly=", "Only generates the source", v => generate_file_list = v },
  109. { "ns=", "Sets the namespace for storing helper classes", v => ns = v },
  110. { "unsafe", "Sets the unsafe flag for the build", v=> unsafef = true },
  111. #if MONOMAC
  112. { "core", "Use this to build monomac.dll", v => binding_third_party = false },
  113. #else
  114. { "core", "Use this to build monotouch.dll", v => binding_third_party = false },
  115. #endif
  116. { "r=", "Adds a reference", v => references.Add (v) },
  117. { "lib=", "Adds the directory to the search path for the compiler", v => libs.Add (v) },
  118. { "compiler=", "Sets the compiler to use", v => compiler = v },
  119. { "sdk=", "Sets the .NET SDK to use", v => net_sdk = v },
  120. { "d=", "Defines a symbol", v => defines.Add (v) },
  121. { "s=", "Adds a source file required to build the API", v => core_sources.Add (v) },
  122. { "v", "Sets verbose mode", v => verbose = true },
  123. { "x=", "Adds the specified file to the build, used after the core files are compiled", v => extra_sources.Add (v) },
  124. { "e", "Generates smaller classes that can not be subclassed (previously called 'external mode')", v => external = true },
  125. { "p", "Sets private mode", v => pmode = false },
  126. { "baselib=", "Sets the base library", v => baselibdll = v },
  127. { "use-zero-copy", v=> zero_copy = true },
  128. { "nostdlib", "Does not reference mscorlib.dll library", l => nostdlib = true },
  129. { "no-mono-path", "Launches compiler with empty MONO_PATH", l => clean_mono_path = true },
  130. { "native-exception-marshalling", "Enable the marshalling support for Objective-C exceptions", l => native_exception_marshalling = true },
  131. { "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) },
  132. #if !MONOMAC
  133. { "link-with=,", "Link with a native library {0:FILE} to the binding, embedded as a resource named {1:ID}",
  134. (path, id) => {
  135. if (path == null || path.Length == 0)
  136. throw new Exception ("-link-with=FILE,ID requires a filename.");
  137. if (id == null || id.Length == 0)
  138. id = Path.GetFileName (path);
  139. if (linkwith.Contains (id))
  140. throw new Exception ("-link-with=FILE,ID cannot assign the same resource id to multiple libraries.");
  141. resources.Add (string.Format ("-res:{0},{1}", path, id));
  142. linkwith.Add (id);
  143. }
  144. },
  145. #endif
  146. };
  147. try {
  148. sources = os.Parse (args);
  149. } catch (Exception e){
  150. Console.Error.WriteLine ("{0}: {1}", tool_name, e.Message);
  151. Console.Error.WriteLine ("see {0} --help for more information", tool_name);
  152. return 1;
  153. }
  154. if (show_help || sources.Count == 0){
  155. Console.WriteLine ("Error: no api file provided");
  156. ShowHelp (os);
  157. return 0;
  158. }
  159. if (alpha)
  160. defines.Add ("ALPHA");
  161. if (tmpdir == null)
  162. tmpdir = GetWorkDir ();
  163. if (outfile == null)
  164. outfile = Path.GetFileNameWithoutExtension (sources [0]) + ".dll";
  165. string refs = (references.Count > 0 ? "-r:" + String.Join (" -r:", references.ToArray ()) : "");
  166. string paths = (libs.Count > 0 ? "-lib:" + String.Join (" -lib:", libs.ToArray ()) : "");
  167. try {
  168. var api_file = sources [0];
  169. var tmpass = Path.Combine (tmpdir, "temp.dll");
  170. // -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources
  171. var cargs = String.Format ("{10} -debug -unsafe -target:library {0} -nowarn:436 -out:{1} -r:{2} {3} {4} {5} -r:{6} {7} {8} {9}",
  172. string.Join (" ", sources.ToArray ()),
  173. tmpass, Environment.GetCommandLineArgs ()[0],
  174. string.Join (" ", core_sources.ToArray ()), refs, unsafef ? "-unsafe" : "",
  175. baselibdll, string.Join (" ", defines.Select (x=> "-define:" + x).ToArray ()), paths,
  176. nostdlib ? "-nostdlib" : null,
  177. !String.IsNullOrEmpty (net_sdk) ? "-sdk:" + net_sdk : null);
  178. var si = new ProcessStartInfo (compiler, cargs) {
  179. UseShellExecute = false,
  180. };
  181. if (clean_mono_path) {
  182. // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler
  183. si.EnvironmentVariables.Remove ("MONO_PATH");
  184. }
  185. if (verbose)
  186. Console.WriteLine ("{0} {1}", si.FileName, si.Arguments);
  187. var p = Process.Start (si);
  188. p.WaitForExit ();
  189. if (p.ExitCode != 0){
  190. Console.WriteLine ("{0}: API binding contains errors.", tool_name);
  191. return 1;
  192. }
  193. Assembly api;
  194. try {
  195. api = Assembly.LoadFrom (tmpass);
  196. } catch (Exception e) {
  197. if (verbose)
  198. Console.WriteLine (e);
  199. Console.Error.WriteLine ("Error loading API definition from {0}", tmpass);
  200. return 1;
  201. }
  202. Assembly baselib;
  203. try {
  204. baselib = Assembly.LoadFrom (baselibdll);
  205. } catch (Exception e){
  206. if (verbose)
  207. Console.WriteLine (e);
  208. Console.Error.WriteLine ("Error loading base library {0}", baselibdll);
  209. return 1;
  210. }
  211. #if !MONOMAC
  212. foreach (object attr in api.GetCustomAttributes (typeof (LinkWithAttribute), true)) {
  213. LinkWithAttribute linkWith = (LinkWithAttribute) attr;
  214. if (!linkwith.Contains (linkWith.LibraryName)) {
  215. Console.Error.WriteLine ("Missing native library {0}, please use `--link-with' to specify the path to this library.", linkWith.LibraryName);
  216. return 1;
  217. }
  218. }
  219. #endif
  220. var types = new List<Type> ();
  221. foreach (var t in api.GetTypes ()){
  222. if (t.GetCustomAttributes (typeof (BaseTypeAttribute), true).Length > 0 ||
  223. t.GetCustomAttributes (typeof (StaticAttribute), true).Length > 0)
  224. types.Add (t);
  225. }
  226. var g = new Generator (pmode, external, debug, types.ToArray ()){
  227. MessagingNS = ns == null ? Path.GetFileNameWithoutExtension (api_file) : ns,
  228. CoreMessagingNS = RootNS + ".ObjCRuntime",
  229. BindThirdPartyLibrary = binding_third_party,
  230. CoreNSObject = CoreObject,
  231. BaseDir = basedir != null ? basedir : tmpdir,
  232. ZeroCopyStrings = zero_copy,
  233. NativeExceptionMarshalling = native_exception_marshalling,
  234. #if MONOMAC
  235. OnlyX86 = true,
  236. #endif
  237. Alpha = alpha,
  238. InlineSelectors = inline_selectors,
  239. };
  240. foreach (var mi in baselib.GetType (RootNS + ".ObjCRuntime.Messaging").GetMethods ()){
  241. if (mi.Name.IndexOf ("_objc_msgSend") != -1)
  242. g.RegisterMethodName (mi.Name);
  243. }
  244. g.Go ();
  245. if (generate_file_list != null){
  246. using (var f = File.CreateText (generate_file_list)){
  247. g.GeneratedFiles.ForEach (x => f.WriteLine (x));
  248. }
  249. return 0;
  250. }
  251. cargs = String.Format ("{0} -target:library -out:{1} {2} {3} {4} {5} {6} {7} -r:{8} {9} {10}",
  252. unsafef ? "-unsafe" : "", /* 0 */
  253. outfile, /* 1 */
  254. string.Join (" ", defines.Select (x=> "-define:" + x).ToArray ()), /* 2 */
  255. String.Join (" ", g.GeneratedFiles.ToArray ()), /* 3 */
  256. String.Join (" ", core_sources.ToArray ()), /* 4 */
  257. String.Join (" ", sources.Skip (1).ToArray ()), /* 5 */
  258. String.Join (" ", extra_sources.ToArray ()), /* 6 */
  259. refs, /* 7 */
  260. baselibdll, /* 8 */
  261. String.Join (" ", resources.ToArray ()), /* 9 */
  262. nostdlib ? "-nostdlib" : null
  263. );
  264. si = new ProcessStartInfo (compiler, cargs) {
  265. UseShellExecute = false,
  266. };
  267. if (verbose)
  268. Console.WriteLine ("{0} {1}", si.FileName, si.Arguments);
  269. p = Process.Start (si);
  270. p.WaitForExit ();
  271. if (p.ExitCode != 0){
  272. Console.WriteLine ("{0}: API binding contains errors.", tool_name);
  273. return 1;
  274. }
  275. } finally {
  276. if (delete_temp)
  277. Directory.Delete (tmpdir, true);
  278. }
  279. return 0;
  280. }
  281. static string GetWorkDir ()
  282. {
  283. while (true){
  284. string p = Path.Combine (Path.GetTempPath(), Path.GetRandomFileName());
  285. if (Directory.Exists (p))
  286. continue;
  287. var di = Directory.CreateDirectory (p);
  288. return di.FullName;
  289. }
  290. }
  291. }