2009-02-13 Jonathan Chambers <joncham@gmail.com>
[mcs.git] / ilasm / Driver.cs
blob6f38e9d67be4078eeb2eb85ef17dd4c69cd8ccdb
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 using Mono.Security;
19 namespace Mono.ILASM {
21 public class Driver {
23 enum Target {
24 Dll,
25 Exe
28 public static int Main (string[] args)
30 // Do everything in Invariant
31 System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
33 DriverMain driver = new DriverMain (args);
34 if (!driver.Run ())
35 return 1;
36 Report.Message ("Operation completed successfully");
37 return 0;
40 private class DriverMain {
42 private ArrayList il_file_list;
43 private string output_file;
44 private Target target = Target.Exe;
45 private string target_string = "exe";
46 private bool show_tokens = false;
47 private bool show_method_def = false;
48 private bool show_method_ref = false;
49 private bool show_parser = false;
50 private bool scan_only = false;
51 private bool debugging_info = false;
52 private CodeGen codegen;
53 private bool keycontainer = false;
54 private string keyname;
55 private StrongName sn;
57 public DriverMain (string[] args)
59 il_file_list = new ArrayList ();
60 ParseArgs (args);
63 public bool Run ()
65 if (il_file_list.Count == 0)
66 Usage ();
67 if (output_file == null)
68 output_file = CreateOutputFilename ();
69 try {
70 codegen = new CodeGen (output_file, target == Target.Dll, debugging_info);
71 foreach (string file_path in il_file_list) {
72 Report.FilePath = file_path;
73 ProcessFile (file_path);
75 if (scan_only)
76 return true;
78 if (Report.ErrorCount > 0)
79 return false;
81 if (target != Target.Dll && !codegen.HasEntryPoint)
82 Report.Error ("No entry point found.");
84 // if we have a key and aren't assembling a netmodule
85 if ((keyname != null) && !codegen.IsThisAssembly (null)) {
86 LoadKey ();
87 // this overrides any attribute or .publickey directive in the source
88 codegen.ThisAssembly.SetPublicKey (sn.PublicKey);
91 try {
92 codegen.Write ();
93 } catch {
94 File.Delete (output_file);
95 throw;
97 } catch (ILAsmException e) {
98 Error (e.ToString ());
99 return false;
100 } catch (PEAPI.PEFileException pe) {
101 Error ("Error : " + pe.Message);
102 return false;
105 try {
106 if (sn != null) {
107 Report.Message ("Signing assembly with the specified strongname keypair");
108 return Sign (output_file);
110 } catch {
111 return false;
114 return true;
117 private void Error (string message)
119 Console.WriteLine (message + "\n");
120 Console.WriteLine ("***** FAILURE *****\n");
123 private void LoadKey ()
125 if (keycontainer) {
126 CspParameters csp = new CspParameters ();
127 csp.KeyContainerName = keyname;
128 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (csp);
129 sn = new StrongName (rsa);
130 } else {
131 byte[] data = null;
132 using (FileStream fs = File.OpenRead (keyname)) {
133 data = new byte [fs.Length];
134 fs.Read (data, 0, data.Length);
135 fs.Close ();
137 sn = new StrongName (data);
141 private bool Sign (string filename)
143 // note: if the file cannot be signed (no public key in it) then
144 // we do not show an error, or a warning, if the key file doesn't
145 // exists
146 return sn.Sign (filename);
149 private void ProcessFile (string file_path)
151 if (!File.Exists (file_path)) {
152 Console.WriteLine ("File does not exist: {0}",
153 file_path);
154 Environment.Exit (2);
156 Report.AssembleFile (file_path, null,
157 target_string, output_file);
158 StreamReader reader = File.OpenText (file_path);
159 ILTokenizer scanner = new ILTokenizer (reader);
161 if (show_tokens)
162 scanner.NewTokenEvent += new NewTokenEvent (ShowToken);
163 //if (show_method_def)
164 // MethodTable.MethodDefinedEvent += new MethodDefinedEvent (ShowMethodDef);
165 //if (show_method_ref)
166 // MethodTable.MethodReferencedEvent += new MethodReferencedEvent (ShowMethodRef);
168 if (scan_only) {
169 ILToken tok;
170 while ((tok = scanner.NextToken) != ILToken.EOF) {
171 Console.WriteLine (tok);
173 return;
176 ILParser parser = new ILParser (codegen, scanner);
177 codegen.BeginSourceFile (file_path);
178 try {
179 if (show_parser)
180 parser.yyparse (new ScannerAdapter (scanner),
181 new yydebug.yyDebugSimple ());
182 else
183 parser.yyparse (new ScannerAdapter (scanner), null);
184 } catch (ILTokenizingException ilte) {
185 Report.Error (ilte.Location, "syntax error at token '" + ilte.Token + "'");
186 } catch (Mono.ILASM.yyParser.yyException ye) {
187 Report.Error (scanner.Reader.Location, ye.Message);
188 } catch (ILAsmException ie) {
189 ie.FilePath = file_path;
190 ie.Location = scanner.Reader.Location;
191 throw;
192 } catch (Exception e){
193 Console.Write ("{0} ({1}, {2}): ",file_path, scanner.Reader.Location.line, scanner.Reader.Location.column);
194 throw;
195 } finally {
196 codegen.EndSourceFile ();
200 public void ShowToken (object sender, NewTokenEventArgs args)
202 Console.WriteLine ("token: '{0}'", args.Token);
205 public void ShowMethodDef (object sender, MethodDefinedEventArgs args)
207 Console.WriteLine ("***** Method defined *****");
208 Console.WriteLine ("-- signature: {0}", args.Signature);
209 Console.WriteLine ("-- name: {0}", args.Name);
210 Console.WriteLine ("-- return type: {0}", args.ReturnType);
211 Console.WriteLine ("-- is in table: {0}", args.IsInTable);
212 Console.WriteLine ("-- method atts: {0}", args.MethodAttributes);
213 Console.WriteLine ("-- impl atts: {0}", args.ImplAttributes);
214 Console.WriteLine ("-- call conv: {0}", args.CallConv);
217 public void ShowMethodRef (object sender, MethodReferencedEventArgs args)
219 Console.WriteLine ("***** Method referenced *****");
220 Console.WriteLine ("-- signature: {0}", args.Signature);
221 Console.WriteLine ("-- name: {0}", args.Name);
222 Console.WriteLine ("-- return type: {0}", args.ReturnType);
223 Console.WriteLine ("-- is in table: {0}", args.IsInTable);
226 private void ParseArgs (string[] args)
228 string command_arg;
229 foreach (string str in args) {
230 if ((str[0] != '-') && (str[0] != '/')) {
231 il_file_list.Add (str);
232 continue;
234 switch (GetCommand (str, out command_arg)) {
235 case "out":
236 case "output":
237 output_file = command_arg;
238 break;
239 case "exe":
240 target = Target.Exe;
241 target_string = "exe";
242 break;
243 case "dll":
244 target = Target.Dll;
245 target_string = "dll";
246 break;
247 case "quiet":
248 Report.Quiet = true;
249 break;
250 case "debug":
251 case "deb":
252 debugging_info = true;
253 break;
254 // Stubs to stay commandline compatible with MS
255 case "listing":
256 case "nologo":
257 case "clock":
258 case "error":
259 case "subsystem":
260 case "flags":
261 case "alignment":
262 case "base":
263 case "resource":
264 break;
265 case "key":
266 if (command_arg.Length > 0)
267 keycontainer = (command_arg [0] == '@');
268 if (keycontainer)
269 keyname = command_arg.Substring (1);
270 else
271 keyname = command_arg;
272 break;
273 case "scan_only":
274 scan_only = true;
275 break;
276 case "show_tokens":
277 show_tokens = true;
278 break;
279 case "show_method_def":
280 show_method_def = true;
281 break;
282 case "show_method_ref":
283 show_method_ref = true;
284 break;
285 case "show_parser":
286 show_parser = true;
287 break;
288 case "-about":
289 if (str[0] != '-')
290 break;
291 About ();
292 break;
293 case "-version":
294 if (str[0] != '-')
295 break;
296 Version ();
297 break;
298 default:
299 if (str [0] == '-')
300 break;
301 il_file_list.Add (str);
302 break;
307 private string GetCommand (string str, out string command_arg)
309 int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
310 string command = str.Substring (1,
311 end_index == -1 ? str.Length - 1 : end_index - 1);
313 if (end_index != -1) {
314 command_arg = str.Substring (end_index+1);
315 } else {
316 command_arg = null;
319 return command.ToLower ();
322 /// <summary>
323 /// Get the first file name and makes it into an output file name
324 /// </summary>
325 private string CreateOutputFilename ()
327 string file_name = (string)il_file_list[0];
328 int ext_index = file_name.LastIndexOf ('.');
330 if (ext_index == -1)
331 ext_index = file_name.Length;
333 return String.Format ("{0}.{1}", file_name.Substring (0, ext_index),
334 target_string);
337 private void Usage ()
339 Console.WriteLine ("Mono ILasm compiler\n" +
340 "ilasm [options] source-files\n" +
341 " --about About the Mono ILasm compiler\n" +
342 " --version Print the version number of the Mono ILasm compiler\n" +
343 " /output:file_name Specifies output file.\n" +
344 " /exe Compile to executable.\n" +
345 " /dll Compile to library.\n" +
346 " /debug Include debug information.\n" +
347 " /key:keyfile Strongname using the specified key file\n" +
348 " /key:@container Strongname using the specified key container\n" +
349 "Options can be of the form -option or /option\n");
350 Environment.Exit (1);
353 private void About ()
355 Console.WriteLine (
356 "For more information on Mono, visit the project Web site\n" +
357 " http://www.go-mono.com\n\n");
358 Environment.Exit (0);
361 private void Version ()
363 string version = System.Reflection.Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
364 Console.WriteLine ("Mono ILasm compiler version {0}", version);
365 Environment.Exit (0);