Update
[mono.git] / mcs / mcs / driver.cs
old mode 100755 (executable)
new mode 100644 (file)
index 8e10379..68a3935
@@ -6,6 +6,7 @@
 // Licensed under the terms of the GNU GPL
 //
 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc
 //
 
 namespace Mono.CSharp
@@ -17,7 +18,7 @@ namespace Mono.CSharp
        using System.IO;
        using System.Text;
        using System.Globalization;
-       using Mono.Languages;
+       using System.Diagnostics;
 
        public enum Target {
                Library, Exe, Module, WinExe
@@ -49,9 +50,6 @@ namespace Mono.CSharp
                // Lookup paths
                static ArrayList link_paths;
 
-               // Whether we want Yacc to output its progress
-               static bool yacc_verbose = false;
-
                // Whether we want to only run the tokenizer
                static bool tokenize = false;
                
@@ -63,7 +61,6 @@ namespace Mono.CSharp
                static bool timestamps = false;
                static bool pause = false;
                static bool show_counters = false;
-               public static bool parser_verbose = false;
                
                //
                // Whether to load the initial config file (what CSC.RSP has by default)
@@ -105,12 +102,6 @@ namespace Mono.CSharp
                //
                static bool using_default_encoder = true;
 
-               //
-               // The system version we are using, if not specified on the commandline we
-               // will use the same version as corlib for looking for libraries in the GAC.
-               //
-               static string sys_version;
-               
                public static void ShowTime (string msg)
                {
                        if (!timestamps)
@@ -182,7 +173,6 @@ namespace Mono.CSharp
                        SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
                                
                        parser = new CSharpParser (reader, file, defines);
-                       parser.yacc_verbose = yacc_verbose;
                        try {
                                parser.parse ();
                        } catch (Exception ex) {
@@ -191,6 +181,19 @@ namespace Mono.CSharp
                                input.Close ();
                        }
                }
+
+               static void OtherFlags ()
+               {
+                       Console.WriteLine (
+                               "Other flags in the compiler\n" +
+                               "   --fatal            Makes errors fatal\n" +
+                               "   --parse            Only parses the source file\n" +
+                               "   --stacktrace       Shows stack trace at error location\n" +
+                               "   --timestamp        Displays time stamps of various compiler events\n" +
+                               "   -2                 Enables experimental C# features\n" +
+                               "   -v                 Verbose parsing (for debugging the parser)\n" + 
+                               "   --mcs-debug X      Sets MCS debugging level to X\n");
+               }
                
                static void Usage ()
                {
@@ -198,6 +201,7 @@ namespace Mono.CSharp
                                "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
                                "mcs [options] source-files\n" +
                                "   --about            About the Mono C# compiler\n" +
+                               "   -addmodule:MODULE  Adds the module to the generated assembly\n" + 
                                "   -checked[+|-]      Set default context to checked\n" +
                                "   -codepage:ID       Sets code page to the one in ID\n" +
                                "                      (number, `utf8' or `reset')\n" +
@@ -207,36 +211,32 @@ namespace Mono.CSharp
                                "   -delaysign[+|-]    Only insert the public key into the assembly (no signing)\n" +
                                "   -doc:FILE          XML Documentation file to generate\n" + 
                                "   -g                 Generate debugging information\n" +
-                               "   --fatal            Makes errors fatal\n" +
                                "   -keycontainer:NAME The key pair container used to strongname the assembly\n" +
                                "   -keyfile:FILE      The strongname key file used to strongname the assembly\n" +
+                               "   -langversion:TEXT  Specifies language version modes: ISO-1 or Default" + Environment.NewLine +
                                "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
                                "   -main:class        Specified the class that contains the entry point\n" +
                                "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
                                "   -nostdlib[+|-]     Does not load core libraries\n" +
                                "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
                                "   -out:FNAME         Specifies output file\n" +
-                               "   --parse            Only parses the source file\n" +
+                               "   -pkg:P1[,Pn]       References packages P1..Pn\n" + 
                                "   --expect-error X   Expect that error X will be encountered\n" +
                                "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
                                "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
-                               "   --stacktrace       Shows stack trace at error location\n" +
                                "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
                                "                      library, module), (short: /t:)\n" +
-                               "   --timestamp        Displays time stamps of various compiler events\n" +
                                "   -unsafe[+|-]       Allows unsafe code\n" +
                                "   -warnaserror[+|-]  Treat warnings as errors\n" +
                                "   -warn:LEVEL        Sets warning level (the highest is 4, the default is 2)\n" +
-                               "   -v                 Verbose parsing (for debugging the parser)\n" +
-                               "   -2                 Enables experimental C# features\n" +
+                               "   -help2             Show other help flags\n" + 
                                "\n" +
                                "Resources:\n" +
                                "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
                                "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
                                "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
                                "   -win32icon:FILE         Use this icon for the output\n" +
-                               "   --mcs-debug X      Sets MCS debugging level to X\n" +
-                                "   @file              Read response file for more options\n\n" +
+                                "   @file                   Read response file for more options\n\n" +
                                "Options can be of the form -option or /option");
                }
 
@@ -254,7 +254,7 @@ namespace Mono.CSharp
                                "For more information on Mono, visit the project Web site\n" +
                                "   http://www.go-mono.com\n\n" +
 
-                               "The compiler was written by Miguel de Icaza, Ravi Pratap and Martin Baulig");
+                               "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja Harinath, Raja Harinath, Raja Harinath, Raja Harinath, Raja Harinath, Raja Harinath, Raja Harinath, Raja Harinath, Raja R Harinath");
                        Environment.Exit (0);
                }
 
@@ -265,11 +265,9 @@ namespace Mono.CSharp
                        bool ok = MainDriver (args);
                        
                        if (ok && Report.Errors == 0) {
-                               Console.Write("Compilation succeeded");
                                if (Report.Warnings > 0) {
-                                       Console.Write(" - {0} warning(s)", Report.Warnings);
+                                       Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
                                }
-                               Console.WriteLine();
                                if (show_counters){
                                        Console.WriteLine ("Counter1: " + counter1);
                                        Console.WriteLine ("Counter2: " + counter2);
@@ -290,21 +288,22 @@ namespace Mono.CSharp
                        string total_log = "";
 
                        try {
-                               char[] path_chars = { '/', '\\', '.' };
+                               char[] path_chars = { '/', '\\' };
 
                                if (assembly.IndexOfAny (path_chars) != -1) {
                                        a = Assembly.LoadFrom (assembly);
                                } else {
-                                       a = LoadAssemblyFromGac (assembly);
-                                       if (a == null)
-                                               a = Assembly.Load (assembly);
+                                       string ass = assembly;
+                                       if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
+                                               ass = assembly.Substring (0, assembly.Length - 4);
+                                       a = Assembly.Load (ass);
                                }
                                TypeManager.AddAssembly (a);
 
                        } catch (FileNotFoundException){
                                foreach (string dir in link_paths){
                                        string full_path = Path.Combine (dir, assembly);
-                                       if (!assembly.EndsWith (".dll"))
+                                       if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
                                                full_path += ".dll";
 
                                        try {
@@ -329,48 +328,6 @@ namespace Mono.CSharp
                        }
                }
 
-               static Assembly LoadAssemblyFromGac (string name)
-               {
-                       PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath",
-                                       BindingFlags.Static|BindingFlags.NonPublic);
-
-                       if (gac == null)
-                               return null;
-
-                       MethodInfo gac_get = gac.GetGetMethod (true);
-                       string use_name = name;
-                       string asmb_path;
-                       string [] canidates;
-
-                       if (name.EndsWith (".dll"))
-                               use_name = name.Substring (0, name.Length - 4);
-                       
-                       asmb_path = Path.Combine ((string) gac_get.Invoke (null, null), use_name);
-
-                       if (!Directory.Exists (asmb_path))
-                               return null;
-
-                       canidates = Directory.GetDirectories (asmb_path, GetSysVersion () + "*");
-                       if (canidates.Length == 0)
-                               canidates = Directory.GetDirectories (asmb_path);
-                       if (canidates.Length == 0)
-                               return null;
-                       try {
-                               Assembly a = Assembly.LoadFrom (Path.Combine (canidates [0], use_name + ".dll"));
-                               return a;
-                       } catch (Exception e) {
-                               return null;
-                       }
-               }
-
-               static string GetSysVersion ()
-               {
-                       if (sys_version != null)
-                               return sys_version;
-                       sys_version = typeof (object).Assembly.GetName ().Version.ToString ();
-                       return sys_version;
-               }
-
                static public void LoadModule (MethodInfo adder_method, string module)
                {
                        Module m;
@@ -674,7 +631,7 @@ namespace Mono.CSharp
 
                static void SetupV2 ()
                {
-                       RootContext.V2 = true;
+                       RootContext.Version = LanguageVersion.Default;
                        defines.Add ("__V2__");
                }
                
@@ -693,12 +650,8 @@ namespace Mono.CSharp
                static bool UnixParseOption (string arg, ref string [] args, ref int i)
                {
                        switch (arg){
-                       case "-vv":
-                               parser_verbose = true;
-                               return true;
-                               
                        case "-v":
-                               yacc_verbose = true;
+                               CSharpParser.yacc_verbose_flag++;
                                return true;
 
                        case "--version":
@@ -726,7 +679,7 @@ namespace Mono.CSharp
                                Usage ();
                                Environment.Exit (0);
                                return true;
-                               
+
                        case "--define":
                                if ((i + 1) >= args.Length){
                                        Usage ();
@@ -1029,22 +982,73 @@ namespace Mono.CSharp
                                
                                resources.Add (value);
                                return true;
+
+                       case "/pkg": {
+                               string packages;
+
+                               if (value == ""){
+                                       Usage ();
+                                       Environment.Exit (1);
+                               }
+                               packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
+                               
+                               ProcessStartInfo pi = new ProcessStartInfo ();
+                               pi.FileName = "pkg-config";
+                               pi.RedirectStandardOutput = true;
+                               pi.UseShellExecute = false;
+                               pi.Arguments = "--libs " + packages;
+                               Process p = null;
+                               try {
+                                       p = Process.Start (pi);
+                               } catch (Exception e) {
+                                       Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
+                                       Environment.Exit (1);
+                               }
+
+                               if (p.StandardOutput == null){
+                                       Report.Warning (-27, "Specified package did not return any information");
+                                       return true;
+                               }
+                               string pkgout = p.StandardOutput.ReadToEnd ();
+                               p.WaitForExit ();
+                               if (p.ExitCode != 0) {
+                                       Report.Error (-27, "Error running pkg-config. Check the above output.");
+                                       Environment.Exit (1);
+                               }
+
+                               if (pkgout != null){
+                                       string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
+                                               Split (new Char [] { ' ', '\t'});
+                                       args = AddArgs (args, xargs);
+                               }
+                               
+                               p.Close ();
+                               return true;
+                       }
                                
                        case "/res":
                        case "/resource":
                                if (value == ""){
-                                       Report.Error (5, arg + " requires an argument");
+                                       Report.Error (5, "-resource requires an argument");
                                        Environment.Exit (1);
                                }
                                if (embedded_resources == null)
                                        embedded_resources = new ArrayList ();
                                
-                               embedded_resources.Add (value);
+                               if (embedded_resources.Contains (value)) {
+                                       Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
+                               }
+                               else if (value.IndexOf (',') != -1 && embedded_resources.Contains (value.Split (',')[1])) {
+                                       Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
+                               }
+                               else {
+                                       embedded_resources.Add (value);
+                               }
                                return true;
                                
                        case "/recurse":
                                if (value == ""){
-                                       Report.Error (5, "/recurse requires an argument");
+                                       Report.Error (5, "-recurse requires an argument");
                                        Environment.Exit (1);
                                }
                                CompileFiles (value, true); 
@@ -1053,7 +1057,7 @@ namespace Mono.CSharp
                        case "/r":
                        case "/reference": {
                                if (value == ""){
-                                       Report.Error (5, arg + " requires an argument");
+                                       Report.Error (5, "-reference requires an argument");
                                        Environment.Exit (1);
                                }
 
@@ -1095,10 +1099,10 @@ namespace Mono.CSharp
                        }
                        case "/doc": {
                                if (value == ""){
-                                       Report.Error (5, arg + " requires an argument");
+                                       Report.Error (2006, arg + " requires an argument");
                                        Environment.Exit (1);
                                }
-                               // TODO handle the /doc argument to generate xml doc
+                               RootContext.Documentation = new Documentation (value);
                                return true;
                        }
                        case "/lib": {
@@ -1114,6 +1118,10 @@ namespace Mono.CSharp
                                        link_paths.Add (dir);
                                return true;
                        }
+
+                       case "/debug-":
+                               want_debugging_support = false;
+                               return true;
                                
                        case "/debug":
                        case "/debug+":
@@ -1193,6 +1201,11 @@ namespace Mono.CSharp
                                load_default_config = false;
                                return true;
 
+                       case "/help2":
+                               OtherFlags ();
+                               Environment.Exit(0);
+                               return true;
+                               
                        case "/help":
                        case "/?":
                                Usage ();
@@ -1243,9 +1256,24 @@ namespace Mono.CSharp
 
                        case "/v2":
                        case "/2":
+                               Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
                                SetupV2 ();
                                return true;
                                
+                       case "/langversion":
+                               switch (value.ToLower (CultureInfo.InvariantCulture)) {
+                                       case "iso-1":
+                                               RootContext.Version = LanguageVersion.ISO_1;
+                                               return true;
+
+                                       case "default":
+                                               SetupV2 ();
+                                               return true;
+                               }
+                               Report.Error (1617, "Invalid option '{0}' for /langversion; must be ISO-1 or Default", value);
+                               Environment.Exit (1);
+                               return false;
+
                        case "/codepage":
                                int cp = -1;
 
@@ -1272,10 +1300,35 @@ namespace Mono.CSharp
                                }
                                return true;
                        }
+
                        //Report.Error (2007, String.Format ("Unrecognized command-line option: '{0}'", option));
                        //Environment.Exit (1);
                        return false;
                }
+
+               static string [] AddArgs (string [] args, string [] extra_args)
+               {
+                       string [] new_args;
+                       new_args = new string [extra_args.Length + args.Length];
+
+                       // if args contains '--' we have to take that into account
+                       // split args into first half and second half based on '--'
+                       // and add the extra_args before --
+                       int split_position = Array.IndexOf (args, "--");
+                       if (split_position != -1)
+                       {
+                               Array.Copy (args, new_args, split_position);
+                               extra_args.CopyTo (new_args, split_position);
+                               Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
+                       }
+                       else
+                       {
+                               args.CopyTo (new_args, 0);
+                               extra_args.CopyTo (new_args, args.Length);
+                       }
+
+                       return new_args;
+               }
                
                /// <summary>
                ///    Parses the arguments, and drives the compilation
@@ -1313,12 +1366,13 @@ namespace Mono.CSharp
                        // path.
                        //
 
-                       int argc = args.Length;
-                       for (i = 0; i < argc; i++){
+                       for (i = 0; i < args.Length; i++){
                                string arg = args [i];
-
+                               if (arg == "")
+                                       continue;
+                               
                                if (arg.StartsWith ("@")){
-                                       string [] new_args, extra_args;
+                                       string [] extra_args;
                                        string response_file = arg.Substring (1);
 
                                        if (response_file_list == null)
@@ -1340,11 +1394,7 @@ namespace Mono.CSharp
                                                return false;
                                        }
 
-                                       new_args = new string [extra_args.Length + argc];
-                                       args.CopyTo (new_args, 0);
-                                       extra_args.CopyTo (new_args, argc);
-                                       args = new_args;
-                                       argc = new_args.Length;
+                                       args = AddArgs (args, extra_args);
                                        continue;
                                }
 
@@ -1378,6 +1428,13 @@ namespace Mono.CSharp
                        if (tokenize)
                                return true;
 
+                       //
+                       // This will point to the NamespaceEntry of the last file that was parsed, and may
+                       // not be meaningful when resolving classes from other files.  So, reset it to prevent
+                       // silent bugs.
+                       //
+                       RootContext.Tree.Types.NamespaceEntry = null;
+
                        //
                        // If we are an exe, require a source file for the entry point
                        //
@@ -1424,6 +1481,7 @@ namespace Mono.CSharp
                        if (timestamps)
                                ShowTime ("Loading references");
                        link_paths.Add (GetSystemDir ());
+                       link_paths.Add (Directory.GetCurrentDirectory ());
                        LoadReferences ();
                        
                        if (timestamps)
@@ -1496,6 +1554,7 @@ namespace Mono.CSharp
                        if (timestamps)
                                ShowTime ("Resolving tree");
                        RootContext.ResolveTree ();
+
                        if (Report.Errors > 0)
                                return false;
                        if (timestamps)
@@ -1506,6 +1565,11 @@ namespace Mono.CSharp
                        RootContext.PopulateTypes ();
                        RootContext.DefineTypes ();
                        
+                       if (RootContext.Documentation != null &&
+                               !RootContext.Documentation.OutputDocComment (
+                                       output_file))
+                               return false;
+
                        TypeManager.InitCodeHelpers ();
 
                        //
@@ -1519,8 +1583,11 @@ namespace Mono.CSharp
                        
                        if (RootContext.VerifyClsCompliance) { 
                                CodeGen.Assembly.ResolveClsCompliance ();
-                               AttributeTester.VerifyModulesClsCompliance ();
-                               TypeManager.LoadAllImportedTypes ();
+                               if (CodeGen.Assembly.IsClsCompliant) {
+                                       AttributeTester.VerifyModulesClsCompliance ();
+                                       TypeManager.LoadAllImportedTypes ();
+                                       AttributeTester.VerifyTopLevelNameClsCompliance ();
+                               }
                        }
                        
                        //
@@ -1558,6 +1625,22 @@ namespace Mono.CSharp
                                MethodInfo ep = RootContext.EntryPoint;
 
                                if (ep == null) {
+                                       if (RootContext.MainClass != null) {
+                                               DeclSpace main_cont = RootContext.Tree.Decls [RootContext.MainClass] as DeclSpace;
+                                               if (main_cont == null) {
+                                                       Report.Error (1555, output_file, "Could not find '{0}' specified for Main method", RootContext.MainClass); 
+                                                       return false;
+                                               }
+
+                                               if (!(main_cont is ClassOrStruct)) {
+                                                       Report.Error (1556, output_file, "'{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
+                                                       return false;
+                                               }
+
+                                               Report.Error (1558, main_cont.Location, "'{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
+                                               return false;
+                                       }
+
                                        if (Report.Errors == 0)
                                                Report.Error (5001, "Program " + output_file +
                                                              " does not have an entry point defined");
@@ -1610,7 +1693,7 @@ namespace Mono.CSharp
                                                        margs [1] = spec.Substring (0, cp);
                                                } else {
                                                        margs [1] = spec;
-                                                       margs [0] = spec.Replace ('/','.').Replace ('\\', '.');
+                                                       margs [0] = Path.GetFileName (spec);
                                                }
 
                                                if (File.Exists ((string) margs [1]))
@@ -1679,7 +1762,6 @@ namespace Mono.CSharp
 #endif
                        return (Report.Errors == 0);
                }
-
        }
 
        //