af7120dce5878fc481227faf290c186e52eb5662
[mono.git] / mcs / ilasm / Driver.cs
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)
10 //
11
12 using System;
13 using System.IO;
14 using System.Reflection;
15 using System.Collections;
16 using System.Security.Cryptography;
17 using Mono.Security;
18
19 namespace Mono.ILASM {
20
21         public class Driver {
22
23                 enum Target {
24                         Dll,
25                         Exe
26                 }
27
28                 public static int Main (string[] args)
29                 {
30                         // Do everything in Invariant
31                         System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
32
33                         DriverMain driver = new DriverMain (args);
34                         if (!driver.Run ())
35                                 return 1;
36                         Report.Message ("Operation completed successfully");
37                         return 0;
38                 }
39
40                 private class DriverMain {
41
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;
56
57                         public DriverMain (string[] args)
58                         {
59                                 il_file_list = new ArrayList ();
60                                 ParseArgs (args);
61                         }
62
63                         public bool Run ()
64                         {
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);
74                                         }
75                                         if (scan_only)
76                                                 return true;
77
78                                         if (Report.ErrorCount > 0)
79                                                 return false;
80
81                                         if (target != Target.Dll && !codegen.HasEntryPoint)
82                                                 Report.Error ("No entry point found.");
83
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);
89                                         }
90
91                                         try {
92                                                 codegen.Write ();
93                                         } catch {
94                                                 File.Delete (output_file);
95                                                 throw;
96                                         }
97                                 } catch (ILAsmException e) {
98                                         Error (e.ToString ());
99                                         return false;
100                                 } catch (PEAPI.PEFileException pe) {
101                                         Error ("Error : " + pe.Message);
102                                         return false;
103                                 } 
104
105                                 try {
106                                         if (sn != null) {
107                                                 Report.Message ("Signing assembly with the specified strongname keypair");
108                                                 return Sign (output_file);
109                                         }
110                                 } catch {
111                                         return false;
112                                 }
113
114                                 return true;
115                         }
116
117                         private void Error (string message)
118                         {
119                                 Console.WriteLine (message + "\n");
120                                 Console.WriteLine ("***** FAILURE *****\n");
121                         }
122
123                         private void LoadKey ()
124                         {
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 ();
136                                         }
137                                         sn = new StrongName (data);
138                                 }
139                         }
140
141                         private bool Sign (string filename)
142                         {
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);
147                         }
148
149                         private void ProcessFile (string file_path)
150                         {
151                                 if (!File.Exists (file_path)) {
152                                         Console.WriteLine ("File does not exist: {0}",
153                                                 file_path);
154                                         Environment.Exit (2);
155                                 }
156                                 Report.AssembleFile (file_path, null,
157                                                 target_string, output_file);
158                                 StreamReader reader = File.OpenText (file_path);
159                                 ILTokenizer scanner = new ILTokenizer (reader);
160
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);
167
168                                 if (scan_only) {
169                                         ILToken tok;
170                                         while ((tok = scanner.NextToken) != ILToken.EOF) {
171                                                 Console.WriteLine (tok);
172                                         }
173                                         return;
174                                 }
175
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){
193                                         Console.Write ("{0} ({1}, {2}): ",file_path, scanner.Reader.Location.line, scanner.Reader.Location.column);
194                                         throw;
195                                 } finally {
196                                         codegen.EndSourceFile ();
197                                 }
198                         }
199
200                         public void ShowToken (object sender, NewTokenEventArgs args)
201                         {
202                                 Console.WriteLine ("token: '{0}'", args.Token);
203                         }
204                         /*
205                         public void ShowMethodDef (object sender, MethodDefinedEventArgs args)
206                         {
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);
215                         }
216
217                         public void ShowMethodRef (object sender, MethodReferencedEventArgs args)
218                         {
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);
224                         }
225                         */
226                         private void ParseArgs (string[] args)
227                         {
228                                 string command_arg;
229                                 foreach (string str in args) {
230                                         if ((str[0] != '-') && (str[0] != '/')) {
231                                                 il_file_list.Add (str);
232                                                 continue;
233                                         }
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;
303                                         }
304                                 }
305                         }
306
307                         private string GetCommand (string str, out string command_arg)
308                         {
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);
312
313                                 if (end_index != -1) {
314                                         command_arg = str.Substring (end_index+1);
315                                 } else {
316                                         command_arg = null;
317                                 }
318
319                                 return command.ToLower ();
320                         }
321
322                         /// <summary>
323                         ///   Get the first file name and makes it into an output file name
324                         /// </summary>
325                         private string CreateOutputFilename ()
326                         {
327                                 string file_name = (string)il_file_list[0];
328                                 int ext_index = file_name.LastIndexOf ('.');
329
330                                 if (ext_index == -1)
331                                         ext_index = file_name.Length;
332
333                                 return String.Format ("{0}.{1}", file_name.Substring (0, ext_index),
334                                         target_string);
335                         }
336
337                         private void Usage ()
338                         {
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);
351                         }
352
353                         private void About ()
354                         {
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);
359                         }
360
361                         private void Version ()
362                         {
363                                 string version = System.Reflection.Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
364                                 Console.WriteLine ("Mono ILasm compiler version {0}", version);
365                                 Environment.Exit (0);
366                         }
367
368                 }
369         }
370 }
371