2009-06-05 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / driver.cs
blob1fecc33299c44a6e07b14caf44bc291e013f710f
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@gnu.org)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
14 namespace Mono.CSharp
16 using System;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Collections;
20 using System.Collections.Specialized;
21 using System.IO;
22 using System.Text;
23 using System.Globalization;
24 using System.Diagnostics;
26 public enum Target {
27 Library, Exe, Module, WinExe
30 /// <summary>
31 /// The compiler driver.
32 /// </summary>
33 class Driver
36 // Assemblies references to be linked. Initialized with
37 // mscorlib.dll here.
38 ArrayList references;
41 // If any of these fail, we ignore the problem. This is so
42 // that we can list all the assemblies in Windows and not fail
43 // if they are missing on Linux.
45 ArrayList soft_references;
47 //
48 // External aliases for assemblies.
50 Hashtable external_aliases;
53 // Modules to be linked
55 ArrayList modules;
57 // Lookup paths
58 static ArrayList link_paths;
60 // Whether we want to only run the tokenizer
61 bool tokenize;
63 string first_source;
65 bool want_debugging_support;
66 bool parse_only;
67 bool timestamps;
70 // Whether to load the initial config file (what CSC.RSP has by default)
71 //
72 bool load_default_config = true;
75 // A list of resource files
77 Resources embedded_resources;
78 string win32ResourceFile;
79 string win32IconFile;
82 // Output file
84 static string output_file;
87 // Last time we took the time
89 DateTime last_time, first_time;
92 // Encoding.
94 Encoding encoding;
96 static readonly char[] argument_value_separator = new char [] { ';', ',' };
98 static public void Reset ()
100 output_file = null;
103 public Driver ()
105 encoding = Encoding.Default;
108 public static Driver Create (string [] args, bool require_files)
110 Driver d = new Driver ();
111 if (!d.ParseArguments (args, require_files))
112 return null;
114 return d;
117 void ShowTime (string msg)
119 if (!timestamps)
120 return;
122 DateTime now = DateTime.Now;
123 TimeSpan span = now - last_time;
124 last_time = now;
126 Console.WriteLine (
127 "[{0:00}:{1:000}] {2}",
128 (int) span.TotalSeconds, span.Milliseconds, msg);
131 void ShowTotalTime (string msg)
133 if (!timestamps)
134 return;
136 DateTime now = DateTime.Now;
137 TimeSpan span = now - first_time;
138 last_time = now;
140 Console.WriteLine (
141 "[{0:00}:{1:000}] {2}",
142 (int) span.TotalSeconds, span.Milliseconds, msg);
145 void tokenize_file (CompilationUnit file)
147 Stream input;
149 try {
150 input = File.OpenRead (file.Name);
151 } catch {
152 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
153 return;
156 using (input){
157 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
158 Tokenizer lexer = new Tokenizer (reader, file);
159 int token, tokens = 0, errors = 0;
161 while ((token = lexer.token ()) != Token.EOF){
162 tokens++;
163 if (token == Token.ERROR)
164 errors++;
166 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
169 return;
172 void Parse (CompilationUnit file)
174 Stream input;
176 try {
177 input = File.OpenRead (file.Name);
178 } catch {
179 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
180 return;
183 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
185 // Check 'MZ' header
186 if (reader.Read () == 77 && reader.Read () == 90) {
187 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
188 input.Close ();
189 return;
192 reader.Position = 0;
193 Parse (reader, file);
194 input.Close ();
197 void Parse (SeekableStreamReader reader, CompilationUnit file)
199 CSharpParser parser = new CSharpParser (reader, file);
200 parser.ErrorOutput = Report.Stderr;
201 try {
202 parser.parse ();
203 } catch (Exception ex) {
204 Report.Error(589, parser.Lexer.Location,
205 "Compilation aborted in file `{0}', {1}", file.Name, ex);
209 static void OtherFlags ()
211 Console.WriteLine (
212 "Other flags in the compiler\n" +
213 " --fatal Makes errors fatal\n" +
214 " --parse Only parses the source file\n" +
215 " --typetest Tests the tokenizer's built-in type parser\n" +
216 " --stacktrace Shows stack trace at error location\n" +
217 " --timestamp Displays time stamps of various compiler events\n" +
218 " --expect-error X Expect that error X will be encountered\n" +
219 " -v Verbose parsing (for debugging the parser)\n" +
220 " --mcs-debug X Sets MCS debugging level to X\n");
223 static void Usage ()
225 Console.WriteLine (
226 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
227 "mcs [options] source-files\n" +
228 " --about About the Mono C# compiler\n" +
229 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
230 " -checked[+|-] Sets default aritmetic overflow context\n" +
231 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
232 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
233 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
234 " -debug[+|-], -g Generate debugging information\n" +
235 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
236 " -doc:FILE Process documentation comments to XML file\n" +
237 " -help Lists all compiler options (short: -?)\n" +
238 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
239 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
240 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, Default, or Future\n" +
241 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
242 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
243 " -noconfig Disables implicitly referenced assemblies\n" +
244 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
245 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
246 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
247 " -out:FILE Specifies output assembly name\n" +
248 #if !SMCS_SOURCE
249 " -pkg:P1[,Pn] References packages P1..Pn\n" +
250 #endif
251 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
252 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
253 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
254 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
255 " KIND can be one of: exe, winexe, library, module\n" +
256 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
257 " -warnaserror[+|-] Treats all warnings as errors\n" +
258 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
259 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
260 " -help2 Shows internal compiler options\n" +
261 "\n" +
262 "Resources:\n" +
263 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
264 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
265 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
266 " -win32icon:FILE Use this icon for the output\n" +
267 " @file Read response file for more options\n\n" +
268 "Options can be of the form -option or /option");
271 static void TargetUsage ()
273 Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
276 static void About ()
278 Console.WriteLine (
279 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
280 "The compiler source code is released under the terms of the \n"+
281 "MIT X11 or GNU GPL licenses\n\n" +
283 "For more information on Mono, visit the project Web site\n" +
284 " http://www.mono-project.com\n\n" +
286 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
287 Environment.Exit (0);
290 public static int Main (string[] args)
292 RootContext.Version = LanguageVersion.Default;
294 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
296 Driver d = Driver.Create (args, true);
297 if (d == null)
298 return 1;
300 if (d.Compile () && Report.Errors == 0) {
301 if (Report.Warnings > 0) {
302 Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
304 Environment.Exit (0);
305 return 0;
309 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
310 Report.Errors, Report.Warnings);
311 Environment.Exit (1);
312 return 1;
315 static public void LoadAssembly (string assembly, bool soft)
317 LoadAssembly (assembly, null, soft);
320 static void Error6 (string name, string log)
322 if (log != null && log.Length > 0)
323 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
324 Report.Error (6, "cannot find metadata file `{0}'", name);
327 static void Error9 (string type, string filename, string log)
329 if (log != null && log.Length > 0)
330 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
331 Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
334 static void BadAssembly (string filename, string log)
336 MethodInfo adder_method = AssemblyClass.AddModule_Method;
338 if (adder_method != null) {
339 AssemblyName an = new AssemblyName ();
340 an.Name = ".temp";
341 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
342 try {
343 object m = null;
344 try {
345 m = adder_method.Invoke (ab, new object [] { filename });
346 } catch (TargetInvocationException ex) {
347 throw ex.InnerException;
350 if (m != null) {
351 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
352 Path.GetFileName (filename));
353 return;
355 } catch (FileNotFoundException) {
356 // did the file get deleted during compilation? who cares? swallow the exception
357 } catch (BadImageFormatException) {
358 // swallow exception
359 } catch (FileLoadException) {
360 // swallow exception
363 Error9 ("assembly", filename, log);
366 static public void LoadAssembly (string assembly, string alias, bool soft)
368 Assembly a = null;
369 string total_log = "";
371 try {
372 try {
373 char[] path_chars = { '/', '\\' };
375 if (assembly.IndexOfAny (path_chars) != -1) {
376 a = Assembly.LoadFrom (assembly);
377 } else {
378 string ass = assembly;
379 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
380 ass = assembly.Substring (0, assembly.Length - 4);
381 a = Assembly.Load (ass);
383 } catch (FileNotFoundException) {
384 bool err = !soft;
385 foreach (string dir in link_paths) {
386 string full_path = Path.Combine (dir, assembly);
387 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
388 full_path += ".dll";
390 try {
391 a = Assembly.LoadFrom (full_path);
392 err = false;
393 break;
394 } catch (FileNotFoundException ff) {
395 if (soft)
396 return;
397 total_log += ff.FusionLog;
400 if (err) {
401 Error6 (assembly, total_log);
402 return;
406 // Extern aliased refs require special handling
407 if (alias == null)
408 GlobalRootNamespace.Instance.AddAssemblyReference (a);
409 else
410 GlobalRootNamespace.Instance.DefineRootNamespace (alias, a);
412 } catch (BadImageFormatException f) {
413 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
414 BadAssembly (f.FileName, f.FusionLog);
415 } catch (FileLoadException f) {
416 // ... while .NET 1.1 throws this
417 BadAssembly (f.FileName, f.FusionLog);
421 static public void LoadModule (string module)
423 Module m = null;
424 string total_log = "";
426 try {
427 try {
428 m = CodeGen.Assembly.AddModule (module);
429 } catch (FileNotFoundException) {
430 bool err = true;
431 foreach (string dir in link_paths) {
432 string full_path = Path.Combine (dir, module);
433 if (!module.EndsWith (".netmodule"))
434 full_path += ".netmodule";
436 try {
437 m = CodeGen.Assembly.AddModule (full_path);
438 err = false;
439 break;
440 } catch (FileNotFoundException ff) {
441 total_log += ff.FusionLog;
444 if (err) {
445 Error6 (module, total_log);
446 return;
450 GlobalRootNamespace.Instance.AddModuleReference (m);
452 } catch (BadImageFormatException f) {
453 Error9 ("module", f.FileName, f.FusionLog);
454 } catch (FileLoadException f) {
455 Error9 ("module", f.FileName, f.FusionLog);
459 /// <summary>
460 /// Loads all assemblies referenced on the command line
461 /// </summary>
462 public void LoadReferences ()
464 link_paths.Add (GetSystemDir ());
465 link_paths.Add (Directory.GetCurrentDirectory ());
468 // Load Core Library for default compilation
470 if (RootContext.StdLib)
471 LoadAssembly ("mscorlib", false);
473 foreach (string r in soft_references)
474 LoadAssembly (r, true);
476 foreach (string r in references)
477 LoadAssembly (r, false);
479 foreach (DictionaryEntry entry in external_aliases)
480 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
482 GlobalRootNamespace.Instance.ComputeNamespaces ();
485 static string [] LoadArgs (string file)
487 StreamReader f;
488 ArrayList args = new ArrayList ();
489 string line;
490 try {
491 f = new StreamReader (file);
492 } catch {
493 return null;
496 StringBuilder sb = new StringBuilder ();
498 while ((line = f.ReadLine ()) != null){
499 int t = line.Length;
501 for (int i = 0; i < t; i++){
502 char c = line [i];
504 if (c == '"' || c == '\''){
505 char end = c;
507 for (i++; i < t; i++){
508 c = line [i];
510 if (c == end)
511 break;
512 sb.Append (c);
514 } else if (c == ' '){
515 if (sb.Length > 0){
516 args.Add (sb.ToString ());
517 sb.Length = 0;
519 } else
520 sb.Append (c);
522 if (sb.Length > 0){
523 args.Add (sb.ToString ());
524 sb.Length = 0;
528 string [] ret_value = new string [args.Count];
529 args.CopyTo (ret_value, 0);
531 return ret_value;
535 // Returns the directory where the system assemblies are installed
537 static string GetSystemDir ()
539 return Path.GetDirectoryName (typeof (object).Assembly.Location);
543 // Given a path specification, splits the path from the file/pattern
545 static void SplitPathAndPattern (string spec, out string path, out string pattern)
547 int p = spec.LastIndexOf ('/');
548 if (p != -1){
550 // Windows does not like /file.cs, switch that to:
551 // "\", "file.cs"
553 if (p == 0){
554 path = "\\";
555 pattern = spec.Substring (1);
556 } else {
557 path = spec.Substring (0, p);
558 pattern = spec.Substring (p + 1);
560 return;
563 p = spec.LastIndexOf ('\\');
564 if (p != -1){
565 path = spec.Substring (0, p);
566 pattern = spec.Substring (p + 1);
567 return;
570 path = ".";
571 pattern = spec;
574 void AddSourceFile (string f)
576 if (first_source == null)
577 first_source = f;
579 Location.AddFile (f);
582 bool ParseArguments (string[] args, bool require_files)
584 references = new ArrayList ();
585 external_aliases = new Hashtable ();
586 soft_references = new ArrayList ();
587 modules = new ArrayList (2);
588 link_paths = new ArrayList ();
590 ArrayList response_file_list = null;
591 bool parsing_options = true;
593 for (int i = 0; i < args.Length; i++) {
594 string arg = args [i];
595 if (arg.Length == 0)
596 continue;
598 if (arg [0] == '@') {
599 string [] extra_args;
600 string response_file = arg.Substring (1);
602 if (response_file_list == null)
603 response_file_list = new ArrayList ();
605 if (response_file_list.Contains (response_file)) {
606 Report.Error (
607 1515, "Response file `" + response_file +
608 "' specified multiple times");
609 return false;
612 response_file_list.Add (response_file);
614 extra_args = LoadArgs (response_file);
615 if (extra_args == null) {
616 Report.Error (2011, "Unable to open response file: " +
617 response_file);
618 return false;
621 args = AddArgs (args, extra_args);
622 continue;
625 if (parsing_options) {
626 if (arg == "--") {
627 parsing_options = false;
628 continue;
631 if (arg [0] == '-') {
632 if (UnixParseOption (arg, ref args, ref i))
633 continue;
635 // Try a -CSCOPTION
636 string csc_opt = "/" + arg.Substring (1);
637 if (CSCParseOption (csc_opt, ref args))
638 continue;
640 Error_WrongOption (arg);
641 return false;
643 if (arg [0] == '/') {
644 if (CSCParseOption (arg, ref args))
645 continue;
647 // Need to skip `/home/test.cs' however /test.cs is considered as error
648 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
649 Error_WrongOption (arg);
650 return false;
655 ProcessSourceFiles (arg, false);
658 if (require_files == false)
659 return true;
662 // If we are an exe, require a source file for the entry point
664 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
665 if (first_source == null) {
666 Report.Error (2008, "No files to compile were specified");
667 return false;
673 // If there is nothing to put in the assembly, and we are not a library
675 if (first_source == null && embedded_resources == null) {
676 Report.Error (2008, "No files to compile were specified");
677 return false;
680 return true;
683 public void Parse ()
685 Location.Initialize ();
687 ArrayList cu = Location.SourceFiles;
688 for (int i = 0; i < cu.Count; ++i) {
689 if (tokenize) {
690 tokenize_file ((CompilationUnit) cu [i]);
691 } else {
692 Parse ((CompilationUnit) cu [i]);
697 void ProcessSourceFiles (string spec, bool recurse)
699 string path, pattern;
701 SplitPathAndPattern (spec, out path, out pattern);
702 if (pattern.IndexOf ('*') == -1){
703 AddSourceFile (spec);
704 return;
707 string [] files = null;
708 try {
709 files = Directory.GetFiles (path, pattern);
710 } catch (System.IO.DirectoryNotFoundException) {
711 Report.Error (2001, "Source file `" + spec + "' could not be found");
712 return;
713 } catch (System.IO.IOException){
714 Report.Error (2001, "Source file `" + spec + "' could not be found");
715 return;
717 foreach (string f in files) {
718 AddSourceFile (f);
721 if (!recurse)
722 return;
724 string [] dirs = null;
726 try {
727 dirs = Directory.GetDirectories (path);
728 } catch {
731 foreach (string d in dirs) {
733 // Don't include path in this string, as each
734 // directory entry already does
735 ProcessSourceFiles (d + "/" + pattern, true);
739 public void ProcessDefaultConfig ()
741 if (!load_default_config)
742 return;
745 // For now the "default config" is harcoded into the compiler
746 // we can move this outside later
748 string [] default_config = {
749 "System",
750 "System.Xml",
751 #if NET_2_1
752 "System.Net",
753 "System.Windows",
754 "System.Windows.Browser",
755 #endif
756 #if false
758 // Is it worth pre-loading all this stuff?
760 "Accessibility",
761 "System.Configuration.Install",
762 "System.Data",
763 "System.Design",
764 "System.DirectoryServices",
765 "System.Drawing.Design",
766 "System.Drawing",
767 "System.EnterpriseServices",
768 "System.Management",
769 "System.Messaging",
770 "System.Runtime.Remoting",
771 "System.Runtime.Serialization.Formatters.Soap",
772 "System.Security",
773 "System.ServiceProcess",
774 "System.Web",
775 "System.Web.RegularExpressions",
776 "System.Web.Services",
777 "System.Windows.Forms"
778 #endif
781 soft_references.AddRange (default_config);
783 if (RootContext.Version > LanguageVersion.ISO_2)
784 soft_references.Add ("System.Core");
787 public static string OutputFile
789 set {
790 output_file = value;
792 get {
793 return Path.GetFileName (output_file);
797 static void SetWarningLevel (string s)
799 int level = -1;
801 try {
802 level = Int32.Parse (s);
803 } catch {
805 if (level < 0 || level > 4){
806 Report.Error (1900, "Warning level must be in the range 0-4");
807 return;
809 Report.WarningLevel = level;
812 static void Version ()
814 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
815 Console.WriteLine ("Mono C# compiler version {0}", version);
816 Environment.Exit (0);
820 // Currently handles the Unix-like command line options, but will be
821 // deprecated in favor of the CSCParseOption, which will also handle the
822 // options that start with a dash in the future.
824 bool UnixParseOption (string arg, ref string [] args, ref int i)
826 switch (arg){
827 case "-v":
828 CSharpParser.yacc_verbose_flag++;
829 return true;
831 case "--version":
832 Version ();
833 return true;
835 case "--parse":
836 parse_only = true;
837 return true;
839 case "--main": case "-m":
840 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
841 if ((i + 1) >= args.Length){
842 Usage ();
843 Environment.Exit (1);
845 RootContext.MainClass = args [++i];
846 return true;
848 case "--unsafe":
849 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
850 RootContext.Unsafe = true;
851 return true;
853 case "/?": case "/h": case "/help":
854 case "--help":
855 Usage ();
856 Environment.Exit (0);
857 return true;
859 case "--define":
860 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
861 if ((i + 1) >= args.Length){
862 Usage ();
863 Environment.Exit (1);
865 RootContext.AddConditional (args [++i]);
866 return true;
868 case "--tokenize":
869 tokenize = true;
870 return true;
872 case "-o":
873 case "--output":
874 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
875 if ((i + 1) >= args.Length){
876 Usage ();
877 Environment.Exit (1);
879 OutputFile = args [++i];
880 return true;
882 case "--checked":
883 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
884 RootContext.Checked = true;
885 return true;
887 case "--stacktrace":
888 Report.Stacktrace = true;
889 return true;
891 case "--linkresource":
892 case "--linkres":
893 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
894 if ((i + 1) >= args.Length){
895 Usage ();
896 Report.Error (5, "Missing argument to --linkres");
897 Environment.Exit (1);
899 if (embedded_resources == null)
900 embedded_resources = new Resources ();
902 embedded_resources.Add (false, args [++i], args [i]);
903 return true;
905 case "--resource":
906 case "--res":
907 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
908 if ((i + 1) >= args.Length){
909 Usage ();
910 Report.Error (5, "Missing argument to --resource");
911 Environment.Exit (1);
913 if (embedded_resources == null)
914 embedded_resources = new Resources ();
916 embedded_resources.Add (true, args [++i], args [i]);
917 return true;
919 case "--target":
920 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
921 if ((i + 1) >= args.Length){
922 Environment.Exit (1);
923 return true;
926 string type = args [++i];
927 switch (type){
928 case "library":
929 RootContext.Target = Target.Library;
930 RootContext.TargetExt = ".dll";
931 break;
933 case "exe":
934 RootContext.Target = Target.Exe;
935 break;
937 case "winexe":
938 RootContext.Target = Target.WinExe;
939 break;
941 case "module":
942 RootContext.Target = Target.Module;
943 RootContext.TargetExt = ".dll";
944 break;
945 default:
946 TargetUsage ();
947 break;
949 return true;
951 case "-r":
952 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
953 if ((i + 1) >= args.Length){
954 Usage ();
955 Environment.Exit (1);
958 string val = args [++i];
959 int idx = val.IndexOf ('=');
960 if (idx > -1) {
961 string alias = val.Substring (0, idx);
962 string assembly = val.Substring (idx + 1);
963 AddExternAlias (alias, assembly);
964 return true;
967 references.Add (val);
968 return true;
970 case "-L":
971 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
972 if ((i + 1) >= args.Length){
973 Usage ();
974 Environment.Exit (1);
976 link_paths.Add (args [++i]);
977 return true;
979 case "--nostdlib":
980 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
981 RootContext.StdLib = false;
982 return true;
984 case "--fatal":
985 Report.Fatal = true;
986 return true;
988 case "--nowarn":
989 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
990 if ((i + 1) >= args.Length){
991 Usage ();
992 Environment.Exit (1);
994 int warn = 0;
996 try {
997 warn = Int32.Parse (args [++i]);
998 } catch {
999 Usage ();
1000 Environment.Exit (1);
1002 Report.SetIgnoreWarning (warn);
1003 return true;
1005 case "--wlevel":
1006 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1007 if ((i + 1) >= args.Length){
1008 Report.Error (
1009 1900,
1010 "--wlevel requires a value from 0 to 4");
1011 Environment.Exit (1);
1014 SetWarningLevel (args [++i]);
1015 return true;
1017 case "--mcs-debug":
1018 if ((i + 1) >= args.Length){
1019 Report.Error (5, "--mcs-debug requires an argument");
1020 Environment.Exit (1);
1023 try {
1024 Report.DebugFlags = Int32.Parse (args [++i]);
1025 } catch {
1026 Report.Error (5, "Invalid argument to --mcs-debug");
1027 Environment.Exit (1);
1029 return true;
1031 case "--about":
1032 About ();
1033 return true;
1035 case "--recurse":
1036 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1037 if ((i + 1) >= args.Length){
1038 Report.Error (5, "--recurse requires an argument");
1039 Environment.Exit (1);
1041 ProcessSourceFiles (args [++i], true);
1042 return true;
1044 case "--timestamp":
1045 timestamps = true;
1046 last_time = first_time = DateTime.Now;
1047 return true;
1049 case "--debug": case "-g":
1050 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1051 want_debugging_support = true;
1052 return true;
1054 case "--noconfig":
1055 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1056 load_default_config = false;
1057 return true;
1060 return false;
1063 #if !SMCS_SOURCE
1064 public static string GetPackageFlags (string packages, bool fatal)
1066 ProcessStartInfo pi = new ProcessStartInfo ();
1067 pi.FileName = "pkg-config";
1068 pi.RedirectStandardOutput = true;
1069 pi.UseShellExecute = false;
1070 pi.Arguments = "--libs " + packages;
1071 Process p = null;
1072 try {
1073 p = Process.Start (pi);
1074 } catch (Exception e) {
1075 Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1076 if (fatal)
1077 Environment.Exit (1);
1078 p.Close ();
1079 return null;
1082 if (p.StandardOutput == null){
1083 Report.Warning (-27, 1, "Specified package did not return any information");
1084 p.Close ();
1085 return null;
1087 string pkgout = p.StandardOutput.ReadToEnd ();
1088 p.WaitForExit ();
1089 if (p.ExitCode != 0) {
1090 Report.Error (-27, "Error running pkg-config. Check the above output.");
1091 if (fatal)
1092 Environment.Exit (1);
1093 p.Close ();
1094 return null;
1096 p.Close ();
1098 return pkgout;
1100 #endif
1103 // This parses the -arg and /arg options to the compiler, even if the strings
1104 // in the following text use "/arg" on the strings.
1106 bool CSCParseOption (string option, ref string [] args)
1108 int idx = option.IndexOf (':');
1109 string arg, value;
1111 if (idx == -1){
1112 arg = option;
1113 value = "";
1114 } else {
1115 arg = option.Substring (0, idx);
1117 value = option.Substring (idx + 1);
1120 switch (arg.ToLower (CultureInfo.InvariantCulture)){
1121 case "/nologo":
1122 return true;
1124 case "/t":
1125 case "/target":
1126 switch (value){
1127 case "exe":
1128 RootContext.Target = Target.Exe;
1129 break;
1131 case "winexe":
1132 RootContext.Target = Target.WinExe;
1133 break;
1135 case "library":
1136 RootContext.Target = Target.Library;
1137 RootContext.TargetExt = ".dll";
1138 break;
1140 case "module":
1141 RootContext.Target = Target.Module;
1142 RootContext.TargetExt = ".netmodule";
1143 break;
1145 default:
1146 TargetUsage ();
1147 break;
1149 return true;
1151 case "/out":
1152 if (value.Length == 0){
1153 Usage ();
1154 Environment.Exit (1);
1156 OutputFile = value;
1157 return true;
1159 case "/o":
1160 case "/o+":
1161 case "/optimize":
1162 case "/optimize+":
1163 RootContext.Optimize = true;
1164 return true;
1166 case "/o-":
1167 case "/optimize-":
1168 RootContext.Optimize = false;
1169 return true;
1171 case "/incremental":
1172 case "/incremental+":
1173 case "/incremental-":
1174 // nothing.
1175 return true;
1177 case "/d":
1178 case "/define": {
1179 if (value.Length == 0){
1180 Usage ();
1181 Environment.Exit (1);
1184 foreach (string d in value.Split (argument_value_separator)) {
1185 if (!Tokenizer.IsValidIdentifier (d)) {
1186 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d);
1187 continue;
1189 RootContext.AddConditional (d);
1191 return true;
1194 case "/bugreport":
1196 // We should collect data, runtime, etc and store in the file specified
1198 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1199 return true;
1200 #if !SMCS_SOURCE
1201 case "/pkg": {
1202 string packages;
1204 if (value.Length == 0){
1205 Usage ();
1206 Environment.Exit (1);
1208 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1209 string pkgout = GetPackageFlags (packages, true);
1211 if (pkgout != null){
1212 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1213 Split (new Char [] { ' ', '\t'});
1214 args = AddArgs (args, xargs);
1217 return true;
1219 #endif
1220 case "/linkres":
1221 case "/linkresource":
1222 case "/res":
1223 case "/resource":
1224 if (embedded_resources == null)
1225 embedded_resources = new Resources ();
1227 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1228 string[] s = value.Split (argument_value_separator);
1229 switch (s.Length) {
1230 case 1:
1231 if (s[0].Length == 0)
1232 goto default;
1233 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1234 break;
1235 case 2:
1236 embedded_resources.Add (embeded, s [0], s [1]);
1237 break;
1238 case 3:
1239 if (s [2] != "public" && s [2] != "private") {
1240 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1241 return true;
1243 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1244 break;
1245 default:
1246 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1247 break;
1250 return true;
1252 case "/recurse":
1253 if (value.Length == 0){
1254 Report.Error (5, "-recurse requires an argument");
1255 Environment.Exit (1);
1257 ProcessSourceFiles (value, true);
1258 return true;
1260 case "/r":
1261 case "/reference": {
1262 if (value.Length == 0){
1263 Report.Error (5, "-reference requires an argument");
1264 Environment.Exit (1);
1267 string[] refs = value.Split (argument_value_separator);
1268 foreach (string r in refs){
1269 string val = r;
1270 int index = val.IndexOf ('=');
1271 if (index > -1) {
1272 string alias = r.Substring (0, index);
1273 string assembly = r.Substring (index + 1);
1274 AddExternAlias (alias, assembly);
1275 return true;
1278 if (val.Length != 0)
1279 references.Add (val);
1281 return true;
1283 case "/addmodule": {
1284 if (value.Length == 0){
1285 Report.Error (5, arg + " requires an argument");
1286 Environment.Exit (1);
1289 string[] refs = value.Split (argument_value_separator);
1290 foreach (string r in refs){
1291 modules.Add (r);
1293 return true;
1295 case "/win32res": {
1296 if (value.Length == 0) {
1297 Report.Error (5, arg + " requires an argument");
1298 Environment.Exit (1);
1301 if (win32IconFile != null)
1302 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1304 win32ResourceFile = value;
1305 return true;
1307 case "/win32icon": {
1308 if (value.Length == 0) {
1309 Report.Error (5, arg + " requires an argument");
1310 Environment.Exit (1);
1313 if (win32ResourceFile != null)
1314 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1316 win32IconFile = value;
1317 return true;
1319 case "/doc": {
1320 if (value.Length == 0){
1321 Report.Error (2006, arg + " requires an argument");
1322 Environment.Exit (1);
1324 RootContext.Documentation = new Documentation (value);
1325 return true;
1327 case "/lib": {
1328 string [] libdirs;
1330 if (value.Length == 0){
1331 Report.Error (5, "/lib requires an argument");
1332 Environment.Exit (1);
1335 libdirs = value.Split (argument_value_separator);
1336 foreach (string dir in libdirs)
1337 link_paths.Add (dir);
1338 return true;
1341 case "/debug-":
1342 want_debugging_support = false;
1343 return true;
1345 case "/debug":
1346 if (value == "full" || value == "")
1347 want_debugging_support = true;
1349 return true;
1351 case "/debug+":
1352 want_debugging_support = true;
1353 return true;
1355 case "/checked":
1356 case "/checked+":
1357 RootContext.Checked = true;
1358 return true;
1360 case "/checked-":
1361 RootContext.Checked = false;
1362 return true;
1364 case "/clscheck":
1365 case "/clscheck+":
1366 return true;
1368 case "/clscheck-":
1369 RootContext.VerifyClsCompliance = false;
1370 return true;
1372 case "/unsafe":
1373 case "/unsafe+":
1374 RootContext.Unsafe = true;
1375 return true;
1377 case "/unsafe-":
1378 RootContext.Unsafe = false;
1379 return true;
1381 case "/warnaserror":
1382 case "/warnaserror+":
1383 if (value.Length == 0) {
1384 Report.WarningsAreErrors = true;
1385 } else {
1386 foreach (string wid in value.Split (argument_value_separator))
1387 Report.AddWarningAsError (wid);
1389 return true;
1391 case "/warnaserror-":
1392 if (value.Length == 0) {
1393 Report.WarningsAreErrors = false;
1394 } else {
1395 foreach (string wid in value.Split (argument_value_separator))
1396 Report.RemoveWarningAsError (wid);
1398 return true;
1400 case "/warn":
1401 SetWarningLevel (value);
1402 return true;
1404 case "/nowarn": {
1405 string [] warns;
1407 if (value.Length == 0){
1408 Report.Error (5, "/nowarn requires an argument");
1409 Environment.Exit (1);
1412 warns = value.Split (argument_value_separator);
1413 foreach (string wc in warns){
1414 try {
1415 if (wc.Trim ().Length == 0)
1416 continue;
1418 int warn = Int32.Parse (wc);
1419 if (warn < 1) {
1420 throw new ArgumentOutOfRangeException("warn");
1422 Report.SetIgnoreWarning (warn);
1423 } catch {
1424 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1427 return true;
1430 case "/noconfig":
1431 load_default_config = false;
1432 return true;
1434 // We just ignore this.
1435 case "/errorreport":
1436 case "/filealign":
1437 case "/platform":
1438 return true;
1440 case "/help2":
1441 OtherFlags ();
1442 Environment.Exit(0);
1443 return true;
1445 case "/help":
1446 case "/?":
1447 Usage ();
1448 Environment.Exit (0);
1449 return true;
1451 case "/main":
1452 case "/m":
1453 if (value.Length == 0){
1454 Report.Error (5, arg + " requires an argument");
1455 Environment.Exit (1);
1457 RootContext.MainClass = value;
1458 return true;
1460 case "/nostdlib":
1461 case "/nostdlib+":
1462 RootContext.StdLib = false;
1463 return true;
1465 case "/nostdlib-":
1466 RootContext.StdLib = true;
1467 return true;
1469 case "/fullpaths":
1470 return true;
1472 case "/keyfile":
1473 if (value == String.Empty) {
1474 Report.Error (5, arg + " requires an argument");
1475 Environment.Exit (1);
1477 RootContext.StrongNameKeyFile = value;
1478 return true;
1479 case "/keycontainer":
1480 if (value == String.Empty) {
1481 Report.Error (5, arg + " requires an argument");
1482 Environment.Exit (1);
1484 RootContext.StrongNameKeyContainer = value;
1485 return true;
1486 case "/delaysign+":
1487 RootContext.StrongNameDelaySign = true;
1488 return true;
1489 case "/delaysign-":
1490 RootContext.StrongNameDelaySign = false;
1491 return true;
1493 case "/langversion":
1494 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1495 case "iso-1":
1496 RootContext.Version = LanguageVersion.ISO_1;
1497 return true;
1499 case "default":
1500 RootContext.Version = LanguageVersion.Default;
1501 #if GMCS_SOURCE
1502 RootContext.AddConditional ("__V2__");
1503 #endif
1504 return true;
1505 #if GMCS_SOURCE
1506 case "iso-2":
1507 RootContext.Version = LanguageVersion.ISO_2;
1508 return true;
1509 case "3":
1510 RootContext.Version = LanguageVersion.V_3;
1511 return true;
1512 case "future":
1513 RootContext.Version = LanguageVersion.Future;
1514 return true;
1515 #endif
1517 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1518 return true;
1520 case "/codepage":
1521 switch (value) {
1522 case "utf8":
1523 encoding = new UTF8Encoding();
1524 break;
1525 case "reset":
1526 encoding = Encoding.Default;
1527 break;
1528 default:
1529 try {
1530 encoding = Encoding.GetEncoding (
1531 Int32.Parse (value));
1532 } catch {
1533 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1535 break;
1537 return true;
1540 return false;
1543 static void Error_WrongOption (string option)
1545 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1548 static string [] AddArgs (string [] args, string [] extra_args)
1550 string [] new_args;
1551 new_args = new string [extra_args.Length + args.Length];
1553 // if args contains '--' we have to take that into account
1554 // split args into first half and second half based on '--'
1555 // and add the extra_args before --
1556 int split_position = Array.IndexOf (args, "--");
1557 if (split_position != -1)
1559 Array.Copy (args, new_args, split_position);
1560 extra_args.CopyTo (new_args, split_position);
1561 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1563 else
1565 args.CopyTo (new_args, 0);
1566 extra_args.CopyTo (new_args, args.Length);
1569 return new_args;
1572 void AddExternAlias (string identifier, string assembly)
1574 if (assembly.Length == 0) {
1575 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1576 return;
1579 if (!IsExternAliasValid (identifier)) {
1580 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1581 return;
1584 // Could here hashtable throw an exception?
1585 external_aliases [identifier] = assembly;
1588 static bool IsExternAliasValid (string identifier)
1590 if (identifier.Length == 0)
1591 return false;
1592 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1593 return false;
1595 for (int i = 1; i < identifier.Length; i++) {
1596 char c = identifier [i];
1597 if (Char.IsLetter (c) || Char.IsDigit (c))
1598 continue;
1600 UnicodeCategory category = Char.GetUnicodeCategory (c);
1601 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1602 category != UnicodeCategory.SpacingCombiningMark ||
1603 category != UnicodeCategory.ConnectorPunctuation)
1604 return false;
1607 return true;
1611 // Main compilation method
1613 public bool Compile ()
1615 // TODO: Should be passed to parser as an argument
1616 RootContext.ToplevelTypes = new ModuleContainer (RootContext.Unsafe);
1618 Parse ();
1619 if (Report.Errors > 0)
1620 return false;
1622 if (tokenize || parse_only)
1623 return true;
1625 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1626 throw new InternalErrorException ("who set it?");
1628 ProcessDefaultConfig ();
1631 // Quick hack
1633 if (output_file == null){
1634 if (first_source == null){
1635 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1636 return false;
1639 int pos = first_source.LastIndexOf ('.');
1641 if (pos > 0)
1642 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1643 else
1644 output_file = first_source + RootContext.TargetExt;
1647 if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1648 return false;
1650 if (RootContext.Target == Target.Module) {
1651 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1652 if (module_only == null) {
1653 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1654 Environment.Exit (1);
1657 MethodInfo set_method = module_only.GetSetMethod (true);
1658 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1661 GlobalRootNamespace.Instance.AddModuleReference (RootContext.ToplevelTypes.Builder);
1664 // Load assemblies required
1666 if (timestamps)
1667 ShowTime ("Loading references");
1669 LoadReferences ();
1671 if (modules.Count > 0) {
1672 foreach (string module in modules)
1673 LoadModule (module);
1676 if (timestamps)
1677 ShowTime ("References loaded");
1679 if (!TypeManager.InitCoreTypes () || Report.Errors > 0)
1680 return false;
1682 TypeManager.InitOptionalCoreTypes ();
1684 if (timestamps)
1685 ShowTime (" Core Types done");
1688 // The second pass of the compiler
1690 if (timestamps)
1691 ShowTime ("Resolving tree");
1692 RootContext.ResolveTree ();
1694 if (Report.Errors > 0)
1695 return false;
1696 if (timestamps)
1697 ShowTime ("Populate tree");
1698 if (!RootContext.StdLib)
1699 RootContext.BootCorlib_PopulateCoreTypes ();
1700 RootContext.PopulateTypes ();
1702 if (Report.Errors == 0 &&
1703 RootContext.Documentation != null &&
1704 !RootContext.Documentation.OutputDocComment (
1705 output_file))
1706 return false;
1709 // Verify using aliases now
1711 NamespaceEntry.VerifyAllUsing ();
1713 if (Report.Errors > 0){
1714 return false;
1717 CodeGen.Assembly.Resolve ();
1719 if (RootContext.VerifyClsCompliance) {
1720 if (CodeGen.Assembly.IsClsCompliant) {
1721 AttributeTester.VerifyModulesClsCompliance ();
1722 TypeManager.LoadAllImportedTypes ();
1725 if (Report.Errors > 0)
1726 return false;
1729 // The code generator
1731 if (timestamps)
1732 ShowTime ("Emitting code");
1733 ShowTotalTime ("Total so far");
1734 RootContext.EmitCode ();
1735 if (timestamps)
1736 ShowTime (" done");
1738 if (Report.Errors > 0){
1739 return false;
1742 if (timestamps)
1743 ShowTime ("Closing types");
1745 RootContext.CloseTypes ();
1747 PEFileKinds k = PEFileKinds.ConsoleApplication;
1749 switch (RootContext.Target) {
1750 case Target.Library:
1751 case Target.Module:
1752 k = PEFileKinds.Dll; break;
1753 case Target.Exe:
1754 k = PEFileKinds.ConsoleApplication; break;
1755 case Target.WinExe:
1756 k = PEFileKinds.WindowApplication; break;
1759 if (RootContext.NeedsEntryPoint) {
1760 Method ep = RootContext.EntryPoint;
1762 if (ep == null) {
1763 if (RootContext.MainClass != null) {
1764 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1765 if (main_cont == null) {
1766 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1767 return false;
1770 if (!(main_cont is ClassOrStruct)) {
1771 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1772 return false;
1775 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1776 return false;
1779 if (Report.Errors == 0)
1780 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1781 output_file);
1782 return false;
1785 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1786 } else if (RootContext.MainClass != null) {
1787 Report.Error (2017, "Cannot specify -main if building a module or library");
1790 if (embedded_resources != null){
1791 if (RootContext.Target == Target.Module) {
1792 Report.Error (1507, "Cannot link resource file when building a module");
1793 return false;
1796 embedded_resources.Emit ();
1800 // Add Win32 resources
1803 if (win32ResourceFile != null) {
1804 try {
1805 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1806 } catch (ArgumentException) {
1807 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1809 } else {
1810 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1813 if (win32IconFile != null) {
1814 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1815 if (define_icon == null) {
1816 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1817 } else {
1818 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1822 if (Report.Errors > 0)
1823 return false;
1825 CodeGen.Save (output_file, want_debugging_support);
1826 if (timestamps) {
1827 ShowTime ("Saved output");
1828 ShowTotalTime ("Total");
1831 Timer.ShowTimers ();
1833 if (Report.ExpectedError != 0) {
1834 if (Report.Errors == 0) {
1835 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1836 "No other errors reported.");
1838 Environment.Exit (2);
1839 } else {
1840 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1841 "However, other errors were reported.");
1843 Environment.Exit (1);
1847 return false;
1850 #if DEBUGME
1851 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1852 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1853 #endif
1854 return (Report.Errors == 0);
1858 class Resources
1860 interface IResource
1862 void Emit ();
1863 string FileName { get; }
1866 class EmbededResource : IResource
1868 #if GMCS_SOURCE
1869 string name;
1870 string file;
1871 ResourceAttributes attributes;
1873 public EmbededResource (string name, string file, bool isPrivate)
1875 this.name = name;
1876 this.file = file;
1877 this.attributes = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1880 public void Emit ()
1882 RootContext.ToplevelTypes.Builder.DefineManifestResource (
1883 name, new FileStream (file, FileMode.Open, FileAccess.Read), attributes);
1886 public string FileName {
1887 get { return file; }
1889 #else
1890 static MethodInfo embed_res;
1892 static EmbededResource () {
1893 Type[] argst = new Type [] {
1894 typeof (string), typeof (string), typeof (ResourceAttributes)
1897 embed_res = typeof (AssemblyBuilder).GetMethod (
1898 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1899 null, CallingConventions.Any, argst, null);
1901 if (embed_res == null) {
1902 Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1906 readonly object[] args;
1908 public EmbededResource (string name, string file, bool isPrivate)
1910 args = new object [3];
1911 args [0] = name;
1912 args [1] = file;
1913 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1916 public void Emit()
1918 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1921 public string FileName {
1922 get {
1923 return (string)args [1];
1926 #endif
1929 class LinkedResource : IResource
1931 readonly string file;
1932 readonly string name;
1933 readonly ResourceAttributes attribute;
1935 public LinkedResource (string name, string file, bool isPrivate)
1937 this.name = name;
1938 this.file = file;
1939 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1942 public void Emit ()
1944 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1947 public string FileName {
1948 get {
1949 return file;
1955 IDictionary embedded_resources = new HybridDictionary ();
1957 public void Add (bool embeded, string file, string name)
1959 Add (embeded, file, name, false);
1962 public void Add (bool embeded, string file, string name, bool isPrivate)
1964 if (embedded_resources.Contains (name)) {
1965 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1966 return;
1968 IResource r = embeded ?
1969 (IResource) new EmbededResource (name, file, isPrivate) :
1970 new LinkedResource (name, file, isPrivate);
1972 embedded_resources.Add (name, r);
1975 public void Emit ()
1977 foreach (IResource r in embedded_resources.Values) {
1978 if (!File.Exists (r.FileName)) {
1979 Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1980 continue;
1983 r.Emit ();
1989 // This is the only public entry point
1991 public class CompilerCallableEntryPoint : MarshalByRefObject {
1992 public static bool InvokeCompiler (string [] args, TextWriter error)
1994 Report.Stderr = error;
1995 try {
1996 Driver d = Driver.Create (args, true);
1997 if (d == null)
1998 return false;
2000 return d.Compile () && Report.Errors == 0;
2002 finally {
2003 Report.Stderr = Console.Error;
2004 Reset ();
2008 public static int[] AllWarningNumbers {
2009 get {
2010 return Report.AllWarnings;
2014 public static void Reset ()
2016 Reset (true);
2019 public static void PartialReset ()
2021 Reset (false);
2024 public static void Reset (bool full_flag)
2026 Driver.Reset ();
2027 RootContext.Reset (full_flag);
2028 Location.Reset ();
2029 Report.Reset ();
2030 TypeManager.Reset ();
2031 PredefinedAttributes.Reset ();
2032 TypeHandle.Reset ();
2034 if (full_flag)
2035 GlobalRootNamespace.Reset ();
2037 NamespaceEntry.Reset ();
2038 CodeGen.Reset ();
2039 Attribute.Reset ();
2040 AttributeTester.Reset ();
2041 AnonymousTypeClass.Reset ();
2042 AnonymousMethodBody.Reset ();
2043 AnonymousMethodStorey.Reset ();
2044 SymbolWriter.Reset ();
2045 Switch.Reset ();
2046 Linq.QueryBlock.TransparentParameter.Reset ();
2047 Convert.Reset ();
2048 TypeInfo.Reset ();