**** Merged from MCS ****
[mono.git] / mcs / gmcs / driver.cs
index 1e53f92ee8ccd5e5c54ab7022908ac7cd2013e67..bc9c756acd9c5351d0cf53c687a89197a07b62e9 100755 (executable)
@@ -14,6 +14,7 @@ namespace Mono.CSharp
        using System.Reflection;
        using System.Reflection.Emit;
        using System.Collections;
+       using System.Diagnostics;
        using System.IO;
        using System.Text;
        using System.Globalization;
@@ -76,6 +77,8 @@ namespace Mono.CSharp
                //
                static ArrayList resources;
                static ArrayList embedded_resources;
+               static string win32ResourceFile;
+               static string win32IconFile;
                
                //
                // An array of the defines from the command line
@@ -101,7 +104,13 @@ namespace Mono.CSharp
                // Whether the user has specified a different encoder manually
                //
                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)
@@ -183,6 +192,19 @@ namespace Mono.CSharp
                        }
                }
                
+               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 ()
                {
                        Console.WriteLine (
@@ -192,35 +214,36 @@ namespace Mono.CSharp
                                "   -checked[+|-]      Set default context to checked\n" +
                                "   -codepage:ID       Sets code page to the one in ID\n" +
                                "                      (number, `utf8' or `reset')\n" +
+                               "   -clscheck[+|-]     Disables CLS Compliance verifications" + Environment.NewLine +
                                "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
-                               "   -debug[+-]         Generate debugging information\n" + 
+                               "   -debug[+|-]        Generate debugging information\n" + 
+                               "   -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" +
                                "   -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" +
-                               "   --mcs-debug X      Sets MCS debugging level to X\n" +
+                               "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
+                               "   -win32icon:FILE         Use this icon for the output\n" +
                                 "   @file              Read response file for more options\n\n" +
                                "Options can be of the form -option or /option");
                }
@@ -276,12 +299,15 @@ 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 = Assembly.Load (assembly);
+                                       string ass = assembly;
+                                       if (ass.EndsWith (".dll"))
+                                               ass = assembly.Substring (0, assembly.Length - 4);
+                                       a = Assembly.Load (ass);
                                }
                                TypeManager.AddAssembly (a);
 
@@ -320,7 +346,7 @@ namespace Mono.CSharp
 
                        try {
                                try {
-                                       m = (Module)adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { module });
+                                       m = (Module)adder_method.Invoke (CodeGen.Assembly.Builder, new object [] { module });
                                }
                                catch (TargetInvocationException ex) {
                                        throw ex.InnerException;
@@ -336,7 +362,7 @@ namespace Mono.CSharp
 
                                        try {
                                                try {
-                                                       m = (Module)adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { full_path });
+                                                       m = (Module)adder_method.Invoke (CodeGen.Assembly.Builder, new object [] { full_path });
                                                }
                                                catch (TargetInvocationException ex) {
                                                        throw ex.InnerException;
@@ -972,6 +998,49 @@ 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 == ""){
@@ -1017,6 +1086,24 @@ namespace Mono.CSharp
                                }
                                return true;
                        }
+                       case "/win32res": {
+                               if (value == "") {
+                                       Report.Error (5, arg + " requires an argument");
+                                       Environment.Exit (1);
+                               }
+
+                               win32ResourceFile = value;
+                               return true;
+                       }
+                       case "/win32icon": {
+                               if (value == "") {
+                                       Report.Error (5, arg + " requires an argument");
+                                       Environment.Exit (1);
+                               }
+
+                               win32IconFile = value;
+                               return true;
+                       }
                        case "/doc": {
                                if (value == ""){
                                        Report.Error (5, arg + " requires an argument");
@@ -1038,6 +1125,10 @@ namespace Mono.CSharp
                                        link_paths.Add (dir);
                                return true;
                        }
+
+                       case "/debug-":
+                               want_debugging_support = false;
+                               return true;
                                
                        case "/debug":
                        case "/debug+":
@@ -1053,6 +1144,14 @@ namespace Mono.CSharp
                                RootContext.Checked = false;
                                return true;
 
+                       case "/clscheck":
+                       case "/clscheck+":
+                               return true;
+
+                       case "/clscheck-":
+                               RootContext.VerifyClsCompliance = false;
+                               return true;
+
                        case "/unsafe":
                        case "/unsafe+":
                                RootContext.Unsafe = true;
@@ -1109,6 +1208,11 @@ namespace Mono.CSharp
                                load_default_config = false;
                                return true;
 
+                       case "/help2":
+                               OtherFlags ();
+                               Environment.Exit(0);
+                               return true;
+                               
                        case "/help":
                        case "/?":
                                Usage ();
@@ -1136,10 +1240,27 @@ namespace Mono.CSharp
                        case "/fullpaths":
                                return true;
 
-                       case "/win32icon":
-                               Report.Error (5, "/win32icon is currently not supported");
+                       case "/keyfile":
+                               if (value == String.Empty) {
+                                       Report.Error (5, arg + " requires an argument");
+                                       Environment.Exit (1);
+                               }
+                               RootContext.StrongNameKeyFile = value;
                                return true;
-                               
+                       case "/keycontainer":
+                               if (value == String.Empty) {
+                                       Report.Error (5, arg + " requires an argument");
+                                       Environment.Exit (1);
+                               }
+                               RootContext.StrongNameKeyContainer = value;
+                               return true;
+                       case "/delaysign+":
+                               RootContext.StrongNameDelaySign = true;
+                               return true;
+                       case "/delaysign-":
+                               RootContext.StrongNameDelaySign = false;
+                               return true;
+
                        case "/v2":
                        case "/2":
                                SetupV2 ();
@@ -1176,6 +1297,17 @@ namespace Mono.CSharp
                        return false;
                }
                
+               static string [] AddArgs (string [] args, string [] extra_args)
+               {
+                       string [] new_args;
+
+                       new_args = new string [extra_args.Length + args.Length];
+                       args.CopyTo (new_args, 0);
+                       extra_args.CopyTo (new_args, args.Length);
+
+                       return new_args;
+               }
+               
                /// <summary>
                ///    Parses the arguments, and drives the compilation
                ///    process.
@@ -1191,7 +1323,7 @@ namespace Mono.CSharp
                        int i;
                        bool parsing_options = true;
 
-                       Console.WriteLine ("Mono C# Compiler {0} for Generics",
+                       Console.WriteLine ("ALPHA SOFTWARE: Mono C# Compiler {0} for Generics",
                                           Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
                        try {
                                encoding = Encoding.GetEncoding (28591);
@@ -1214,12 +1346,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)
@@ -1241,11 +1374,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;
                                }
 
@@ -1279,17 +1408,33 @@ namespace Mono.CSharp
                        if (tokenize)
                                return true;
                        
+                       //
+                       // If we are an exe, require a source file for the entry point
+                       //
+                       if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe){
                        if (first_source == null){
                                Report.Error (2008, "No files to compile were specified");
                                return false;
                        }
 
+                       }
+
+                       //
+                       // If there is nothing to put in the assembly, and we are not a library
+                       //
+                       if (first_source == null && embedded_resources == null && resources == null){
+                                       Report.Error (2008, "No files to compile were specified");
+                                       return false;
+                       }
+
                        if (Report.Errors > 0)
                                return false;
                        
                        if (parse_only)
                                return true;
                        
+                       Tokenizer.Cleanup ();
+                       
                        //
                        // Load Core Library for default compilation
                        //
@@ -1309,6 +1454,7 @@ namespace Mono.CSharp
                        if (timestamps)
                                ShowTime ("Loading references");
                        link_paths.Add (GetSystemDir ());
+                       link_paths.Add (Directory.GetCurrentDirectory ());
                        LoadReferences ();
                        
                        if (timestamps)
@@ -1339,10 +1485,11 @@ namespace Mono.CSharp
                                        Environment.Exit (1);
                                }
 
-                               module_only.SetValue (CodeGen.AssemblyBuilder, true, null);
+                               MethodInfo set_method = module_only.GetSetMethod (true);
+                               set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
                        }
 
-                       TypeManager.AddModule (CodeGen.ModuleBuilder);
+                       TypeManager.AddModule (CodeGen.Module.Builder);
 
                        if (modules.Count > 0) {
                                MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
@@ -1400,6 +1547,12 @@ namespace Mono.CSharp
                                return false;
                        }
                        
+                       if (RootContext.VerifyClsCompliance) { 
+                               CodeGen.Assembly.ResolveClsCompliance ();
+                               AttributeTester.VerifyModulesClsCompliance ();
+                               TypeManager.LoadAllImportedTypes ();
+                       }
+                       
                        //
                        // The code generator
                        //
@@ -1441,7 +1594,7 @@ namespace Mono.CSharp
                                        return false;
                                }
                                
-                               CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
+                               CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
                        } else if (RootContext.MainClass != null) {
                                Report.Error (2017, "Can not specify -main: when building module or library");
                        }
@@ -1461,7 +1614,7 @@ namespace Mono.CSharp
                                        } else
                                                file = res = spec;
 
-                                       CodeGen.AssemblyBuilder.AddResourceFile (res, file);
+                                       CodeGen.Assembly.Builder.AddResourceFile (res, file);
                                }
                        }
                        
@@ -1470,9 +1623,13 @@ namespace Mono.CSharp
                                Type[] argst = new Type [2];
                                argst [0] = argst [1] = typeof (string);
 
-                               MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, CallingConventions.Any, argst, null);
+                               MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod (
+                                       "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
+                                       null, CallingConventions.Any, argst, null);
+                               
                                if (embed_res == null) {
-                                       Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
+                                       Report.Warning (0, new Location (-1),
+                                                       "Cannot embed resources on this runtime: try the Mono runtime instead.");
                                } else {
                                        foreach (string spec in embedded_resources) {
                                                int cp;
@@ -1481,11 +1638,13 @@ namespace Mono.CSharp
                                                if (cp != -1){
                                                        margs [0] = spec.Substring (cp + 1);
                                                        margs [1] = spec.Substring (0, cp);
-                                               } else
-                                                       margs [0] = margs [1] = spec;
+                                               } else {
+                                                       margs [1] = spec;
+                                                       margs [0] = spec.Replace ('/','.').Replace ('\\', '.');
+                                               }
 
                                                if (File.Exists ((string) margs [1]))
-                                                       embed_res.Invoke (CodeGen.AssemblyBuilder, margs);
+                                                       embed_res.Invoke (CodeGen.Assembly.Builder, margs);
                                                else {
                                                        Report.Error (1566, "Can not find the resource " + margs [1]);
                                                }
@@ -1493,6 +1652,29 @@ namespace Mono.CSharp
                                }
                        }
 
+                       //
+                       // Add Win32 resources
+                       //
+
+                       CodeGen.Assembly.Builder.DefineVersionInfoResource ();
+
+                       if (win32ResourceFile != null) {
+                               try {
+                                       CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
+                               }
+                               catch (ArgumentException) {
+                                       Report.Warning (0, new Location (-1), "Cannot embed win32 resources on this runtime: try the Mono runtime instead.");
+                               }
+                       }
+
+                       if (win32IconFile != null) {
+                               MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+                               if (define_icon == null) {
+                                       Report.Warning (0, new Location (-1), "Cannot embed icon resource on this runtime: try the Mono runtime instead.");
+                               }
+                               define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
+                       }
+
                        if (Report.Errors > 0)
                                return false;
                        
@@ -1505,8 +1687,19 @@ namespace Mono.CSharp
                        Timer.ShowTimers ();
                        
                        if (Report.ExpectedError != 0){
-                               Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
+                               if (Report.Errors == 0) {
+                                       Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
+                                               "No other errors reported.");
+                                       
+                                       Environment.Exit (2);
+                               } else {
+                                       Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
+                                               "However, other errors were reported.");
+                                       
                                Environment.Exit (1);
+                               }
+                               
+                               
                                return false;
                        }