[mini] Always emit safepoints, except WASM
[mono-project.git] / mcs / ilasm / Driver.cs
blobdc4929d79d48e3aaf63ff102d40665671dd3477a
1 //
2 // Mono.ILASM.Driver
3 // Main Command line interface for Mono ILasm Compiler
4 //
5 // Author(s):
6 // Jackson Harper (Jackson@LatitudeGeo.com)
7 //
8 // (C) 2003 Jackson Harper, All rights reserved
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 using System;
13 using System.IO;
14 using System.Reflection;
15 using System.Collections;
16 using System.Security.Cryptography;
17 #if HAS_MONO_SECURITY
18 using Mono.Security;
19 #endif
21 namespace Mono.ILASM {
23 public class Driver {
25 enum Target {
26 Dll,
27 Exe
30 public static int Main (string[] args)
32 // Do everything in Invariant
33 System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
35 DriverMain driver = new DriverMain (args);
36 if (!driver.Run ())
37 return 1;
38 Report.Message ("Operation completed successfully");
39 return 0;
42 private class DriverMain {
44 private ArrayList il_file_list;
45 private string output_file;
46 private Target target = Target.Exe;
47 private string target_string = "exe";
48 private bool show_tokens = false;
49 // private bool show_method_def = false;
50 // private bool show_method_ref = false;
51 private bool show_parser = false;
52 private bool scan_only = false;
53 private bool debugging_info = false;
54 private CodeGen codegen;
55 private bool keycontainer = false;
56 private string keyname;
57 #if HAS_MONO_SECURITY
58 private StrongName sn;
59 #endif
60 bool noautoinherit;
62 public DriverMain (string[] args)
64 il_file_list = new ArrayList ();
65 ParseArgs (args);
68 public bool Run ()
70 if (il_file_list.Count == 0)
71 Usage ();
72 if (output_file == null)
73 output_file = CreateOutputFilename ();
74 try {
75 codegen = new CodeGen (output_file, target == Target.Dll, debugging_info, noautoinherit);
76 foreach (string file_path in il_file_list) {
77 Report.FilePath = file_path;
78 ProcessFile (file_path);
80 if (scan_only)
81 return true;
83 if (Report.ErrorCount > 0)
84 return false;
86 if (target != Target.Dll && !codegen.HasEntryPoint)
87 Report.Error ("No entry point found.");
89 // if we have a key and aren't assembling a netmodule
90 if ((keyname != null) && !codegen.IsThisAssembly (null)) {
91 #if HAS_MONO_SECURITY
92 LoadKey ();
93 // this overrides any attribute or .publickey directive in the source
94 codegen.ThisAssembly.SetPublicKey (sn.PublicKey);
95 #else
96 throw new NotSupportedException ();
97 #endif
100 try {
101 codegen.Write ();
102 } catch {
103 File.Delete (output_file);
104 throw;
106 } catch (ILAsmException e) {
107 Error (e.ToString ());
108 return false;
109 } catch (PEAPI.PEFileException pe) {
110 Error ("Error : " + pe.Message);
111 return false;
114 #if HAS_MONO_SECURITY
115 try {
116 if (sn != null) {
117 Report.Message ("Signing assembly with the specified strongname keypair");
118 return Sign (output_file);
120 } catch {
121 return false;
123 #endif
125 return true;
128 private void Error (string message)
130 Console.WriteLine (message + "\n");
131 Console.WriteLine ("***** FAILURE *****\n");
134 #if HAS_MONO_SECURITY
135 private void LoadKey ()
137 if (keycontainer) {
138 CspParameters csp = new CspParameters ();
139 csp.KeyContainerName = keyname;
140 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (csp);
141 sn = new StrongName (rsa);
142 } else {
143 byte[] data = null;
144 using (FileStream fs = File.OpenRead (keyname)) {
145 data = new byte [fs.Length];
146 fs.Read (data, 0, data.Length);
147 fs.Close ();
149 sn = new StrongName (data);
153 private bool Sign (string filename)
155 // note: if the file cannot be signed (no public key in it) then
156 // we do not show an error, or a warning, if the key file doesn't
157 // exists
158 return sn.Sign (filename);
160 #endif
162 private void ProcessFile (string file_path)
164 if (!File.Exists (file_path)) {
165 Console.WriteLine ("File does not exist: {0}",
166 file_path);
167 Environment.Exit (2);
169 Report.AssembleFile (file_path, null,
170 target_string, output_file);
171 StreamReader reader = File.OpenText (file_path);
172 ILTokenizer scanner = new ILTokenizer (reader);
174 if (show_tokens)
175 scanner.NewTokenEvent += new NewTokenEvent (ShowToken);
176 //if (show_method_def)
177 // MethodTable.MethodDefinedEvent += new MethodDefinedEvent (ShowMethodDef);
178 //if (show_method_ref)
179 // MethodTable.MethodReferencedEvent += new MethodReferencedEvent (ShowMethodRef);
181 if (scan_only) {
182 ILToken tok;
183 while ((tok = scanner.NextToken) != ILToken.EOF) {
184 Console.WriteLine (tok);
186 return;
189 ILParser parser = new ILParser (codegen, scanner);
190 codegen.BeginSourceFile (file_path);
191 try {
192 if (show_parser)
193 parser.yyparse (new ScannerAdapter (scanner),
194 new yydebug.yyDebugSimple ());
195 else
196 parser.yyparse (new ScannerAdapter (scanner), null);
197 } catch (ILTokenizingException ilte) {
198 Report.Error (ilte.Location, "syntax error at token '" + ilte.Token + "'");
199 } catch (Mono.ILASM.yyParser.yyException ye) {
200 Report.Error (scanner.Reader.Location, ye.Message);
201 } catch (ILAsmException ie) {
202 ie.FilePath = file_path;
203 ie.Location = scanner.Reader.Location;
204 throw;
205 } catch (Exception){
206 Console.Write ("{0} ({1}, {2}): ",file_path, scanner.Reader.Location.line, scanner.Reader.Location.column);
207 throw;
208 } finally {
209 codegen.EndSourceFile ();
213 public void ShowToken (object sender, NewTokenEventArgs args)
215 Console.WriteLine ("token: '{0}'", args.Token);
218 public void ShowMethodDef (object sender, MethodDefinedEventArgs args)
220 Console.WriteLine ("***** Method defined *****");
221 Console.WriteLine ("-- signature: {0}", args.Signature);
222 Console.WriteLine ("-- name: {0}", args.Name);
223 Console.WriteLine ("-- return type: {0}", args.ReturnType);
224 Console.WriteLine ("-- is in table: {0}", args.IsInTable);
225 Console.WriteLine ("-- method atts: {0}", args.MethodAttributes);
226 Console.WriteLine ("-- impl atts: {0}", args.ImplAttributes);
227 Console.WriteLine ("-- call conv: {0}", args.CallConv);
230 public void ShowMethodRef (object sender, MethodReferencedEventArgs args)
232 Console.WriteLine ("***** Method referenced *****");
233 Console.WriteLine ("-- signature: {0}", args.Signature);
234 Console.WriteLine ("-- name: {0}", args.Name);
235 Console.WriteLine ("-- return type: {0}", args.ReturnType);
236 Console.WriteLine ("-- is in table: {0}", args.IsInTable);
239 private void ParseArgs (string[] args)
241 string command_arg;
242 foreach (string str in args) {
243 if ((str[0] != '-') && (str[0] != '/')) {
244 il_file_list.Add (str);
245 continue;
247 switch (GetCommand (str, out command_arg)) {
248 case "out":
249 case "output":
250 output_file = command_arg;
251 break;
252 case "exe":
253 target = Target.Exe;
254 target_string = "exe";
255 break;
256 case "dll":
257 target = Target.Dll;
258 target_string = "dll";
259 break;
260 case "quiet":
261 Report.Quiet = true;
262 break;
263 case "debug":
264 case "deb":
265 debugging_info = true;
266 break;
267 // Stubs to stay commandline compatible with MS
268 case "listing":
269 case "nologo":
270 case "clock":
271 case "error":
272 case "subsystem":
273 case "flags":
274 case "alignment":
275 case "base":
276 case "resource":
277 break;
278 case "key":
279 if (command_arg.Length > 0)
280 keycontainer = (command_arg [0] == '@');
281 if (keycontainer)
282 keyname = command_arg.Substring (1);
283 else
284 keyname = command_arg;
285 break;
286 case "noautoinherit":
287 noautoinherit = true;
288 break;
289 case "scan_only":
290 scan_only = true;
291 break;
292 case "show_tokens":
293 show_tokens = true;
294 break;
295 case "show_method_def":
296 // show_method_def = true;
297 break;
298 case "show_method_ref":
299 // show_method_ref = true;
300 break;
301 case "show_parser":
302 show_parser = true;
303 break;
304 case "-about":
305 if (str[0] != '-')
306 break;
307 About ();
308 break;
309 case "-version":
310 if (str[0] != '-')
311 break;
312 Version ();
313 break;
314 default:
315 if (str [0] == '-')
316 break;
317 il_file_list.Add (str);
318 break;
323 private string GetCommand (string str, out string command_arg)
325 int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
326 string command = str.Substring (1,
327 end_index == -1 ? str.Length - 1 : end_index - 1);
329 if (end_index != -1) {
330 command_arg = str.Substring (end_index+1);
331 } else {
332 command_arg = null;
335 return command.ToLower ();
338 /// <summary>
339 /// Get the first file name and makes it into an output file name
340 /// </summary>
341 private string CreateOutputFilename ()
343 string file_name = (string)il_file_list[0];
344 int ext_index = file_name.LastIndexOf ('.');
346 if (ext_index == -1)
347 ext_index = file_name.Length;
349 return String.Format ("{0}.{1}", file_name.Substring (0, ext_index),
350 target_string);
353 private void Usage ()
355 Console.WriteLine ("Mono IL assembler compiler\n" +
356 "ilasm [options] source-files\n" +
357 " --about About the Mono IL assembler compiler\n" +
358 " --version Print the version number of the compiler\n" +
359 " /output:file_name Specifies output file.\n" +
360 " /exe Compile to executable.\n" +
361 " /dll Compile to library.\n" +
362 " /debug Include debug information.\n" +
363 " /key:keyfile Strongname using the specified key file\n" +
364 " /key:@container Strongname using the specified key container\n" +
365 " /noautoinherit Disable inheriting from System.Object by default\n" +
366 "Options can be of the form -option or /option\n");
367 Environment.Exit (1);
370 private void About ()
372 Console.WriteLine (
373 "For more information on Mono, visit the project Web site\n" +
374 " http://www.go-mono.com\n\n");
375 Environment.Exit (0);
378 private void Version ()
380 string version = System.Reflection.Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
381 Console.WriteLine ("Mono IL assembler compiler version {0}", version);
382 Environment.Exit (0);