2006-04-26 Atsushi Enomoto <atsushi@ximian.com>
[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                         Console.WriteLine ("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
56                         public DriverMain (string[] args)
57                         {
58                                 il_file_list = new ArrayList ();
59                                 ParseArgs (args);
60                         }
61
62                         public bool Run ()
63                         {
64                                 if (il_file_list.Count == 0)
65                                         Usage ();
66                                 if (output_file == null)
67                                         output_file = CreateOutputFilename ();
68                                 try {
69                                         codegen = new CodeGen (output_file, target == Target.Dll, debugging_info);
70                                         foreach (string file_path in il_file_list)
71                                                 ProcessFile (file_path);
72                                         if (scan_only)
73                                                 return true;
74
75                                         if (Report.ErrorCount > 0)
76                                                 return false;
77
78                                         if (target != Target.Dll && !codegen.HasEntryPoint)
79                                                 Report.Error ("No entry point found.");
80
81                                         try {
82                                                 codegen.Write ();
83                                         } catch {
84                                                 File.Delete (output_file);
85                                                 throw;
86                                         }
87                                 } catch (ILAsmException e) {
88                                         Error (e.Message);
89                                         return false;
90                                 } catch (PEAPI.PEFileException pe) {
91                                         Error (pe.Message);
92                                         return false;
93                                 } 
94
95                                 try {
96                                         if (keyname != null) {
97                                                 Console.WriteLine ("Signing assembly with the specified strongname keypair");
98                                                 return Sign (output_file);
99                                         }
100                                 } catch {
101                                         return false;
102                                 }
103
104                                 return true;
105                         }
106
107                         private void Error (string message)
108                         {
109                                 Console.WriteLine ("Error : " + message + "\n");
110                                 Console.WriteLine ("***** FAILURE *****\n");
111                         }
112
113                         private bool Sign (string filename)
114                         {
115                                 // note: if the file cannot be signed (no public key in it) then
116                                 // we do not show an error, or a warning, if the key file doesn't 
117                                 // exists
118                                 StrongName sn = null;
119                                 if (keycontainer) {
120                                         CspParameters csp = new CspParameters ();
121                                         csp.KeyContainerName = keyname;
122                                         RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (csp);
123                                         sn = new StrongName (rsa);
124                                 } else {
125                                         byte[] data = null;
126                                         using (FileStream fs = File.OpenRead (keyname)) {
127                                                 data = new byte [fs.Length];
128                                                 fs.Read (data, 0, data.Length);
129                                                 fs.Close ();
130                                         }
131                                         sn = new StrongName (data);
132                                 }
133                                 return sn.Sign (filename);
134                         }
135
136                         private void ProcessFile (string file_path)
137                         {
138                                 if (!File.Exists (file_path)) {
139                                         Console.WriteLine ("File does not exist: {0}",
140                                                 file_path);
141                                         Environment.Exit (2);
142                                 }
143                                 Report.AssembleFile (file_path, null,
144                                                 target_string, output_file);
145                                 StreamReader reader = File.OpenText (file_path);
146                                 ILTokenizer scanner = new ILTokenizer (reader);
147
148                                 if (show_tokens)
149                                         scanner.NewTokenEvent += new NewTokenEvent (ShowToken);
150                                 //if (show_method_def)
151                                 //        MethodTable.MethodDefinedEvent += new MethodDefinedEvent (ShowMethodDef);
152                                 //if (show_method_ref)
153                                 //       MethodTable.MethodReferencedEvent += new MethodReferencedEvent (ShowMethodRef);
154
155                                 if (scan_only) {
156                                         ILToken tok;
157                                         while ((tok = scanner.NextToken) != ILToken.EOF) {
158                                                 Console.WriteLine (tok);
159                                         }
160                                         return;
161                                 }
162
163                                 ILParser parser = new ILParser (codegen, scanner);
164                                 codegen.BeginSourceFile (file_path);
165                                 try {
166                                         if (show_parser)
167                                                 parser.yyparse (new ScannerAdapter (scanner),
168                                                                 new yydebug.yyDebugSimple ());
169                                         else
170                                                 parser.yyparse (new ScannerAdapter (scanner),  null);
171                                 } catch (ILTokenizingException ilte) {
172                                         Report.Error (file_path + "(" + ilte.Location.line + ") : error : " +
173                                                         "syntax error at token '" + ilte.Token + "'.");
174                                 } catch (Mono.ILASM.yyParser.yyException) {
175                                         Report.Error ("Error at: " + scanner.Reader.Location);
176                                 } catch {
177                                         Console.WriteLine ("Error at: " + scanner.Reader.Location);
178                                         throw;
179                                 } finally {
180                                         codegen.EndSourceFile ();
181                                 }
182                         }
183
184                         public void ShowToken (object sender, NewTokenEventArgs args)
185                         {
186                                 Console.WriteLine ("token: '{0}'", args.Token);
187                         }
188                         /*
189                         public void ShowMethodDef (object sender, MethodDefinedEventArgs args)
190                         {
191                                 Console.WriteLine ("***** Method defined *****");
192                                 Console.WriteLine ("-- signature:   {0}", args.Signature);
193                                 Console.WriteLine ("-- name:        {0}", args.Name);
194                                 Console.WriteLine ("-- return type: {0}", args.ReturnType);
195                                 Console.WriteLine ("-- is in table: {0}", args.IsInTable);
196                                 Console.WriteLine ("-- method atts: {0}", args.MethodAttributes);
197                                 Console.WriteLine ("-- impl atts:   {0}", args.ImplAttributes);
198                                 Console.WriteLine ("-- call conv:   {0}", args.CallConv);
199                         }
200
201                         public void ShowMethodRef (object sender, MethodReferencedEventArgs args)
202                         {
203                                 Console.WriteLine ("***** Method referenced *****");
204                                 Console.WriteLine ("-- signature:   {0}", args.Signature);
205                                 Console.WriteLine ("-- name:        {0}", args.Name);
206                                 Console.WriteLine ("-- return type: {0}", args.ReturnType);
207                                 Console.WriteLine ("-- is in table: {0}", args.IsInTable);
208                         }
209                         */
210                         private void ParseArgs (string[] args)
211                         {
212                                 string command_arg;
213                                 foreach (string str in args) {
214                                         if ((str[0] != '-') && (str[0] != '/')) {
215                                                 il_file_list.Add (str);
216                                                 continue;
217                                         }
218                                         switch (GetCommand (str, out command_arg)) {
219                                         case "out":
220                                         case "output":
221                                                 output_file = command_arg;
222                                                 break;
223                                         case "exe":
224                                                 target = Target.Exe;
225                                                 target_string = "exe";
226                                                 break;
227                                         case "dll":
228                                                 target = Target.Dll;
229                                                 target_string = "dll";
230                                                 break;
231                                         case "quiet":
232                                                 Report.Quiet = true;
233                                                 break;
234                                         case "debug":
235                                         case "deb":
236                                                 if (str[0] != '-')
237                                                         break;
238                                                 debugging_info = true;
239                                                 break;
240                                         // Stubs to stay commandline compatible with MS 
241                                         case "listing":
242                                         case "nologo":
243                                         case "clock":
244                                         case "error":
245                                         case "subsystem":
246                                         case "flags":
247                                         case "alignment":
248                                         case "base":
249                                         case "resource":
250                                                 break;
251                                         case "key":
252                                                 if (command_arg.Length > 0)
253                                                         keycontainer = (command_arg [0] == '@');
254                                                 if (keycontainer)
255                                                         keyname = command_arg.Substring (1);
256                                                 else
257                                                         keyname = command_arg;
258                                                 break;
259                                         case "scan_only":
260                                                 scan_only = true;
261                                                 break;
262                                         case "show_tokens":
263                                                 show_tokens = true;
264                                                 break;
265                                         case "show_method_def":
266                                                 show_method_def = true;
267                                                 break;
268                                         case "show_method_ref":
269                                                 show_method_ref = true;
270                                                 break;
271                                         case "show_parser":
272                                                 show_parser = true;
273                                                 break;
274                                         case "-about":
275                                                 if (str[0] != '-')
276                                                         break;
277                                                 About ();
278                                                 break;
279                                         case "-version":
280                                                 if (str[0] != '-')
281                                                         break;
282                                                 Version ();
283                                                 break;
284                                         default:
285                                                 if (str [0] == '-')
286                                                         break;
287                                                 il_file_list.Add (str);
288                                                 break;
289                                         }
290                                 }
291                         }
292
293                         private string GetCommand (string str, out string command_arg)
294                         {
295                                 int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
296                                 string command = str.Substring (1,
297                                         end_index == -1 ? str.Length - 1 : end_index - 1);
298
299                                 if (end_index != -1) {
300                                         command_arg = str.Substring (end_index+1);
301                                 } else {
302                                         command_arg = null;
303                                 }
304
305                                 return command.ToLower ();
306                         }
307
308                         /// <summary>
309                         ///   Get the first file name and makes it into an output file name
310                         /// </summary>
311                         private string CreateOutputFilename ()
312                         {
313                                 string file_name = (string)il_file_list[0];
314                                 int ext_index = file_name.LastIndexOf ('.');
315
316                                 if (ext_index == -1)
317                                         ext_index = file_name.Length;
318
319                                 return String.Format ("{0}.{1}", file_name.Substring (0, ext_index),
320                                         target_string);
321                         }
322
323                         private void Usage ()
324                         {
325                                 Console.WriteLine ("Mono ILasm compiler\n" +
326                                         "ilasm [options] source-files\n" +
327                                         "   --about            About the Mono ILasm compiler\n" +
328                                         "   --version          Print the version number of the Mono ILasm compiler\n" +
329                                         "   /output:file_name  Specifies output file.\n" +
330                                         "   /exe               Compile to executable.\n" +
331                                         "   /dll               Compile to library.\n" +
332                                         "   /debug             Include debug information.\n" +
333                                         "   /key:keyfile       Strongname using the specified key file\n" +
334                                         "   /key:@container    Strongname using the specified key container\n" +
335                                         "Options can be of the form -option or /option\n");
336                                 Environment.Exit (1);
337                         }
338
339                         private void About ()
340                         {
341                                 Console.WriteLine (
342                                         "For more information on Mono, visit the project Web site\n" +
343                                         "   http://www.go-mono.com\n\n");
344                                 Environment.Exit (0);
345                         }
346
347                         private void Version ()
348                         {
349                                 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
350                                 Console.WriteLine ("Mono ILasm compiler version {0}", version);
351                                 Environment.Exit (0);
352                         }
353
354                 }
355         }
356 }
357