2 // driver.cs: The compiler command line driver.
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
5 // Based on mcs by : Miguel de Icaza (miguel@gnu.org)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2002 Rafael Teixeira
12 namespace Mono.Languages
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections;
19 using System.Globalization;
21 using Mono.GetOptions;
25 Library, Exe, Module, WinExe
34 /// The compiler driver.
36 public class Driver : Options
39 //------------------------------------------------------------------
40 [Option("[Mono] Only parses the source file (for debugging the tokenizer)", "parse")]
41 public bool parse_only = false;
43 [Option("[Mono] Only tokenizes source files")]
44 public bool tokenize = false;
46 [Option("[Mono] Shows stack trace at Error location")]
47 public bool stacktrace { set { Report.Stacktrace = value; } }
49 [Option("[Mono] Displays time stamps of various compiler events")]
55 last_time = DateTime.Now;
56 debug_arglist.Add("timestamp");
60 // Mono-specific options
61 //------------------------------------------------------------------
62 [Option("About the MonoBASIC compiler", "about")]
63 public override WhatToDoNext DoAbout()
65 return base.DoAbout();
68 [Option("[Mono] Don\'t assume the standard library", "nostdlib")]
69 public bool NoStandardLibraries { set { RootContext.StdLib = !value; } }
71 [Option("[Mono] Disables implicit references to assemblies", "noconfig")]
72 public bool NoConfig { set { load_default_config = !value; } }
74 [Option("[Mono] Allows unsafe code", "unsafe")]
75 public bool AllowUnsafeCode { set { RootContext.Unsafe = value; } }
77 [Option("[Mono] Set default context to checked", "checked")]
78 public bool Checked { set { RootContext.Checked = value; } }
80 [Option("[Mono] Debugger {arguments}", "debug-args")]
81 public WhatToDoNext SetDebugArgs(string args)
84 debug_arglist.AddRange (args.Split (sep));
85 return WhatToDoNext.GoAhead;
88 [Option("[Mono] Ignores warning number {XXXX}", "ignorewarn")]
89 public WhatToDoNext SetIgnoreWarning(int warn)
91 Report.SetIgnoreWarning(warn);
92 return WhatToDoNext.GoAhead;
95 [Option("[Mono] Sets warning {level} (the highest is 4, the default)", "wlevel")]
96 public int WarningLevel { set { RootContext.WarningLevel = value; } }
98 [Option("[Mono] Makes errors fatal", "fatal")]
99 public bool Fatal { set { Report.Fatal = value; } }
101 // Output file options
102 //------------------------------------------------------------------
103 [Option("Specifies the output {file} name", 'o', "out")]
104 public string OutputFileName = null;
106 [Option("Specifies the target {type} for the output file (exe [default], winexe, library, module)", "target")]
107 public WhatToDoNext SetTarget(string type)
109 switch (type.ToLower())
112 target = Target.Library;
121 target = Target.WinExe;
125 target = Target.Module;
129 return WhatToDoNext.GoAhead;
132 // input file options
133 //------------------------------------------------------------------
134 public ArrayList AddedModules = new ArrayList();
136 [Option("[NOT IMPLEMENTED YET]References metadata from specified {module}", "addmodule")]
137 public string AddedModule { set { AddedModules.Add(value); } }
139 [Option("[NOT IMPLEMENTED YET]Include all files in the current directory and subdirectories according to the {wildcard}", "recurse")]
140 public WhatToDoNext Recurse(string wildcard)
142 //AddFiles (DirName, true); // TODO wrong semantics
143 return WhatToDoNext.GoAhead;
146 [Option(-1, "References metadata from the specified {assembly}", 'r', "reference")]
147 public string AddedReference { set { references.Add(value); } }
150 //------------------------------------------------------------------
151 public ArrayList EmbeddedResources = new ArrayList();
153 [Option(-1, "Adds the specified {file} as an embedded assembly resource", "resource", "res")]
154 public string AddedResource { set { EmbeddedResources.Add(value); } }
156 public ArrayList LinkedResources = new ArrayList();
158 [Option(-1, "[NOT IMPLEMENTED YET]Adds the specified {file} as a linked assembly resource", "linkresource", "linkres")]
159 public string AddedLinkresource { set { LinkedResources.Add(value); } }
161 public ArrayList Win32Resources = new ArrayList();
163 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 resource {file} (.res)", "win32resource")]
164 public string AddedWin32resource { set { Win32Resources.Add(value); } }
166 public ArrayList Win32Icons = new ArrayList();
168 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 icon {file} (.ico) for the default Win32 resources", "win32icon")]
169 public string AddedWin32icon { set { Win32Icons.Add(value); } }
171 // code generation options
172 //------------------------------------------------------------------
173 [Option("[NOT IMPLEMENTED YET]Enable optimizations", "optimize")]
174 public bool optimize = false;
176 [Option("[NOT IMPLEMENTED YET]Remove integer checks. Default off.")]
177 public bool removeintchecks = false;
179 // TODO: handle VB.NET [+|-] boolean syntax
180 [Option("Emit debugging information", 'g', "debug")]
181 public bool want_debugging_support = false;
183 [Option("Emit full debugging information (default)", "debug:full")]
184 public bool fullDebugging = false;
186 [Option("[IGNORED]Emit PDB file only", "debug:pdbonly")]
187 public bool pdbOnly = false;
189 // errors and warnings options
190 //------------------------------------------------------------------
191 [Option("Treat warnings as errors", "warnaserror")]
192 public bool WarningsAreErrors { set { Report.WarningsAreErrors = value; } }
194 [Option("Disable warnings", "nowarn")]
195 public bool NoWarnings { set { if (value) RootContext.WarningLevel = 0; } }
199 //------------------------------------------------------------------
200 public Hashtable Defines = new Hashtable();
202 [Option(-1, "Declares global conditional compilation symbol(s). {symbol-list}:name=value,...", 'd', "define")]
203 public string define {
206 foreach(string item in value.Split(','))
208 string[] dados = item.Split('=');
211 if (dados.Length > 1)
212 Defines.Add(dados[0], dados[1]);
214 Defines.Add(dados[0], string.Empty);
218 Error ("Could not define symbol" + dados[0]);
224 private string[] importsList = null;
226 [Option("[NOT IMPLEMENTED YET]Declare global Imports for namespaces in referenced metadata files. {import-list}:namespace,...", "imports")]
227 public WhatToDoNext imports(string importslist)
229 importsList = importslist.Split(',');
230 return WhatToDoNext.GoAhead;
233 // TODO: handle VB.NET [+|-] boolean syntax
234 [Option("[NOT IMPLEMENTED YET]Require explicit declaration of variables")]
235 public bool optionexplicit { set { Mono.MonoBASIC.Parser.InitialOptionExplicit = value; } }
237 // TODO: handle VB.NET [+|-] boolean syntax
238 [Option("[NOT IMPLEMENTED YET]Enforce strict language semantics")]
239 public bool optionstrict { set { Mono.MonoBASIC.Parser.InitialOptionStrict = value; } }
241 [Option("[NOT IMPLEMENTED YET]Specifies binary-style string comparisons. This is the default", "optioncompare:binary")]
242 public bool optioncomparebinary { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = true; } }
244 [Option("[NOT IMPLEMENTED YET]Specifies text-style string comparisons.", "optioncompare:text")]
245 public bool optioncomparetext { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = false; } }
247 [Option("Specifies de root {namespace} for all type declarations")]
248 public string rootnamespace { set { RootContext.RootNamespace = value; } }
250 // Miscellaneous options
251 //------------------------------------------------------------------
253 [Option("[IGNORED]Do not display compiler copyright banner")]
254 public bool nologo = false;
256 [Option("[NOT IMPLEMENTED YET]Quiet output mode")]
257 public bool quiet = false;
259 // TODO: semantics are different and should be adjusted
260 [Option("Display verbose messages", 'v')]
261 public bool verbose { set { GenericParser.yacc_verbose_flag = value; } }
264 //------------------------------------------------------------------
265 // TODO: force option to accept number in hex format
266 [Option("[NOT IMPLEMENTED YET]The base {address} for a library or module (hex)")]
267 public int baseaddress;
269 [Option("[NOT IMPLEMENTED YET]Create bug report {file}")]
270 public string bugreport;
272 // TODO: handle VB.NET [+|-] boolean syntax
273 [Option("[NOT IMPLEMENTED YET]Delay-sign the assembly using only the public portion of the strong name key")]
274 public bool delaysign;
276 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key {container}")]
277 public string keycontainer;
279 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key {file}")]
280 public string keyfile;
282 public string[] libpath = null;
284 [Option("List of directories to search for metadata references {path-list}:path;...", "libpath")]
285 public WhatToDoNext setlibpath(string pathlist)
287 libpath = pathlist.Split(';');
288 return WhatToDoNext.GoAhead;
291 [Option(@"Specifies the Class or Module that contains Sub Main.
292 It can also be a {class} that inherits from System.Windows.Forms.Form.",
294 public string main { set { RootContext.MainClass = value; } }
296 // TODO: handle VB.NET [+|-] boolean syntax
297 [Option("[IGNORED]Emit compiler output in UTF8 character encoding")]
298 public bool utf8output;
300 // TODO : response file support
302 ArrayList defines = new ArrayList();
303 ArrayList references = new ArrayList();
304 ArrayList soft_references = new ArrayList();
305 string first_source = null;
306 Target target = Target.Exe;
307 string target_ext = ".exe";
308 ArrayList debug_arglist = new ArrayList ();
309 bool timestamps = false;
310 Hashtable source_files = new Hashtable ();
311 bool load_default_config = true;
314 // Last time we took the time
317 void ShowTime (string msg)
319 DateTime now = DateTime.Now;
320 TimeSpan span = now - last_time;
324 "[{0:00}:{1:000}] {2}",
325 (int) span.TotalSeconds, span.Milliseconds, msg);
328 public int LoadAssembly (string assembly, bool soft)
331 string total_log = "";
335 char[] path_chars = { '/', '\\' };
337 if (assembly.IndexOfAny (path_chars) != -1)
338 a = Assembly.LoadFrom(assembly);
340 a = Assembly.Load(assembly);
341 TypeManager.AddAssembly (a);
344 catch (FileNotFoundException)
348 foreach (string dir in libpath)
350 string full_path = dir + "/" + assembly + ".dll";
354 a = Assembly.LoadFrom (full_path);
355 TypeManager.AddAssembly (a);
358 catch (FileNotFoundException ff)
360 total_log += ff.FusionLog;
368 catch (BadImageFormatException f)
370 Error ("// Bad file format while loading assembly");
371 Error ("Log: " + f.FusionLog);
373 } catch (FileLoadException f){
374 Error ("File Load Exception: " + assembly);
375 Error ("Log: " + f.FusionLog);
377 } catch (ArgumentNullException){
378 Error ("// Argument Null exception ");
382 Report.Error (6, "Can not find assembly `" + assembly + "'" );
383 Console.WriteLine ("Log: \n" + total_log);
388 void Error(string message)
390 Console.WriteLine(message);
394 /// Loads all assemblies referenced on the command line
396 public int LoadReferences ()
400 foreach (string r in references)
401 errors += LoadAssembly (r, false);
403 foreach (string r in soft_references)
404 errors += LoadAssembly (r, true);
409 void SetupDefaultDefines ()
411 defines = new ArrayList ();
412 defines.Add ("__MonoBASIC__");
417 // Returns the directory where the system assemblies are installed
419 string GetSystemDir ()
421 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
423 foreach (Assembly a in assemblies){
424 string codebase = a.CodeBase;
425 if (codebase.EndsWith ("corlib.dll")){
426 return codebase.Substring (0, codebase.LastIndexOf ("/"));
430 Report.Error (-15, "Can not compute my system path");
435 // Given a path specification, splits the path from the file/pattern
437 void SplitPathAndPattern (string spec, out string path, out string pattern)
439 int p = spec.LastIndexOf ("/");
442 // Windows does not like /file.cs, switch that to:
447 pattern = spec.Substring (1);
449 path = spec.Substring (0, p);
450 pattern = spec.Substring (p + 1);
455 p = spec.LastIndexOf ("\\");
457 path = spec.Substring (0, p);
458 pattern = spec.Substring (p + 1);
466 bool AddFiles (string spec, bool recurse)
468 string path, pattern;
470 SplitPathAndPattern(spec, out path, out pattern);
471 if (pattern.IndexOf("*") == -1)
477 string [] files = null;
479 files = Directory.GetFiles(path, pattern);
480 } catch (System.IO.DirectoryNotFoundException) {
481 Report.Error (2001, "Source file `" + spec + "' could not be found");
483 } catch (System.IO.IOException){
484 Report.Error (2001, "Source file `" + spec + "' could not be found");
487 foreach (string f in files)
493 string [] dirs = null;
496 dirs = Directory.GetDirectories(path);
500 foreach (string d in dirs) {
502 // Don't include path in this string, as each
503 // directory entry already does
504 AddFiles (d + "/" + pattern, true);
510 void DefineDefaultConfig ()
513 // For now the "default config" is harcoded into the compiler
514 // we can move this outside later
516 string [] default_config =
521 "Microsoft.VisualBasic" ,
522 #if EXTRA_DEFAULT_REFS
524 // Is it worth pre-loading all this stuff?
527 "System.Configuration.Install",
529 "System.DirectoryServices",
530 "System.Drawing.Design",
532 "System.EnterpriseServices",
535 "System.Runtime.Remoting",
536 "System.Runtime.Serialization.Formatters.Soap",
538 "System.ServiceProcess",
540 "System.Web.RegularExpressions",
541 "System.Web.Services" ,
542 "System.Windows.Forms"
546 foreach (string def in default_config)
547 soft_references.Add(def);
551 public void AddFile(string fileName)
554 if (first_source == null)
557 if (source_files.Contains(f))
558 Report.Error(1516, "Source file '" + f + "' specified multiple times");
560 source_files.Add(f, f);
563 void ProcessSourceFile(string filename)
566 GenericParser.Tokenize(filename);
568 GenericParser.Parse(filename);
571 string outputFile_Name = null;
573 string outputFileName
577 if (outputFile_Name == null)
579 if (OutputFileName == null)
581 int pos = first_source.LastIndexOf(".");
584 OutputFileName = first_source.Substring(0, pos);
586 OutputFileName = first_source;
588 string bname = CodeGen.Basename(OutputFileName);
589 if (bname.IndexOf(".") == -1)
590 OutputFileName += target_ext;
591 outputFile_Name = OutputFileName;
593 return outputFile_Name;
597 bool ParseAll() // Phase 1
599 if (first_source == null)
601 Report.Error(2008, "No files to compile were specified");
605 foreach(string filename in source_files.Values)
606 ProcessSourceFile(filename);
608 if (tokenize || parse_only || (Report.Errors > 0))
611 return true; // everything went well go ahead
614 void InitializeDebuggingSupport()
616 string[] debug_args = new string [debug_arglist.Count];
617 debug_arglist.CopyTo(debug_args);
618 CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
619 TypeManager.AddModule(CodeGen.ModuleBuilder);
622 public bool ResolveAllTypes() // Phase 2
624 // Load Core Library for default compilation
625 if (RootContext.StdLib)
626 references.Insert(0, "mscorlib");
628 if (load_default_config)
629 DefineDefaultConfig();
632 ShowTime("Loading references");
634 // Load assemblies required
635 if (LoadReferences() > 0)
637 Error ("Could not load one or more assemblies");
642 ShowTime("References loaded");
644 InitializeDebuggingSupport();
647 // Before emitting, we need to get the core
648 // types emitted from the user defined types
649 // or from the system ones.
652 ShowTime ("Initializing Core Types");
654 if (!RootContext.StdLib)
655 RootContext.ResolveCore ();
656 if (Report.Errors > 0)
659 TypeManager.InitCoreTypes();
660 if (Report.Errors > 0)
664 ShowTime (" Core Types done");
667 ShowTime ("Resolving tree");
669 // The second pass of the compiler
670 RootContext.ResolveTree ();
671 if (Report.Errors > 0)
675 ShowTime ("Populate tree");
677 if (!RootContext.StdLib)
678 RootContext.BootCorlib_PopulateCoreTypes();
679 if (Report.Errors > 0)
682 RootContext.PopulateTypes();
683 if (Report.Errors > 0)
686 TypeManager.InitCodeHelpers();
687 if (Report.Errors > 0)
695 bool hasSWF = false, isForm = false;
696 string mainclass = GetFQMainClass();
698 foreach (string r in references) {
699 if (r.IndexOf ("System.Windows.Forms") >= 0) {
704 if (mainclass != ".") {
705 Type t = TypeManager.LookupType(mainclass);
707 isForm = t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
709 return (hasSWF && isForm);
712 string GetFQMainClass()
714 if (RootContext.RootNamespace != "")
715 return RootContext.RootNamespace + "." + RootContext.MainClass;
717 return RootContext.MainClass;
722 if (target == Target.Exe || target == Target.WinExe)
724 MethodInfo ep = RootContext.EntryPoint;
728 // If we don't have a valid entry point yet
729 // AND if System.Windows.Forms is included
730 // among the dependencies, we have to build
731 // a new entry point on-the-fly. Otherwise we
732 // won't be able to compile SWF code out of the box.
736 Type t = TypeManager.LookupType(GetFQMainClass());
739 TypeBuilder tb = t as TypeBuilder;
740 MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
741 typeof(void), new Type[0]);
743 Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
744 Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
745 Type[] args = new Type[1];
747 MethodInfo mi = SWFA.GetMethod("Run", args);
748 ILGenerator ig = mb.GetILGenerator();
749 ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
751 ig.Emit (OpCodes.Newobj, ci);
752 ig.Emit (OpCodes.Call, mi);
753 ig.Emit (OpCodes.Ret);
755 RootContext.EntryPoint = mb as MethodInfo;
762 bool GenerateAssembly()
765 // The code generator
768 ShowTime ("Emitting code");
772 RootContext.EmitCode();
774 if (Report.Errors > 0)
782 ShowTime ("Closing types");
784 RootContext.CloseTypes ();
785 if (Report.Errors > 0)
791 PEFileKinds k = PEFileKinds.ConsoleApplication;
793 if (target == Target.Library || target == Target.Module)
795 else if (target == Target.Exe)
796 k = PEFileKinds.ConsoleApplication;
797 else if (target == Target.WinExe)
798 k = PEFileKinds.WindowApplication;
800 if (target == Target.Exe || target == Target.WinExe)
802 MethodInfo ep = RootContext.EntryPoint;
806 Report.Error (5001, "Program " + outputFileName +
807 " does not have an entry point defined");
811 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
815 if (EmbeddedResources != null)
816 foreach (string file in EmbeddedResources)
817 CodeGen.AssemblyBuilder.AddResourceFile (file, file);
819 CodeGen.Save(outputFileName);
822 ShowTime ("Saved output");
825 if (want_debugging_support)
827 CodeGen.SaveSymbols ();
829 ShowTime ("Saved symbols");
835 public void CompileAll()
838 VB.NET expects the default namespace to be "" (empty string)
840 if (RootContext.RootNamespace == "")
842 RootContext.RootNamespace = System.IO.Path.GetFileNameWithoutExtension(outputFileName);
845 if (!ParseAll()) // Phase 1
848 if (!ResolveAllTypes()) // Phase 2
851 GenerateAssembly(); // Phase 3
855 /// Parses the arguments, and calls the compilation process.
857 int MainDriver(string [] args)
859 SetupDefaultDefines();
863 if (first_source == null)
872 return Report.ProcessResults(quiet);
875 public static int Main (string[] args)
877 Driver Exec = new Driver();
879 Report.Stacktrace = false;
881 return Exec.MainDriver(args);