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 string ass = assembly;
348 if (ass.EndsWith (".dll"))
349 ass = assembly.Substring (0, assembly.Length - 4);
350 a = Assembly.Load (ass);
352 TypeManager.AddAssembly (a);
355 catch (FileNotFoundException)
359 foreach (string dir in libpath)
361 string full_path = dir + "/" + assembly + ".dll";
365 a = Assembly.LoadFrom (full_path);
366 TypeManager.AddAssembly (a);
369 catch (FileNotFoundException ff)
371 total_log += ff.FusionLog;
379 catch (BadImageFormatException f)
381 Error ("// Bad file format while loading assembly");
382 Error ("Log: " + f.FusionLog);
384 } catch (FileLoadException f){
385 Error ("File Load Exception: " + assembly);
386 Error ("Log: " + f.FusionLog);
388 } catch (ArgumentNullException){
389 Error ("// Argument Null exception ");
393 Report.Error (6, "Can not find assembly `" + assembly + "'" );
394 Console.WriteLine ("Log: \n" + total_log);
399 void Error(string message)
401 Console.WriteLine(message);
405 /// Loads all assemblies referenced on the command line
407 public int LoadReferences ()
411 foreach (string r in references)
412 errors += LoadAssembly (r, false);
414 foreach (string r in soft_references)
415 errors += LoadAssembly (r, true);
420 void SetupDefaultDefines ()
422 defines = new ArrayList ();
423 defines.Add ("__MonoBASIC__");
426 void SetupDefaultImports()
428 Mono.MonoBASIC.Parser.ImportsList = new ArrayList();
429 Mono.MonoBASIC.Parser.ImportsList.Add("Microsoft.VisualBasic");
434 // Returns the directory where the system assemblies are installed
436 string GetSystemDir ()
438 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
440 foreach (Assembly a in assemblies){
441 string codebase = a.CodeBase;
442 if (codebase.EndsWith ("corlib.dll")){
443 return codebase.Substring (0, codebase.LastIndexOf ("/"));
447 Report.Error (-15, "Can not compute my system path");
452 // Given a path specification, splits the path from the file/pattern
454 void SplitPathAndPattern (string spec, out string path, out string pattern)
456 int p = spec.LastIndexOf ("/");
459 // Windows does not like /file.cs, switch that to:
464 pattern = spec.Substring (1);
466 path = spec.Substring (0, p);
467 pattern = spec.Substring (p + 1);
472 p = spec.LastIndexOf ("\\");
474 path = spec.Substring (0, p);
475 pattern = spec.Substring (p + 1);
483 bool AddFiles (string spec, bool recurse)
485 string path, pattern;
487 SplitPathAndPattern(spec, out path, out pattern);
488 if (pattern.IndexOf("*") == -1)
494 string [] files = null;
496 files = Directory.GetFiles(path, pattern);
497 } catch (System.IO.DirectoryNotFoundException) {
498 Report.Error (2001, "Source file `" + spec + "' could not be found");
500 } catch (System.IO.IOException){
501 Report.Error (2001, "Source file `" + spec + "' could not be found");
504 foreach (string f in files)
510 string [] dirs = null;
513 dirs = Directory.GetDirectories(path);
517 foreach (string d in dirs) {
519 // Don't include path in this string, as each
520 // directory entry already does
521 AddFiles (d + "/" + pattern, true);
527 void DefineDefaultConfig ()
530 // For now the "default config" is harcoded into the compiler
531 // we can move this outside later
533 string [] default_config =
538 "Microsoft.VisualBasic" ,
539 #if EXTRA_DEFAULT_REFS
541 // Is it worth pre-loading all this stuff?
544 "System.Configuration.Install",
546 "System.DirectoryServices",
547 "System.Drawing.Design",
549 "System.EnterpriseServices",
552 "System.Runtime.Remoting",
553 "System.Runtime.Serialization.Formatters.Soap",
555 "System.ServiceProcess",
557 "System.Web.RegularExpressions",
558 "System.Web.Services" ,
559 "System.Windows.Forms"
563 foreach (string def in default_config)
564 soft_references.Add(def);
568 public void AddFile(string fileName)
571 if (first_source == null)
574 if (source_files.Contains(f))
575 Report.Error(1516, "Source file '" + f + "' specified multiple times");
577 source_files.Add(f, f);
580 void ProcessSourceFile(string filename)
583 GenericParser.Tokenize(filename);
585 GenericParser.Parse(filename);
588 string outputFile_Name = null;
590 string outputFileName
594 if (outputFile_Name == null)
596 if (OutputFileName == null)
598 int pos = first_source.LastIndexOf(".");
601 OutputFileName = first_source.Substring(0, pos);
603 OutputFileName = first_source;
605 string bname = CodeGen.Basename(OutputFileName);
606 if (bname.IndexOf(".") == -1)
607 OutputFileName += target_ext;
608 outputFile_Name = OutputFileName;
610 return outputFile_Name;
614 bool ParseAll() // Phase 1
616 if (first_source == null)
618 Report.Error(2008, "No files to compile were specified");
622 foreach(string filename in source_files.Values)
623 ProcessSourceFile(filename);
625 if (tokenize || parse_only || (Report.Errors > 0))
628 return true; // everything went well go ahead
631 void InitializeDebuggingSupport()
633 string[] debug_args = new string [debug_arglist.Count];
634 debug_arglist.CopyTo(debug_args);
635 CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
636 TypeManager.AddModule(CodeGen.ModuleBuilder);
639 public bool ResolveAllTypes() // Phase 2
641 // Load Core Library for default compilation
642 if (RootContext.StdLib)
643 references.Insert(0, "mscorlib");
645 if (load_default_config)
646 DefineDefaultConfig();
649 ShowTime("Loading references");
651 // Load assemblies required
652 if (LoadReferences() > 0)
654 Error ("Could not load one or more assemblies");
659 ShowTime("References loaded");
661 InitializeDebuggingSupport();
664 // Before emitting, we need to get the core
665 // types emitted from the user defined types
666 // or from the system ones.
669 ShowTime ("Initializing Core Types");
671 if (!RootContext.StdLib)
672 RootContext.ResolveCore ();
673 if (Report.Errors > 0)
676 TypeManager.InitCoreTypes();
677 if (Report.Errors > 0)
681 ShowTime (" Core Types done");
684 ShowTime ("Resolving tree");
686 // The second pass of the compiler
687 RootContext.ResolveTree ();
688 if (Report.Errors > 0)
692 ShowTime ("Populate tree");
694 if (!RootContext.StdLib)
695 RootContext.BootCorlib_PopulateCoreTypes();
696 if (Report.Errors > 0)
699 RootContext.PopulateTypes();
700 if (Report.Errors > 0)
703 TypeManager.InitCodeHelpers();
704 if (Report.Errors > 0)
712 string mainclass = GetFQMainClass();
714 if (mainclass != null) {
715 foreach (string r in references) {
716 if (r.IndexOf ("System.Windows.Forms") >= 0) {
717 Type t = TypeManager.LookupType(mainclass);
719 return t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
727 string GetFQMainClass()
729 if (RootContext.RootNamespace != "")
730 return RootContext.RootNamespace + "." + RootContext.MainClass;
732 return RootContext.MainClass;
737 if (target == Target.Exe || target == Target.WinExe)
739 MethodInfo ep = RootContext.EntryPoint;
743 // If we don't have a valid entry point yet
744 // AND if System.Windows.Forms is included
745 // among the dependencies, we have to build
746 // a new entry point on-the-fly. Otherwise we
747 // won't be able to compile SWF code out of the box.
751 Type t = TypeManager.LookupType(GetFQMainClass());
754 TypeBuilder tb = t as TypeBuilder;
755 MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
756 typeof(void), new Type[0]);
758 Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
759 Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
760 Type[] args = new Type[1];
762 MethodInfo mi = SWFA.GetMethod("Run", args);
763 ILGenerator ig = mb.GetILGenerator();
764 ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
766 ig.Emit (OpCodes.Newobj, ci);
767 ig.Emit (OpCodes.Call, mi);
768 ig.Emit (OpCodes.Ret);
770 RootContext.EntryPoint = mb as MethodInfo;
777 bool GenerateAssembly()
780 // The code generator
783 ShowTime ("Emitting code");
787 RootContext.EmitCode();
789 if (Report.Errors > 0)
797 ShowTime ("Closing types");
799 RootContext.CloseTypes ();
800 if (Report.Errors > 0)
806 PEFileKinds k = PEFileKinds.ConsoleApplication;
808 if (target == Target.Library || target == Target.Module)
810 else if (target == Target.Exe)
811 k = PEFileKinds.ConsoleApplication;
812 else if (target == Target.WinExe)
813 k = PEFileKinds.WindowApplication;
815 if (target == Target.Exe || target == Target.WinExe)
817 MethodInfo ep = RootContext.EntryPoint;
821 Report.Error (30737, "Program " + outputFileName +
822 " does not have an entry point defined");
826 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
830 if (EmbeddedResources != null)
831 foreach (string file in EmbeddedResources)
832 CodeGen.AssemblyBuilder.AddResourceFile (file, file);
834 CodeGen.Save(outputFileName);
837 ShowTime ("Saved output");
840 if (want_debugging_support)
842 CodeGen.SaveSymbols ();
844 ShowTime ("Saved symbols");
850 public void CompileAll()
853 VB.NET expects the default namespace to be "" (empty string)
855 if (RootContext.RootNamespace == "")
857 RootContext.RootNamespace = System.IO.Path.GetFileNameWithoutExtension(outputFileName);
860 if (!ParseAll()) // Phase 1
863 if (!ResolveAllTypes()) // Phase 2
866 GenerateAssembly(); // Phase 3
870 /// Parses the arguments, and calls the compilation process.
872 int MainDriver(string [] args)
874 Console.WriteLine ("--------");
875 Console.WriteLine ("MonoBASIC: THIS IS STILL ALPHA AND UNSUPPORTED SOFTWARE, USE AT YOUR OWN RISK.");
876 Console.WriteLine ("--------");
877 SetupDefaultDefines();
879 SetupDefaultImports();
883 if (first_source == null)
892 return Report.ProcessResults(quiet);
895 public static int Main (string[] args)
897 Driver Exec = new Driver();
899 Report.Stacktrace = false;
901 return Exec.MainDriver(args);