2009-02-20 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / driver.cs
blobf0f98d2777314a71619382c37cef72b799761634
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 else if (d.Compile () && Report.Errors == 0) {
301 if (Report.Warnings > 0) {
302 Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
304 return 0;
305 } else {
306 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
307 Report.Errors, Report.Warnings);
308 return 1;
312 static public void LoadAssembly (string assembly, bool soft)
314 LoadAssembly (assembly, null, soft);
317 static void Error6 (string name, string log)
319 if (log != null && log.Length > 0)
320 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
321 Report.Error (6, "cannot find metadata file `{0}'", name);
324 static void Error9 (string type, string filename, string log)
326 if (log != null && log.Length > 0)
327 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
328 Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
331 static void BadAssembly (string filename, string log)
333 MethodInfo adder_method = AssemblyClass.AddModule_Method;
335 if (adder_method != null) {
336 AssemblyName an = new AssemblyName ();
337 an.Name = ".temp";
338 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
339 try {
340 object m = null;
341 try {
342 m = adder_method.Invoke (ab, new object [] { filename });
343 } catch (TargetInvocationException ex) {
344 throw ex.InnerException;
347 if (m != null) {
348 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
349 Path.GetFileName (filename));
350 return;
352 } catch (FileNotFoundException) {
353 // did the file get deleted during compilation? who cares? swallow the exception
354 } catch (BadImageFormatException) {
355 // swallow exception
356 } catch (FileLoadException) {
357 // swallow exception
360 Error9 ("assembly", filename, log);
363 static public void LoadAssembly (string assembly, string alias, bool soft)
365 Assembly a = null;
366 string total_log = "";
368 try {
369 try {
370 char[] path_chars = { '/', '\\' };
372 if (assembly.IndexOfAny (path_chars) != -1) {
373 a = Assembly.LoadFrom (assembly);
374 } else {
375 string ass = assembly;
376 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
377 ass = assembly.Substring (0, assembly.Length - 4);
378 a = Assembly.Load (ass);
380 } catch (FileNotFoundException) {
381 bool err = !soft;
382 foreach (string dir in link_paths) {
383 string full_path = Path.Combine (dir, assembly);
384 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
385 full_path += ".dll";
387 try {
388 a = Assembly.LoadFrom (full_path);
389 err = false;
390 break;
391 } catch (FileNotFoundException ff) {
392 if (soft)
393 return;
394 total_log += ff.FusionLog;
397 if (err) {
398 Error6 (assembly, total_log);
399 return;
403 // Extern aliased refs require special handling
404 if (alias == null)
405 RootNamespace.Global.AddAssemblyReference (a);
406 else
407 RootNamespace.DefineRootNamespace (alias, a);
409 } catch (BadImageFormatException f) {
410 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
411 BadAssembly (f.FileName, f.FusionLog);
412 } catch (FileLoadException f) {
413 // ... while .NET 1.1 throws this
414 BadAssembly (f.FileName, f.FusionLog);
418 static public void LoadModule (string module)
420 Module m = null;
421 string total_log = "";
423 try {
424 try {
425 m = CodeGen.Assembly.AddModule (module);
426 } catch (FileNotFoundException) {
427 bool err = true;
428 foreach (string dir in link_paths) {
429 string full_path = Path.Combine (dir, module);
430 if (!module.EndsWith (".netmodule"))
431 full_path += ".netmodule";
433 try {
434 m = CodeGen.Assembly.AddModule (full_path);
435 err = false;
436 break;
437 } catch (FileNotFoundException ff) {
438 total_log += ff.FusionLog;
441 if (err) {
442 Error6 (module, total_log);
443 return;
447 RootNamespace.Global.AddModuleReference (m);
449 } catch (BadImageFormatException f) {
450 Error9 ("module", f.FileName, f.FusionLog);
451 } catch (FileLoadException f) {
452 Error9 ("module", f.FileName, f.FusionLog);
456 /// <summary>
457 /// Loads all assemblies referenced on the command line
458 /// </summary>
459 public void LoadReferences ()
461 link_paths.Add (GetSystemDir ());
462 link_paths.Add (Directory.GetCurrentDirectory ());
465 // Load Core Library for default compilation
467 if (RootContext.StdLib)
468 LoadAssembly ("mscorlib", false);
470 foreach (string r in soft_references)
471 LoadAssembly (r, true);
473 foreach (string r in references)
474 LoadAssembly (r, false);
476 foreach (DictionaryEntry entry in external_aliases)
477 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
479 RootNamespace.ComputeNamespaces ();
482 static string [] LoadArgs (string file)
484 StreamReader f;
485 ArrayList args = new ArrayList ();
486 string line;
487 try {
488 f = new StreamReader (file);
489 } catch {
490 return null;
493 StringBuilder sb = new StringBuilder ();
495 while ((line = f.ReadLine ()) != null){
496 int t = line.Length;
498 for (int i = 0; i < t; i++){
499 char c = line [i];
501 if (c == '"' || c == '\''){
502 char end = c;
504 for (i++; i < t; i++){
505 c = line [i];
507 if (c == end)
508 break;
509 sb.Append (c);
511 } else if (c == ' '){
512 if (sb.Length > 0){
513 args.Add (sb.ToString ());
514 sb.Length = 0;
516 } else
517 sb.Append (c);
519 if (sb.Length > 0){
520 args.Add (sb.ToString ());
521 sb.Length = 0;
525 string [] ret_value = new string [args.Count];
526 args.CopyTo (ret_value, 0);
528 return ret_value;
532 // Returns the directory where the system assemblies are installed
534 static string GetSystemDir ()
536 return Path.GetDirectoryName (typeof (object).Assembly.Location);
540 // Given a path specification, splits the path from the file/pattern
542 static void SplitPathAndPattern (string spec, out string path, out string pattern)
544 int p = spec.LastIndexOf ('/');
545 if (p != -1){
547 // Windows does not like /file.cs, switch that to:
548 // "\", "file.cs"
550 if (p == 0){
551 path = "\\";
552 pattern = spec.Substring (1);
553 } else {
554 path = spec.Substring (0, p);
555 pattern = spec.Substring (p + 1);
557 return;
560 p = spec.LastIndexOf ('\\');
561 if (p != -1){
562 path = spec.Substring (0, p);
563 pattern = spec.Substring (p + 1);
564 return;
567 path = ".";
568 pattern = spec;
571 void AddSourceFile (string f)
573 if (first_source == null)
574 first_source = f;
576 Location.AddFile (f);
579 bool ParseArguments (string[] args, bool require_files)
581 references = new ArrayList ();
582 external_aliases = new Hashtable ();
583 soft_references = new ArrayList ();
584 modules = new ArrayList (2);
585 link_paths = new ArrayList ();
587 ArrayList response_file_list = null;
588 bool parsing_options = true;
590 for (int i = 0; i < args.Length; i++) {
591 string arg = args [i];
592 if (arg.Length == 0)
593 continue;
595 if (arg [0] == '@') {
596 string [] extra_args;
597 string response_file = arg.Substring (1);
599 if (response_file_list == null)
600 response_file_list = new ArrayList ();
602 if (response_file_list.Contains (response_file)) {
603 Report.Error (
604 1515, "Response file `" + response_file +
605 "' specified multiple times");
606 return false;
609 response_file_list.Add (response_file);
611 extra_args = LoadArgs (response_file);
612 if (extra_args == null) {
613 Report.Error (2011, "Unable to open response file: " +
614 response_file);
615 return false;
618 args = AddArgs (args, extra_args);
619 continue;
622 if (parsing_options) {
623 if (arg == "--") {
624 parsing_options = false;
625 continue;
628 if (arg [0] == '-') {
629 if (UnixParseOption (arg, ref args, ref i))
630 continue;
632 // Try a -CSCOPTION
633 string csc_opt = "/" + arg.Substring (1);
634 if (CSCParseOption (csc_opt, ref args))
635 continue;
637 Error_WrongOption (arg);
638 return false;
640 if (arg [0] == '/') {
641 if (CSCParseOption (arg, ref args))
642 continue;
644 // Need to skip `/home/test.cs' however /test.cs is considered as error
645 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
646 Error_WrongOption (arg);
647 return false;
652 ProcessSourceFiles (arg, false);
655 if (require_files == false)
656 return true;
659 // If we are an exe, require a source file for the entry point
661 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
662 if (first_source == null) {
663 Report.Error (2008, "No files to compile were specified");
664 return false;
670 // If there is nothing to put in the assembly, and we are not a library
672 if (first_source == null && embedded_resources == null) {
673 Report.Error (2008, "No files to compile were specified");
674 return false;
677 return true;
680 public void Parse ()
682 Location.Initialize ();
684 ArrayList cu = Location.SourceFiles;
685 for (int i = 0; i < cu.Count; ++i) {
686 if (tokenize) {
687 tokenize_file ((CompilationUnit) cu [i]);
688 } else {
689 Parse ((CompilationUnit) cu [i]);
694 void ProcessSourceFiles (string spec, bool recurse)
696 string path, pattern;
698 SplitPathAndPattern (spec, out path, out pattern);
699 if (pattern.IndexOf ('*') == -1){
700 AddSourceFile (spec);
701 return;
704 string [] files = null;
705 try {
706 files = Directory.GetFiles (path, pattern);
707 } catch (System.IO.DirectoryNotFoundException) {
708 Report.Error (2001, "Source file `" + spec + "' could not be found");
709 return;
710 } catch (System.IO.IOException){
711 Report.Error (2001, "Source file `" + spec + "' could not be found");
712 return;
714 foreach (string f in files) {
715 AddSourceFile (f);
718 if (!recurse)
719 return;
721 string [] dirs = null;
723 try {
724 dirs = Directory.GetDirectories (path);
725 } catch {
728 foreach (string d in dirs) {
730 // Don't include path in this string, as each
731 // directory entry already does
732 ProcessSourceFiles (d + "/" + pattern, true);
736 public void ProcessDefaultConfig ()
738 if (!load_default_config)
739 return;
742 // For now the "default config" is harcoded into the compiler
743 // we can move this outside later
745 string [] default_config = {
746 "System",
747 "System.Xml",
748 #if NET_2_1
749 "System.Net",
750 "System.Windows",
751 "System.Windows.Browser",
752 #endif
753 #if false
755 // Is it worth pre-loading all this stuff?
757 "Accessibility",
758 "System.Configuration.Install",
759 "System.Data",
760 "System.Design",
761 "System.DirectoryServices",
762 "System.Drawing.Design",
763 "System.Drawing",
764 "System.EnterpriseServices",
765 "System.Management",
766 "System.Messaging",
767 "System.Runtime.Remoting",
768 "System.Runtime.Serialization.Formatters.Soap",
769 "System.Security",
770 "System.ServiceProcess",
771 "System.Web",
772 "System.Web.RegularExpressions",
773 "System.Web.Services",
774 "System.Windows.Forms"
775 #endif
778 soft_references.AddRange (default_config);
780 if (RootContext.Version > LanguageVersion.ISO_2)
781 soft_references.Add ("System.Core");
784 public static string OutputFile
786 set {
787 output_file = value;
789 get {
790 return Path.GetFileName (output_file);
794 static void SetWarningLevel (string s)
796 int level = -1;
798 try {
799 level = Int32.Parse (s);
800 } catch {
802 if (level < 0 || level > 4){
803 Report.Error (1900, "Warning level must be in the range 0-4");
804 return;
806 Report.WarningLevel = level;
809 static void Version ()
811 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
812 Console.WriteLine ("Mono C# compiler version {0}", version);
813 Environment.Exit (0);
817 // Currently handles the Unix-like command line options, but will be
818 // deprecated in favor of the CSCParseOption, which will also handle the
819 // options that start with a dash in the future.
821 bool UnixParseOption (string arg, ref string [] args, ref int i)
823 switch (arg){
824 case "-v":
825 CSharpParser.yacc_verbose_flag++;
826 return true;
828 case "--version":
829 Version ();
830 return true;
832 case "--parse":
833 parse_only = true;
834 return true;
836 case "--main": case "-m":
837 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
838 if ((i + 1) >= args.Length){
839 Usage ();
840 Environment.Exit (1);
842 RootContext.MainClass = args [++i];
843 return true;
845 case "--unsafe":
846 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
847 RootContext.Unsafe = true;
848 return true;
850 case "/?": case "/h": case "/help":
851 case "--help":
852 Usage ();
853 Environment.Exit (0);
854 return true;
856 case "--define":
857 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
858 if ((i + 1) >= args.Length){
859 Usage ();
860 Environment.Exit (1);
862 RootContext.AddConditional (args [++i]);
863 return true;
865 case "--tokenize":
866 tokenize = true;
867 return true;
869 case "-o":
870 case "--output":
871 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
872 if ((i + 1) >= args.Length){
873 Usage ();
874 Environment.Exit (1);
876 OutputFile = args [++i];
877 return true;
879 case "--checked":
880 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
881 RootContext.Checked = true;
882 return true;
884 case "--stacktrace":
885 Report.Stacktrace = true;
886 return true;
888 case "--linkresource":
889 case "--linkres":
890 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
891 if ((i + 1) >= args.Length){
892 Usage ();
893 Report.Error (5, "Missing argument to --linkres");
894 Environment.Exit (1);
896 if (embedded_resources == null)
897 embedded_resources = new Resources ();
899 embedded_resources.Add (false, args [++i], args [i]);
900 return true;
902 case "--resource":
903 case "--res":
904 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
905 if ((i + 1) >= args.Length){
906 Usage ();
907 Report.Error (5, "Missing argument to --resource");
908 Environment.Exit (1);
910 if (embedded_resources == null)
911 embedded_resources = new Resources ();
913 embedded_resources.Add (true, args [++i], args [i]);
914 return true;
916 case "--target":
917 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
918 if ((i + 1) >= args.Length){
919 Environment.Exit (1);
920 return true;
923 string type = args [++i];
924 switch (type){
925 case "library":
926 RootContext.Target = Target.Library;
927 RootContext.TargetExt = ".dll";
928 break;
930 case "exe":
931 RootContext.Target = Target.Exe;
932 break;
934 case "winexe":
935 RootContext.Target = Target.WinExe;
936 break;
938 case "module":
939 RootContext.Target = Target.Module;
940 RootContext.TargetExt = ".dll";
941 break;
942 default:
943 TargetUsage ();
944 break;
946 return true;
948 case "-r":
949 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
950 if ((i + 1) >= args.Length){
951 Usage ();
952 Environment.Exit (1);
955 string val = args [++i];
956 int idx = val.IndexOf ('=');
957 if (idx > -1) {
958 string alias = val.Substring (0, idx);
959 string assembly = val.Substring (idx + 1);
960 AddExternAlias (alias, assembly);
961 return true;
964 references.Add (val);
965 return true;
967 case "-L":
968 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
969 if ((i + 1) >= args.Length){
970 Usage ();
971 Environment.Exit (1);
973 link_paths.Add (args [++i]);
974 return true;
976 case "--nostdlib":
977 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
978 RootContext.StdLib = false;
979 return true;
981 case "--fatal":
982 Report.Fatal = true;
983 return true;
985 case "--werror":
986 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
987 Report.WarningsAreErrors = true;
988 return true;
990 case "--nowarn":
991 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
992 if ((i + 1) >= args.Length){
993 Usage ();
994 Environment.Exit (1);
996 int warn = 0;
998 try {
999 warn = Int32.Parse (args [++i]);
1000 } catch {
1001 Usage ();
1002 Environment.Exit (1);
1004 Report.SetIgnoreWarning (warn);
1005 return true;
1007 case "--wlevel":
1008 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1009 if ((i + 1) >= args.Length){
1010 Report.Error (
1011 1900,
1012 "--wlevel requires a value from 0 to 4");
1013 Environment.Exit (1);
1016 SetWarningLevel (args [++i]);
1017 return true;
1019 case "--mcs-debug":
1020 if ((i + 1) >= args.Length){
1021 Report.Error (5, "--mcs-debug requires an argument");
1022 Environment.Exit (1);
1025 try {
1026 Report.DebugFlags = Int32.Parse (args [++i]);
1027 } catch {
1028 Report.Error (5, "Invalid argument to --mcs-debug");
1029 Environment.Exit (1);
1031 return true;
1033 case "--about":
1034 About ();
1035 return true;
1037 case "--recurse":
1038 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1039 if ((i + 1) >= args.Length){
1040 Report.Error (5, "--recurse requires an argument");
1041 Environment.Exit (1);
1043 ProcessSourceFiles (args [++i], true);
1044 return true;
1046 case "--timestamp":
1047 timestamps = true;
1048 last_time = first_time = DateTime.Now;
1049 return true;
1051 case "--debug": case "-g":
1052 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1053 want_debugging_support = true;
1054 return true;
1056 case "--noconfig":
1057 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1058 load_default_config = false;
1059 return true;
1062 return false;
1065 #if !SMCS_SOURCE
1066 public static string GetPackageFlags (string packages, bool fatal)
1068 ProcessStartInfo pi = new ProcessStartInfo ();
1069 pi.FileName = "pkg-config";
1070 pi.RedirectStandardOutput = true;
1071 pi.UseShellExecute = false;
1072 pi.Arguments = "--libs " + packages;
1073 Process p = null;
1074 try {
1075 p = Process.Start (pi);
1076 } catch (Exception e) {
1077 Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1078 if (fatal)
1079 Environment.Exit (1);
1080 p.Close ();
1081 return null;
1084 if (p.StandardOutput == null){
1085 Report.Warning (-27, 1, "Specified package did not return any information");
1086 p.Close ();
1087 return null;
1089 string pkgout = p.StandardOutput.ReadToEnd ();
1090 p.WaitForExit ();
1091 if (p.ExitCode != 0) {
1092 Report.Error (-27, "Error running pkg-config. Check the above output.");
1093 if (fatal)
1094 Environment.Exit (1);
1095 p.Close ();
1096 return null;
1098 p.Close ();
1100 return pkgout;
1102 #endif
1105 // This parses the -arg and /arg options to the compiler, even if the strings
1106 // in the following text use "/arg" on the strings.
1108 bool CSCParseOption (string option, ref string [] args)
1110 int idx = option.IndexOf (':');
1111 string arg, value;
1113 if (idx == -1){
1114 arg = option;
1115 value = "";
1116 } else {
1117 arg = option.Substring (0, idx);
1119 value = option.Substring (idx + 1);
1122 switch (arg.ToLower (CultureInfo.InvariantCulture)){
1123 case "/nologo":
1124 return true;
1126 case "/t":
1127 case "/target":
1128 switch (value){
1129 case "exe":
1130 RootContext.Target = Target.Exe;
1131 break;
1133 case "winexe":
1134 RootContext.Target = Target.WinExe;
1135 break;
1137 case "library":
1138 RootContext.Target = Target.Library;
1139 RootContext.TargetExt = ".dll";
1140 break;
1142 case "module":
1143 RootContext.Target = Target.Module;
1144 RootContext.TargetExt = ".netmodule";
1145 break;
1147 default:
1148 TargetUsage ();
1149 break;
1151 return true;
1153 case "/out":
1154 if (value.Length == 0){
1155 Usage ();
1156 Environment.Exit (1);
1158 OutputFile = value;
1159 return true;
1161 case "/o":
1162 case "/o+":
1163 case "/optimize":
1164 case "/optimize+":
1165 RootContext.Optimize = true;
1166 return true;
1168 case "/o-":
1169 case "/optimize-":
1170 RootContext.Optimize = false;
1171 return true;
1173 case "/incremental":
1174 case "/incremental+":
1175 case "/incremental-":
1176 // nothing.
1177 return true;
1179 case "/d":
1180 case "/define": {
1181 if (value.Length == 0){
1182 Usage ();
1183 Environment.Exit (1);
1186 foreach (string d in value.Split (argument_value_separator)) {
1187 if (!Tokenizer.IsValidIdentifier (d)) {
1188 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d);
1189 continue;
1191 RootContext.AddConditional (d);
1193 return true;
1196 case "/bugreport":
1198 // We should collect data, runtime, etc and store in the file specified
1200 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1201 return true;
1202 #if !SMCS_SOURCE
1203 case "/pkg": {
1204 string packages;
1206 if (value.Length == 0){
1207 Usage ();
1208 Environment.Exit (1);
1210 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1211 string pkgout = GetPackageFlags (packages, true);
1213 if (pkgout != null){
1214 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1215 Split (new Char [] { ' ', '\t'});
1216 args = AddArgs (args, xargs);
1219 return true;
1221 #endif
1222 case "/linkres":
1223 case "/linkresource":
1224 case "/res":
1225 case "/resource":
1226 if (embedded_resources == null)
1227 embedded_resources = new Resources ();
1229 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1230 string[] s = value.Split (argument_value_separator);
1231 switch (s.Length) {
1232 case 1:
1233 if (s[0].Length == 0)
1234 goto default;
1235 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1236 break;
1237 case 2:
1238 embedded_resources.Add (embeded, s [0], s [1]);
1239 break;
1240 case 3:
1241 if (s [2] != "public" && s [2] != "private") {
1242 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1243 return true;
1245 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1246 break;
1247 default:
1248 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1249 break;
1252 return true;
1254 case "/recurse":
1255 if (value.Length == 0){
1256 Report.Error (5, "-recurse requires an argument");
1257 Environment.Exit (1);
1259 ProcessSourceFiles (value, true);
1260 return true;
1262 case "/r":
1263 case "/reference": {
1264 if (value.Length == 0){
1265 Report.Error (5, "-reference requires an argument");
1266 Environment.Exit (1);
1269 string[] refs = value.Split (argument_value_separator);
1270 foreach (string r in refs){
1271 string val = r;
1272 int index = val.IndexOf ('=');
1273 if (index > -1) {
1274 string alias = r.Substring (0, index);
1275 string assembly = r.Substring (index + 1);
1276 AddExternAlias (alias, assembly);
1277 return true;
1280 if (val.Length != 0)
1281 references.Add (val);
1283 return true;
1285 case "/addmodule": {
1286 if (value.Length == 0){
1287 Report.Error (5, arg + " requires an argument");
1288 Environment.Exit (1);
1291 string[] refs = value.Split (argument_value_separator);
1292 foreach (string r in refs){
1293 modules.Add (r);
1295 return true;
1297 case "/win32res": {
1298 if (value.Length == 0) {
1299 Report.Error (5, arg + " requires an argument");
1300 Environment.Exit (1);
1303 if (win32IconFile != null)
1304 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1306 win32ResourceFile = value;
1307 return true;
1309 case "/win32icon": {
1310 if (value.Length == 0) {
1311 Report.Error (5, arg + " requires an argument");
1312 Environment.Exit (1);
1315 if (win32ResourceFile != null)
1316 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1318 win32IconFile = value;
1319 return true;
1321 case "/doc": {
1322 if (value.Length == 0){
1323 Report.Error (2006, arg + " requires an argument");
1324 Environment.Exit (1);
1326 RootContext.Documentation = new Documentation (value);
1327 return true;
1329 case "/lib": {
1330 string [] libdirs;
1332 if (value.Length == 0){
1333 Report.Error (5, "/lib requires an argument");
1334 Environment.Exit (1);
1337 libdirs = value.Split (argument_value_separator);
1338 foreach (string dir in libdirs)
1339 link_paths.Add (dir);
1340 return true;
1343 case "/debug-":
1344 want_debugging_support = false;
1345 return true;
1347 case "/debug":
1348 case "/debug+":
1349 want_debugging_support = true;
1350 return true;
1352 case "/checked":
1353 case "/checked+":
1354 RootContext.Checked = true;
1355 return true;
1357 case "/checked-":
1358 RootContext.Checked = false;
1359 return true;
1361 case "/clscheck":
1362 case "/clscheck+":
1363 return true;
1365 case "/clscheck-":
1366 RootContext.VerifyClsCompliance = false;
1367 return true;
1369 case "/unsafe":
1370 case "/unsafe+":
1371 RootContext.Unsafe = true;
1372 return true;
1374 case "/unsafe-":
1375 RootContext.Unsafe = false;
1376 return true;
1378 case "/warnaserror":
1379 if (value.Length == 0) {
1380 Report.WarningsAreErrors = true;
1381 } else {
1382 foreach (string wid in value.Split (argument_value_separator))
1383 Report.AddWarningAsError (wid);
1385 return true;
1387 case "/warnaserror+":
1388 Report.WarningsAreErrors = true;
1389 return true;
1391 case "/warnaserror-":
1392 Report.WarningsAreErrors = false;
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 Parse ();
1602 if (Report.Errors > 0)
1603 return false;
1605 if (tokenize || parse_only)
1606 return true;
1608 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1609 throw new InternalErrorException ("who set it?");
1611 ProcessDefaultConfig ();
1614 // Quick hack
1616 if (output_file == null){
1617 if (first_source == null){
1618 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1619 return false;
1622 int pos = first_source.LastIndexOf ('.');
1624 if (pos > 0)
1625 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1626 else
1627 output_file = first_source + RootContext.TargetExt;
1630 if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1631 return false;
1633 if (RootContext.Target == Target.Module) {
1634 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1635 if (module_only == null) {
1636 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1637 Environment.Exit (1);
1640 MethodInfo set_method = module_only.GetSetMethod (true);
1641 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1644 RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1647 // Load assemblies required
1649 if (timestamps)
1650 ShowTime ("Loading references");
1652 LoadReferences ();
1654 if (modules.Count > 0) {
1655 foreach (string module in modules)
1656 LoadModule (module);
1659 if (timestamps)
1660 ShowTime ("References loaded");
1662 if (!TypeManager.InitCoreTypes () || Report.Errors > 0)
1663 return false;
1665 TypeManager.InitOptionalCoreTypes ();
1667 if (timestamps)
1668 ShowTime (" Core Types done");
1670 CodeGen.Module.Resolve ();
1673 // The second pass of the compiler
1675 if (timestamps)
1676 ShowTime ("Resolving tree");
1677 RootContext.ResolveTree ();
1679 if (Report.Errors > 0)
1680 return false;
1681 if (timestamps)
1682 ShowTime ("Populate tree");
1683 if (!RootContext.StdLib)
1684 RootContext.BootCorlib_PopulateCoreTypes ();
1685 RootContext.PopulateTypes ();
1687 if (Report.Errors == 0 &&
1688 RootContext.Documentation != null &&
1689 !RootContext.Documentation.OutputDocComment (
1690 output_file))
1691 return false;
1694 // Verify using aliases now
1696 NamespaceEntry.VerifyAllUsing ();
1698 if (Report.Errors > 0){
1699 return false;
1702 CodeGen.Assembly.Resolve ();
1704 if (RootContext.VerifyClsCompliance) {
1705 if (CodeGen.Assembly.IsClsCompliant) {
1706 AttributeTester.VerifyModulesClsCompliance ();
1707 TypeManager.LoadAllImportedTypes ();
1710 if (Report.Errors > 0)
1711 return false;
1714 // The code generator
1716 if (timestamps)
1717 ShowTime ("Emitting code");
1718 ShowTotalTime ("Total so far");
1719 RootContext.EmitCode ();
1720 if (timestamps)
1721 ShowTime (" done");
1723 if (Report.Errors > 0){
1724 return false;
1727 if (timestamps)
1728 ShowTime ("Closing types");
1730 RootContext.CloseTypes ();
1732 PEFileKinds k = PEFileKinds.ConsoleApplication;
1734 switch (RootContext.Target) {
1735 case Target.Library:
1736 case Target.Module:
1737 k = PEFileKinds.Dll; break;
1738 case Target.Exe:
1739 k = PEFileKinds.ConsoleApplication; break;
1740 case Target.WinExe:
1741 k = PEFileKinds.WindowApplication; break;
1744 if (RootContext.NeedsEntryPoint) {
1745 Method ep = RootContext.EntryPoint;
1747 if (ep == null) {
1748 if (RootContext.MainClass != null) {
1749 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1750 if (main_cont == null) {
1751 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1752 return false;
1755 if (!(main_cont is ClassOrStruct)) {
1756 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1757 return false;
1760 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1761 return false;
1764 if (Report.Errors == 0)
1765 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1766 output_file);
1767 return false;
1770 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1771 } else if (RootContext.MainClass != null) {
1772 Report.Error (2017, "Cannot specify -main if building a module or library");
1775 if (embedded_resources != null){
1776 if (RootContext.Target == Target.Module) {
1777 Report.Error (1507, "Cannot link resource file when building a module");
1778 return false;
1781 embedded_resources.Emit ();
1785 // Add Win32 resources
1788 if (win32ResourceFile != null) {
1789 try {
1790 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1791 } catch (ArgumentException) {
1792 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1794 } else {
1795 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1798 if (win32IconFile != null) {
1799 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1800 if (define_icon == null) {
1801 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1802 } else {
1803 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1807 if (Report.Errors > 0)
1808 return false;
1810 CodeGen.Save (output_file, want_debugging_support);
1811 if (timestamps) {
1812 ShowTime ("Saved output");
1813 ShowTotalTime ("Total");
1816 Timer.ShowTimers ();
1818 if (Report.ExpectedError != 0) {
1819 if (Report.Errors == 0) {
1820 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1821 "No other errors reported.");
1823 Environment.Exit (2);
1824 } else {
1825 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1826 "However, other errors were reported.");
1828 Environment.Exit (1);
1832 return false;
1835 #if DEBUGME
1836 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1837 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1838 #endif
1839 return (Report.Errors == 0);
1843 class Resources
1845 interface IResource
1847 void Emit ();
1848 string FileName { get; }
1851 class EmbededResource : IResource
1853 static MethodInfo embed_res;
1855 static EmbededResource () {
1856 Type[] argst = new Type [] {
1857 typeof (string), typeof (string), typeof (ResourceAttributes)
1860 embed_res = typeof (AssemblyBuilder).GetMethod (
1861 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1862 null, CallingConventions.Any, argst, null);
1864 if (embed_res == null) {
1865 Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1869 readonly object[] args;
1871 public EmbededResource (string name, string file, bool isPrivate)
1873 args = new object [3];
1874 args [0] = name;
1875 args [1] = file;
1876 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1879 public void Emit()
1881 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1884 public string FileName {
1885 get {
1886 return (string)args [1];
1891 class LinkedResource : IResource
1893 readonly string file;
1894 readonly string name;
1895 readonly ResourceAttributes attribute;
1897 public LinkedResource (string name, string file, bool isPrivate)
1899 this.name = name;
1900 this.file = file;
1901 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1904 public void Emit ()
1906 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1909 public string FileName {
1910 get {
1911 return file;
1917 IDictionary embedded_resources = new HybridDictionary ();
1919 public void Add (bool embeded, string file, string name)
1921 Add (embeded, file, name, false);
1924 public void Add (bool embeded, string file, string name, bool isPrivate)
1926 if (embedded_resources.Contains (name)) {
1927 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1928 return;
1930 IResource r = embeded ?
1931 (IResource) new EmbededResource (name, file, isPrivate) :
1932 new LinkedResource (name, file, isPrivate);
1934 embedded_resources.Add (name, r);
1937 public void Emit ()
1939 foreach (IResource r in embedded_resources.Values) {
1940 if (!File.Exists (r.FileName)) {
1941 Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1942 continue;
1945 r.Emit ();
1951 // This is the only public entry point
1953 public class CompilerCallableEntryPoint : MarshalByRefObject {
1954 public static bool InvokeCompiler (string [] args, TextWriter error)
1956 Report.Stderr = error;
1957 try {
1958 Driver d = Driver.Create (args, true);
1959 if (d == null)
1960 return false;
1962 return d.Compile () && Report.Errors == 0;
1964 finally {
1965 Report.Stderr = Console.Error;
1966 Reset ();
1970 public static int[] AllWarningNumbers {
1971 get {
1972 return Report.AllWarnings;
1976 public static void Reset ()
1978 Reset (true);
1981 public static void PartialReset ()
1983 Reset (false);
1986 public static void Reset (bool full_flag)
1988 Driver.Reset ();
1989 RootContext.Reset (full_flag);
1990 Tokenizer.Reset ();
1991 Location.Reset ();
1992 Report.Reset ();
1993 TypeManager.Reset ();
1994 TypeHandle.Reset ();
1996 if (full_flag)
1997 RootNamespace.Reset ();
1999 NamespaceEntry.Reset ();
2000 CodeGen.Reset ();
2001 Attribute.Reset ();
2002 AttributeTester.Reset ();
2003 AnonymousTypeClass.Reset ();
2004 AnonymousMethodBody.Reset ();
2005 AnonymousMethodStorey.Reset ();
2006 SymbolWriter.Reset ();
2007 Switch.Reset ();
2008 Linq.QueryBlock.TransparentParameter.Reset ();
2009 Convert.Reset ();
2010 TypeInfo.Reset ();