X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fdriver.cs;h=7b5d86680eb3160bf5bce1f1471f8b004743b6d4;hb=168d424a84ed56998b15dd011e49291c581dd5a9;hp=c94d211cdddf12f308d34cc579fbc57df11acc45;hpb=6cfd2055426c190ca2f6a9f8ca3af2da6f6a79d0;p=mono.git diff --git a/mcs/mcs/driver.cs b/mcs/mcs/driver.cs index c94d211cddd..7b5d86680eb 100644 --- a/mcs/mcs/driver.cs +++ b/mcs/mcs/driver.cs @@ -1,12 +1,14 @@ // // driver.cs: The compiler command line driver. // -// Author: Miguel de Icaza (miguel@gnu.org) +// Authors: +// Miguel de Icaza (miguel@gnu.org) +// Marek Safar (marek.safar@gmail.com) // -// Licensed under the terms of the GNU GPL +// Dual licensed under the terms of the MIT X11 or GNU GPL // -// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com) -// (C) 2004, 2005 Novell, Inc +// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com) +// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc // namespace Mono.CSharp @@ -28,9 +30,8 @@ namespace Mono.CSharp /// /// The compiler driver. /// - public class Driver + class Driver { - // // Assemblies references to be linked. Initialized with // mscorlib.dll here. @@ -57,21 +58,18 @@ namespace Mono.CSharp static ArrayList link_paths; // Whether we want to only run the tokenizer - static bool tokenize = false; + bool tokenize; - static string first_source; - - static bool want_debugging_support = false; + string first_source; - static bool parse_only = false; - static bool timestamps = false; - static bool pause = false; - static bool show_counters = false; + bool want_debugging_support; + bool parse_only; + bool timestamps; // // Whether to load the initial config file (what CSC.RSP has by default) // - static bool load_default_config = true; + bool load_default_config = true; // // A list of resource files @@ -83,41 +81,51 @@ namespace Mono.CSharp // // An array of the defines from the command line // - static ArrayList defines; + ArrayList defines; // // Output file // - static string output_file = null; + static string output_file; // // Last time we took the time // - static DateTime last_time, first_time; + DateTime last_time, first_time; // // Encoding. // - static Encoding encoding; - + Encoding encoding; static public void Reset () { - want_debugging_support = false; - parse_only = false; - timestamps = false; - pause = false; - show_counters = false; - load_default_config = true; embedded_resources = null; win32ResourceFile = win32IconFile = null; - defines = null; output_file = null; - encoding = null; - first_source = null; } - public static void ShowTime (string msg) + public Driver () + { + encoding = Encoding.Default; + + // + // Setup default defines + // + defines = new ArrayList (); + defines.Add ("__MonoCS__"); + } + + public static Driver Create (string [] args) + { + Driver d = new Driver (); + if (!d.ParseArguments (args)) + return null; + + return d; + } + + void ShowTime (string msg) { if (!timestamps) return; @@ -131,7 +139,7 @@ namespace Mono.CSharp (int) span.TotalSeconds, span.Milliseconds, msg); } - public static void ShowTotalTime (string msg) + void ShowTotalTime (string msg) { if (!timestamps) return; @@ -145,7 +153,7 @@ namespace Mono.CSharp (int) span.TotalSeconds, span.Milliseconds, msg); } - static void tokenize_file (SourceFile file) + void tokenize_file (CompilationUnit file) { Stream input; @@ -172,16 +180,14 @@ namespace Mono.CSharp return; } - // MonoTODO("Change error code for aborted compilation to something reasonable")] - static void parse (SourceFile file) + void Parse (CompilationUnit file) { - CSharpParser parser; Stream input; try { input = File.OpenRead (file.Name); } catch { - Report.Error (2001, "Source file `" + file.Name + "' could not be found"); + Report.Error (2001, "Source file `{0}' could not be found", file.Name); return; } @@ -195,14 +201,19 @@ namespace Mono.CSharp } reader.Position = 0; - parser = new CSharpParser (reader, file, defines); + Parse (reader, file); + input.Close (); + } + + void Parse (SeekableStreamReader reader, CompilationUnit file) + { + CSharpParser parser = new CSharpParser (reader, file, defines); parser.ErrorOutput = Report.Stderr; try { parser.parse (); } catch (Exception ex) { - Report.Error(666, "Compilation aborted: " + ex); - } finally { - input.Close (); + Report.Error(589, parser.Lexer.Location, + "Compilation aborted in file `{0}', {1}", file.Name, ex); } } @@ -212,10 +223,10 @@ namespace Mono.CSharp "Other flags in the compiler\n" + " --fatal Makes errors fatal\n" + " --parse Only parses the source file\n" + + " --typetest Tests the tokenizer's built-in type parser\n" + " --stacktrace Shows stack trace at error location\n" + " --timestamp Displays time stamps of various compiler events\n" + " --expect-error X Expect that error X will be encountered\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"); } @@ -223,40 +234,42 @@ namespace Mono.CSharp static void Usage () { Console.WriteLine ( - "Mono C# compiler, (C) 2001 - 2005 Novell, Inc.\n" + + "Mono C# compiler, Copyright 2001 - 2008 Novell, 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" + + " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" + + " -checked[+|-] Sets default aritmetic overflow context\n" + " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" + - " -clscheck[+|-] Disables CLS Compliance verifications" + Environment.NewLine + - " -define:S1[;S2] Defines one or more symbols (short: /d:)\n" + + " -clscheck[+|-] Disables CLS Compliance verifications\n" + + " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" + " -debug[+|-], -g Generate debugging information\n" + " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" + - " -doc:FILE XML Documentation file to generate\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\n" + - " -lib:PATH1,PATH2 Adds the paths to the assembly link path\n" + - " -main:class Specified the class that contains the entry point\n" + + " -doc:FILE Process documentation comments to XML file\n" + + " -help Lists all compiler options (short: -?)\n" + + " -keycontainer:NAME The key pair container used to sign the output assembly\n" + + " -keyfile:FILE The key file used to strongname the ouput assembly\n" + + " -langversion:TEXT Specifies language version modes: ISO-1, ISO-2, or Default\n" + + " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" + + " -main:CLASS Specifies the class with the Main method (short: -m)\n" + " -noconfig[+|-] Disables implicit references to assemblies\n" + - " -nostdlib[+|-] Does not load core libraries\n" + - " -nowarn:W1[,W2] Disables one or more warnings\n" + - " -optimize[+|-] Enables code optimalizations\n" + - " -out:FNAME Specifies output file\n" + + " -nostdlib[+|-] Does not reference mscorlib.dll library\n" + + " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" + + " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" + + " -out:FILE Specifies output assembly name\n" + " -pkg:P1[,Pn] References packages P1..Pn\n" + - " -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" + - " -reference:ASS References the specified assembly (-r:ASS)\n" + - " -target:KIND Specifies the target (KIND is one of: exe, winexe,\n" + - " library, module), (short: /t:)\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" + - " -help2 Show other help flags\n" + + " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" + + " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" + + " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" + + " -target:KIND Specifies the format of the output assembly (short: -t)\n" + + " KIND can be one of: exe, winexe, library, module\n" + + " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" + + " -warnaserror[+|-] Treats all warnings as errors\n" + + " -warn:0-4 Sets warning level, the default is 3 (short -w:)\n" + + " -help2 Shows internal compiler options\n" + "\n" + "Resources:\n" + - " -linkresource:FILE[,ID] Links FILE as a resource\n" + - " -resource:FILE[,ID] Embed FILE as a resource\n" + + " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" + + " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\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" + @@ -271,34 +284,31 @@ namespace Mono.CSharp static void About () { Console.WriteLine ( - "The Mono C# compiler is (C) 2001-2005, Novell, Inc.\n\n" + - "The compiler source code is released under the terms of the GNU GPL\n\n" + + "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" + + "The compiler source code is released under the terms of the \n"+ + "MIT X11 or GNU GPL licenses\n\n" + "For more information on Mono, visit the project Web site\n" + - " http://www.go-mono.com\n\n" + + " http://www.mono-project.com\n\n" + - "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath"); + "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto"); Environment.Exit (0); } - public static int counter1, counter2; - public static int Main (string[] args) { + RootContext.Version = LanguageVersion.Default; + Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t"; - bool ok = MainDriver (args); - - if (ok && Report.Errors == 0) { + Driver d = Driver.Create (args); + if (d == null) + return 1; + + if (d.Compile () && Report.Errors == 0) { if (Report.Warnings > 0) { Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings); } - if (show_counters){ - Console.WriteLine ("Counter1: " + counter1); - Console.WriteLine ("Counter2: " + counter2); - } - if (pause) - Console.ReadLine (); return 0; } else { Console.WriteLine("Compilation failed: {0} error(s), {1} warnings", @@ -312,102 +322,142 @@ namespace Mono.CSharp LoadAssembly (assembly, null, soft); } + static void Error6 (string name, string log) + { + if (log != null && log.Length > 0) + Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous "); + Report.Error (6, "cannot find metadata file `{0}'", name); + } + + static void Error9 (string type, string filename, string log) + { + if (log != null && log.Length > 0) + Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous "); + Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type); + } + + static void BadAssembly (string filename, string log) + { + MethodInfo adder_method = AssemblyClass.AddModule_Method; + + if (adder_method != null) { + AssemblyName an = new AssemblyName (); + an.Name = ".temp"; + AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run); + try { + object m = null; + try { + m = adder_method.Invoke (ab, new object [] { filename }); + } catch (TargetInvocationException ex) { + throw ex.InnerException; + } + + if (m != null) { + Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead", + Path.GetFileName (filename)); + return; + } + } catch (FileNotFoundException) { + // did the file get deleted during compilation? who cares? swallow the exception + } catch (BadImageFormatException) { + // swallow exception + } catch (FileLoadException) { + // swallow exception + } + } + Error9 ("assembly", filename, log); + } + static public void LoadAssembly (string assembly, string alias, bool soft) { - Assembly a; + Assembly a = null; string total_log = ""; try { - char[] path_chars = { '/', '\\' }; + try { + char[] path_chars = { '/', '\\' }; - if (assembly.IndexOfAny (path_chars) != -1) { - a = Assembly.LoadFrom (assembly); - } else { - string ass = assembly; - if (ass.EndsWith (".dll") || ass.EndsWith (".exe")) - ass = assembly.Substring (0, assembly.Length - 4); - a = Assembly.Load (ass); + if (assembly.IndexOfAny (path_chars) != -1) { + a = Assembly.LoadFrom (assembly); + } else { + string ass = assembly; + if (ass.EndsWith (".dll") || ass.EndsWith (".exe")) + ass = assembly.Substring (0, assembly.Length - 4); + a = Assembly.Load (ass); + } + } catch (FileNotFoundException) { + bool err = !soft; + foreach (string dir in link_paths) { + string full_path = Path.Combine (dir, assembly); + if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe")) + full_path += ".dll"; + + try { + a = Assembly.LoadFrom (full_path); + err = false; + break; + } catch (FileNotFoundException ff) { + if (soft) + return; + total_log += ff.FusionLog; + } + } + if (err) { + Error6 (assembly, total_log); + return; + } } + // Extern aliased refs require special handling if (alias == null) RootNamespace.Global.AddAssemblyReference (a); else RootNamespace.DefineRootNamespace (alias, a); - } catch (FileNotFoundException){ - foreach (string dir in link_paths){ - string full_path = Path.Combine (dir, assembly); - if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe")) - full_path += ".dll"; - - try { - a = Assembly.LoadFrom (full_path); - if (alias == null) - RootNamespace.Global.AddAssemblyReference (a); - else - RootNamespace.DefineRootNamespace (alias, a); - return; - } catch (FileNotFoundException ff) { - total_log += ff.FusionLog; - continue; - } - } - if (!soft) { - Report.Error (6, "Cannot find assembly `" + assembly + "'" ); - Console.WriteLine ("Log: \n" + total_log); - } } catch (BadImageFormatException f) { - Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog); - } catch (FileLoadException f){ - Report.Error(6, "Cannot load assembly " + f.FusionLog); - } catch (ArgumentNullException){ - Report.Error(6, "Cannot load assembly (null argument)"); + // .NET 2.0 throws this if we try to load a module without an assembly manifest ... + BadAssembly (f.FileName, f.FusionLog); + } catch (FileLoadException f) { + // ... while .NET 1.1 throws this + BadAssembly (f.FileName, f.FusionLog); } } - static public void LoadModule (MethodInfo adder_method, string module) + static public void LoadModule (string module) { - Module m; + Module m = null; string total_log = ""; try { try { - m = (Module)adder_method.Invoke (CodeGen.Assembly.Builder, new object [] { module }); - } - catch (TargetInvocationException ex) { - throw ex.InnerException; - } - RootNamespace.Global.AddModuleReference (m); - - } - catch (FileNotFoundException){ - foreach (string dir in link_paths){ - string full_path = Path.Combine (dir, module); - if (!module.EndsWith (".netmodule")) - full_path += ".netmodule"; + m = CodeGen.Assembly.AddModule (module); + } catch (FileNotFoundException) { + bool err = true; + foreach (string dir in link_paths) { + string full_path = Path.Combine (dir, module); + if (!module.EndsWith (".netmodule")) + full_path += ".netmodule"; - try { try { - m = (Module)adder_method.Invoke (CodeGen.Assembly.Builder, new object [] { full_path }); - } - catch (TargetInvocationException ex) { - throw ex.InnerException; + m = CodeGen.Assembly.AddModule (full_path); + err = false; + break; + } catch (FileNotFoundException ff) { + total_log += ff.FusionLog; } - RootNamespace.Global.AddModuleReference (m); + } + if (err) { + Error6 (module, total_log); return; - } catch (FileNotFoundException ff) { - total_log += ff.FusionLog; - continue; } } - Report.Error (6, "Cannot find module `" + module + "'" ); - Console.WriteLine ("Log: \n" + total_log); + + RootNamespace.Global.AddModuleReference (m); + } catch (BadImageFormatException f) { - Report.Error(6, "Cannot load module (bad file format)" + f.FusionLog); - } catch (FileLoadException f){ - Report.Error(6, "Cannot load module " + f.FusionLog); - } catch (ArgumentNullException){ - Report.Error(6, "Cannot load module (null argument)"); + Error9 ("module", f.FileName, f.FusionLog); + } catch (FileLoadException f) { + Error9 ("module", f.FileName, f.FusionLog); } } @@ -416,24 +466,24 @@ namespace Mono.CSharp /// static public void LoadReferences () { - foreach (string r in references) - LoadAssembly (r, false); + // + // Load Core Library for default compilation + // + if (RootContext.StdLib) + LoadAssembly ("mscorlib", false); foreach (string r in soft_references) LoadAssembly (r, true); + foreach (string r in references) + LoadAssembly (r, false); + foreach (DictionaryEntry entry in external_aliases) LoadAssembly ((string) entry.Value, (string) entry.Key, false); return; } - static void SetupDefaultDefines () - { - defines = new ArrayList (); - defines.Add ("__MonoCS__"); - } - static string [] LoadArgs (string file) { StreamReader f; @@ -523,7 +573,7 @@ namespace Mono.CSharp pattern = spec; } - static void ProcessFile (string f) + void AddSourceFile (string f) { if (first_source == null) first_source = f; @@ -531,26 +581,125 @@ namespace Mono.CSharp Location.AddFile (f); } - static void ProcessFiles () + bool ParseArguments (string[] args) + { + references = new ArrayList (); + external_aliases = new Hashtable (); + soft_references = new ArrayList (); + modules = new ArrayList (2); + link_paths = new ArrayList (); + + ArrayList response_file_list = null; + bool parsing_options = true; + + for (int i = 0; i < args.Length; i++) { + string arg = args [i]; + if (arg.Length == 0) + continue; + + if (arg.StartsWith ("@")) { + string [] extra_args; + string response_file = arg.Substring (1); + + if (response_file_list == null) + response_file_list = new ArrayList (); + + if (response_file_list.Contains (response_file)) { + Report.Error ( + 1515, "Response file `" + response_file + + "' specified multiple times"); + return false; + } + + response_file_list.Add (response_file); + + extra_args = LoadArgs (response_file); + if (extra_args == null) { + Report.Error (2011, "Unable to open response file: " + + response_file); + return false; + } + + args = AddArgs (args, extra_args); + continue; + } + + if (parsing_options) { + if (arg == "--") { + parsing_options = false; + continue; + } + + if (arg.StartsWith ("-")) { + if (UnixParseOption (arg, ref args, ref i)) + continue; + + // Try a -CSCOPTION + string csc_opt = "/" + arg.Substring (1); + if (CSCParseOption (csc_opt, ref args, ref i)) + continue; + + Error_WrongOption (arg); + return false; + } + if (arg [0] == '/') { + if (CSCParseOption (arg, ref args, ref i)) + continue; + + // Need to skip `/home/test.cs' however /test.cs is considered as error + if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) { + Error_WrongOption (arg); + return false; + } + } + } + + ProcessSourceFiles (arg, false); + } + + // + // If we are an exe, require a source file for the entry point + // + if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) { + 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) { + Report.Error (2008, "No files to compile were specified"); + return false; + } + + return true; + } + + public void Parse () { Location.Initialize (); - foreach (SourceFile file in Location.SourceFiles) { + int files_count = Location.SourceFiles.Length; + for (int i = 0; i < files_count; ++i) { if (tokenize) { - tokenize_file (file); + tokenize_file (Location.SourceFiles [i]); } else { - parse (file); + Parse (Location.SourceFiles [i]); } } } - static void CompileFiles (string spec, bool recurse) + void ProcessSourceFiles (string spec, bool recurse) { string path, pattern; SplitPathAndPattern (spec, out path, out pattern); if (pattern.IndexOf ('*') == -1){ - ProcessFile (spec); + AddSourceFile (spec); return; } @@ -565,7 +714,7 @@ namespace Mono.CSharp return; } foreach (string f in files) { - ProcessFile (f); + AddSourceFile (f); } if (!recurse) @@ -582,7 +731,7 @@ namespace Mono.CSharp // Don't include path in this string, as each // directory entry already does - CompileFiles (d + "/" + pattern, true); + ProcessSourceFiles (d + "/" + pattern, true); } } @@ -595,6 +744,12 @@ namespace Mono.CSharp string [] default_config = { "System", "System.Xml", +#if NET_2_1 + "System.Core", + "System.Net", + "System.Windows", + "System.Windows.Browser", +#endif #if false // // Is it worth pre-loading all this stuff? @@ -620,9 +775,10 @@ namespace Mono.CSharp #endif }; - int p = 0; - foreach (string def in default_config) - soft_references.Insert (p++, def); + if (RootContext.Version == LanguageVersion.LINQ) + soft_references.Add ("System.Core"); + + soft_references.AddRange (default_config); } public static string OutputFile @@ -647,15 +803,9 @@ namespace Mono.CSharp Report.Error (1900, "Warning level must be in the range 0-4"); return; } - RootContext.WarningLevel = level; + Report.WarningLevel = level; } - static void SetupV2 () - { - RootContext.Version = LanguageVersion.Default; - defines.Add ("__V2__"); - } - static void Version () { string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString (); @@ -668,7 +818,7 @@ namespace Mono.CSharp // deprecated in favor of the CSCParseOption, which will also handle the // options that start with a dash in the future. // - static bool UnixParseOption (string arg, ref string [] args, ref int i) + bool UnixParseOption (string arg, ref string [] args, ref int i) { switch (arg){ case "-v": @@ -712,23 +862,6 @@ namespace Mono.CSharp defines.Add (args [++i]); return true; - case "--show-counters": - show_counters = true; - return true; - - case "--expect-error": { - int code = 0; - - try { - code = Int32.Parse ( - args [++i], NumberStyles.AllowLeadingSign); - Report.ExpectedError = code; - } catch { - Report.Error (-14, "Invalid number specified"); - } - return true; - } - case "--tokenize": tokenize = true; return true; @@ -853,7 +986,7 @@ namespace Mono.CSharp Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror"); Report.WarningsAreErrors = true; return true; - + case "--nowarn": Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn"); if ((i + 1) >= args.Length){ @@ -907,7 +1040,7 @@ namespace Mono.CSharp Report.Error (5, "--recurse requires an argument"); Environment.Exit (1); } - CompileFiles (args [++i], true); + ProcessSourceFiles (args [++i], true); return true; case "--timestamp": @@ -915,10 +1048,6 @@ namespace Mono.CSharp last_time = first_time = DateTime.Now; return true; - case "--pause": - pause = true; - return true; - case "--debug": case "-g": Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug"); want_debugging_support = true; @@ -937,7 +1066,7 @@ namespace Mono.CSharp // This parses the -arg and /arg options to the compiler, even if the strings // in the following text use "/arg" on the strings. // - static bool CSCParseOption (string option, ref string [] args, ref int i) + bool CSCParseOption (string option, ref string [] args, ref int i) { int idx = option.IndexOf (':'); string arg, value; @@ -983,18 +1112,21 @@ namespace Mono.CSharp return true; case "/out": - if (value == ""){ + if (value.Length == 0){ Usage (); Environment.Exit (1); } OutputFile = value; return true; + case "/o": + case "/o+": case "/optimize": case "/optimize+": RootContext.Optimize = true; return true; + case "/o-": case "/optimize-": RootContext.Optimize = false; return true; @@ -1007,15 +1139,16 @@ namespace Mono.CSharp case "/d": case "/define": { - string [] defs; - - if (value == ""){ + if (value.Length == 0){ Usage (); Environment.Exit (1); } - defs = value.Split (new Char [] {';', ','}); - foreach (string d in defs){ + foreach (string d in value.Split (';', ',')){ + if (!Tokenizer.IsValidIdentifier (d)) { + Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d); + continue; + } defines.Add (d); } return true; @@ -1031,7 +1164,7 @@ namespace Mono.CSharp case "/pkg": { string packages; - if (value == ""){ + if (value.Length == 0){ Usage (); Environment.Exit (1); } @@ -1104,16 +1237,16 @@ namespace Mono.CSharp return true; case "/recurse": - if (value == ""){ + if (value.Length == 0){ Report.Error (5, "-recurse requires an argument"); Environment.Exit (1); } - CompileFiles (value, true); + ProcessSourceFiles (value, true); return true; case "/r": case "/reference": { - if (value == ""){ + if (value.Length == 0){ Report.Error (5, "-reference requires an argument"); Environment.Exit (1); } @@ -1121,7 +1254,7 @@ namespace Mono.CSharp string [] refs = value.Split (new char [] { ';', ',' }); foreach (string r in refs){ string val = r; - int index = val.IndexOf ("="); + int index = val.IndexOf ('='); if (index > -1) { string alias = r.Substring (0, index); string assembly = r.Substring (index + 1); @@ -1134,7 +1267,7 @@ namespace Mono.CSharp return true; } case "/addmodule": { - if (value == ""){ + if (value.Length == 0){ Report.Error (5, arg + " requires an argument"); Environment.Exit (1); } @@ -1146,7 +1279,7 @@ namespace Mono.CSharp return true; } case "/win32res": { - if (value == "") { + if (value.Length == 0) { Report.Error (5, arg + " requires an argument"); Environment.Exit (1); } @@ -1155,7 +1288,7 @@ namespace Mono.CSharp return true; } case "/win32icon": { - if (value == "") { + if (value.Length == 0) { Report.Error (5, arg + " requires an argument"); Environment.Exit (1); } @@ -1164,7 +1297,7 @@ namespace Mono.CSharp return true; } case "/doc": { - if (value == ""){ + if (value.Length == 0){ Report.Error (2006, arg + " requires an argument"); Environment.Exit (1); } @@ -1174,7 +1307,7 @@ namespace Mono.CSharp case "/lib": { string [] libdirs; - if (value == ""){ + if (value.Length == 0){ Report.Error (5, "/lib requires an argument"); Environment.Exit (1); } @@ -1236,7 +1369,7 @@ namespace Mono.CSharp case "/nowarn": { string [] warns; - if (value == ""){ + if (value.Length == 0){ Report.Error (5, "/nowarn requires an argument"); Environment.Exit (1); } @@ -1278,7 +1411,7 @@ namespace Mono.CSharp case "/main": case "/m": - if (value == ""){ + if (value.Length == 0){ Report.Error (5, arg + " requires an argument"); Environment.Exit (1); } @@ -1318,23 +1451,29 @@ namespace Mono.CSharp RootContext.StrongNameDelaySign = false; return true; - 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; + case "iso-1": + RootContext.Version = LanguageVersion.ISO_1; + return true; + + case "default": + RootContext.Version = LanguageVersion.Default; +#if GMCS_SOURCE + defines.Add ("__V2__"); +#endif + return true; +#if GMCS_SOURCE + case "iso-2": + RootContext.Version = LanguageVersion.ISO_2; + return true; + + case "linq": + Report.Warning (-30, 1, "Deprecated: The `linq' option is no longer required and should not be used"); + return true; +#endif } - Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value); + Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value); return true; case "/codepage": @@ -1427,148 +1566,20 @@ namespace Mono.CSharp return true; } - /// - /// Parses the arguments, and drives the compilation - /// process. - /// - /// - /// - /// TODO: Mostly structured to debug the compiler - /// now, needs to be turned into a real driver soon. - /// - // [MonoTODO("Change error code for unknown argument to something reasonable")] - internal static bool MainDriver (string [] args) + // + // Main compilation method + // + public bool Compile () { - int i; - bool parsing_options = true; - - encoding = Encoding.Default; - - references = new ArrayList (); - external_aliases = new Hashtable (); - soft_references = new ArrayList (); - modules = new ArrayList (); - link_paths = new ArrayList (); - - SetupDefaultDefines (); - - // - // Setup defaults - // - // This is not required because Assembly.Load knows about this - // path. - // - - Hashtable response_file_list = null; - - for (i = 0; i < args.Length; i++){ - string arg = args [i]; - if (arg == "") - continue; - - if (arg.StartsWith ("@")){ - string [] extra_args; - string response_file = arg.Substring (1); - - if (response_file_list == null) - response_file_list = new Hashtable (); - - if (response_file_list.Contains (response_file)){ - Report.Error ( - 1515, "Response file `" + response_file + - "' specified multiple times"); - Environment.Exit (1); - } - - response_file_list.Add (response_file, response_file); - - extra_args = LoadArgs (response_file); - if (extra_args == null){ - Report.Error (2011, "Unable to open response file: " + - response_file); - return false; - } - - args = AddArgs (args, extra_args); - continue; - } - - if (parsing_options){ - if (arg == "--"){ - parsing_options = false; - continue; - } - - if (arg.StartsWith ("-")){ - if (UnixParseOption (arg, ref args, ref i)) - continue; - - // Try a -CSCOPTION - string csc_opt = "/" + arg.Substring (1); - if (CSCParseOption (csc_opt, ref args, ref i)) - continue; - - Error_WrongOption (arg); - return false; - } else { - if (arg [0] == '/'){ - if (CSCParseOption (arg, ref args, ref i)) - continue; - - // Need to skip `/home/test.cs' however /test.cs is considered as error - if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) { - Error_WrongOption (arg); - return false; - } - } - } - } - - CompileFiles (arg, false); - } - - ProcessFiles (); - - 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 - // - if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){ - 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){ - Report.Error (2008, "No files to compile were specified"); - return false; - } - + Parse (); if (Report.Errors > 0) return false; - - if (parse_only) + + if (tokenize || parse_only) return true; - // - // Load Core Library for default compilation - // - if (RootContext.StdLib) - references.Insert (0, "mscorlib"); + if (RootContext.ToplevelTypes.NamespaceEntry != null) + throw new InternalErrorException ("who set it?"); if (load_default_config) DefineDefaultConfig (); @@ -1597,6 +1608,11 @@ namespace Mono.CSharp // Quick hack // if (output_file == null){ + if (first_source == null){ + Report.Error (1562, "If no source files are specified you must specify the output file with -out:"); + return false; + } + int pos = first_source.LastIndexOf ('.'); if (pos > 0) @@ -1622,34 +1638,19 @@ namespace Mono.CSharp RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder); if (modules.Count > 0) { - MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic); - if (adder_method == null) { - Report.RuntimeMissingSupport (Location.Null, "/addmodule"); - Environment.Exit (1); - } - foreach (string module in modules) - LoadModule (adder_method, module); + LoadModule (module); } - // - // Before emitting, we need to get the core - // types emitted from the user defined types - // or from the system ones. - // - if (timestamps) - ShowTime ("Initializing Core Types"); - if (!RootContext.StdLib){ - RootContext.ResolveCore (); - if (Report.Errors > 0) - return false; - } - - TypeManager.InitCoreTypes (); + if (!TypeManager.InitCoreTypes ()) + return false; + + TypeManager.InitOptionalCoreTypes (); + if (timestamps) ShowTime (" Core Types done"); - CodeGen.Module.ResolveAttributes (); + CodeGen.Module.Resolve (); // // The second pass of the compiler @@ -1664,11 +1665,8 @@ namespace Mono.CSharp ShowTime ("Populate tree"); if (!RootContext.StdLib) RootContext.BootCorlib_PopulateCoreTypes (); - RootContext.PopulateTypes (); - TypeManager.InitCodeHelpers (); - RootContext.DefineTypes (); if (Report.Errors == 0 && @@ -1717,7 +1715,7 @@ namespace Mono.CSharp RootContext.CloseTypes (); PEFileKinds k = PEFileKinds.ConsoleApplication; - + switch (RootContext.Target) { case Target.Library: case Target.Module: @@ -1733,7 +1731,7 @@ namespace Mono.CSharp if (ep == null) { if (RootContext.MainClass != null) { - DeclSpace main_cont = RootContext.Tree.GetDecl (MemberName.FromDotted (RootContext.MainClass)); + DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace; if (main_cont == null) { Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); return false; @@ -1772,15 +1770,14 @@ namespace Mono.CSharp // Add Win32 resources // - CodeGen.Assembly.Builder.DefineVersionInfoResource (); - if (win32ResourceFile != null) { try { CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile); - } - catch (ArgumentException) { + } catch (ArgumentException) { Report.RuntimeMissingSupport (Location.Null, "resource embeding"); } + } else { + CodeGen.Assembly.Builder.DefineVersionInfoResource (); } if (win32IconFile != null) { @@ -1794,7 +1791,7 @@ namespace Mono.CSharp if (Report.Errors > 0) return false; - CodeGen.Save (output_file); + CodeGen.Save (output_file, want_debugging_support); if (timestamps) { ShowTime ("Saved output"); ShowTotalTime ("Total"); @@ -1890,7 +1887,7 @@ namespace Mono.CSharp public void Emit () { - CodeGen.Assembly.Builder.AddResourceFile (name, file, attribute); + CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute); } public string FileName { @@ -1942,7 +1939,11 @@ namespace Mono.CSharp { Report.Stderr = error; try { - return Driver.MainDriver (args) && Report.Errors == 0; + Driver d = Driver.Create (args); + if (d == null) + return false; + + return d.Compile () && Report.Errors == 0; } finally { Report.Stderr = Console.Error; @@ -1959,14 +1960,20 @@ namespace Mono.CSharp static void Reset () { Driver.Reset (); - Location.Reset (); RootContext.Reset (); + Tokenizer.Reset (); + Location.Reset (); Report.Reset (); TypeManager.Reset (); TypeHandle.Reset (); RootNamespace.Reset (); NamespaceEntry.Reset (); CodeGen.Reset (); + Attribute.Reset (); + AttributeTester.Reset (); + AnonymousTypeClass.Reset (); + AnonymousMethodBody.Reset (); + AnonymousMethodStorey.Reset (); } } }