2 // driver.cs: The compiler command line driver.
\r
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
\r
5 // Based on mcs by : Miguel de Icaza (miguel@gnu.org)
\r
7 // Licensed under the terms of the GNU GPL
\r
9 // (C) 2002 Rafael Teixeira
\r
12 namespace Mono.Languages
\r
15 using System.Reflection;
\r
16 using System.Reflection.Emit;
\r
17 using System.Collections;
\r
19 using System.Globalization;
\r
21 using Mono.GetOptions;
\r
25 Library, Exe, Module, WinExe
\r
34 /// The compiler driver.
\r
36 public class Driver : Options
\r
38 // Temporary options
\r
39 //------------------------------------------------------------------
\r
40 [Option("[Mono] Only parses the source file (for debugging the tokenizer)", "parse")]
\r
41 public bool parse_only = false;
\r
43 [Option("[Mono] Only tokenizes source files")]
\r
44 public bool tokenize = false;
\r
46 [Option("[Mono] Shows stack trace at Error location")]
\r
47 public bool stacktrace { set { Report.Stacktrace = value; } }
\r
49 [Option("[Mono] Displays time stamps of various compiler events")]
\r
50 public bool timestamp
\r
55 last_time = DateTime.Now;
\r
56 debug_arglist.Add("timestamp");
\r
60 // Mono-specific options
\r
61 //------------------------------------------------------------------
\r
62 [Option("About the MonoBASIC compiler", "about")]
\r
63 public override WhatToDoNext DoAbout()
\r
65 return base.DoAbout();
\r
68 [Option("[Mono] Don\'t assume the standard library", "nostdlib")]
\r
69 public bool nostdlib { set { RootContext.StdLib = !value; } }
\r
71 [Option("[Mono] Disables implicit references to assemblies", "noconfig")]
\r
72 public bool NoConfig { set { load_default_config = !value; } }
\r
74 [Option("[Mono] Allows unsafe code", "unsafe")]
\r
75 public bool AllowUnsafeCode { set { RootContext.Unsafe = value; } }
\r
77 [Option("[Mono] Set default context to checked", "checked")]
\r
78 public bool Checked { set { RootContext.Checked = value; } }
\r
80 [Option("[Mono] Debugger arguments", "debug-args")]
\r
81 public WhatToDoNext SetDebugArgs(string args)
\r
83 char[] sep = { ',' };
\r
84 debug_arglist.AddRange (args.Split (sep));
\r
85 return WhatToDoNext.GoAhead;
\r
88 [Option("[Mono] Ignores warning number PARAM", "ignorewarn")]
\r
89 public WhatToDoNext SetIgnoreWarning(int warn)
\r
91 Report.SetIgnoreWarning(warn);
\r
92 return WhatToDoNext.GoAhead;
\r
95 [Option("[Mono] Sets warning level (the highest is 4, the default)", "wlevel")]
\r
96 public int wlevel { set { RootContext.WarningLevel = value; } }
\r
98 [Option("[Mono] Makes errors fatal", "fatal")]
\r
99 public bool Fatal { set { Report.Fatal = value; } }
\r
101 [Option("[Mono] Adds path to the assembly link path")]
\r
102 public string[] linkpaths = null;
\r
104 // Output file options
\r
105 //------------------------------------------------------------------
\r
106 [Option("Specifies the output file name", 'o', "out")]
\r
107 public string output_file = null;
\r
109 [Option("Specifies the target type for the output file (exe [default], winexe, library, module)", "target")]
\r
110 public WhatToDoNext SetTarget(string type)
\r
112 switch (type.ToLower())
\r
115 target = Target.Library;
\r
116 target_ext = ".dll";
\r
120 target = Target.Exe;
\r
124 target = Target.WinExe;
\r
128 target = Target.Module;
\r
129 target_ext = ".dll";
\r
132 return WhatToDoNext.GoAhead;
\r
135 // input file options
\r
136 //------------------------------------------------------------------
\r
137 [Option("[NOT IMPLEMENTED YET]Reference metadata from specified module", "addmodule")]
\r
138 public string[] addedModules = null;
\r
140 [Option("[NOT IMPLEMENTED YET]Include all files in the current directory and subdirectories according to the wildcard", "recurse")]
\r
141 public WhatToDoNext recurse(string wildcard)
\r
143 //AddFiles (DirName, true); // TODO wrong semantics
\r
144 return WhatToDoNext.GoAhead;
\r
147 [Option(-1, "References metadata from the specified assembly", 'r', "reference")]
\r
148 public string reference { set { references.Add(value); } }
\r
150 // resource options
\r
151 //------------------------------------------------------------------
\r
152 public ArrayList EmbeddedResources = new ArrayList();
\r
154 // TODO : accept a multi-letter short form: 'res'
\r
155 [Option(-1, "Adds the specified file as an embedded assembly resource", "resource")]
\r
156 public string resource { set { EmbeddedResources.Add(value); } }
\r
158 public ArrayList LinkedResources = new ArrayList();
\r
160 // TODO : accept a multi-letter short form: 'linkres'
\r
161 [Option(-1, "[NOT IMPLEMENTED YET]Adds the specified file as an embedded assembly resource", "linkresource")]
\r
162 public string linkresource { set { LinkedResources.Add(value); } }
\r
164 public ArrayList Win32Resources = new ArrayList();
\r
166 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 resource file (.res)", "win32resource")]
\r
167 public string win32resource { set { Win32Resources.Add(value); } }
\r
169 public ArrayList Win32Icons = new ArrayList();
\r
171 // TODO : accept a multi-letter short form: 'res'
\r
172 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 icon file (.ico) for the default Win32 resources", "win32icon")]
\r
173 public string win32icon { set { Win32Icons.Add(value); } }
\r
176 // code generation options
\r
177 //------------------------------------------------------------------
\r
178 [Option("[NOT IMPLEMENTED YET]Enable optimizations")]
\r
179 public bool optimize = false;
\r
181 [Option("[NOT IMPLEMENTED YET]Remove integer checks. Default off.")]
\r
182 public bool removeintchecks = false;
\r
184 // TODO: handle VB.NET [+|-] boolean syntax
\r
185 [Option("Emit debugging information", "debug")]
\r
186 public bool want_debugging_support = false;
\r
188 [Option("Emit full debugging information (default)", "debug:full")]
\r
189 public bool fullDebugging = false;
\r
191 [Option("[IGNORED]Emit PDB file only", "debug:pdbonly")]
\r
192 public bool pdbOnly = false;
\r
194 // errors and warnings options
\r
195 //------------------------------------------------------------------
\r
196 [Option("Treat warnings as errors", "warnaserror")]
\r
197 public bool WarningsAreErrors { set { Report.WarningsAreErrors = value; } }
\r
199 [Option("Disable warnings")]
\r
200 public bool nowarn { set { if (value) RootContext.WarningLevel = 0; } }
\r
203 // language options
\r
204 //------------------------------------------------------------------
\r
205 public Hashtable Defines = new Hashtable();
\r
207 // TODO: Symbol-List parsing
\r
208 [Option(-1, "[NOT IMPLEMENTED YET]Declares global conditional compilation symbol(s). symbol list:name=value,...", 'd', "define")]
\r
209 public string define {
\r
211 foreach(string item in value.Split(',')) {
\r
212 string[] dados = item.Split('=');
\r
213 if (dados.Length > 1)
\r
214 Defines.Add(dados[0], dados[1]);
\r
216 Defines.Add(dados[0], string.Empty);
\r
221 private string[] importsList = null;
\r
223 [Option("[NOT IMPLEMENTED YET]Declare global Imports for namespaces in referenced metadata files. import list:namespace,...", "imports")]
\r
224 public WhatToDoNext imports(string importslist)
\r
226 importsList = importslist.Split(';');
\r
227 return WhatToDoNext.GoAhead;
\r
230 // TODO: handle VB.NET [+|-] boolean syntax
\r
231 [Option("[NOT IMPLEMENTED YET]Require explicit declaration of variables")]
\r
232 public bool optionexplicit = false;
\r
234 // TODO: handle VB.NET [+|-] boolean syntax
\r
235 [Option("[NOT IMPLEMENTED YET]Enforce strict language semantics")]
\r
236 public bool optionstrict = false;
\r
238 [Option("Specifies de root namespace for all type declarations")]
\r
239 public string rootnamespace { set { RootContext.RootNamespace = value; } }
\r
241 private OptionCompare optioncompare = OptionCompare.Binary;
\r
243 [Option("[NOT IMPLEMENTED YET]Specifies binary-style string comparisons. This is the default", "optioncompare:binary")]
\r
244 public bool optioncomparebinary { set { optioncompare = OptionCompare.Binary; } }
\r
246 [Option("[NOT IMPLEMENTED YET]Specifies text-style string comparisons.", "optioncompare:text")]
\r
247 public bool optioncomparetext { set { optioncompare = OptionCompare.Text; } }
\r
249 // Miscellaneous options
\r
250 //------------------------------------------------------------------
\r
252 [Option("[NOT IMPLEMENTED YET]Do not display compiler copyright banner")]
\r
253 public bool nologo = false;
\r
255 [Option("[NOT IMPLEMENTED YET]Quiet output mode")]
\r
256 public bool quiet = false;
\r
258 // TODO: semantics are different and should be adjusted
\r
259 [Option("Display verbose messages", 'v')]
\r
260 public bool verbose { set { GenericParser.yacc_verbose_flag = value; } }
\r
262 // Advanced options
\r
263 //------------------------------------------------------------------
\r
264 // TODO: force option to accept number in hex format
\r
265 [Option("[NOT IMPLEMENTED YET]The base address for a library or module (hex)")]
\r
266 public int baseaddress;
\r
268 [Option("[NOT IMPLEMENTED YET]Create bug report file")]
\r
269 public string bugreport;
\r
271 // TODO: handle VB.NET [+|-] boolean syntax
\r
272 [Option("[NOT IMPLEMENTED YET]Delay-sign the assembly using only the public portion of the strong name key")]
\r
273 public bool delaysign;
\r
275 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key container")]
\r
276 public string keycontainer;
\r
278 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key file")]
\r
279 public string keyfile;
\r
281 public string[] libpath = null;
\r
283 [Option("[NOT IMPLEMENTED YET]List of directories to search for metada references (semi-colon delimited)", "libpath")]
\r
284 public WhatToDoNext setlibpath(string pathlist)
\r
286 libpath = pathlist.Split(';');
\r
287 return WhatToDoNext.GoAhead;
\r
290 [Option("Specifies the Class or Module that contains Sub Main.It can also be a Class that inherits from System.Windows.Forms.Form.", 'm', "main")]
\r
291 public string main { set { RootContext.MainClass = value; } }
\r
293 // TODO: handle VB.NET [+|-] boolean syntax
\r
294 [Option("[NOT IMPLEMENTED YET]Emit compiler output in UTF8 character encoding")]
\r
295 public bool utf8output;
\r
297 // TODO : response file support
\r
299 ArrayList defines = new ArrayList();
\r
300 ArrayList references = new ArrayList();
\r
301 ArrayList soft_references = new ArrayList();
\r
302 string first_source = null;
\r
303 Target target = Target.Exe;
\r
304 string target_ext = ".exe";
\r
305 ArrayList debug_arglist = new ArrayList ();
\r
306 bool timestamps = false;
\r
307 Hashtable source_files = new Hashtable ();
\r
308 bool load_default_config = true;
\r
311 // Last time we took the time
\r
313 DateTime last_time;
\r
314 void ShowTime (string msg)
\r
316 DateTime now = DateTime.Now;
\r
317 TimeSpan span = now - last_time;
\r
320 Console.WriteLine (
\r
321 "[{0:00}:{1:000}] {2}",
\r
322 (int) span.TotalSeconds, span.Milliseconds, msg);
\r
325 public static int Main (string[] args)
\r
327 Driver Exec = new Driver();
\r
329 return Exec.MainDriver(args);
\r
332 public int LoadAssembly (string assembly, bool soft)
\r
335 string total_log = "";
\r
338 char[] path_chars = { '/', '\\' };
\r
340 if (assembly.IndexOfAny (path_chars) != -1)
\r
341 a = Assembly.LoadFrom(assembly);
\r
343 a = Assembly.Load(assembly);
\r
344 TypeManager.AddAssembly (a);
\r
346 } catch (FileNotFoundException){
\r
347 foreach (string dir in linkpaths){
\r
348 string full_path = dir + "/" + assembly + ".dll";
\r
351 a = Assembly.LoadFrom (full_path);
\r
352 TypeManager.AddAssembly (a);
\r
354 } catch (FileNotFoundException ff) {
\r
355 total_log += ff.FusionLog;
\r
361 } catch (BadImageFormatException f) {
\r
362 Error ("// Bad file format while loading assembly");
\r
363 Error ("Log: " + f.FusionLog);
\r
365 } catch (FileLoadException f){
\r
366 Error ("File Load Exception: " + assembly);
\r
367 Error ("Log: " + f.FusionLog);
\r
369 } catch (ArgumentNullException){
\r
370 Error ("// Argument Null exception ");
\r
374 Report.Error (6, "Can not find assembly `" + assembly + "'" );
\r
375 Console.WriteLine ("Log: \n" + total_log);
\r
380 void Error(string message)
\r
382 Console.WriteLine(message);
\r
386 /// Loads all assemblies referenced on the command line
\r
388 public int LoadReferences ()
\r
392 foreach (string r in references)
\r
393 errors += LoadAssembly (r, false);
\r
395 foreach (string r in soft_references)
\r
396 errors += LoadAssembly (r, true);
\r
401 void SetupDefaultDefines ()
\r
403 defines = new ArrayList ();
\r
404 defines.Add ("__MonoBASIC__");
\r
409 // Returns the directory where the system assemblies are installed
\r
411 string GetSystemDir ()
\r
413 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
\r
415 foreach (Assembly a in assemblies){
\r
416 string codebase = a.CodeBase;
\r
417 if (codebase.EndsWith ("corlib.dll")){
\r
418 return codebase.Substring (0, codebase.LastIndexOf ("/"));
\r
422 Report.Error (-15, "Can not compute my system path");
\r
427 // Given a path specification, splits the path from the file/pattern
\r
429 void SplitPathAndPattern (string spec, out string path, out string pattern)
\r
431 int p = spec.LastIndexOf ("/");
\r
434 // Windows does not like /file.cs, switch that to:
\r
439 pattern = spec.Substring (1);
\r
441 path = spec.Substring (0, p);
\r
442 pattern = spec.Substring (p + 1);
\r
447 p = spec.LastIndexOf ("\\");
\r
449 path = spec.Substring (0, p);
\r
450 pattern = spec.Substring (p + 1);
\r
458 bool AddFiles (string spec, bool recurse)
\r
460 string path, pattern;
\r
462 SplitPathAndPattern(spec, out path, out pattern);
\r
463 if (pattern.IndexOf("*") == -1)
\r
469 string [] files = null;
\r
471 files = Directory.GetFiles(path, pattern);
\r
472 } catch (System.IO.DirectoryNotFoundException) {
\r
473 Report.Error (2001, "Source file `" + spec + "' could not be found");
\r
475 } catch (System.IO.IOException){
\r
476 Report.Error (2001, "Source file `" + spec + "' could not be found");
\r
479 foreach (string f in files)
\r
485 string [] dirs = null;
\r
488 dirs = Directory.GetDirectories(path);
\r
492 foreach (string d in dirs) {
\r
494 // Don't include path in this string, as each
\r
495 // directory entry already does
\r
496 AddFiles (d + "/" + pattern, true);
\r
502 void DefineDefaultConfig ()
\r
505 // For now the "default config" is harcoded into the compiler
\r
506 // we can move this outside later
\r
508 string [] default_config =
\r
513 "Microsoft.VisualBasic" ,
\r
514 #if EXTRA_DEFAULT_REFS
\r
516 // Is it worth pre-loading all this stuff?
\r
519 "System.Configuration.Install",
\r
521 "System.DirectoryServices",
\r
522 "System.Drawing.Design",
\r
524 "System.EnterpriseServices",
\r
525 "System.Management",
\r
526 "System.Messaging",
\r
527 "System.Runtime.Remoting",
\r
528 "System.Runtime.Serialization.Formatters.Soap",
\r
530 "System.ServiceProcess",
\r
532 "System.Web.RegularExpressions",
\r
533 "System.Web.Services" ,
\r
534 "System.Windows.Forms"
\r
538 foreach (string def in default_config)
\r
539 soft_references.Add(def);
\r
542 [ArgumentProcessor]
\r
543 public void AddFile(string fileName)
\r
545 string f = fileName;
\r
546 if (first_source == null)
\r
549 if (source_files.Contains(f))
\r
550 Report.Error(1516, "Source file '" + f + "' specified multiple times");
\r
552 source_files.Add(f, f);
\r
555 void ProcessSourceFile(string filename)
\r
558 GenericParser.Tokenize(filename);
\r
560 GenericParser.Parse(filename);
\r
563 string outputFile_Name = null;
\r
565 string outputFileName
\r
569 if (outputFile_Name == null)
\r
571 if (output_file == null)
\r
573 int pos = first_source.LastIndexOf(".");
\r
576 output_file = first_source.Substring(0, pos);
\r
578 output_file = first_source;
\r
580 string bname = CodeGen.Basename(output_file);
\r
581 if (bname.IndexOf(".") == -1)
\r
582 output_file += target_ext;
\r
583 outputFile_Name = output_file;
\r
585 return outputFile_Name;
\r
590 /// Parses the arguments, and calls the compilation process.
\r
592 int MainDriver(string [] args)
\r
595 if (first_source == null)
\r
603 if (Report.Errors == 0)
\r
605 Console.Write("Compilation succeeded");
\r
606 if (Report.Warnings > 0)
\r
608 Console.Write(" - {0} warning(s)", Report.Warnings);
\r
610 Console.WriteLine();
\r
613 Console.WriteLine("Compilation failed: {0} Error(s), {1} warnings",
\r
614 Report.Errors, Report.Warnings);
\r
620 SetupDefaultDefines();
\r
623 bool ParseAll() // Phase 1
\r
625 if (first_source == null)
\r
627 Report.Error(2008, "No files to compile were specified");
\r
631 foreach(string filename in source_files.Values)
\r
632 ProcessSourceFile(filename);
\r
634 if (tokenize || parse_only || (Report.Errors > 0))
\r
637 return true; // everything went well go ahead
\r
640 void InitializeDebuggingSupport()
\r
642 string[] debug_args = new string [debug_arglist.Count];
\r
643 debug_arglist.CopyTo(debug_args);
\r
644 CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
\r
645 TypeManager.AddModule(CodeGen.ModuleBuilder);
\r
648 public bool ResolveAllTypes() // Phase 2
\r
650 // Load Core Library for default compilation
\r
651 if (RootContext.StdLib)
\r
652 references.Insert(0, "mscorlib");
\r
654 if (load_default_config)
\r
655 DefineDefaultConfig();
\r
658 ShowTime("Loading references");
\r
660 // Load assemblies required
\r
661 if (LoadReferences() > 0)
\r
663 Error ("Could not load one or more assemblies");
\r
668 ShowTime("References loaded");
\r
670 InitializeDebuggingSupport();
\r
673 // Before emitting, we need to get the core
\r
674 // types emitted from the user defined types
\r
675 // or from the system ones.
\r
678 ShowTime ("Initializing Core Types");
\r
680 if (!RootContext.StdLib)
\r
681 RootContext.ResolveCore ();
\r
682 if (Report.Errors > 0)
\r
685 TypeManager.InitCoreTypes();
\r
686 if (Report.Errors > 0)
\r
690 ShowTime (" Core Types done");
\r
693 ShowTime ("Resolving tree");
\r
695 // The second pass of the compiler
\r
696 RootContext.ResolveTree ();
\r
697 if (Report.Errors > 0)
\r
701 ShowTime ("Populate tree");
\r
703 if (!RootContext.StdLib)
\r
704 RootContext.BootCorlib_PopulateCoreTypes();
\r
705 if (Report.Errors > 0)
\r
708 RootContext.PopulateTypes();
\r
709 if (Report.Errors > 0)
\r
712 TypeManager.InitCodeHelpers();
\r
713 if (Report.Errors > 0)
\r
719 bool GenerateAssembly()
\r
722 // The code generator
\r
725 ShowTime ("Emitting code");
\r
727 RootContext.EmitCode();
\r
728 if (Report.Errors > 0)
\r
732 ShowTime (" done");
\r
736 ShowTime ("Closing types");
\r
738 RootContext.CloseTypes ();
\r
739 if (Report.Errors > 0)
\r
743 ShowTime (" done");
\r
745 PEFileKinds k = PEFileKinds.ConsoleApplication;
\r
747 if (target == Target.Library || target == Target.Module)
\r
748 k = PEFileKinds.Dll;
\r
749 else if (target == Target.Exe)
\r
750 k = PEFileKinds.ConsoleApplication;
\r
751 else if (target == Target.WinExe)
\r
752 k = PEFileKinds.WindowApplication;
\r
754 if (target == Target.Exe || target == Target.WinExe)
\r
756 MethodInfo ep = RootContext.EntryPoint;
\r
760 Report.Error (5001, "Program " + outputFileName +
\r
761 " does not have an entry point defined");
\r
765 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
\r
768 // Add the resources
\r
769 if (EmbeddedResources != null)
\r
770 foreach (string file in EmbeddedResources)
\r
771 CodeGen.AssemblyBuilder.AddResourceFile (file, file);
\r
773 CodeGen.Save(outputFileName);
\r
776 ShowTime ("Saved output");
\r
779 if (want_debugging_support)
\r
781 CodeGen.SaveSymbols ();
\r
783 ShowTime ("Saved symbols");
\r
789 public void CompileAll()
\r
792 if (RootContext.RootNamespace == "")
\r
794 RootContext.RootNamespace =
\r
795 System.IO.Path.GetFileNameWithoutExtension(outputFileName);
\r
798 if (!ParseAll()) // Phase 1
\r
801 if (!ResolveAllTypes()) // Phase 2
\r
804 if (!GenerateAssembly()) // Phase 3
\r
807 if (Report.ExpectedError != 0)
\r
808 Error("Failed to report expected Error " + Report.ExpectedError);
\r