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); } }
149 // support for the Compact Framework
150 //------------------------------------------------------------------
151 [Option("[NOT IMPLEMENTED YET]Sets the compiler to target the Compact Framework","netcf")]
152 public bool CompileForCompactFramework = false;
154 [Option("[NOT IMPLEMENTED YET]Specifies the {path} to the location of mscorlib.dll and microsoft.visualbasic.dll", "sdkpath")]
155 public string SDKPath = null;
158 //------------------------------------------------------------------
159 public ArrayList EmbeddedResources = new ArrayList();
161 [Option(-1, "Adds the specified {file} as an embedded assembly resource", "resource", "res")]
162 public string AddedResource { set { EmbeddedResources.Add(value); } }
164 public ArrayList LinkedResources = new ArrayList();
166 [Option(-1, "[NOT IMPLEMENTED YET]Adds the specified {file} as a linked assembly resource", "linkresource", "linkres")]
167 public string AddedLinkresource { set { LinkedResources.Add(value); } }
169 public ArrayList Win32Resources = new ArrayList();
171 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 resource {file} (.res)", "win32resource")]
172 public string AddedWin32resource { set { Win32Resources.Add(value); } }
174 public ArrayList Win32Icons = new ArrayList();
176 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 icon {file} (.ico) for the default Win32 resources", "win32icon")]
177 public string AddedWin32icon { set { Win32Icons.Add(value); } }
179 // code generation options
180 //------------------------------------------------------------------
181 [Option("[NOT IMPLEMENTED YET]Enable optimizations", "optimize")]
182 public bool optimize = false;
184 [Option("[NOT IMPLEMENTED YET]Remove integer checks. Default off.")]
185 public bool removeintchecks = false;
187 // TODO: handle VB.NET [+|-] boolean syntax
188 [Option("Emit debugging information", 'g', "debug")]
189 public bool want_debugging_support = false;
191 [Option("Emit full debugging information (default)", "debug:full")]
192 public bool fullDebugging = false;
194 [Option("[IGNORED]Emit PDB file only", "debug:pdbonly")]
195 public bool pdbOnly = false;
197 // errors and warnings options
198 //------------------------------------------------------------------
199 [Option("Treat warnings as errors", "warnaserror")]
200 public bool WarningsAreErrors { set { Report.WarningsAreErrors = value; } }
202 [Option("Disable warnings", "nowarn")]
203 public bool NoWarnings { set { if (value) RootContext.WarningLevel = 0; } }
207 //------------------------------------------------------------------
208 public Hashtable Defines = new Hashtable();
210 [Option(-1, "Declares global conditional compilation symbol(s). {symbol-list}:name=value,...", 'd', "define")]
211 public string define {
214 foreach(string item in value.Split(','))
216 string[] dados = item.Split('=');
219 if (dados.Length > 1)
220 Defines.Add(dados[0], dados[1]);
222 Defines.Add(dados[0], string.Empty);
226 Error ("Could not define symbol" + dados[0]);
232 [Option("Declare global Imports for namespaces in referenced metadata files. {import-list}:namespace,...", "imports")]
233 public WhatToDoNext imports(string importslist)
235 Mono.MonoBASIC.Parser.ImportsList.AddRange(importslist.Split(','));
236 return WhatToDoNext.GoAhead;
239 // TODO: handle VB.NET [+|-] boolean syntax
240 [Option("[NOT IMPLEMENTED YET]Require explicit declaration of variables")]
241 public bool optionexplicit { set { Mono.MonoBASIC.Parser.InitialOptionExplicit = value; } }
243 // TODO: handle VB.NET [+|-] boolean syntax
244 [Option("[NOT IMPLEMENTED YET]Enforce strict language semantics")]
245 public bool optionstrict { set { Mono.MonoBASIC.Parser.InitialOptionStrict = value; } }
247 [Option("[NOT IMPLEMENTED YET]Specifies binary-style string comparisons. This is the default", "optioncompare:binary")]
248 public bool optioncomparebinary { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = true; } }
250 [Option("[NOT IMPLEMENTED YET]Specifies text-style string comparisons.", "optioncompare:text")]
251 public bool optioncomparetext { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = false; } }
253 [Option("Specifies de root {namespace} for all type declarations")]
254 public string rootnamespace { set { RootContext.RootNamespace = value; } }
256 // Miscellaneous options
257 //------------------------------------------------------------------
259 [Option("[IGNORED]Do not display compiler copyright banner")]
260 public bool nologo = false;
262 [Option("[NOT IMPLEMENTED YET]Quiet output mode")]
263 public bool quiet = false;
265 // TODO: semantics are different and should be adjusted
266 [Option("Display verbose messages", 'v')]
267 public bool verbose { set { GenericParser.yacc_verbose_flag = value; } }
270 //------------------------------------------------------------------
271 // TODO: force option to accept number in hex format
272 [Option("[NOT IMPLEMENTED YET]The base {address} for a library or module (hex)")]
273 public int baseaddress;
275 [Option("[NOT IMPLEMENTED YET]Create bug report {file}")]
276 public string bugreport;
278 // TODO: handle VB.NET [+|-] boolean syntax
279 [Option("[NOT IMPLEMENTED YET]Delay-sign the assembly using only the public portion of the strong name key")]
280 public bool delaysign;
282 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key {container}")]
283 public string keycontainer;
285 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key {file}")]
286 public string keyfile;
288 public string[] libpath = null;
290 [Option("List of directories to search for metadata references {path-list}:path;...", "libpath")]
291 public WhatToDoNext setlibpath(string pathlist)
293 libpath = pathlist.Split(';');
294 return WhatToDoNext.GoAhead;
297 [Option(@"Specifies the Class or Module that contains Sub Main.
298 It can also be a {class} that inherits from System.Windows.Forms.Form.",
300 public string main { set { RootContext.MainClass = value; } }
302 // TODO: handle VB.NET [+|-] boolean syntax
303 [Option("[IGNORED]Emit compiler output in UTF8 character encoding")]
304 public bool utf8output;
306 // TODO : response file support
308 ArrayList defines = new ArrayList();
309 ArrayList references = new ArrayList();
310 ArrayList soft_references = new ArrayList();
312 string first_source = null;
313 Target target = Target.Exe;
314 string target_ext = ".exe";
315 ArrayList debug_arglist = new ArrayList ();
316 bool timestamps = false;
317 Hashtable source_files = new Hashtable ();
318 bool load_default_config = true;
321 // Last time we took the time
324 void ShowTime (string msg)
326 DateTime now = DateTime.Now;
327 TimeSpan span = now - last_time;
331 "[{0:00}:{1:000}] {2}",
332 (int) span.TotalSeconds, span.Milliseconds, msg);
335 public int LoadAssembly (string assembly, bool soft)
338 string total_log = "";
342 char[] path_chars = { '/', '\\' };
344 if (assembly.IndexOfAny (path_chars) != -1)
345 a = Assembly.LoadFrom(assembly);
347 a = Assembly.Load(assembly);
348 TypeManager.AddAssembly (a);
351 catch (FileNotFoundException)
355 foreach (string dir in libpath)
357 string full_path = dir + "/" + assembly + ".dll";
361 a = Assembly.LoadFrom (full_path);
362 TypeManager.AddAssembly (a);
365 catch (FileNotFoundException ff)
367 total_log += ff.FusionLog;
375 catch (BadImageFormatException f)
377 Error ("// Bad file format while loading assembly");
378 Error ("Log: " + f.FusionLog);
380 } catch (FileLoadException f){
381 Error ("File Load Exception: " + assembly);
382 Error ("Log: " + f.FusionLog);
384 } catch (ArgumentNullException){
385 Error ("// Argument Null exception ");
389 Report.Error (6, "Can not find assembly `" + assembly + "'" );
390 Console.WriteLine ("Log: \n" + total_log);
395 void Error(string message)
397 Console.WriteLine(message);
401 /// Loads all assemblies referenced on the command line
403 public int LoadReferences ()
407 foreach (string r in references)
408 errors += LoadAssembly (r, false);
410 foreach (string r in soft_references)
411 errors += LoadAssembly (r, true);
416 void SetupDefaultDefines ()
418 defines = new ArrayList ();
419 defines.Add ("__MonoBASIC__");
422 void SetupDefaultImports()
424 Mono.MonoBASIC.Parser.ImportsList = new ArrayList();
425 Mono.MonoBASIC.Parser.ImportsList.Add("Microsoft.VisualBasic");
430 // Returns the directory where the system assemblies are installed
432 string GetSystemDir ()
434 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
436 foreach (Assembly a in assemblies){
437 string codebase = a.CodeBase;
438 if (codebase.EndsWith ("corlib.dll")){
439 return codebase.Substring (0, codebase.LastIndexOf ("/"));
443 Report.Error (-15, "Can not compute my system path");
448 // Given a path specification, splits the path from the file/pattern
450 void SplitPathAndPattern (string spec, out string path, out string pattern)
452 int p = spec.LastIndexOf ("/");
455 // Windows does not like /file.cs, switch that to:
460 pattern = spec.Substring (1);
462 path = spec.Substring (0, p);
463 pattern = spec.Substring (p + 1);
468 p = spec.LastIndexOf ("\\");
470 path = spec.Substring (0, p);
471 pattern = spec.Substring (p + 1);
479 bool AddFiles (string spec, bool recurse)
481 string path, pattern;
483 SplitPathAndPattern(spec, out path, out pattern);
484 if (pattern.IndexOf("*") == -1)
490 string [] files = null;
492 files = Directory.GetFiles(path, pattern);
493 } catch (System.IO.DirectoryNotFoundException) {
494 Report.Error (2001, "Source file `" + spec + "' could not be found");
496 } catch (System.IO.IOException){
497 Report.Error (2001, "Source file `" + spec + "' could not be found");
500 foreach (string f in files)
506 string [] dirs = null;
509 dirs = Directory.GetDirectories(path);
513 foreach (string d in dirs) {
515 // Don't include path in this string, as each
516 // directory entry already does
517 AddFiles (d + "/" + pattern, true);
523 void DefineDefaultConfig ()
526 // For now the "default config" is harcoded into the compiler
527 // we can move this outside later
529 string [] default_config =
534 "Microsoft.VisualBasic" ,
535 #if EXTRA_DEFAULT_REFS
537 // Is it worth pre-loading all this stuff?
540 "System.Configuration.Install",
542 "System.DirectoryServices",
543 "System.Drawing.Design",
545 "System.EnterpriseServices",
548 "System.Runtime.Remoting",
549 "System.Runtime.Serialization.Formatters.Soap",
551 "System.ServiceProcess",
553 "System.Web.RegularExpressions",
554 "System.Web.Services" ,
555 "System.Windows.Forms"
559 foreach (string def in default_config)
560 soft_references.Add(def);
564 public void AddFile(string fileName)
567 if (first_source == null)
570 if (source_files.Contains(f))
571 Report.Error(1516, "Source file '" + f + "' specified multiple times");
573 source_files.Add(f, f);
576 void ProcessSourceFile(string filename)
579 GenericParser.Tokenize(filename);
581 GenericParser.Parse(filename);
584 string outputFile_Name = null;
586 string outputFileName
590 if (outputFile_Name == null)
592 if (OutputFileName == null)
594 int pos = first_source.LastIndexOf(".");
597 OutputFileName = first_source.Substring(0, pos);
599 OutputFileName = first_source;
601 string bname = CodeGen.Basename(OutputFileName);
602 if (bname.IndexOf(".") == -1)
603 OutputFileName += target_ext;
604 outputFile_Name = OutputFileName;
606 return outputFile_Name;
610 bool ParseAll() // Phase 1
612 if (first_source == null)
614 Report.Error(2008, "No files to compile were specified");
618 foreach(string filename in source_files.Values)
619 ProcessSourceFile(filename);
621 if (tokenize || parse_only || (Report.Errors > 0))
624 return true; // everything went well go ahead
627 void InitializeDebuggingSupport()
629 string[] debug_args = new string [debug_arglist.Count];
630 debug_arglist.CopyTo(debug_args);
631 CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
632 TypeManager.AddModule(CodeGen.ModuleBuilder);
635 public bool ResolveAllTypes() // Phase 2
637 // Load Core Library for default compilation
638 if (RootContext.StdLib)
639 references.Insert(0, "mscorlib");
641 if (load_default_config)
642 DefineDefaultConfig();
645 ShowTime("Loading references");
647 // Load assemblies required
648 if (LoadReferences() > 0)
650 Error ("Could not load one or more assemblies");
655 ShowTime("References loaded");
657 InitializeDebuggingSupport();
660 // Before emitting, we need to get the core
661 // types emitted from the user defined types
662 // or from the system ones.
665 ShowTime ("Initializing Core Types");
667 if (!RootContext.StdLib)
668 RootContext.ResolveCore ();
669 if (Report.Errors > 0)
672 TypeManager.InitCoreTypes();
673 if (Report.Errors > 0)
677 ShowTime (" Core Types done");
680 ShowTime ("Resolving tree");
682 // The second pass of the compiler
683 RootContext.ResolveTree ();
684 if (Report.Errors > 0)
688 ShowTime ("Populate tree");
690 if (!RootContext.StdLib)
691 RootContext.BootCorlib_PopulateCoreTypes();
692 if (Report.Errors > 0)
695 RootContext.PopulateTypes();
696 if (Report.Errors > 0)
699 TypeManager.InitCodeHelpers();
700 if (Report.Errors > 0)
708 string mainclass = GetFQMainClass();
710 if (mainclass != null) {
711 foreach (string r in references) {
712 if (r.IndexOf ("System.Windows.Forms") >= 0) {
713 Type t = TypeManager.LookupType(mainclass);
715 return t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
723 string GetFQMainClass()
725 if (RootContext.RootNamespace != "")
726 return RootContext.RootNamespace + "." + RootContext.MainClass;
728 return RootContext.MainClass;
733 if (target == Target.Exe || target == Target.WinExe)
735 MethodInfo ep = RootContext.EntryPoint;
739 // If we don't have a valid entry point yet
740 // AND if System.Windows.Forms is included
741 // among the dependencies, we have to build
742 // a new entry point on-the-fly. Otherwise we
743 // won't be able to compile SWF code out of the box.
747 Type t = TypeManager.LookupType(GetFQMainClass());
750 TypeBuilder tb = t as TypeBuilder;
751 MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
752 typeof(void), new Type[0]);
754 Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
755 Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
756 Type[] args = new Type[1];
758 MethodInfo mi = SWFA.GetMethod("Run", args);
759 ILGenerator ig = mb.GetILGenerator();
760 ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
762 ig.Emit (OpCodes.Newobj, ci);
763 ig.Emit (OpCodes.Call, mi);
764 ig.Emit (OpCodes.Ret);
766 RootContext.EntryPoint = mb as MethodInfo;
773 bool GenerateAssembly()
776 // The code generator
779 ShowTime ("Emitting code");
783 RootContext.EmitCode();
785 if (Report.Errors > 0)
793 ShowTime ("Closing types");
795 RootContext.CloseTypes ();
796 if (Report.Errors > 0)
802 PEFileKinds k = PEFileKinds.ConsoleApplication;
804 if (target == Target.Library || target == Target.Module)
806 else if (target == Target.Exe)
807 k = PEFileKinds.ConsoleApplication;
808 else if (target == Target.WinExe)
809 k = PEFileKinds.WindowApplication;
811 if (target == Target.Exe || target == Target.WinExe)
813 MethodInfo ep = RootContext.EntryPoint;
817 Report.Error (5001, "Program " + outputFileName +
818 " does not have an entry point defined");
822 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
826 if (EmbeddedResources != null)
827 foreach (string file in EmbeddedResources)
828 CodeGen.AssemblyBuilder.AddResourceFile (file, file);
830 CodeGen.Save(outputFileName);
833 ShowTime ("Saved output");
836 if (want_debugging_support)
838 CodeGen.SaveSymbols ();
840 ShowTime ("Saved symbols");
846 public void CompileAll()
849 VB.NET expects the default namespace to be "" (empty string)
851 if (RootContext.RootNamespace == "")
853 RootContext.RootNamespace = System.IO.Path.GetFileNameWithoutExtension(outputFileName);
856 if (!ParseAll()) // Phase 1
859 if (!ResolveAllTypes()) // Phase 2
862 GenerateAssembly(); // Phase 3
866 /// Parses the arguments, and calls the compilation process.
868 int MainDriver(string [] args)
870 SetupDefaultDefines();
872 SetupDefaultImports();
876 if (first_source == null)
885 return Report.ProcessResults(quiet);
888 public static int Main (string[] args)
890 Driver Exec = new Driver();
892 Report.Stacktrace = false;
894 return Exec.MainDriver(args);