2006-11-14 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / ilasm / Driver.cs
index 5896d9987faff11f681eb961fb54882901493b03..eb5ee04410a28defe6249da57ae4c7317dc83b28 100644 (file)
@@ -6,12 +6,15 @@
 //  Jackson Harper (Jackson@LatitudeGeo.com)
 //
 // (C) 2003 Jackson Harper, All rights reserved
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
 //
 
 using System;
 using System.IO;
 using System.Reflection;
 using System.Collections;
+using System.Security.Cryptography;
+using Mono.Security;
 
 namespace Mono.ILASM {
 
@@ -24,15 +27,13 @@ namespace Mono.ILASM {
 
                 public static int Main (string[] args)
                 {
+                        // Do everything in Invariant
+                       System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
+
                         DriverMain driver = new DriverMain (args);
-                        try {
-                                driver.Run ();
-                        } catch (Exception e) {
-                                Console.WriteLine (e);
-                                Console.WriteLine ("Error while compiling.");
+                        if (!driver.Run ())
                                 return 1;
-                        }
-                        Console.Write ("Compilation succeeded");
+                        Console.WriteLine ("Operation completed successfully");
                         return 0;
                 }
 
@@ -41,12 +42,17 @@ namespace Mono.ILASM {
                         private ArrayList il_file_list;
                         private string output_file;
                         private Target target = Target.Exe;
+                        private string target_string = "exe";
                         private bool show_tokens = false;
                         private bool show_method_def = false;
                         private bool show_method_ref = false;
                         private bool show_parser = false;
                         private bool scan_only = false;
+                       private bool debugging_info = false;
                         private CodeGen codegen;
+                       private bool keycontainer = false;
+                       private string keyname;
+                       private StrongName sn;
 
                         public DriverMain (string[] args)
                         {
@@ -54,23 +60,92 @@ namespace Mono.ILASM {
                                 ParseArgs (args);
                         }
 
-                        public void Run ()
+                        public bool Run ()
                         {
-                                if (il_file_list.Count == 0) {
+                                if (il_file_list.Count == 0)
                                         Usage ();
-                                        return;
-                                }
                                 if (output_file == null)
-                                        output_file = CreateOutputFile ();
-                                codegen = new CodeGen (output_file, target == Target.Dll, true);
-                                foreach (string file_path in il_file_list)
-                                        ProcessFile (file_path);
-                                if (scan_only)
-                                        return;
+                                        output_file = CreateOutputFilename ();
+                                try {
+                                        codegen = new CodeGen (output_file, target == Target.Dll, debugging_info);
+                                        foreach (string file_path in il_file_list) {
+                                                Report.FilePath = file_path;
+                                                ProcessFile (file_path);
+                                        }
+                                        if (scan_only)
+                                                return true;
+
+                                        if (Report.ErrorCount > 0)
+                                                return false;
+
+                                        if (target != Target.Dll && !codegen.HasEntryPoint)
+                                                Report.Error ("No entry point found.");
+
+                                       // if we have a key and aren't assembling a netmodule
+                                       if ((keyname != null) && !codegen.IsThisAssembly (null)) {
+                                               LoadKey ();
+                                               // this overrides any attribute or .publickey directive in the source
+                                               codegen.ThisAssembly.SetPublicKey (sn.PublicKey);
+                                       }
+
+                                        try {
+                                                codegen.Write ();
+                                        } catch {
+                                                File.Delete (output_file);
+                                                throw;
+                                        }
+                                } catch (ILAsmException e) {
+                                        Error (e.ToString ());
+                                        return false;
+                                } catch (PEAPI.PEFileException pe) {
+                                        Error ("Error : " + pe.Message);
+                                        return false;
+                                } 
+
+                                try {
+                                       if (sn != null) {
+                                               Console.WriteLine ("Signing assembly with the specified strongname keypair");
+                                               return Sign (output_file);
+                                       }
+                                } catch {
+                                        return false;
+                                }
 
-                                codegen.Write ();
+                                return true;
                         }
 
+                        private void Error (string message)
+                        {
+                                Console.WriteLine (message + "\n");
+                                Console.WriteLine ("***** FAILURE *****\n");
+                        }
+
+                       private void LoadKey ()
+                       {
+                               if (keycontainer) {
+                                       CspParameters csp = new CspParameters ();
+                                       csp.KeyContainerName = keyname;
+                                       RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (csp);
+                                       sn = new StrongName (rsa);
+                               } else {
+                                       byte[] data = null;
+                                       using (FileStream fs = File.OpenRead (keyname)) {
+                                               data = new byte [fs.Length];
+                                               fs.Read (data, 0, data.Length);
+                                               fs.Close ();
+                                       }
+                                       sn = new StrongName (data);
+                               }
+                       }
+
+                       private bool Sign (string filename)
+                       {
+                               // note: if the file cannot be signed (no public key in it) then
+                               // we do not show an error, or a warning, if the key file doesn't 
+                               // exists
+                               return sn.Sign (filename);
+                       }
+
                         private void ProcessFile (string file_path)
                         {
                                 if (!File.Exists (file_path)) {
@@ -78,6 +153,8 @@ namespace Mono.ILASM {
                                                 file_path);
                                         Environment.Exit (2);
                                 }
+                                Report.AssembleFile (file_path, null,
+                                                target_string, output_file);
                                 StreamReader reader = File.OpenText (file_path);
                                 ILTokenizer scanner = new ILTokenizer (reader);
 
@@ -96,11 +173,28 @@ namespace Mono.ILASM {
                                         return;
                                 }
 
-                                ILParser parser = new ILParser (codegen);
-                                if (show_parser)
-                                        parser.yyparse (new ScannerAdapter (scanner),  new yydebug.yyDebugSimple ());
-                                else
-                                        parser.yyparse (new ScannerAdapter (scanner),  null);
+                                ILParser parser = new ILParser (codegen, scanner);
+                               codegen.BeginSourceFile (file_path);
+                                try {
+                                        if (show_parser)
+                                                parser.yyparse (new ScannerAdapter (scanner),
+                                                                new yydebug.yyDebugSimple ());
+                                        else
+                                                parser.yyparse (new ScannerAdapter (scanner),  null);
+                                } catch (ILTokenizingException ilte) {
+                                        Report.Error (ilte.Location, "syntax error at token '" + ilte.Token + "'");
+                                } catch (Mono.ILASM.yyParser.yyException ye) {
+                                        Report.Error (scanner.Reader.Location, ye.Message);
+                                } catch (ILAsmException ie) {
+                                        ie.FilePath = file_path;
+                                        ie.Location = scanner.Reader.Location;
+                                        throw;
+                                } catch (Exception e){
+                                        Console.Write ("{0} ({1}, {2}): ",file_path, scanner.Reader.Location.line, scanner.Reader.Location.column);
+                                        throw;
+                                } finally {
+                                       codegen.EndSourceFile ();
+                               }
                         }
 
                         public void ShowToken (object sender, NewTokenEventArgs args)
@@ -138,40 +232,76 @@ namespace Mono.ILASM {
                                                 continue;
                                         }
                                         switch (GetCommand (str, out command_arg)) {
-                                                case "out":
-                                                        output_file = command_arg;
-                                                        break;
-                                                case "exe":
-                                                        target = Target.Exe;
-                                                        break;
-                                                case "dll":
-                                                        target = Target.Dll;
+                                        case "out":
+                                        case "output":
+                                                output_file = command_arg;
+                                                break;
+                                        case "exe":
+                                                target = Target.Exe;
+                                                target_string = "exe";
+                                                break;
+                                        case "dll":
+                                                target = Target.Dll;
+                                                target_string = "dll";
+                                                break;
+                                        case "quiet":
+                                                Report.Quiet = true;
+                                                break;
+                                        case "debug":
+                                        case "deb":
+                                               if (str[0] != '-')
+                                                       break;
+                                               debugging_info = true;
+                                               break;
+                                        // Stubs to stay commandline compatible with MS 
+                                        case "listing":
+                                        case "nologo":
+                                        case "clock":
+                                        case "error":
+                                        case "subsystem":
+                                        case "flags":
+                                        case "alignment":
+                                        case "base":
+                                        case "resource":
+                                                break;
+                                        case "key":
+                                               if (command_arg.Length > 0)
+                                                       keycontainer = (command_arg [0] == '@');
+                                               if (keycontainer)
+                                                       keyname = command_arg.Substring (1);
+                                               else
+                                                       keyname = command_arg;
+                                               break;
+                                        case "scan_only":
+                                                scan_only = true;
+                                                break;
+                                        case "show_tokens":
+                                                show_tokens = true;
+                                                break;
+                                        case "show_method_def":
+                                                show_method_def = true;
+                                                break;
+                                        case "show_method_ref":
+                                                show_method_ref = true;
+                                                break;
+                                        case "show_parser":
+                                                show_parser = true;
+                                                break;
+                                        case "-about":
+                                                if (str[0] != '-')
                                                         break;
-                                                case "scan_only":
-                                                        scan_only = true;
+                                                About ();
+                                                break;
+                                        case "-version":
+                                                if (str[0] != '-')
                                                         break;
-                                                case "show_tokens":
-                                                        show_tokens = true;
-                                                        break;
-                                                case "show_method_def":
-                                                        show_method_def = true;
-                                                        break;
-                                                case "show_method_ref":
-                                                        show_method_ref = true;
-                                                        break;
-                                                case "show_parser":
-                                                        show_parser = true;
-                                                        break;
-                                                case "-about":
-                                                        if (str[0] != '-')
-                                                                break;
-                                                        About ();
-                                                        break;
-                                                case "-version":
-                                                        if (str[0] != '-')
-                                                                break;
-                                                        Version ();
+                                                Version ();
+                                                break;
+                                        default:
+                                                if (str [0] == '-')
                                                         break;
+                                                il_file_list.Add (str);
+                                                break;
                                         }
                                 }
                         }
@@ -194,7 +324,7 @@ namespace Mono.ILASM {
                         /// <summary>
                         ///   Get the first file name and makes it into an output file name
                         /// </summary>
-                        private string CreateOutputFile ()
+                        private string CreateOutputFilename ()
                         {
                                 string file_name = (string)il_file_list[0];
                                 int ext_index = file_name.LastIndexOf ('.');
@@ -203,7 +333,7 @@ namespace Mono.ILASM {
                                         ext_index = file_name.Length;
 
                                 return String.Format ("{0}.{1}", file_name.Substring (0, ext_index),
-                                        target.ToString ().ToLower ());
+                                        target_string);
                         }
 
                         private void Usage ()
@@ -212,10 +342,14 @@ namespace Mono.ILASM {
                                         "ilasm [options] source-files\n" +
                                         "   --about            About the Mono ILasm compiler\n" +
                                         "   --version          Print the version number of the Mono ILasm compiler\n" +
-                                        "   /out:file_name     Specifies output file.\n" +
+                                        "   /output:file_name  Specifies output file.\n" +
                                         "   /exe               Compile to executable.\n" +
                                         "   /dll               Compile to library.\n" +
+                                        "   /debug             Include debug information.\n" +
+                                       "   /key:keyfile       Strongname using the specified key file\n" +
+                                       "   /key:@container    Strongname using the specified key container\n" +
                                         "Options can be of the form -option or /option\n");
+                                Environment.Exit (1);
                         }
 
                         private void About ()
@@ -228,7 +362,7 @@ namespace Mono.ILASM {
 
                         private void Version ()
                         {
-                                string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
+                                string version = System.Reflection.Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
                                 Console.WriteLine ("Mono ILasm compiler version {0}", version);
                                 Environment.Exit (0);
                         }