// // CompilerOptions.cs: The compiler command line options processor. // // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com) // Based on mcs by : Miguel de Icaza (miguel@gnu.org) // // Licensed under the terms of the GNU GPL // // (C) 2002, 2003, 2004 Rafael Teixeira // namespace Mono.MonoBASIC { using System; using System.Collections; using System.IO; using System.Text; using System.Reflection; using System.Reflection.Emit; using Mono.GetOptions; using Mono.GetOptions.Useful; public enum OptionCompare { Binary, Text }; public enum InternalCompilerErrorReportAction { prompt, send, none } public delegate void ErrorReporter (int num, string msg); public delegate void ModuleAdder (System.Reflection.Module module); public delegate void AssemblyAdder (Assembly loadedAssembly); /// /// The compiler command line options processor. /// public class CompilerOptions : CommonCompilerOptions { ErrorReporter reportError; // // For now the "default config" is harcoded into the compiler // we can move this outside later // public string [] AssembliesToReferenceSoftly = { "System", "System.Data", "System.Xml", "Microsoft.VisualBasic" , #if EXTRA_DEFAULT_REFS // // Is it worth pre-loading all this stuff? // "Accessibility", "System.Configuration.Install", "System.Design", "System.DirectoryServices", "System.Drawing.Design", "System.Drawing", "System.EnterpriseServices", "System.Management", "System.Messaging", "System.Runtime.Remoting", "System.Runtime.Serialization.Formatters.Soap", "System.Security", "System.ServiceProcess", "System.Web", "System.Web.RegularExpressions", "System.Web.Services" , "System.Windows.Forms" #endif }; public CompilerOptions(string [] args, ErrorReporter reportError) : base(args) { this.reportError = reportError; } private void LoadAssembly (AssemblyAdder adder, string assemblyName, ref int errors, bool soft) { Assembly a = null; string total_log = ""; try { char[] path_chars = { '/', '\\' }; if (assemblyName.IndexOfAny (path_chars) != -1) a = Assembly.LoadFrom(assemblyName); else { string ass = assemblyName; if (ass.EndsWith (".dll")) ass = assemblyName.Substring (0, assemblyName.Length - 4); a = Assembly.Load (ass); adder(a); return; } } catch (FileNotFoundException) { if (PathsToSearchForLibraries != null) { foreach (string dir in PathsToSearchForLibraries) { string full_path = Path.Combine(dir, assemblyName + ".dll"); try { a = Assembly.LoadFrom (full_path); adder(a); return; } catch (FileNotFoundException ff) { total_log += ff.FusionLog; continue; } } } if (soft) return; reportError(6, "Can not find assembly '" + assemblyName + "'\nLog: " + total_log); } catch (BadImageFormatException f) { reportError(6, "Bad file format while loading assembly\nLog: " + f.FusionLog); } catch (FileLoadException f){ reportError(6, "File Load Exception: " + assemblyName + "\nLog: " + f.FusionLog); } catch (ArgumentNullException){ reportError(6, "Argument Null exception"); } errors++; } /// /// Loads all assemblies referenced on the command line /// public bool LoadReferencedAssemblies (AssemblyAdder adder) { StartTime("Loading referenced assemblies"); int errors = 0; int soft_errors = 0; // Load Core Library for default compilation if (!NoStandardLibraries) LoadAssembly(adder, "mscorlib", ref errors, false); foreach (string r in AssembliesToReference) LoadAssembly(adder, r, ref errors, false); if (!NoConfig) foreach (string r in AssembliesToReferenceSoftly) if (!(AssembliesToReference.Contains(r) || AssembliesToReference.Contains (r + ".dll"))) LoadAssembly(adder, r, ref soft_errors, true); ShowTime("References loaded"); return errors == 0; } private void LoadModule (MethodInfo adder_method, AssemblyBuilder assemblyBuilder, ModuleAdder adder, string module, ref int errors) { System.Reflection.Module m; string total_log = ""; try { try { m = (System.Reflection.Module)adder_method.Invoke (assemblyBuilder, new object [] { module }); } catch (TargetInvocationException ex) { throw ex.InnerException; } adder(m); } catch (FileNotFoundException) { foreach (string dir in PathsToSearchForLibraries) { string full_path = Path.Combine (dir, module); if (!module.EndsWith (".netmodule")) full_path += ".netmodule"; try { try { m = (System.Reflection.Module) adder_method.Invoke (assemblyBuilder, new object [] { full_path }); } catch (TargetInvocationException ex) { throw ex.InnerException; } adder(m); return; } catch (FileNotFoundException ff) { total_log += ff.FusionLog; continue; } } reportError(6, "Cannot find module `" + module + "'" ); Console.WriteLine ("Log: \n" + total_log); } catch (BadImageFormatException f) { reportError(6, "Cannot load module (bad file format)" + f.FusionLog); } catch (FileLoadException f) { reportError(6, "Cannot load module " + f.FusionLog); } catch (ArgumentNullException) { reportError(6, "Cannot load module (null argument)"); } errors++; } public void UnsupportedFeatureOnthisRuntime(string feature) { reportError(0, string.Format("Cannot use {0} on this runtime: Try the Mono runtime instead.", feature)); Environment.Exit (1); } public bool LoadAddedNetModules(AssemblyBuilder assemblyBuilder, ModuleAdder adder) { int errors = 0; if (NetModulesToAdd.Count > 0) { StartTime("Loading added netmodules"); MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic); if (adder_method == null) UnsupportedFeatureOnthisRuntime("/addmodule"); foreach (string module in NetModulesToAdd) LoadModule (adder_method, assemblyBuilder, adder, module, ref errors); ShowTime(" Done"); } return errors == 0; } public void AdjustCodegenWhenTargetIsNetModule(AssemblyBuilder assemblyBuilder) { if (TargetFileType == TargetType.Module) { StartTime("Adjusting AssemblyBuilder for NetModule target"); PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); if (module_only == null) UnsupportedFeatureOnthisRuntime("/target:module"); MethodInfo set_method = module_only.GetSetMethod (true); set_method.Invoke (assemblyBuilder, BindingFlags.Default, null, new object[]{true}, null); ShowTime(" Done"); } } // // Given a path specification, splits the path from the file/pattern // void SplitPathAndPattern (string spec, out string path, out string pattern) { int p = spec.LastIndexOf ("/"); if (p != -1){ // // Windows does not like /file.cs, switch that to: // "\", "file.cs" // if (p == 0){ path = "\\"; pattern = spec.Substring (1); } else { path = spec.Substring (0, p); pattern = spec.Substring (p + 1); } return; } p = spec.LastIndexOf ("\\"); if (p != -1){ path = spec.Substring (0, p); pattern = spec.Substring (p + 1); return; } path = "."; pattern = spec; } bool AddFiles (string spec, bool recurse) { string path, pattern; SplitPathAndPattern(spec, out path, out pattern); if (pattern.IndexOf("*") == -1) { DefaultArgumentProcessor(spec); return true; } string [] files = null; try { files = Directory.GetFiles(path, pattern); } catch (System.IO.DirectoryNotFoundException) { Report.Error (2001, "Source file '" + spec + "' could not be found"); return false; } catch (System.IO.IOException){ Report.Error (2001, "Source file '" + spec + "' could not be found"); return false; } foreach (string f in files) DefaultArgumentProcessor (f); if (!recurse) return true; string [] dirs = null; try { dirs = Directory.GetDirectories(path); } catch { } foreach (string d in dirs) { // Don't include path in this string, as each // directory entry already does AddFiles (d + "/" + pattern, true); } return true; } public void EmbedResources(AssemblyBuilder builder) { if (EmbeddedResources != null) foreach (string file in EmbeddedResources) builder.AddResourceFile (file, file); // TODO: deal with resource IDs } #if NET_2_0 [Option("Specify target CPU platform {ID}. ID can be x86, Itanium, x64 (AMD 64bit) or anycpu (the default).", "platform", SecondLevelHelp = true)] public string TargetPlatform; [Option("What {action} (prompt | send | none) should be done when an internal compiler error occurs.\tThe default is none what just prints the error data in the compiler output", "errorreport", SecondLevelHelp = true)] public InternalCompilerErrorReportAction HowToReportErrors = InternalCompilerErrorReportAction.none; [Option("Filealign internal blocks to the {blocksize} in bytes. Valid values are 512, 1024, 2048, 4096, and 8192.", "filealign", SecondLevelHelp = true)] public int FileAlignBlockSize = 0; // 0 means use appropriate (not fixed) default [Option("Generate documentation from xml commments.", "doc", SecondLevelHelp = true, VBCStyleBoolean = true)] public bool GenerateXmlDocumentation = false; [Option("Generate documentation from xml commments to an specific {file}.", "docto", SecondLevelHelp = true)] public string GenerateXmlDocumentationToFileName = null; #endif // Temporary options //------------------------------------------------------------------ [Option("[IGNORED] Only parses the source file (for debugging the tokenizer)", "parse", SecondLevelHelp = true)] public bool OnlyParse = false; [Option("[IGNORED] Only tokenizes source files", "tokenize", SecondLevelHelp = true)] public bool Tokenize = false; [Option("Shows stack trace at Error location", "stacktrace", SecondLevelHelp = true)] public bool Stacktrace = false; [Option("Makes errors fatal", "fatal", SecondLevelHelp = true)] public bool MakeErrorsFatal = false; [Option("Displays time stamps of various compiler events", "timestamp", SecondLevelHelp = true)] public virtual bool PrintTimeStamps { set { printTimeStamps = true; last_time = DateTime.Now; DebugListOfArguments.Add("timestamp"); } } // redefining some inherited options //------------------------------------------------------------------ [Option("About the MonoBASIC compiler", "about")] public override WhatToDoNext DoAbout() { return base.DoAbout(); } [KillOption] public override WhatToDoNext DoUsage() { return WhatToDoNext.GoAhead; } // language options //------------------------------------------------------------------ [Option("Require explicit declaration of variables", "optionexplicit", VBCStyleBoolean = true)] public bool OptionExplicit = false; [Option("Enforce strict language semantics", "optionstrict", VBCStyleBoolean = true)] public bool OptionStrict = false; [Option("Specifies binary-style string comparisons. This is the default", "optioncompare:binary")] public bool OptionCompareBinary = true; [Option("Specifies text-style string comparisons.", "optioncompare:text")] public bool OptionCompareText { set { OptionCompareBinary = false; } } protected override void InitializeOtherDefaults() { DefineSymbol = "__MonoBASIC__"; ImportNamespaces = "Microsoft.VisualBasic"; } private bool printTimeStamps = false; // // Last time we took the time // DateTime last_time; public void StartTime (string msg) { if (!printTimeStamps) return; last_time = DateTime.Now; Console.WriteLine("[*] {0}", msg); } public void ShowTime (string msg) { if (!printTimeStamps) return; DateTime now = DateTime.Now; TimeSpan span = now - last_time; last_time = now; Console.WriteLine ( "[{0:00}:{1:000}] {2}", (int) span.TotalSeconds, span.Milliseconds, msg); } public bool BeQuiet { get { return DontShowBanner || SuccintErrorDisplay; } } public bool NothingToCompile { get { if (SourceFilesToCompile.Count == 0) { if (!BeQuiet) DoHelp(); return true; } if (!BeQuiet) { ShowBanner(); // TODO: remove next lines when the compiler has matured enough Console.WriteLine ("--------"); Console.WriteLine ("THIS IS AN ALPHA SOFTWARE."); Console.WriteLine ("--------"); } return false; } } } }