2 // driver.cs: The compiler command line driver.
5 // Miguel de Icaza (miguel@gnu.org)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections.Generic;
20 using System.Globalization;
21 using System.Diagnostics;
26 /// The compiler driver.
33 internal int fatal_errors;
36 // Last time we took the time
41 internal readonly CompilerContext ctx;
43 static readonly char[] argument_value_separator = new char [] { ';', ',' };
45 private Driver (CompilerContext ctx)
50 public static Driver Create (string[] args, bool require_files, ReportPrinter printer)
52 Driver d = new Driver (new CompilerContext (new Report (printer)));
54 if (!d.ParseArguments (args, require_files))
61 get { return ctx.Report; }
64 void ShowTime (string msg)
71 Console.WriteLine ("{0,5}ms {1}", stopwatch.ElapsedMilliseconds, msg);
73 stopwatch = Stopwatch.StartNew ();
76 void ShowTotalTime (string msg)
81 DateTime now = DateTime.Now;
82 TimeSpan span = now - first_time;
85 "[{0:00}:{1:000}] {2}",
86 (int) span.TotalSeconds, span.Milliseconds, msg);
89 void tokenize_file (CompilationUnit file, CompilerContext ctx)
94 input = File.OpenRead (file.Name);
96 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
101 SeekableStreamReader reader = new SeekableStreamReader (input, RootContext.Encoding);
102 Tokenizer lexer = new Tokenizer (reader, file, ctx);
103 int token, tokens = 0, errors = 0;
105 while ((token = lexer.token ()) != Token.EOF){
107 if (token == Token.ERROR)
110 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
116 void Parse (CompilationUnit file, ModuleContainer module)
121 input = File.OpenRead (file.Name);
123 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
128 if (input.ReadByte () == 77 && input.ReadByte () == 90) {
129 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
135 SeekableStreamReader reader = new SeekableStreamReader (input, RootContext.Encoding);
137 Parse (reader, file, module);
142 void Parse (SeekableStreamReader reader, CompilationUnit file, ModuleContainer module)
144 CSharpParser parser = new CSharpParser (reader, file, module);
148 static void OtherFlags ()
151 "Other flags in the compiler\n" +
152 " --fatal[=COUNT] Makes errors after COUNT fatal\n" +
153 " --lint Enhanced warnings\n" +
154 " --parse Only parses the source file\n" +
155 " --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
156 " --stacktrace Shows stack trace at error location\n" +
157 " --timestamp Displays time stamps of various compiler events\n" +
158 " -v Verbose parsing (for debugging the parser)\n" +
159 " --mcs-debug X Sets MCS debugging level to X\n");
165 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
166 "mcs [options] source-files\n" +
167 " --about About the Mono C# compiler\n" +
168 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
169 " -checked[+|-] Sets default aritmetic overflow context\n" +
170 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
171 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
172 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
173 " -debug[+|-], -g Generate debugging information\n" +
174 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
175 " -doc:FILE Process documentation comments to XML file\n" +
176 " -help Lists all compiler options (short: -?)\n" +
177 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
178 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
179 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, Default, or Future\n" +
180 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
181 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
182 " -noconfig Disables implicitly referenced assemblies\n" +
183 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
184 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
185 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
186 " -out:FILE Specifies output assembly name\n" +
188 " -pkg:P1[,Pn] References packages P1..Pn\n" +
190 " -platform:ARCH Specifies the target platform of the output assembly\n" +
191 " ARCH can be one of: anycpu, x86, x64 or itanium\n" +
192 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
193 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
194 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
195 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
196 " KIND can be one of: exe, winexe, library, module\n" +
197 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
198 " -warnaserror[+|-] Treats all warnings as errors\n" +
199 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
200 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
201 " -helpinternal Shows internal and advanced compiler options\n" +
204 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
205 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
206 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
207 " -win32icon:FILE Use this icon for the output\n" +
208 " @file Read response file for more options\n\n" +
209 "Options can be of the form -option or /option");
214 Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
220 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
221 "The compiler source code is released under the terms of the \n"+
222 "MIT X11 or GNU GPL licenses\n\n" +
224 "For more information on Mono, visit the project Web site\n" +
225 " http://www.mono-project.com\n\n" +
227 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
228 Environment.Exit (0);
231 public static int Main (string[] args)
233 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
234 var crp = new ConsoleReportPrinter ();
235 Driver d = Driver.Create (args, true, crp);
239 crp.Fatal = d.fatal_errors;
241 if (d.Compile () && d.Report.Errors == 0) {
242 if (d.Report.Warnings > 0) {
243 Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
245 Environment.Exit (0);
250 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
251 d.Report.Errors, d.Report.Warnings);
252 Environment.Exit (1);
256 static string [] LoadArgs (string file)
259 var args = new List<string> ();
262 f = new StreamReader (file);
267 StringBuilder sb = new StringBuilder ();
269 while ((line = f.ReadLine ()) != null){
272 for (int i = 0; i < t; i++){
275 if (c == '"' || c == '\''){
278 for (i++; i < t; i++){
285 } else if (c == ' '){
287 args.Add (sb.ToString ());
294 args.Add (sb.ToString ());
299 return args.ToArray ();
303 // Given a path specification, splits the path from the file/pattern
305 static void SplitPathAndPattern (string spec, out string path, out string pattern)
307 int p = spec.LastIndexOf ('/');
310 // Windows does not like /file.cs, switch that to:
315 pattern = spec.Substring (1);
317 path = spec.Substring (0, p);
318 pattern = spec.Substring (p + 1);
323 p = spec.LastIndexOf ('\\');
325 path = spec.Substring (0, p);
326 pattern = spec.Substring (p + 1);
334 void AddSourceFile (string f)
336 if (first_source == null)
339 Location.AddFile (Report, f);
342 bool ParseArguments (string[] args, bool require_files)
344 List<string> response_file_list = null;
345 bool parsing_options = true;
347 for (int i = 0; i < args.Length; i++) {
348 string arg = args [i];
352 if (arg [0] == '@') {
353 string [] extra_args;
354 string response_file = arg.Substring (1);
356 if (response_file_list == null)
357 response_file_list = new List<string> ();
359 if (response_file_list.Contains (response_file)) {
361 1515, "Response file `" + response_file +
362 "' specified multiple times");
366 response_file_list.Add (response_file);
368 extra_args = LoadArgs (response_file);
369 if (extra_args == null) {
370 Report.Error (2011, "Unable to open response file: " +
375 args = AddArgs (args, extra_args);
379 if (parsing_options) {
381 parsing_options = false;
385 if (arg [0] == '-') {
386 if (UnixParseOption (arg, ref args, ref i))
390 string csc_opt = "/" + arg.Substring (1);
391 if (CSCParseOption (csc_opt, ref args))
394 Error_WrongOption (arg);
397 if (arg [0] == '/') {
398 if (CSCParseOption (arg, ref args))
401 // Need to skip `/home/test.cs' however /test.cs is considered as error
402 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
403 Error_WrongOption (arg);
409 ProcessSourceFiles (arg, false);
412 if (require_files == false)
416 // If we are an exe, require a source file for the entry point
418 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
419 if (first_source == null) {
420 Report.Error (2008, "No files to compile were specified");
427 // If there is nothing to put in the assembly, and we are not a library
429 if (first_source == null && RootContext.Resources == null) {
430 Report.Error (2008, "No files to compile were specified");
437 public void Parse (ModuleContainer module)
439 Location.Initialize ();
441 var cu = Location.SourceFiles;
442 for (int i = 0; i < cu.Count; ++i) {
443 if (RootContext.TokenizeOnly) {
444 tokenize_file (cu [i], ctx);
446 Parse (cu [i], module);
451 void ProcessSourceFiles (string spec, bool recurse)
453 string path, pattern;
455 SplitPathAndPattern (spec, out path, out pattern);
456 if (pattern.IndexOf ('*') == -1){
457 AddSourceFile (spec);
461 string [] files = null;
463 files = Directory.GetFiles (path, pattern);
464 } catch (System.IO.DirectoryNotFoundException) {
465 Report.Error (2001, "Source file `" + spec + "' could not be found");
467 } catch (System.IO.IOException){
468 Report.Error (2001, "Source file `" + spec + "' could not be found");
471 foreach (string f in files) {
478 string [] dirs = null;
481 dirs = Directory.GetDirectories (path);
485 foreach (string d in dirs) {
487 // Don't include path in this string, as each
488 // directory entry already does
489 ProcessSourceFiles (d + "/" + pattern, true);
493 void SetWarningLevel (string s)
498 level = Int32.Parse (s);
501 if (level < 0 || level > 4){
502 Report.Error (1900, "Warning level must be in the range 0-4");
505 Report.WarningLevel = level;
508 static void Version ()
510 string version = System.Reflection.Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
511 Console.WriteLine ("Mono C# compiler version {0}", version);
512 Environment.Exit (0);
516 // Currently handles the Unix-like command line options, but will be
517 // deprecated in favor of the CSCParseOption, which will also handle the
518 // options that start with a dash in the future.
520 bool UnixParseOption (string arg, ref string [] args, ref int i)
524 CSharpParser.yacc_verbose_flag++;
532 RootContext.ParseOnly = true;
535 case "--main": case "-m":
536 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
537 if ((i + 1) >= args.Length){
539 Environment.Exit (1);
541 RootContext.MainClass = args [++i];
545 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
546 RootContext.Unsafe = true;
549 case "/?": case "/h": case "/help":
552 Environment.Exit (0);
556 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
557 if ((i + 1) >= args.Length){
559 Environment.Exit (1);
561 RootContext.AddConditional (args [++i]);
565 RootContext.TokenizeOnly = true;
570 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
571 if ((i + 1) >= args.Length){
573 Environment.Exit (1);
575 RootContext.OutputFile = args [++i];
579 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
580 RootContext.Checked = true;
584 Report.Printer.Stacktrace = true;
587 case "--linkresource":
589 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
590 if ((i + 1) >= args.Length){
592 Report.Error (5, "Missing argument to --linkres");
593 Environment.Exit (1);
596 AddResource (new AssemblyResource (args[++i], args[i]));
601 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
602 if ((i + 1) >= args.Length){
604 Report.Error (5, "Missing argument to --resource");
605 Environment.Exit (1);
608 AddResource (new AssemblyResource (args[++i], args[i], true));
612 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
613 if ((i + 1) >= args.Length){
614 Environment.Exit (1);
618 string type = args [++i];
621 RootContext.Target = Target.Library;
622 RootContext.TargetExt = ".dll";
626 RootContext.Target = Target.Exe;
630 RootContext.Target = Target.WinExe;
634 RootContext.Target = Target.Module;
635 RootContext.TargetExt = ".dll";
644 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
645 if ((i + 1) >= args.Length){
647 Environment.Exit (1);
650 string val = args [++i];
651 int idx = val.IndexOf ('=');
653 string alias = val.Substring (0, idx);
654 string assembly = val.Substring (idx + 1);
655 AddAssemblyReference (alias, assembly);
659 AddAssemblyReference (val);
663 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
664 if ((i + 1) >= args.Length){
666 Environment.Exit (1);
668 RootContext.ReferencesLookupPaths.Add (args [++i]);
672 RootContext.EnhancedWarnings = true;
676 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
677 RootContext.StdLib = false;
681 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
682 if ((i + 1) >= args.Length){
684 Environment.Exit (1);
689 warn = Int32.Parse (args [++i]);
692 Environment.Exit (1);
694 Report.SetIgnoreWarning (warn);
698 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
699 if ((i + 1) >= args.Length){
702 "--wlevel requires a value from 0 to 4");
703 Environment.Exit (1);
706 SetWarningLevel (args [++i]);
710 if ((i + 1) >= args.Length){
711 Report.Error (5, "--mcs-debug requires an argument");
712 Environment.Exit (1);
716 Report.DebugFlags = Int32.Parse (args [++i]);
718 Report.Error (5, "Invalid argument to --mcs-debug");
719 Environment.Exit (1);
728 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
729 if ((i + 1) >= args.Length){
730 Report.Error (5, "--recurse requires an argument");
731 Environment.Exit (1);
733 ProcessSourceFiles (args [++i], true);
740 case "--debug": case "-g":
741 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
742 RootContext.GenerateDebugInfo = true;
746 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
747 RootContext.LoadDefaultReferences = false;
751 if (arg.StartsWith ("--fatal")){
752 if (arg.StartsWith ("--fatal=")){
753 if (!Int32.TryParse (arg.Substring (8), out fatal_errors))
759 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
760 string version = arg.Substring (10);
765 RootContext.StdLibRuntimeVersion = RuntimeVersion.v1;
769 RootContext.StdLibRuntimeVersion = RuntimeVersion.v2;
773 RootContext.StdLibRuntimeVersion = RuntimeVersion.v4;
786 public static string GetPackageFlags (string packages, bool fatal, Report report)
788 ProcessStartInfo pi = new ProcessStartInfo ();
789 pi.FileName = "pkg-config";
790 pi.RedirectStandardOutput = true;
791 pi.UseShellExecute = false;
792 pi.Arguments = "--libs " + packages;
795 p = Process.Start (pi);
796 } catch (Exception e) {
797 report.Error (-27, "Couldn't run pkg-config: " + e.Message);
799 Environment.Exit (1);
804 if (p.StandardOutput == null){
805 report.Warning (-27, 1, "Specified package did not return any information");
809 string pkgout = p.StandardOutput.ReadToEnd ();
811 if (p.ExitCode != 0) {
812 report.Error (-27, "Error running pkg-config. Check the above output.");
814 Environment.Exit (1);
825 // This parses the -arg and /arg options to the compiler, even if the strings
826 // in the following text use "/arg" on the strings.
828 bool CSCParseOption (string option, ref string [] args)
830 int idx = option.IndexOf (':');
837 arg = option.Substring (0, idx);
839 value = option.Substring (idx + 1);
842 switch (arg.ToLowerInvariant ()){
850 RootContext.Target = Target.Exe;
854 RootContext.Target = Target.WinExe;
858 RootContext.Target = Target.Library;
859 RootContext.TargetExt = ".dll";
863 RootContext.Target = Target.Module;
864 RootContext.TargetExt = ".netmodule";
874 if (value.Length == 0) {
875 Error_RequiresFileName (option);
878 RootContext.OutputFile = value;
885 RootContext.Optimize = true;
890 RootContext.Optimize = false;
893 // TODO: Not supported by csc 3.5+
895 case "/incremental+":
896 case "/incremental-":
902 if (value.Length == 0){
904 Environment.Exit (1);
907 foreach (string d in value.Split (argument_value_separator)) {
908 string conditional = d.Trim ();
909 if (!Tokenizer.IsValidIdentifier (conditional)) {
910 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
913 RootContext.AddConditional (conditional);
920 // We should collect data, runtime, etc and store in the file specified
922 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
928 if (value.Length == 0){
930 Environment.Exit (1);
932 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
933 string pkgout = GetPackageFlags (packages, true, Report);
936 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
937 Split (new Char [] { ' ', '\t'});
938 args = AddArgs (args, xargs);
945 case "/linkresource":
948 AssemblyResource res = null;
949 string[] s = value.Split (argument_value_separator);
952 if (s[0].Length == 0)
954 res = new AssemblyResource (s [0], Path.GetFileName (s[0]));
957 res = new AssemblyResource (s [0], s [1]);
960 if (s [2] != "public" && s [2] != "private") {
961 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
964 res = new AssemblyResource (s[0], s[1], s[2] == "private");
967 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
972 res.IsEmbeded = arg [1] == 'r' || arg [1] == 'R';
979 if (value.Length == 0) {
980 Error_RequiresFileName (option);
983 ProcessSourceFiles (value, true);
988 if (value.Length == 0) {
989 Error_RequiresFileName (option);
993 string[] refs = value.Split (argument_value_separator);
994 foreach (string r in refs){
999 int index = val.IndexOf ('=');
1001 string alias = r.Substring (0, index);
1002 string assembly = r.Substring (index + 1);
1003 AddAssemblyReference (alias, assembly);
1004 if (refs.Length != 1) {
1005 Report.Error (2034, "Cannot specify multiple aliases using single /reference option");
1009 AddAssemblyReference (val);
1014 case "/addmodule": {
1015 if (value.Length == 0) {
1016 Error_RequiresFileName (option);
1020 string[] refs = value.Split (argument_value_separator);
1021 foreach (string r in refs){
1022 RootContext.Modules.Add (r);
1027 if (value.Length == 0) {
1028 Error_RequiresFileName (option);
1032 if (RootContext.Win32IconFile != null)
1033 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1035 RootContext.Win32ResourceFile = value;
1038 case "/win32icon": {
1039 if (value.Length == 0) {
1040 Error_RequiresFileName (option);
1044 if (RootContext.Win32ResourceFile != null)
1045 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1047 RootContext.Win32IconFile = value;
1051 if (value.Length == 0) {
1052 Error_RequiresFileName (option);
1056 RootContext.Documentation = new Documentation (value);
1062 if (value.Length == 0) {
1063 Error_RequiresFileName (option);
1067 libdirs = value.Split (argument_value_separator);
1068 foreach (string dir in libdirs)
1069 RootContext.ReferencesLookupPaths.Add (dir);
1074 RootContext.GenerateDebugInfo = false;
1078 if (value == "full" || value == "")
1079 RootContext.GenerateDebugInfo = true;
1084 RootContext.GenerateDebugInfo = true;
1089 RootContext.Checked = true;
1093 RootContext.Checked = false;
1098 RootContext.VerifyClsCompliance = true;
1102 RootContext.VerifyClsCompliance = false;
1107 RootContext.Unsafe = true;
1111 RootContext.Unsafe = false;
1114 case "/warnaserror":
1115 case "/warnaserror+":
1116 if (value.Length == 0) {
1117 Report.WarningsAreErrors = true;
1119 foreach (string wid in value.Split (argument_value_separator))
1120 Report.AddWarningAsError (wid);
1124 case "/warnaserror-":
1125 if (value.Length == 0) {
1126 Report.WarningsAreErrors = false;
1128 foreach (string wid in value.Split (argument_value_separator))
1129 Report.RemoveWarningAsError (wid);
1134 if (value.Length == 0) {
1135 Error_RequiresArgument (option);
1139 SetWarningLevel (value);
1143 if (value.Length == 0){
1144 Error_RequiresArgument (option);
1148 var warns = value.Split (argument_value_separator);
1149 foreach (string wc in warns){
1151 if (wc.Trim ().Length == 0)
1154 int warn = Int32.Parse (wc);
1156 throw new ArgumentOutOfRangeException("warn");
1158 Report.SetIgnoreWarning (warn);
1160 Report.Error (1904, "`{0}' is not a valid warning number", wc);
1167 RootContext.LoadDefaultReferences = false;
1171 if (value.Length == 0) {
1172 Error_RequiresArgument (option);
1176 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1178 RootContext.Platform = Platform.AnyCPU;
1181 RootContext.Platform = Platform.X86;
1184 RootContext.Platform = Platform.X64;
1187 RootContext.Platform = Platform.IA64;
1190 Report.Error (1672, "Invalid platform type for -platform. Valid options are `anycpu', `x86', `x64' or `itanium'");
1196 // We just ignore this.
1197 case "/errorreport":
1199 if (value.Length == 0) {
1200 Error_RequiresArgument (option);
1206 case "/helpinternal":
1208 Environment.Exit(0);
1214 Environment.Exit (0);
1219 if (value.Length == 0){
1220 Error_RequiresArgument (option);
1223 RootContext.MainClass = value;
1228 RootContext.StdLib = false;
1232 RootContext.StdLib = true;
1239 if (value.Length == 0) {
1240 Error_RequiresFileName (option);
1244 RootContext.StrongNameKeyFile = value;
1247 case "/keycontainer":
1248 if (value.Length == 0) {
1249 Error_RequiresArgument (option);
1253 RootContext.StrongNameKeyContainer = value;
1257 RootContext.StrongNameDelaySign = true;
1260 RootContext.StrongNameDelaySign = false;
1263 case "/langversion":
1264 if (value.Length == 0) {
1265 Error_RequiresArgument (option);
1269 switch (value.ToLowerInvariant ()) {
1271 RootContext.Version = LanguageVersion.ISO_1;
1274 RootContext.Version = LanguageVersion.Default;
1275 RootContext.AddConditional ("__V2__");
1278 RootContext.Version = LanguageVersion.ISO_2;
1281 RootContext.Version = LanguageVersion.V_3;
1284 RootContext.Version = LanguageVersion.Future;
1288 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1292 if (value.Length == 0) {
1293 Error_RequiresArgument (option);
1299 RootContext.Encoding = new UTF8Encoding();
1302 RootContext.Encoding = Encoding.Default;
1306 RootContext.Encoding = Encoding.GetEncoding (Int32.Parse (value));
1308 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1321 void Error_WrongOption (string option)
1323 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1326 void Error_RequiresFileName (string option)
1328 Report.Error (2005, "Missing file specification for `{0}' option", option);
1331 void Error_RequiresArgument (string option)
1333 Report.Error (2006, "Missing argument for `{0}' option", option);
1336 static string [] AddArgs (string [] args, string [] extra_args)
1339 new_args = new string [extra_args.Length + args.Length];
1341 // if args contains '--' we have to take that into account
1342 // split args into first half and second half based on '--'
1343 // and add the extra_args before --
1344 int split_position = Array.IndexOf (args, "--");
1345 if (split_position != -1)
1347 Array.Copy (args, new_args, split_position);
1348 extra_args.CopyTo (new_args, split_position);
1349 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1353 args.CopyTo (new_args, 0);
1354 extra_args.CopyTo (new_args, args.Length);
1360 void AddAssemblyReference (string assembly)
1362 RootContext.AssemblyReferences.Add (assembly);
1365 void AddAssemblyReference (string alias, string assembly)
1367 if (assembly.Length == 0) {
1368 Report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
1372 if (!IsExternAliasValid (alias)) {
1373 Report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
1377 RootContext.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
1380 void AddResource (AssemblyResource res)
1382 if (RootContext.Resources == null) {
1383 RootContext.Resources = new List<AssemblyResource> ();
1384 RootContext.Resources.Add (res);
1388 if (RootContext.Resources.Contains (res)) {
1389 ctx.Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
1393 RootContext.Resources.Add (res);
1396 static bool IsExternAliasValid (string identifier)
1398 if (identifier.Length == 0)
1400 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1403 for (int i = 1; i < identifier.Length; i++) {
1404 char c = identifier [i];
1405 if (Char.IsLetter (c) || Char.IsDigit (c))
1408 UnicodeCategory category = Char.GetUnicodeCategory (c);
1409 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1410 category != UnicodeCategory.SpacingCombiningMark ||
1411 category != UnicodeCategory.ConnectorPunctuation)
1419 // Main compilation method
1421 public bool Compile ()
1423 var module = new ModuleContainer (ctx);
1424 RootContext.ToplevelTypes = module;
1427 stopwatch = Stopwatch.StartNew ();
1428 first_time = DateTime.Now;
1432 ShowTime ("Parsing source files");
1434 if (Report.Errors > 0)
1437 if (RootContext.TokenizeOnly || RootContext.ParseOnly)
1440 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1441 throw new InternalErrorException ("who set it?");
1446 var output_file = RootContext.OutputFile;
1447 string output_file_name;
1448 if (output_file == null) {
1449 if (first_source == null) {
1450 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1454 int pos = first_source.LastIndexOf ('.');
1457 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1459 output_file = first_source + RootContext.TargetExt;
1461 output_file_name = output_file;
1463 output_file_name = Path.GetFileName (output_file);
1467 // Load assemblies required
1470 stopwatch = Stopwatch.StartNew ();
1473 var assembly = new AssemblyDefinitionStatic (module, output_file_name, output_file);
1474 module.SetDeclaringAssembly (assembly);
1476 var importer = new StaticImporter ();
1477 assembly.Importer = importer;
1479 var loader = new StaticLoader (importer, ctx);
1480 loader.LoadReferences (module);
1482 ShowTime ("Imporing referenced assemblies");
1484 if (!ctx.BuildinTypes.CheckDefinitions (module))
1487 ShowTime ("Initializing predefined types");
1489 if (!assembly.Create (loader.Domain))
1492 // System.Object was not loaded, use compiled assembly as corlib
1493 if (loader.Corlib == null)
1494 loader.Corlib = assembly.Builder;
1496 loader.LoadModules (assembly, module.GlobalRootNamespace);
1498 var assembly = new AssemblyDefinitionDynamic (module, output_file_name, output_file);
1499 module.SetDeclaringAssembly (assembly);
1501 var importer = new ReflectionImporter (ctx.BuildinTypes);
1502 assembly.Importer = importer;
1504 var loader = new DynamicLoader (importer, ctx);
1505 loader.LoadReferences (module);
1507 ShowTime ("Imporing referenced assemblies");
1509 if (!ctx.BuildinTypes.CheckDefinitions (module))
1512 ShowTime ("Initializing predefined types");
1514 if (!assembly.Create (AppDomain.CurrentDomain, AssemblyBuilderAccess.Save))
1517 loader.LoadModules (assembly, module.GlobalRootNamespace);
1521 ShowTime ("Types definition");
1523 if (Report.Errors > 0)
1526 if (Report.Errors == 0 &&
1527 RootContext.Documentation != null &&
1528 !RootContext.Documentation.OutputDocComment (
1529 output_file, Report))
1533 // Verify using aliases now
1535 NamespaceEntry.VerifyAllUsing ();
1537 if (Report.Errors > 0){
1541 assembly.Resolve ();
1543 if (Report.Errors > 0)
1547 // The code generator
1550 stopwatch = Stopwatch.StartNew ();
1554 ShowTime ("Resolving and emitting members blocks");
1556 if (Report.Errors > 0){
1560 module.CloseType ();
1562 ShowTime ("Closing types");
1565 stopwatch = Stopwatch.StartNew ();
1567 assembly.EmbedResources ();
1568 ShowTime ("Embedding resources");
1570 if (Report.Errors > 0)
1574 stopwatch = Stopwatch.StartNew ();
1582 ShowTime ("Saving output assembly");
1584 ShowTotalTime ("Total");
1586 Timer.ShowTimers ();
1588 return (Report.Errors == 0);
1593 // This is the only public entry point
1595 public class CompilerCallableEntryPoint : MarshalByRefObject {
1596 public static bool InvokeCompiler (string [] args, TextWriter error)
1599 StreamReportPrinter srp = new StreamReportPrinter (error);
1600 Driver d = Driver.Create (args, true, srp);
1604 return d.Compile () && srp.ErrorsCount == 0;
1610 public static int[] AllWarningNumbers {
1612 return Report.AllWarnings;
1616 public static void Reset ()
1621 public static void PartialReset ()
1626 public static void Reset (bool full_flag)
1628 CSharpParser.yacc_verbose_flag = 0;
1634 RootContext.Reset (full_flag);
1635 TypeManager.Reset ();
1636 ArrayContainer.Reset ();
1637 ReferenceContainer.Reset ();
1638 PointerContainer.Reset ();
1642 UnaryMutator.Reset ();
1644 ConstantFold.Reset ();
1645 CastFromDecimal.Reset ();
1646 StringConcat.Reset ();
1648 NamespaceEntry.Reset ();
1650 AnonymousTypeClass.Reset ();
1651 AnonymousMethodBody.Reset ();
1652 AnonymousMethodStorey.Reset ();
1653 SymbolWriter.Reset ();
1655 Linq.QueryBlock.TransparentParameter.Reset ();