* Vbc.cs (AddResponseFileCommands): Escape DefineConstants as it can
[mcs.git] / mcs / driver.cs
blob4476e56c6b0ccdc6dc4c5b3c82c64dcebb56311b
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 case "/debug+":
1347 want_debugging_support = true;
1348 return true;
1350 case "/checked":
1351 case "/checked+":
1352 RootContext.Checked = true;
1353 return true;
1355 case "/checked-":
1356 RootContext.Checked = false;
1357 return true;
1359 case "/clscheck":
1360 case "/clscheck+":
1361 return true;
1363 case "/clscheck-":
1364 RootContext.VerifyClsCompliance = false;
1365 return true;
1367 case "/unsafe":
1368 case "/unsafe+":
1369 RootContext.Unsafe = true;
1370 return true;
1372 case "/unsafe-":
1373 RootContext.Unsafe = false;
1374 return true;
1376 case "/warnaserror":
1377 case "/warnaserror+":
1378 if (value.Length == 0) {
1379 Report.WarningsAreErrors = true;
1380 } else {
1381 foreach (string wid in value.Split (argument_value_separator))
1382 Report.AddWarningAsError (wid);
1384 return true;
1386 case "/warnaserror-":
1387 if (value.Length == 0) {
1388 Report.WarningsAreErrors = false;
1389 } else {
1390 foreach (string wid in value.Split (argument_value_separator))
1391 Report.RemoveWarningAsError (wid);
1393 return true;
1395 case "/warn":
1396 SetWarningLevel (value);
1397 return true;
1399 case "/nowarn": {
1400 string [] warns;
1402 if (value.Length == 0){
1403 Report.Error (5, "/nowarn requires an argument");
1404 Environment.Exit (1);
1407 warns = value.Split (argument_value_separator);
1408 foreach (string wc in warns){
1409 try {
1410 if (wc.Trim ().Length == 0)
1411 continue;
1413 int warn = Int32.Parse (wc);
1414 if (warn < 1) {
1415 throw new ArgumentOutOfRangeException("warn");
1417 Report.SetIgnoreWarning (warn);
1418 } catch {
1419 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1422 return true;
1425 case "/noconfig":
1426 load_default_config = false;
1427 return true;
1429 case "/help2":
1430 OtherFlags ();
1431 Environment.Exit(0);
1432 return true;
1434 case "/help":
1435 case "/?":
1436 Usage ();
1437 Environment.Exit (0);
1438 return true;
1440 case "/main":
1441 case "/m":
1442 if (value.Length == 0){
1443 Report.Error (5, arg + " requires an argument");
1444 Environment.Exit (1);
1446 RootContext.MainClass = value;
1447 return true;
1449 case "/nostdlib":
1450 case "/nostdlib+":
1451 RootContext.StdLib = false;
1452 return true;
1454 case "/nostdlib-":
1455 RootContext.StdLib = true;
1456 return true;
1458 case "/fullpaths":
1459 return true;
1461 case "/keyfile":
1462 if (value == String.Empty) {
1463 Report.Error (5, arg + " requires an argument");
1464 Environment.Exit (1);
1466 RootContext.StrongNameKeyFile = value;
1467 return true;
1468 case "/keycontainer":
1469 if (value == String.Empty) {
1470 Report.Error (5, arg + " requires an argument");
1471 Environment.Exit (1);
1473 RootContext.StrongNameKeyContainer = value;
1474 return true;
1475 case "/delaysign+":
1476 RootContext.StrongNameDelaySign = true;
1477 return true;
1478 case "/delaysign-":
1479 RootContext.StrongNameDelaySign = false;
1480 return true;
1482 case "/langversion":
1483 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1484 case "iso-1":
1485 RootContext.Version = LanguageVersion.ISO_1;
1486 return true;
1488 case "default":
1489 RootContext.Version = LanguageVersion.Default;
1490 #if GMCS_SOURCE
1491 RootContext.AddConditional ("__V2__");
1492 #endif
1493 return true;
1494 #if GMCS_SOURCE
1495 case "iso-2":
1496 RootContext.Version = LanguageVersion.ISO_2;
1497 return true;
1498 case "future":
1499 RootContext.Version = LanguageVersion.Future;
1500 return true;
1501 #endif
1503 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
1504 return true;
1506 case "/codepage":
1507 switch (value) {
1508 case "utf8":
1509 encoding = new UTF8Encoding();
1510 break;
1511 case "reset":
1512 encoding = Encoding.Default;
1513 break;
1514 default:
1515 try {
1516 encoding = Encoding.GetEncoding (
1517 Int32.Parse (value));
1518 } catch {
1519 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1521 break;
1523 return true;
1526 return false;
1529 static void Error_WrongOption (string option)
1531 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1534 static string [] AddArgs (string [] args, string [] extra_args)
1536 string [] new_args;
1537 new_args = new string [extra_args.Length + args.Length];
1539 // if args contains '--' we have to take that into account
1540 // split args into first half and second half based on '--'
1541 // and add the extra_args before --
1542 int split_position = Array.IndexOf (args, "--");
1543 if (split_position != -1)
1545 Array.Copy (args, new_args, split_position);
1546 extra_args.CopyTo (new_args, split_position);
1547 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1549 else
1551 args.CopyTo (new_args, 0);
1552 extra_args.CopyTo (new_args, args.Length);
1555 return new_args;
1558 void AddExternAlias (string identifier, string assembly)
1560 if (assembly.Length == 0) {
1561 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1562 return;
1565 if (!IsExternAliasValid (identifier)) {
1566 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1567 return;
1570 // Could here hashtable throw an exception?
1571 external_aliases [identifier] = assembly;
1574 static bool IsExternAliasValid (string identifier)
1576 if (identifier.Length == 0)
1577 return false;
1578 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1579 return false;
1581 for (int i = 1; i < identifier.Length; i++) {
1582 char c = identifier [i];
1583 if (Char.IsLetter (c) || Char.IsDigit (c))
1584 continue;
1586 UnicodeCategory category = Char.GetUnicodeCategory (c);
1587 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1588 category != UnicodeCategory.SpacingCombiningMark ||
1589 category != UnicodeCategory.ConnectorPunctuation)
1590 return false;
1593 return true;
1597 // Main compilation method
1599 public bool Compile ()
1601 // TODO: Should be passed to parser as an argument
1602 RootContext.ToplevelTypes = new ModuleContainer (RootContext.Unsafe);
1604 Parse ();
1605 if (Report.Errors > 0)
1606 return false;
1608 if (tokenize || parse_only)
1609 return true;
1611 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1612 throw new InternalErrorException ("who set it?");
1614 ProcessDefaultConfig ();
1617 // Quick hack
1619 if (output_file == null){
1620 if (first_source == null){
1621 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1622 return false;
1625 int pos = first_source.LastIndexOf ('.');
1627 if (pos > 0)
1628 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1629 else
1630 output_file = first_source + RootContext.TargetExt;
1633 if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1634 return false;
1636 if (RootContext.Target == Target.Module) {
1637 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1638 if (module_only == null) {
1639 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1640 Environment.Exit (1);
1643 MethodInfo set_method = module_only.GetSetMethod (true);
1644 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1647 GlobalRootNamespace.Instance.AddModuleReference (RootContext.ToplevelTypes.Builder);
1650 // Load assemblies required
1652 if (timestamps)
1653 ShowTime ("Loading references");
1655 LoadReferences ();
1657 if (modules.Count > 0) {
1658 foreach (string module in modules)
1659 LoadModule (module);
1662 if (timestamps)
1663 ShowTime ("References loaded");
1665 if (!TypeManager.InitCoreTypes () || Report.Errors > 0)
1666 return false;
1668 TypeManager.InitOptionalCoreTypes ();
1670 if (timestamps)
1671 ShowTime (" Core Types done");
1674 // The second pass of the compiler
1676 if (timestamps)
1677 ShowTime ("Resolving tree");
1678 RootContext.ResolveTree ();
1680 if (Report.Errors > 0)
1681 return false;
1682 if (timestamps)
1683 ShowTime ("Populate tree");
1684 if (!RootContext.StdLib)
1685 RootContext.BootCorlib_PopulateCoreTypes ();
1686 RootContext.PopulateTypes ();
1688 if (Report.Errors == 0 &&
1689 RootContext.Documentation != null &&
1690 !RootContext.Documentation.OutputDocComment (
1691 output_file))
1692 return false;
1695 // Verify using aliases now
1697 NamespaceEntry.VerifyAllUsing ();
1699 if (Report.Errors > 0){
1700 return false;
1703 CodeGen.Assembly.Resolve ();
1705 if (RootContext.VerifyClsCompliance) {
1706 if (CodeGen.Assembly.IsClsCompliant) {
1707 AttributeTester.VerifyModulesClsCompliance ();
1708 TypeManager.LoadAllImportedTypes ();
1711 if (Report.Errors > 0)
1712 return false;
1715 // The code generator
1717 if (timestamps)
1718 ShowTime ("Emitting code");
1719 ShowTotalTime ("Total so far");
1720 RootContext.EmitCode ();
1721 if (timestamps)
1722 ShowTime (" done");
1724 if (Report.Errors > 0){
1725 return false;
1728 if (timestamps)
1729 ShowTime ("Closing types");
1731 RootContext.CloseTypes ();
1733 PEFileKinds k = PEFileKinds.ConsoleApplication;
1735 switch (RootContext.Target) {
1736 case Target.Library:
1737 case Target.Module:
1738 k = PEFileKinds.Dll; break;
1739 case Target.Exe:
1740 k = PEFileKinds.ConsoleApplication; break;
1741 case Target.WinExe:
1742 k = PEFileKinds.WindowApplication; break;
1745 if (RootContext.NeedsEntryPoint) {
1746 Method ep = RootContext.EntryPoint;
1748 if (ep == null) {
1749 if (RootContext.MainClass != null) {
1750 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1751 if (main_cont == null) {
1752 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1753 return false;
1756 if (!(main_cont is ClassOrStruct)) {
1757 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1758 return false;
1761 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1762 return false;
1765 if (Report.Errors == 0)
1766 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1767 output_file);
1768 return false;
1771 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1772 } else if (RootContext.MainClass != null) {
1773 Report.Error (2017, "Cannot specify -main if building a module or library");
1776 if (embedded_resources != null){
1777 if (RootContext.Target == Target.Module) {
1778 Report.Error (1507, "Cannot link resource file when building a module");
1779 return false;
1782 embedded_resources.Emit ();
1786 // Add Win32 resources
1789 if (win32ResourceFile != null) {
1790 try {
1791 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1792 } catch (ArgumentException) {
1793 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1795 } else {
1796 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1799 if (win32IconFile != null) {
1800 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1801 if (define_icon == null) {
1802 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1803 } else {
1804 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1808 if (Report.Errors > 0)
1809 return false;
1811 CodeGen.Save (output_file, want_debugging_support);
1812 if (timestamps) {
1813 ShowTime ("Saved output");
1814 ShowTotalTime ("Total");
1817 Timer.ShowTimers ();
1819 if (Report.ExpectedError != 0) {
1820 if (Report.Errors == 0) {
1821 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1822 "No other errors reported.");
1824 Environment.Exit (2);
1825 } else {
1826 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1827 "However, other errors were reported.");
1829 Environment.Exit (1);
1833 return false;
1836 #if DEBUGME
1837 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1838 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1839 #endif
1840 return (Report.Errors == 0);
1844 class Resources
1846 interface IResource
1848 void Emit ();
1849 string FileName { get; }
1852 class EmbededResource : IResource
1854 static MethodInfo embed_res;
1856 static EmbededResource () {
1857 Type[] argst = new Type [] {
1858 typeof (string), typeof (string), typeof (ResourceAttributes)
1861 embed_res = typeof (AssemblyBuilder).GetMethod (
1862 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1863 null, CallingConventions.Any, argst, null);
1865 if (embed_res == null) {
1866 Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1870 readonly object[] args;
1872 public EmbededResource (string name, string file, bool isPrivate)
1874 args = new object [3];
1875 args [0] = name;
1876 args [1] = file;
1877 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1880 public void Emit()
1882 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1885 public string FileName {
1886 get {
1887 return (string)args [1];
1892 class LinkedResource : IResource
1894 readonly string file;
1895 readonly string name;
1896 readonly ResourceAttributes attribute;
1898 public LinkedResource (string name, string file, bool isPrivate)
1900 this.name = name;
1901 this.file = file;
1902 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1905 public void Emit ()
1907 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1910 public string FileName {
1911 get {
1912 return file;
1918 IDictionary embedded_resources = new HybridDictionary ();
1920 public void Add (bool embeded, string file, string name)
1922 Add (embeded, file, name, false);
1925 public void Add (bool embeded, string file, string name, bool isPrivate)
1927 if (embedded_resources.Contains (name)) {
1928 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1929 return;
1931 IResource r = embeded ?
1932 (IResource) new EmbededResource (name, file, isPrivate) :
1933 new LinkedResource (name, file, isPrivate);
1935 embedded_resources.Add (name, r);
1938 public void Emit ()
1940 foreach (IResource r in embedded_resources.Values) {
1941 if (!File.Exists (r.FileName)) {
1942 Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1943 continue;
1946 r.Emit ();
1952 // This is the only public entry point
1954 public class CompilerCallableEntryPoint : MarshalByRefObject {
1955 public static bool InvokeCompiler (string [] args, TextWriter error)
1957 Report.Stderr = error;
1958 try {
1959 Driver d = Driver.Create (args, true);
1960 if (d == null)
1961 return false;
1963 return d.Compile () && Report.Errors == 0;
1965 finally {
1966 Report.Stderr = Console.Error;
1967 Reset ();
1971 public static int[] AllWarningNumbers {
1972 get {
1973 return Report.AllWarnings;
1977 public static void Reset ()
1979 Reset (true);
1982 public static void PartialReset ()
1984 Reset (false);
1987 public static void Reset (bool full_flag)
1989 Driver.Reset ();
1990 RootContext.Reset (full_flag);
1991 Location.Reset ();
1992 Report.Reset ();
1993 TypeManager.Reset ();
1994 PredefinedAttributes.Reset ();
1995 TypeHandle.Reset ();
1997 if (full_flag)
1998 GlobalRootNamespace.Reset ();
2000 NamespaceEntry.Reset ();
2001 CodeGen.Reset ();
2002 Attribute.Reset ();
2003 AttributeTester.Reset ();
2004 AnonymousTypeClass.Reset ();
2005 AnonymousMethodBody.Reset ();
2006 AnonymousMethodStorey.Reset ();
2007 SymbolWriter.Reset ();
2008 Switch.Reset ();
2009 Linq.QueryBlock.TransparentParameter.Reset ();
2010 Convert.Reset ();
2011 TypeInfo.Reset ();