2006-12-16 Chris Toshok <toshok@ximian.com>
[mcs.git] / mcs / driver.cs
blob3ec7835afdad2dfac4a5fda7b1406478d633e6f0
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
9 // (C) 2004, 2005 Novell, Inc
12 namespace Mono.CSharp
14 using System;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections;
18 using System.Collections.Specialized;
19 using System.IO;
20 using System.Text;
21 using System.Globalization;
22 using System.Diagnostics;
24 public enum Target {
25 Library, Exe, Module, WinExe
28 /// <summary>
29 /// The compiler driver.
30 /// </summary>
31 public class Driver
35 // Assemblies references to be linked. Initialized with
36 // mscorlib.dll here.
37 static ArrayList references;
40 // If any of these fail, we ignore the problem. This is so
41 // that we can list all the assemblies in Windows and not fail
42 // if they are missing on Linux.
44 static ArrayList soft_references;
46 //
47 // External aliases for assemblies.
49 static Hashtable external_aliases;
52 // Modules to be linked
54 static ArrayList modules;
56 // Lookup paths
57 static ArrayList link_paths;
59 // Whether we want to only run the tokenizer
60 static bool tokenize = false;
62 static string first_source;
64 static bool want_debugging_support = false;
66 static bool parse_only = false;
67 static bool timestamps = false;
68 static bool pause = false;
69 static bool show_counters = false;
72 // Whether to load the initial config file (what CSC.RSP has by default)
73 //
74 static bool load_default_config = true;
77 // A list of resource files
79 static Resources embedded_resources;
80 static string win32ResourceFile;
81 static string win32IconFile;
84 // An array of the defines from the command line
86 static ArrayList defines;
89 // Output file
91 static string output_file = null;
94 // Last time we took the time
96 static DateTime last_time, first_time;
99 // Encoding.
101 static Encoding encoding;
103 static public void Reset ()
105 want_debugging_support = false;
106 parse_only = false;
107 timestamps = false;
108 pause = false;
109 show_counters = false;
110 load_default_config = true;
111 embedded_resources = null;
112 win32ResourceFile = win32IconFile = null;
113 defines = null;
114 output_file = null;
115 encoding = null;
116 first_source = null;
119 public static void ShowTime (string msg)
121 if (!timestamps)
122 return;
124 DateTime now = DateTime.Now;
125 TimeSpan span = now - last_time;
126 last_time = now;
128 Console.WriteLine (
129 "[{0:00}:{1:000}] {2}",
130 (int) span.TotalSeconds, span.Milliseconds, msg);
133 public static void ShowTotalTime (string msg)
135 if (!timestamps)
136 return;
138 DateTime now = DateTime.Now;
139 TimeSpan span = now - first_time;
140 last_time = now;
142 Console.WriteLine (
143 "[{0:00}:{1:000}] {2}",
144 (int) span.TotalSeconds, span.Milliseconds, msg);
147 static void tokenize_file (SourceFile file)
149 Stream input;
151 try {
152 input = File.OpenRead (file.Name);
153 } catch {
154 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
155 return;
158 using (input){
159 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
160 Tokenizer lexer = new Tokenizer (reader, file, defines);
161 int token, tokens = 0, errors = 0;
163 while ((token = lexer.token ()) != Token.EOF){
164 tokens++;
165 if (token == Token.ERROR)
166 errors++;
168 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
171 return;
174 // MonoTODO("Change error code for aborted compilation to something reasonable")]
175 static void parse (SourceFile file)
177 CSharpParser parser;
178 Stream input;
180 try {
181 input = File.OpenRead (file.Name);
182 } catch {
183 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
184 return;
187 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
189 // Check 'MZ' header
190 if (reader.Read () == 77 && reader.Read () == 90) {
191 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
192 input.Close ();
193 return;
196 reader.Position = 0;
197 parser = new CSharpParser (reader, file, defines);
198 parser.ErrorOutput = Report.Stderr;
199 try {
200 parser.parse ();
201 } catch (Exception ex) {
202 Report.Error(666, "Compilation aborted: " + ex);
203 } finally {
204 input.Close ();
208 static void OtherFlags ()
210 Console.WriteLine (
211 "Other flags in the compiler\n" +
212 " --fatal Makes errors fatal\n" +
213 " --parse Only parses the source file\n" +
214 " --stacktrace Shows stack trace at error location\n" +
215 " --timestamp Displays time stamps of various compiler events\n" +
216 " --expect-error X Expect that error X will be encountered\n" +
217 " -2 Enables experimental C# features\n" +
218 " -v Verbose parsing (for debugging the parser)\n" +
219 " --mcs-debug X Sets MCS debugging level to X\n");
222 static void Usage ()
224 Console.WriteLine (
225 "Mono C# compiler, (C) 2001 - 2005 Novell, Inc.\n" +
226 "mcs [options] source-files\n" +
227 " --about About the Mono C# compiler\n" +
228 " -addmodule:MODULE Adds the module to the generated assembly\n" +
229 " -checked[+|-] Set default context to checked\n" +
230 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
231 " -clscheck[+|-] Disables CLS Compliance verifications" + Environment.NewLine +
232 " -define:S1[;S2] Defines one or more symbols (short: /d:)\n" +
233 " -debug[+|-], -g Generate debugging information\n" +
234 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
235 " -doc:FILE XML Documentation file to generate\n" +
236 " -keycontainer:NAME The key pair container used to strongname the assembly\n" +
237 " -keyfile:FILE The strongname key file used to strongname the assembly\n" +
238 " -langversion:TEXT Specifies language version modes: ISO-1 or Default\n" +
239 " -lib:PATH1,PATH2 Adds the paths to the assembly link path\n" +
240 " -main:class Specified the class that contains the entry point\n" +
241 " -noconfig[+|-] Disables implicit references to assemblies\n" +
242 " -nostdlib[+|-] Does not load core libraries\n" +
243 " -nowarn:W1[,W2] Disables one or more warnings\n" +
244 " -optimize[+|-] Enables code optimalizations\n" +
245 " -out:FNAME Specifies output file\n" +
246 " -pkg:P1[,Pn] References packages P1..Pn\n" +
247 " -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" +
248 " -reference:ASS References the specified assembly (-r:ASS)\n" +
249 " -target:KIND Specifies the target (KIND is one of: exe, winexe,\n" +
250 " library, module), (short: /t:)\n" +
251 " -unsafe[+|-] Allows unsafe code\n" +
252 " -warnaserror[+|-] Treat warnings as errors\n" +
253 " -warn:LEVEL Sets warning level (the highest is 4, the default is 2)\n" +
254 " -help2 Show other help flags\n" +
255 "\n" +
256 "Resources:\n" +
257 " -linkresource:FILE[,ID] Links FILE as a resource\n" +
258 " -resource:FILE[,ID] Embed FILE as a resource\n" +
259 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
260 " -win32icon:FILE Use this icon for the output\n" +
261 " @file Read response file for more options\n\n" +
262 "Options can be of the form -option or /option");
265 static void TargetUsage ()
267 Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
270 static void About ()
272 Console.WriteLine (
273 "The Mono C# compiler is (C) 2001-2005, Novell, Inc.\n\n" +
274 "The compiler source code is released under the terms of the GNU GPL\n\n" +
276 "For more information on Mono, visit the project Web site\n" +
277 " http://www.go-mono.com\n\n" +
279 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath");
280 Environment.Exit (0);
283 public static int counter1, counter2;
285 public static int Main (string[] args)
287 #if GMCS_SOURCE
288 RootContext.Version = LanguageVersion.Default;
289 #endif
290 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
292 bool ok = MainDriver (args);
294 if (ok && Report.Errors == 0) {
295 if (Report.Warnings > 0) {
296 Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
298 if (show_counters){
299 Console.WriteLine ("Counter1: " + counter1);
300 Console.WriteLine ("Counter2: " + counter2);
302 if (pause)
303 Console.ReadLine ();
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; try using the '-addmodule' option", filename);
349 return;
351 } catch (FileNotFoundException) {
352 // did the file get deleted during compilation? who cares? swallow the exception
353 } catch (BadImageFormatException) {
354 // swallow exception
355 } catch (FileLoadException) {
356 // swallow exception
359 Error9 ("assembly", filename, log);
362 static public void LoadAssembly (string assembly, string alias, bool soft)
364 Assembly a = null;
365 string total_log = "";
367 try {
368 try {
369 char[] path_chars = { '/', '\\' };
371 if (assembly.IndexOfAny (path_chars) != -1) {
372 a = Assembly.LoadFrom (assembly);
373 } else {
374 string ass = assembly;
375 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
376 ass = assembly.Substring (0, assembly.Length - 4);
377 a = Assembly.Load (ass);
379 } catch (FileNotFoundException) {
380 bool err = !soft;
381 foreach (string dir in link_paths) {
382 string full_path = Path.Combine (dir, assembly);
383 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
384 full_path += ".dll";
386 try {
387 a = Assembly.LoadFrom (full_path);
388 err = false;
389 break;
390 } catch (FileNotFoundException ff) {
391 total_log += ff.FusionLog;
394 if (err) {
395 Error6 (assembly, total_log);
396 return;
400 // Extern aliased refs require special handling
401 if (alias == null)
402 RootNamespace.Global.AddAssemblyReference (a);
403 else
404 RootNamespace.DefineRootNamespace (alias, a);
406 } catch (BadImageFormatException f) {
407 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
408 BadAssembly (f.FileName, f.FusionLog);
409 } catch (FileLoadException f) {
410 // ... while .NET 1.1 throws this
411 BadAssembly (f.FileName, f.FusionLog);
415 static public void LoadModule (string module)
417 Module m = null;
418 string total_log = "";
420 try {
421 try {
422 m = CodeGen.Assembly.AddModule (module);
423 } catch (FileNotFoundException) {
424 bool err = true;
425 foreach (string dir in link_paths) {
426 string full_path = Path.Combine (dir, module);
427 if (!module.EndsWith (".netmodule"))
428 full_path += ".netmodule";
430 try {
431 m = CodeGen.Assembly.AddModule (full_path);
432 err = false;
433 break;
434 } catch (FileNotFoundException ff) {
435 total_log += ff.FusionLog;
438 if (err) {
439 Error6 (module, total_log);
440 return;
444 RootNamespace.Global.AddModuleReference (m);
446 } catch (BadImageFormatException f) {
447 Error9 ("module", f.FileName, f.FusionLog);
448 } catch (FileLoadException f) {
449 Error9 ("module", f.FileName, f.FusionLog);
453 /// <summary>
454 /// Loads all assemblies referenced on the command line
455 /// </summary>
456 static public void LoadReferences ()
458 foreach (string r in references)
459 LoadAssembly (r, false);
461 foreach (string r in soft_references)
462 LoadAssembly (r, true);
464 foreach (DictionaryEntry entry in external_aliases)
465 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
467 return;
470 static void SetupDefaultDefines ()
472 defines = new ArrayList ();
473 defines.Add ("__MonoCS__");
476 static string [] LoadArgs (string file)
478 StreamReader f;
479 ArrayList args = new ArrayList ();
480 string line;
481 try {
482 f = new StreamReader (file);
483 } catch {
484 return null;
487 StringBuilder sb = new StringBuilder ();
489 while ((line = f.ReadLine ()) != null){
490 int t = line.Length;
492 for (int i = 0; i < t; i++){
493 char c = line [i];
495 if (c == '"' || c == '\''){
496 char end = c;
498 for (i++; i < t; i++){
499 c = line [i];
501 if (c == end)
502 break;
503 sb.Append (c);
505 } else if (c == ' '){
506 if (sb.Length > 0){
507 args.Add (sb.ToString ());
508 sb.Length = 0;
510 } else
511 sb.Append (c);
513 if (sb.Length > 0){
514 args.Add (sb.ToString ());
515 sb.Length = 0;
519 string [] ret_value = new string [args.Count];
520 args.CopyTo (ret_value, 0);
522 return ret_value;
526 // Returns the directory where the system assemblies are installed
528 static string GetSystemDir ()
530 return Path.GetDirectoryName (typeof (object).Assembly.Location);
534 // Given a path specification, splits the path from the file/pattern
536 static void SplitPathAndPattern (string spec, out string path, out string pattern)
538 int p = spec.LastIndexOf ('/');
539 if (p != -1){
541 // Windows does not like /file.cs, switch that to:
542 // "\", "file.cs"
544 if (p == 0){
545 path = "\\";
546 pattern = spec.Substring (1);
547 } else {
548 path = spec.Substring (0, p);
549 pattern = spec.Substring (p + 1);
551 return;
554 p = spec.LastIndexOf ('\\');
555 if (p != -1){
556 path = spec.Substring (0, p);
557 pattern = spec.Substring (p + 1);
558 return;
561 path = ".";
562 pattern = spec;
565 static void ProcessFile (string f)
567 if (first_source == null)
568 first_source = f;
570 Location.AddFile (f);
573 static void ProcessFiles ()
575 Location.Initialize ();
577 foreach (SourceFile file in Location.SourceFiles) {
578 if (tokenize) {
579 tokenize_file (file);
580 } else {
581 parse (file);
586 static void CompileFiles (string spec, bool recurse)
588 string path, pattern;
590 SplitPathAndPattern (spec, out path, out pattern);
591 if (pattern.IndexOf ('*') == -1){
592 ProcessFile (spec);
593 return;
596 string [] files = null;
597 try {
598 files = Directory.GetFiles (path, pattern);
599 } catch (System.IO.DirectoryNotFoundException) {
600 Report.Error (2001, "Source file `" + spec + "' could not be found");
601 return;
602 } catch (System.IO.IOException){
603 Report.Error (2001, "Source file `" + spec + "' could not be found");
604 return;
606 foreach (string f in files) {
607 ProcessFile (f);
610 if (!recurse)
611 return;
613 string [] dirs = null;
615 try {
616 dirs = Directory.GetDirectories (path);
617 } catch {
620 foreach (string d in dirs) {
622 // Don't include path in this string, as each
623 // directory entry already does
624 CompileFiles (d + "/" + pattern, true);
628 static void DefineDefaultConfig ()
631 // For now the "default config" is harcoded into the compiler
632 // we can move this outside later
634 string [] default_config = {
635 "System",
636 "System.Xml",
637 #if false
639 // Is it worth pre-loading all this stuff?
641 "Accessibility",
642 "System.Configuration.Install",
643 "System.Data",
644 "System.Design",
645 "System.DirectoryServices",
646 "System.Drawing.Design",
647 "System.Drawing",
648 "System.EnterpriseServices",
649 "System.Management",
650 "System.Messaging",
651 "System.Runtime.Remoting",
652 "System.Runtime.Serialization.Formatters.Soap",
653 "System.Security",
654 "System.ServiceProcess",
655 "System.Web",
656 "System.Web.RegularExpressions",
657 "System.Web.Services",
658 "System.Windows.Forms"
659 #endif
662 int p = 0;
663 foreach (string def in default_config)
664 soft_references.Insert (p++, def);
667 public static string OutputFile
669 set {
670 output_file = value;
672 get {
673 return Path.GetFileName (output_file);
677 static void SetWarningLevel (string s)
679 int level = -1;
681 try {
682 level = Int32.Parse (s);
683 } catch {
685 if (level < 0 || level > 4){
686 Report.Error (1900, "Warning level must be in the range 0-4");
687 return;
689 RootContext.WarningLevel = level;
692 static void SetupV2 ()
694 RootContext.Version = LanguageVersion.Default;
695 defines.Add ("__V2__");
698 static void Version ()
700 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
701 Console.WriteLine ("Mono C# compiler version {0}", version);
702 Environment.Exit (0);
706 // Currently handles the Unix-like command line options, but will be
707 // deprecated in favor of the CSCParseOption, which will also handle the
708 // options that start with a dash in the future.
710 static bool UnixParseOption (string arg, ref string [] args, ref int i)
712 switch (arg){
713 case "-v":
714 CSharpParser.yacc_verbose_flag++;
715 return true;
717 case "--version":
718 Version ();
719 return true;
721 case "--parse":
722 parse_only = true;
723 return true;
725 case "--main": case "-m":
726 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
727 if ((i + 1) >= args.Length){
728 Usage ();
729 Environment.Exit (1);
731 RootContext.MainClass = args [++i];
732 return true;
734 case "--unsafe":
735 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
736 RootContext.Unsafe = true;
737 return true;
739 case "/?": case "/h": case "/help":
740 case "--help":
741 Usage ();
742 Environment.Exit (0);
743 return true;
745 case "--define":
746 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
747 if ((i + 1) >= args.Length){
748 Usage ();
749 Environment.Exit (1);
751 defines.Add (args [++i]);
752 return true;
754 case "--show-counters":
755 show_counters = true;
756 return true;
758 case "--expect-error": {
759 int code = 0;
761 try {
762 code = Int32.Parse (
763 args [++i], NumberStyles.AllowLeadingSign);
764 Report.ExpectedError = code;
765 } catch {
766 Report.Error (-14, "Invalid number specified");
768 return true;
771 case "--tokenize":
772 tokenize = true;
773 return true;
775 case "-o":
776 case "--output":
777 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
778 if ((i + 1) >= args.Length){
779 Usage ();
780 Environment.Exit (1);
782 OutputFile = args [++i];
783 return true;
785 case "--checked":
786 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
787 RootContext.Checked = true;
788 return true;
790 case "--stacktrace":
791 Report.Stacktrace = true;
792 return true;
794 case "--linkresource":
795 case "--linkres":
796 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
797 if ((i + 1) >= args.Length){
798 Usage ();
799 Report.Error (5, "Missing argument to --linkres");
800 Environment.Exit (1);
802 if (embedded_resources == null)
803 embedded_resources = new Resources ();
805 embedded_resources.Add (false, args [++i], args [i]);
806 return true;
808 case "--resource":
809 case "--res":
810 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
811 if ((i + 1) >= args.Length){
812 Usage ();
813 Report.Error (5, "Missing argument to --resource");
814 Environment.Exit (1);
816 if (embedded_resources == null)
817 embedded_resources = new Resources ();
819 embedded_resources.Add (true, args [++i], args [i]);
820 return true;
822 case "--target":
823 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
824 if ((i + 1) >= args.Length){
825 Environment.Exit (1);
826 return true;
829 string type = args [++i];
830 switch (type){
831 case "library":
832 RootContext.Target = Target.Library;
833 RootContext.TargetExt = ".dll";
834 break;
836 case "exe":
837 RootContext.Target = Target.Exe;
838 break;
840 case "winexe":
841 RootContext.Target = Target.WinExe;
842 break;
844 case "module":
845 RootContext.Target = Target.Module;
846 RootContext.TargetExt = ".dll";
847 break;
848 default:
849 TargetUsage ();
850 break;
852 return true;
854 case "-r":
855 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
856 if ((i + 1) >= args.Length){
857 Usage ();
858 Environment.Exit (1);
861 string val = args [++i];
862 int idx = val.IndexOf ('=');
863 if (idx > -1) {
864 string alias = val.Substring (0, idx);
865 string assembly = val.Substring (idx + 1);
866 AddExternAlias (alias, assembly);
867 return true;
870 references.Add (val);
871 return true;
873 case "-L":
874 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
875 if ((i + 1) >= args.Length){
876 Usage ();
877 Environment.Exit (1);
879 link_paths.Add (args [++i]);
880 return true;
882 case "--nostdlib":
883 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
884 RootContext.StdLib = false;
885 return true;
887 case "--fatal":
888 Report.Fatal = true;
889 return true;
891 case "--werror":
892 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
893 Report.WarningsAreErrors = true;
894 return true;
896 case "--nowarn":
897 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
898 if ((i + 1) >= args.Length){
899 Usage ();
900 Environment.Exit (1);
902 int warn = 0;
904 try {
905 warn = Int32.Parse (args [++i]);
906 } catch {
907 Usage ();
908 Environment.Exit (1);
910 Report.SetIgnoreWarning (warn);
911 return true;
913 case "--wlevel":
914 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
915 if ((i + 1) >= args.Length){
916 Report.Error (
917 1900,
918 "--wlevel requires a value from 0 to 4");
919 Environment.Exit (1);
922 SetWarningLevel (args [++i]);
923 return true;
925 case "--mcs-debug":
926 if ((i + 1) >= args.Length){
927 Report.Error (5, "--mcs-debug requires an argument");
928 Environment.Exit (1);
931 try {
932 Report.DebugFlags = Int32.Parse (args [++i]);
933 } catch {
934 Report.Error (5, "Invalid argument to --mcs-debug");
935 Environment.Exit (1);
937 return true;
939 case "--about":
940 About ();
941 return true;
943 case "--recurse":
944 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
945 if ((i + 1) >= args.Length){
946 Report.Error (5, "--recurse requires an argument");
947 Environment.Exit (1);
949 CompileFiles (args [++i], true);
950 return true;
952 case "--timestamp":
953 timestamps = true;
954 last_time = first_time = DateTime.Now;
955 return true;
957 case "--pause":
958 pause = true;
959 return true;
961 case "--debug": case "-g":
962 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
963 want_debugging_support = true;
964 return true;
966 case "--noconfig":
967 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
968 load_default_config = false;
969 return true;
972 return false;
976 // This parses the -arg and /arg options to the compiler, even if the strings
977 // in the following text use "/arg" on the strings.
979 static bool CSCParseOption (string option, ref string [] args, ref int i)
981 int idx = option.IndexOf (':');
982 string arg, value;
984 if (idx == -1){
985 arg = option;
986 value = "";
987 } else {
988 arg = option.Substring (0, idx);
990 value = option.Substring (idx + 1);
993 switch (arg){
994 case "/nologo":
995 return true;
997 case "/t":
998 case "/target":
999 switch (value){
1000 case "exe":
1001 RootContext.Target = Target.Exe;
1002 break;
1004 case "winexe":
1005 RootContext.Target = Target.WinExe;
1006 break;
1008 case "library":
1009 RootContext.Target = Target.Library;
1010 RootContext.TargetExt = ".dll";
1011 break;
1013 case "module":
1014 RootContext.Target = Target.Module;
1015 RootContext.TargetExt = ".netmodule";
1016 break;
1018 default:
1019 TargetUsage ();
1020 break;
1022 return true;
1024 case "/out":
1025 if (value.Length == 0){
1026 Usage ();
1027 Environment.Exit (1);
1029 OutputFile = value;
1030 return true;
1032 case "/optimize":
1033 case "/optimize+":
1034 RootContext.Optimize = true;
1035 return true;
1037 case "/optimize-":
1038 RootContext.Optimize = false;
1039 return true;
1041 case "/incremental":
1042 case "/incremental+":
1043 case "/incremental-":
1044 // nothing.
1045 return true;
1047 case "/d":
1048 case "/define": {
1049 string [] defs;
1051 if (value.Length == 0){
1052 Usage ();
1053 Environment.Exit (1);
1056 defs = value.Split (new Char [] {';', ','});
1057 foreach (string d in defs){
1058 defines.Add (d);
1060 return true;
1063 case "/bugreport":
1065 // We should collect data, runtime, etc and store in the file specified
1067 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1068 return true;
1070 case "/pkg": {
1071 string packages;
1073 if (value.Length == 0){
1074 Usage ();
1075 Environment.Exit (1);
1077 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1079 ProcessStartInfo pi = new ProcessStartInfo ();
1080 pi.FileName = "pkg-config";
1081 pi.RedirectStandardOutput = true;
1082 pi.UseShellExecute = false;
1083 pi.Arguments = "--libs " + packages;
1084 Process p = null;
1085 try {
1086 p = Process.Start (pi);
1087 } catch (Exception e) {
1088 Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1089 Environment.Exit (1);
1092 if (p.StandardOutput == null){
1093 Report.Warning (-27, 1, "Specified package did not return any information");
1094 return true;
1096 string pkgout = p.StandardOutput.ReadToEnd ();
1097 p.WaitForExit ();
1098 if (p.ExitCode != 0) {
1099 Report.Error (-27, "Error running pkg-config. Check the above output.");
1100 Environment.Exit (1);
1103 if (pkgout != null){
1104 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1105 Split (new Char [] { ' ', '\t'});
1106 args = AddArgs (args, xargs);
1109 p.Close ();
1110 return true;
1113 case "/linkres":
1114 case "/linkresource":
1115 case "/res":
1116 case "/resource":
1117 if (embedded_resources == null)
1118 embedded_resources = new Resources ();
1120 bool embeded = arg.StartsWith ("/r");
1121 string[] s = value.Split (',');
1122 switch (s.Length) {
1123 case 1:
1124 if (s[0].Length == 0)
1125 goto default;
1126 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1127 break;
1128 case 2:
1129 embedded_resources.Add (embeded, s [0], s [1]);
1130 break;
1131 case 3:
1132 if (s [2] != "public" && s [2] != "private") {
1133 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1134 return true;
1136 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1137 break;
1138 default:
1139 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1140 break;
1143 return true;
1145 case "/recurse":
1146 if (value.Length == 0){
1147 Report.Error (5, "-recurse requires an argument");
1148 Environment.Exit (1);
1150 CompileFiles (value, true);
1151 return true;
1153 case "/r":
1154 case "/reference": {
1155 if (value.Length == 0){
1156 Report.Error (5, "-reference requires an argument");
1157 Environment.Exit (1);
1160 string [] refs = value.Split (new char [] { ';', ',' });
1161 foreach (string r in refs){
1162 string val = r;
1163 int index = val.IndexOf ('=');
1164 if (index > -1) {
1165 string alias = r.Substring (0, index);
1166 string assembly = r.Substring (index + 1);
1167 AddExternAlias (alias, assembly);
1168 return true;
1171 references.Add (val);
1173 return true;
1175 case "/addmodule": {
1176 if (value.Length == 0){
1177 Report.Error (5, arg + " requires an argument");
1178 Environment.Exit (1);
1181 string [] refs = value.Split (new char [] { ';', ',' });
1182 foreach (string r in refs){
1183 modules.Add (r);
1185 return true;
1187 case "/win32res": {
1188 if (value.Length == 0) {
1189 Report.Error (5, arg + " requires an argument");
1190 Environment.Exit (1);
1193 win32ResourceFile = value;
1194 return true;
1196 case "/win32icon": {
1197 if (value.Length == 0) {
1198 Report.Error (5, arg + " requires an argument");
1199 Environment.Exit (1);
1202 win32IconFile = value;
1203 return true;
1205 case "/doc": {
1206 if (value.Length == 0){
1207 Report.Error (2006, arg + " requires an argument");
1208 Environment.Exit (1);
1210 RootContext.Documentation = new Documentation (value);
1211 return true;
1213 case "/lib": {
1214 string [] libdirs;
1216 if (value.Length == 0){
1217 Report.Error (5, "/lib requires an argument");
1218 Environment.Exit (1);
1221 libdirs = value.Split (new Char [] { ',' });
1222 foreach (string dir in libdirs)
1223 link_paths.Add (dir);
1224 return true;
1227 case "/debug-":
1228 want_debugging_support = false;
1229 return true;
1231 case "/debug":
1232 case "/debug+":
1233 want_debugging_support = true;
1234 return true;
1236 case "/checked":
1237 case "/checked+":
1238 RootContext.Checked = true;
1239 return true;
1241 case "/checked-":
1242 RootContext.Checked = false;
1243 return true;
1245 case "/clscheck":
1246 case "/clscheck+":
1247 return true;
1249 case "/clscheck-":
1250 RootContext.VerifyClsCompliance = false;
1251 return true;
1253 case "/unsafe":
1254 case "/unsafe+":
1255 RootContext.Unsafe = true;
1256 return true;
1258 case "/unsafe-":
1259 RootContext.Unsafe = false;
1260 return true;
1262 case "/warnaserror":
1263 case "/warnaserror+":
1264 Report.WarningsAreErrors = true;
1265 return true;
1267 case "/warnaserror-":
1268 Report.WarningsAreErrors = false;
1269 return true;
1271 case "/warn":
1272 SetWarningLevel (value);
1273 return true;
1275 case "/nowarn": {
1276 string [] warns;
1278 if (value.Length == 0){
1279 Report.Error (5, "/nowarn requires an argument");
1280 Environment.Exit (1);
1283 warns = value.Split (new Char [] {','});
1284 foreach (string wc in warns){
1285 try {
1286 int warn = Int32.Parse (wc);
1287 if (warn < 1) {
1288 throw new ArgumentOutOfRangeException("warn");
1290 Report.SetIgnoreWarning (warn);
1291 } catch {
1292 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1295 return true;
1298 case "/noconfig-":
1299 load_default_config = true;
1300 return true;
1302 case "/noconfig":
1303 case "/noconfig+":
1304 load_default_config = false;
1305 return true;
1307 case "/help2":
1308 OtherFlags ();
1309 Environment.Exit(0);
1310 return true;
1312 case "/help":
1313 case "/?":
1314 Usage ();
1315 Environment.Exit (0);
1316 return true;
1318 case "/main":
1319 case "/m":
1320 if (value.Length == 0){
1321 Report.Error (5, arg + " requires an argument");
1322 Environment.Exit (1);
1324 RootContext.MainClass = value;
1325 return true;
1327 case "/nostdlib":
1328 case "/nostdlib+":
1329 RootContext.StdLib = false;
1330 return true;
1332 case "/nostdlib-":
1333 RootContext.StdLib = true;
1334 return true;
1336 case "/fullpaths":
1337 return true;
1339 case "/keyfile":
1340 if (value == String.Empty) {
1341 Report.Error (5, arg + " requires an argument");
1342 Environment.Exit (1);
1344 RootContext.StrongNameKeyFile = value;
1345 return true;
1346 case "/keycontainer":
1347 if (value == String.Empty) {
1348 Report.Error (5, arg + " requires an argument");
1349 Environment.Exit (1);
1351 RootContext.StrongNameKeyContainer = value;
1352 return true;
1353 case "/delaysign+":
1354 RootContext.StrongNameDelaySign = true;
1355 return true;
1356 case "/delaysign-":
1357 RootContext.StrongNameDelaySign = false;
1358 return true;
1360 case "/v2":
1361 case "/2":
1362 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1363 SetupV2 ();
1364 return true;
1366 case "/langversion":
1367 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1368 case "iso-1":
1369 RootContext.Version = LanguageVersion.ISO_1;
1370 return true;
1372 case "default":
1373 SetupV2 ();
1374 return true;
1376 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value);
1377 return true;
1379 case "/codepage":
1380 switch (value) {
1381 case "utf8":
1382 encoding = new UTF8Encoding();
1383 break;
1384 case "reset":
1385 encoding = Encoding.Default;
1386 break;
1387 default:
1388 try {
1389 encoding = Encoding.GetEncoding (
1390 Int32.Parse (value));
1391 } catch {
1392 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1394 break;
1396 return true;
1399 return false;
1402 static void Error_WrongOption (string option)
1404 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1407 static string [] AddArgs (string [] args, string [] extra_args)
1409 string [] new_args;
1410 new_args = new string [extra_args.Length + args.Length];
1412 // if args contains '--' we have to take that into account
1413 // split args into first half and second half based on '--'
1414 // and add the extra_args before --
1415 int split_position = Array.IndexOf (args, "--");
1416 if (split_position != -1)
1418 Array.Copy (args, new_args, split_position);
1419 extra_args.CopyTo (new_args, split_position);
1420 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1422 else
1424 args.CopyTo (new_args, 0);
1425 extra_args.CopyTo (new_args, args.Length);
1428 return new_args;
1431 static void AddExternAlias (string identifier, string assembly)
1433 if (assembly.Length == 0) {
1434 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1435 return;
1438 if (!IsExternAliasValid (identifier)) {
1439 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1440 return;
1443 // Could here hashtable throw an exception?
1444 external_aliases [identifier] = assembly;
1447 static bool IsExternAliasValid (string identifier)
1449 if (identifier.Length == 0)
1450 return false;
1451 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1452 return false;
1454 for (int i = 1; i < identifier.Length; i++) {
1455 char c = identifier [i];
1456 if (Char.IsLetter (c) || Char.IsDigit (c))
1457 continue;
1459 UnicodeCategory category = Char.GetUnicodeCategory (c);
1460 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1461 category != UnicodeCategory.SpacingCombiningMark ||
1462 category != UnicodeCategory.ConnectorPunctuation)
1463 return false;
1466 return true;
1469 /// <summary>
1470 /// Parses the arguments, and drives the compilation
1471 /// process.
1472 /// </summary>
1474 /// <remarks>
1475 /// TODO: Mostly structured to debug the compiler
1476 /// now, needs to be turned into a real driver soon.
1477 /// </remarks>
1478 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1479 internal static bool MainDriver (string [] args)
1481 int i;
1482 bool parsing_options = true;
1484 encoding = Encoding.Default;
1486 references = new ArrayList ();
1487 external_aliases = new Hashtable ();
1488 soft_references = new ArrayList ();
1489 modules = new ArrayList ();
1490 link_paths = new ArrayList ();
1492 SetupDefaultDefines ();
1495 // Setup defaults
1497 // This is not required because Assembly.Load knows about this
1498 // path.
1501 Hashtable response_file_list = null;
1503 for (i = 0; i < args.Length; i++){
1504 string arg = args [i];
1505 if (arg.Length == 0)
1506 continue;
1508 if (arg.StartsWith ("@")){
1509 string [] extra_args;
1510 string response_file = arg.Substring (1);
1512 if (response_file_list == null)
1513 response_file_list = new Hashtable ();
1515 if (response_file_list.Contains (response_file)){
1516 Report.Error (
1517 1515, "Response file `" + response_file +
1518 "' specified multiple times");
1519 Environment.Exit (1);
1522 response_file_list.Add (response_file, response_file);
1524 extra_args = LoadArgs (response_file);
1525 if (extra_args == null){
1526 Report.Error (2011, "Unable to open response file: " +
1527 response_file);
1528 return false;
1531 args = AddArgs (args, extra_args);
1532 continue;
1535 if (parsing_options){
1536 if (arg == "--"){
1537 parsing_options = false;
1538 continue;
1541 if (arg.StartsWith ("-")){
1542 if (UnixParseOption (arg, ref args, ref i))
1543 continue;
1545 // Try a -CSCOPTION
1546 string csc_opt = "/" + arg.Substring (1);
1547 if (CSCParseOption (csc_opt, ref args, ref i))
1548 continue;
1550 Error_WrongOption (arg);
1551 return false;
1552 } else {
1553 if (arg [0] == '/'){
1554 if (CSCParseOption (arg, ref args, ref i))
1555 continue;
1557 // Need to skip `/home/test.cs' however /test.cs is considered as error
1558 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
1559 Error_WrongOption (arg);
1560 return false;
1566 CompileFiles (arg, false);
1569 ProcessFiles ();
1571 if (tokenize)
1572 return true;
1574 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1575 throw new InternalErrorException ("who set it?");
1578 // If we are an exe, require a source file for the entry point
1580 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){
1581 if (first_source == null){
1582 Report.Error (2008, "No files to compile were specified");
1583 return false;
1589 // If there is nothing to put in the assembly, and we are not a library
1591 if (first_source == null && embedded_resources == null){
1592 Report.Error (2008, "No files to compile were specified");
1593 return false;
1596 if (Report.Errors > 0)
1597 return false;
1599 if (parse_only)
1600 return true;
1603 // Load Core Library for default compilation
1605 if (RootContext.StdLib)
1606 references.Insert (0, "mscorlib");
1608 if (load_default_config)
1609 DefineDefaultConfig ();
1611 if (Report.Errors > 0){
1612 return false;
1616 // Load assemblies required
1618 if (timestamps)
1619 ShowTime ("Loading references");
1620 link_paths.Add (GetSystemDir ());
1621 link_paths.Add (Directory.GetCurrentDirectory ());
1622 LoadReferences ();
1624 if (timestamps)
1625 ShowTime (" References loaded");
1627 if (Report.Errors > 0){
1628 return false;
1632 // Quick hack
1634 if (output_file == null){
1635 if (first_source == null){
1636 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1637 return false;
1640 int pos = first_source.LastIndexOf ('.');
1642 if (pos > 0)
1643 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1644 else
1645 output_file = first_source + RootContext.TargetExt;
1648 if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1649 return false;
1651 if (RootContext.Target == Target.Module) {
1652 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1653 if (module_only == null) {
1654 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1655 Environment.Exit (1);
1658 MethodInfo set_method = module_only.GetSetMethod (true);
1659 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1662 RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1664 if (modules.Count > 0) {
1665 foreach (string module in modules)
1666 LoadModule (module);
1670 // Before emitting, we need to get the core
1671 // types emitted from the user defined types
1672 // or from the system ones.
1674 if (timestamps)
1675 ShowTime ("Initializing Core Types");
1676 if (!RootContext.StdLib){
1677 RootContext.ResolveCore ();
1678 if (Report.Errors > 0)
1679 return false;
1682 TypeManager.InitCoreTypes ();
1683 if (timestamps)
1684 ShowTime (" Core Types done");
1686 CodeGen.Module.Resolve ();
1689 // The second pass of the compiler
1691 if (timestamps)
1692 ShowTime ("Resolving tree");
1693 RootContext.ResolveTree ();
1695 if (Report.Errors > 0)
1696 return false;
1697 if (timestamps)
1698 ShowTime ("Populate tree");
1699 if (!RootContext.StdLib)
1700 RootContext.BootCorlib_PopulateCoreTypes ();
1701 RootContext.PopulateTypes ();
1703 TypeManager.InitCodeHelpers ();
1705 RootContext.DefineTypes ();
1707 if (Report.Errors == 0 &&
1708 RootContext.Documentation != null &&
1709 !RootContext.Documentation.OutputDocComment (
1710 output_file))
1711 return false;
1714 // Verify using aliases now
1716 NamespaceEntry.VerifyAllUsing ();
1718 if (Report.Errors > 0){
1719 return false;
1722 CodeGen.Assembly.Resolve ();
1724 if (RootContext.VerifyClsCompliance) {
1725 if (CodeGen.Assembly.IsClsCompliant) {
1726 AttributeTester.VerifyModulesClsCompliance ();
1727 TypeManager.LoadAllImportedTypes ();
1730 if (Report.Errors > 0)
1731 return false;
1734 // The code generator
1736 if (timestamps)
1737 ShowTime ("Emitting code");
1738 ShowTotalTime ("Total so far");
1739 RootContext.EmitCode ();
1740 if (timestamps)
1741 ShowTime (" done");
1743 if (Report.Errors > 0){
1744 return false;
1747 if (timestamps)
1748 ShowTime ("Closing types");
1750 RootContext.CloseTypes ();
1752 PEFileKinds k = PEFileKinds.ConsoleApplication;
1754 switch (RootContext.Target) {
1755 case Target.Library:
1756 case Target.Module:
1757 k = PEFileKinds.Dll; break;
1758 case Target.Exe:
1759 k = PEFileKinds.ConsoleApplication; break;
1760 case Target.WinExe:
1761 k = PEFileKinds.WindowApplication; break;
1764 if (RootContext.NeedsEntryPoint) {
1765 MethodInfo ep = RootContext.EntryPoint;
1767 if (ep == null) {
1768 if (RootContext.MainClass != null) {
1769 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1770 if (main_cont == null) {
1771 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1772 return false;
1775 if (!(main_cont is ClassOrStruct)) {
1776 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1777 return false;
1780 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1781 return false;
1784 if (Report.Errors == 0)
1785 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1786 output_file);
1787 return false;
1790 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1791 } else if (RootContext.MainClass != null) {
1792 Report.Error (2017, "Cannot specify -main if building a module or library");
1795 if (embedded_resources != null){
1796 if (RootContext.Target == Target.Module) {
1797 Report.Error (1507, "Cannot link resource file when building a module");
1798 return false;
1801 embedded_resources.Emit ();
1805 // Add Win32 resources
1808 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1810 if (win32ResourceFile != null) {
1811 try {
1812 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1814 catch (ArgumentException) {
1815 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1819 if (win32IconFile != null) {
1820 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1821 if (define_icon == null) {
1822 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1824 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1827 if (Report.Errors > 0)
1828 return false;
1830 CodeGen.Save (output_file);
1831 if (timestamps) {
1832 ShowTime ("Saved output");
1833 ShowTotalTime ("Total");
1836 Timer.ShowTimers ();
1838 if (Report.ExpectedError != 0) {
1839 if (Report.Errors == 0) {
1840 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1841 "No other errors reported.");
1843 Environment.Exit (2);
1844 } else {
1845 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1846 "However, other errors were reported.");
1848 Environment.Exit (1);
1852 return false;
1855 #if DEBUGME
1856 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1857 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1858 #endif
1859 return (Report.Errors == 0);
1863 class Resources
1865 interface IResource
1867 void Emit ();
1868 string FileName { get; }
1871 class EmbededResource : IResource
1873 static MethodInfo embed_res;
1875 static EmbededResource () {
1876 Type[] argst = new Type [] {
1877 typeof (string), typeof (string), typeof (ResourceAttributes)
1880 embed_res = typeof (AssemblyBuilder).GetMethod (
1881 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1882 null, CallingConventions.Any, argst, null);
1884 if (embed_res == null) {
1885 Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1889 readonly object[] args;
1891 public EmbededResource (string name, string file, bool isPrivate)
1893 args = new object [3];
1894 args [0] = name;
1895 args [1] = file;
1896 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1899 public void Emit()
1901 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1904 public string FileName {
1905 get {
1906 return (string)args [1];
1911 class LinkedResource : IResource
1913 readonly string file;
1914 readonly string name;
1915 readonly ResourceAttributes attribute;
1917 public LinkedResource (string name, string file, bool isPrivate)
1919 this.name = name;
1920 this.file = file;
1921 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1924 public void Emit ()
1926 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1929 public string FileName {
1930 get {
1931 return file;
1937 IDictionary embedded_resources = new HybridDictionary ();
1939 public void Add (bool embeded, string file, string name)
1941 Add (embeded, file, name, false);
1944 public void Add (bool embeded, string file, string name, bool isPrivate)
1946 if (embedded_resources.Contains (name)) {
1947 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1948 return;
1950 IResource r = embeded ?
1951 (IResource) new EmbededResource (name, file, isPrivate) :
1952 new LinkedResource (name, file, isPrivate);
1954 embedded_resources.Add (name, r);
1957 public void Emit ()
1959 foreach (IResource r in embedded_resources.Values) {
1960 if (!File.Exists (r.FileName)) {
1961 Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1962 continue;
1965 r.Emit ();
1971 // This is the only public entry point
1973 public class CompilerCallableEntryPoint : MarshalByRefObject {
1974 public static bool InvokeCompiler (string [] args, TextWriter error)
1976 Report.Stderr = error;
1977 try {
1978 return Driver.MainDriver (args) && Report.Errors == 0;
1980 finally {
1981 Report.Stderr = Console.Error;
1982 Reset ();
1986 public static int[] AllWarningNumbers {
1987 get {
1988 return Report.AllWarnings;
1992 static void Reset ()
1994 Driver.Reset ();
1995 Location.Reset ();
1996 RootContext.Reset ();
1997 Report.Reset ();
1998 TypeManager.Reset ();
1999 TypeHandle.Reset ();
2000 RootNamespace.Reset ();
2001 NamespaceEntry.Reset ();
2002 CodeGen.Reset ();
2003 Attribute.Reset ();
2004 AttributeTester.Reset ();