2009-07-20 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / driver.cs
blob07ca2e63f7931aaf39e31c7358ac07307b76f575
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 #if GMCS_SOURCE
31 enum Platform {
32 AnyCPU, X86, X64, IA64
34 #endif
36 /// <summary>
37 /// The compiler driver.
38 /// </summary>
39 class Driver
42 // Assemblies references to be linked. Initialized with
43 // mscorlib.dll here.
44 ArrayList references;
47 // If any of these fail, we ignore the problem. This is so
48 // that we can list all the assemblies in Windows and not fail
49 // if they are missing on Linux.
51 ArrayList soft_references;
53 //
54 // External aliases for assemblies.
56 Hashtable external_aliases;
59 // Modules to be linked
61 ArrayList modules;
63 // Lookup paths
64 static ArrayList link_paths;
66 // Whether we want to only run the tokenizer
67 bool tokenize;
69 string first_source;
71 bool want_debugging_support;
72 bool parse_only;
73 bool timestamps;
76 // Whether to load the initial config file (what CSC.RSP has by default)
77 //
78 bool load_default_config = true;
81 // A list of resource files
83 Resources embedded_resources;
84 string win32ResourceFile;
85 string win32IconFile;
88 // Output file
90 static string output_file;
93 // Last time we took the time
95 DateTime last_time, first_time;
98 // Encoding.
100 Encoding encoding;
102 static readonly char[] argument_value_separator = new char [] { ';', ',' };
104 static public void Reset ()
106 output_file = null;
109 public Driver ()
111 encoding = Encoding.Default;
114 public static Driver Create (string [] args, bool require_files)
116 Driver d = new Driver ();
117 if (!d.ParseArguments (args, require_files))
118 return null;
120 return d;
123 void ShowTime (string msg)
125 if (!timestamps)
126 return;
128 DateTime now = DateTime.Now;
129 TimeSpan span = now - last_time;
130 last_time = now;
132 Console.WriteLine (
133 "[{0:00}:{1:000}] {2}",
134 (int) span.TotalSeconds, span.Milliseconds, msg);
137 void ShowTotalTime (string msg)
139 if (!timestamps)
140 return;
142 DateTime now = DateTime.Now;
143 TimeSpan span = now - first_time;
144 last_time = now;
146 Console.WriteLine (
147 "[{0:00}:{1:000}] {2}",
148 (int) span.TotalSeconds, span.Milliseconds, msg);
151 void tokenize_file (CompilationUnit file)
153 Stream input;
155 try {
156 input = File.OpenRead (file.Name);
157 } catch {
158 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
159 return;
162 using (input){
163 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
164 Tokenizer lexer = new Tokenizer (reader, file);
165 int token, tokens = 0, errors = 0;
167 while ((token = lexer.token ()) != Token.EOF){
168 tokens++;
169 if (token == Token.ERROR)
170 errors++;
172 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
175 return;
178 void Parse (CompilationUnit file)
180 Stream input;
182 try {
183 input = File.OpenRead (file.Name);
184 } catch {
185 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
186 return;
189 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
191 // Check 'MZ' header
192 if (reader.Read () == 77 && reader.Read () == 90) {
193 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
194 input.Close ();
195 return;
198 reader.Position = 0;
199 Parse (reader, file);
200 input.Close ();
203 void Parse (SeekableStreamReader reader, CompilationUnit file)
205 CSharpParser parser = new CSharpParser (reader, file);
206 parser.ErrorOutput = Report.Stderr;
207 try {
208 parser.parse ();
209 } catch (Exception ex) {
210 Report.Error(589, parser.Lexer.Location,
211 "Compilation aborted in file `{0}', {1}", file.Name, ex);
215 static void OtherFlags ()
217 Console.WriteLine (
218 "Other flags in the compiler\n" +
219 " --fatal Makes errors fatal\n" +
220 " --parse Only parses the source file\n" +
221 " --typetest Tests the tokenizer's built-in type parser\n" +
222 " --stacktrace Shows stack trace at error location\n" +
223 " --timestamp Displays time stamps of various compiler events\n" +
224 " --expect-error X Expect that error X will be encountered\n" +
225 " -v Verbose parsing (for debugging the parser)\n" +
226 " --mcs-debug X Sets MCS debugging level to X\n");
229 static void Usage ()
231 Console.WriteLine (
232 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
233 "mcs [options] source-files\n" +
234 " --about About the Mono C# compiler\n" +
235 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
236 " -checked[+|-] Sets default aritmetic overflow context\n" +
237 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
238 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
239 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
240 " -debug[+|-], -g Generate debugging information\n" +
241 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
242 " -doc:FILE Process documentation comments to XML file\n" +
243 " -help Lists all compiler options (short: -?)\n" +
244 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
245 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
246 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, Default, or Future\n" +
247 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
248 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
249 " -noconfig Disables implicitly referenced assemblies\n" +
250 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
251 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
252 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
253 " -out:FILE Specifies output assembly name\n" +
254 #if !SMCS_SOURCE
255 " -pkg:P1[,Pn] References packages P1..Pn\n" +
256 #endif
257 " -platform:ARCH Specifies the target platform of the output assembly\n" +
258 " ARCH can be one of: anycpu, x86, x64 or itanium\n" +
259 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
260 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
261 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
262 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
263 " KIND can be one of: exe, winexe, library, module\n" +
264 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
265 " -warnaserror[+|-] Treats all warnings as errors\n" +
266 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
267 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
268 " -help2 Shows internal compiler options\n" +
269 "\n" +
270 "Resources:\n" +
271 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
272 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
273 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
274 " -win32icon:FILE Use this icon for the output\n" +
275 " @file Read response file for more options\n\n" +
276 "Options can be of the form -option or /option");
279 static void TargetUsage ()
281 Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
284 static void About ()
286 Console.WriteLine (
287 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
288 "The compiler source code is released under the terms of the \n"+
289 "MIT X11 or GNU GPL licenses\n\n" +
291 "For more information on Mono, visit the project Web site\n" +
292 " http://www.mono-project.com\n\n" +
294 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
295 Environment.Exit (0);
298 public static int Main (string[] args)
300 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
302 Driver d = Driver.Create (args, true);
303 if (d == null)
304 return 1;
306 if (d.Compile () && Report.Errors == 0) {
307 if (Report.Warnings > 0) {
308 Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
310 Environment.Exit (0);
311 return 0;
315 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
316 Report.Errors, Report.Warnings);
317 Environment.Exit (1);
318 return 1;
321 static public void LoadAssembly (string assembly, bool soft)
323 LoadAssembly (assembly, null, soft);
326 static void Error6 (string name, string log)
328 if (log != null && log.Length > 0)
329 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
330 Report.Error (6, "cannot find metadata file `{0}'", name);
333 static void Error9 (string type, string filename, string log)
335 if (log != null && log.Length > 0)
336 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
337 Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
340 static void BadAssembly (string filename, string log)
342 MethodInfo adder_method = AssemblyClass.AddModule_Method;
344 if (adder_method != null) {
345 AssemblyName an = new AssemblyName ();
346 an.Name = ".temp";
347 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
348 try {
349 object m = null;
350 try {
351 m = adder_method.Invoke (ab, new object [] { filename });
352 } catch (TargetInvocationException ex) {
353 throw ex.InnerException;
356 if (m != null) {
357 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
358 Path.GetFileName (filename));
359 return;
361 } catch (FileNotFoundException) {
362 // did the file get deleted during compilation? who cares? swallow the exception
363 } catch (BadImageFormatException) {
364 // swallow exception
365 } catch (FileLoadException) {
366 // swallow exception
369 Error9 ("assembly", filename, log);
372 static public void LoadAssembly (string assembly, string alias, bool soft)
374 Assembly a = null;
375 string total_log = "";
377 try {
378 try {
379 char[] path_chars = { '/', '\\' };
381 if (assembly.IndexOfAny (path_chars) != -1) {
382 a = Assembly.LoadFrom (assembly);
383 } else {
384 string ass = assembly;
385 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
386 ass = assembly.Substring (0, assembly.Length - 4);
387 a = Assembly.Load (ass);
389 } catch (FileNotFoundException) {
390 bool err = !soft;
391 foreach (string dir in link_paths) {
392 string full_path = Path.Combine (dir, assembly);
393 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
394 full_path += ".dll";
396 try {
397 a = Assembly.LoadFrom (full_path);
398 err = false;
399 break;
400 } catch (FileNotFoundException ff) {
401 if (soft)
402 return;
403 total_log += ff.FusionLog;
406 if (err) {
407 Error6 (assembly, total_log);
408 return;
412 // Extern aliased refs require special handling
413 if (alias == null)
414 GlobalRootNamespace.Instance.AddAssemblyReference (a);
415 else
416 GlobalRootNamespace.Instance.DefineRootNamespace (alias, a);
418 } catch (BadImageFormatException f) {
419 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
420 BadAssembly (f.FileName, f.FusionLog);
421 } catch (FileLoadException f) {
422 // ... while .NET 1.1 throws this
423 BadAssembly (f.FileName, f.FusionLog);
427 static public void LoadModule (string module)
429 Module m = null;
430 string total_log = "";
432 try {
433 try {
434 m = CodeGen.Assembly.AddModule (module);
435 } catch (FileNotFoundException) {
436 bool err = true;
437 foreach (string dir in link_paths) {
438 string full_path = Path.Combine (dir, module);
439 if (!module.EndsWith (".netmodule"))
440 full_path += ".netmodule";
442 try {
443 m = CodeGen.Assembly.AddModule (full_path);
444 err = false;
445 break;
446 } catch (FileNotFoundException ff) {
447 total_log += ff.FusionLog;
450 if (err) {
451 Error6 (module, total_log);
452 return;
456 GlobalRootNamespace.Instance.AddModuleReference (m);
458 } catch (BadImageFormatException f) {
459 Error9 ("module", f.FileName, f.FusionLog);
460 } catch (FileLoadException f) {
461 Error9 ("module", f.FileName, f.FusionLog);
465 /// <summary>
466 /// Loads all assemblies referenced on the command line
467 /// </summary>
468 public void LoadReferences ()
470 link_paths.Add (GetSystemDir ());
471 link_paths.Add (Directory.GetCurrentDirectory ());
474 // Load Core Library for default compilation
476 if (RootContext.StdLib)
477 LoadAssembly ("mscorlib", false);
479 foreach (string r in soft_references)
480 LoadAssembly (r, true);
482 foreach (string r in references)
483 LoadAssembly (r, false);
485 foreach (DictionaryEntry entry in external_aliases)
486 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
488 GlobalRootNamespace.Instance.ComputeNamespaces ();
491 static string [] LoadArgs (string file)
493 StreamReader f;
494 ArrayList args = new ArrayList ();
495 string line;
496 try {
497 f = new StreamReader (file);
498 } catch {
499 return null;
502 StringBuilder sb = new StringBuilder ();
504 while ((line = f.ReadLine ()) != null){
505 int t = line.Length;
507 for (int i = 0; i < t; i++){
508 char c = line [i];
510 if (c == '"' || c == '\''){
511 char end = c;
513 for (i++; i < t; i++){
514 c = line [i];
516 if (c == end)
517 break;
518 sb.Append (c);
520 } else if (c == ' '){
521 if (sb.Length > 0){
522 args.Add (sb.ToString ());
523 sb.Length = 0;
525 } else
526 sb.Append (c);
528 if (sb.Length > 0){
529 args.Add (sb.ToString ());
530 sb.Length = 0;
534 string [] ret_value = new string [args.Count];
535 args.CopyTo (ret_value, 0);
537 return ret_value;
541 // Returns the directory where the system assemblies are installed
543 static string GetSystemDir ()
545 return Path.GetDirectoryName (typeof (object).Assembly.Location);
549 // Given a path specification, splits the path from the file/pattern
551 static void SplitPathAndPattern (string spec, out string path, out string pattern)
553 int p = spec.LastIndexOf ('/');
554 if (p != -1){
556 // Windows does not like /file.cs, switch that to:
557 // "\", "file.cs"
559 if (p == 0){
560 path = "\\";
561 pattern = spec.Substring (1);
562 } else {
563 path = spec.Substring (0, p);
564 pattern = spec.Substring (p + 1);
566 return;
569 p = spec.LastIndexOf ('\\');
570 if (p != -1){
571 path = spec.Substring (0, p);
572 pattern = spec.Substring (p + 1);
573 return;
576 path = ".";
577 pattern = spec;
580 void AddSourceFile (string f)
582 if (first_source == null)
583 first_source = f;
585 Location.AddFile (f);
588 bool ParseArguments (string[] args, bool require_files)
590 references = new ArrayList ();
591 external_aliases = new Hashtable ();
592 soft_references = new ArrayList ();
593 modules = new ArrayList (2);
594 link_paths = new ArrayList ();
596 ArrayList response_file_list = null;
597 bool parsing_options = true;
599 for (int i = 0; i < args.Length; i++) {
600 string arg = args [i];
601 if (arg.Length == 0)
602 continue;
604 if (arg [0] == '@') {
605 string [] extra_args;
606 string response_file = arg.Substring (1);
608 if (response_file_list == null)
609 response_file_list = new ArrayList ();
611 if (response_file_list.Contains (response_file)) {
612 Report.Error (
613 1515, "Response file `" + response_file +
614 "' specified multiple times");
615 return false;
618 response_file_list.Add (response_file);
620 extra_args = LoadArgs (response_file);
621 if (extra_args == null) {
622 Report.Error (2011, "Unable to open response file: " +
623 response_file);
624 return false;
627 args = AddArgs (args, extra_args);
628 continue;
631 if (parsing_options) {
632 if (arg == "--") {
633 parsing_options = false;
634 continue;
637 if (arg [0] == '-') {
638 if (UnixParseOption (arg, ref args, ref i))
639 continue;
641 // Try a -CSCOPTION
642 string csc_opt = "/" + arg.Substring (1);
643 if (CSCParseOption (csc_opt, ref args))
644 continue;
646 Error_WrongOption (arg);
647 return false;
649 if (arg [0] == '/') {
650 if (CSCParseOption (arg, ref args))
651 continue;
653 // Need to skip `/home/test.cs' however /test.cs is considered as error
654 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
655 Error_WrongOption (arg);
656 return false;
661 ProcessSourceFiles (arg, false);
664 if (require_files == false)
665 return true;
668 // If we are an exe, require a source file for the entry point
670 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
671 if (first_source == null) {
672 Report.Error (2008, "No files to compile were specified");
673 return false;
679 // If there is nothing to put in the assembly, and we are not a library
681 if (first_source == null && embedded_resources == null) {
682 Report.Error (2008, "No files to compile were specified");
683 return false;
686 return true;
689 public void Parse ()
691 Location.Initialize ();
693 ArrayList cu = Location.SourceFiles;
694 for (int i = 0; i < cu.Count; ++i) {
695 if (tokenize) {
696 tokenize_file ((CompilationUnit) cu [i]);
697 } else {
698 Parse ((CompilationUnit) cu [i]);
703 void ProcessSourceFiles (string spec, bool recurse)
705 string path, pattern;
707 SplitPathAndPattern (spec, out path, out pattern);
708 if (pattern.IndexOf ('*') == -1){
709 AddSourceFile (spec);
710 return;
713 string [] files = null;
714 try {
715 files = Directory.GetFiles (path, pattern);
716 } catch (System.IO.DirectoryNotFoundException) {
717 Report.Error (2001, "Source file `" + spec + "' could not be found");
718 return;
719 } catch (System.IO.IOException){
720 Report.Error (2001, "Source file `" + spec + "' could not be found");
721 return;
723 foreach (string f in files) {
724 AddSourceFile (f);
727 if (!recurse)
728 return;
730 string [] dirs = null;
732 try {
733 dirs = Directory.GetDirectories (path);
734 } catch {
737 foreach (string d in dirs) {
739 // Don't include path in this string, as each
740 // directory entry already does
741 ProcessSourceFiles (d + "/" + pattern, true);
745 public void ProcessDefaultConfig ()
747 if (!load_default_config)
748 return;
751 // For now the "default config" is harcoded into the compiler
752 // we can move this outside later
754 string [] default_config = {
755 "System",
756 "System.Xml",
757 #if NET_2_1
758 "System.Net",
759 "System.Windows",
760 "System.Windows.Browser",
761 #endif
762 #if false
764 // Is it worth pre-loading all this stuff?
766 "Accessibility",
767 "System.Configuration.Install",
768 "System.Data",
769 "System.Design",
770 "System.DirectoryServices",
771 "System.Drawing.Design",
772 "System.Drawing",
773 "System.EnterpriseServices",
774 "System.Management",
775 "System.Messaging",
776 "System.Runtime.Remoting",
777 "System.Runtime.Serialization.Formatters.Soap",
778 "System.Security",
779 "System.ServiceProcess",
780 "System.Web",
781 "System.Web.RegularExpressions",
782 "System.Web.Services",
783 "System.Windows.Forms"
784 #endif
787 soft_references.AddRange (default_config);
789 if (RootContext.Version > LanguageVersion.ISO_2)
790 soft_references.Add ("System.Core");
791 if (RootContext.Version > LanguageVersion.V_3)
792 soft_references.Add ("Microsoft.CSharp");
795 public static string OutputFile
797 set {
798 output_file = value;
800 get {
801 return Path.GetFileName (output_file);
805 static void SetWarningLevel (string s)
807 int level = -1;
809 try {
810 level = Int32.Parse (s);
811 } catch {
813 if (level < 0 || level > 4){
814 Report.Error (1900, "Warning level must be in the range 0-4");
815 return;
817 Report.WarningLevel = level;
820 static void Version ()
822 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
823 Console.WriteLine ("Mono C# compiler version {0}", version);
824 Environment.Exit (0);
828 // Currently handles the Unix-like command line options, but will be
829 // deprecated in favor of the CSCParseOption, which will also handle the
830 // options that start with a dash in the future.
832 bool UnixParseOption (string arg, ref string [] args, ref int i)
834 switch (arg){
835 case "-v":
836 CSharpParser.yacc_verbose_flag++;
837 return true;
839 case "--version":
840 Version ();
841 return true;
843 case "--parse":
844 parse_only = true;
845 return true;
847 case "--main": case "-m":
848 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
849 if ((i + 1) >= args.Length){
850 Usage ();
851 Environment.Exit (1);
853 RootContext.MainClass = args [++i];
854 return true;
856 case "--unsafe":
857 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
858 RootContext.Unsafe = true;
859 return true;
861 case "/?": case "/h": case "/help":
862 case "--help":
863 Usage ();
864 Environment.Exit (0);
865 return true;
867 case "--define":
868 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
869 if ((i + 1) >= args.Length){
870 Usage ();
871 Environment.Exit (1);
873 RootContext.AddConditional (args [++i]);
874 return true;
876 case "--tokenize":
877 tokenize = true;
878 return true;
880 case "-o":
881 case "--output":
882 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
883 if ((i + 1) >= args.Length){
884 Usage ();
885 Environment.Exit (1);
887 OutputFile = args [++i];
888 return true;
890 case "--checked":
891 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
892 RootContext.Checked = true;
893 return true;
895 case "--stacktrace":
896 Report.Stacktrace = true;
897 return true;
899 case "--linkresource":
900 case "--linkres":
901 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
902 if ((i + 1) >= args.Length){
903 Usage ();
904 Report.Error (5, "Missing argument to --linkres");
905 Environment.Exit (1);
907 if (embedded_resources == null)
908 embedded_resources = new Resources ();
910 embedded_resources.Add (false, args [++i], args [i]);
911 return true;
913 case "--resource":
914 case "--res":
915 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
916 if ((i + 1) >= args.Length){
917 Usage ();
918 Report.Error (5, "Missing argument to --resource");
919 Environment.Exit (1);
921 if (embedded_resources == null)
922 embedded_resources = new Resources ();
924 embedded_resources.Add (true, args [++i], args [i]);
925 return true;
927 case "--target":
928 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
929 if ((i + 1) >= args.Length){
930 Environment.Exit (1);
931 return true;
934 string type = args [++i];
935 switch (type){
936 case "library":
937 RootContext.Target = Target.Library;
938 RootContext.TargetExt = ".dll";
939 break;
941 case "exe":
942 RootContext.Target = Target.Exe;
943 break;
945 case "winexe":
946 RootContext.Target = Target.WinExe;
947 break;
949 case "module":
950 RootContext.Target = Target.Module;
951 RootContext.TargetExt = ".dll";
952 break;
953 default:
954 TargetUsage ();
955 break;
957 return true;
959 case "-r":
960 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
961 if ((i + 1) >= args.Length){
962 Usage ();
963 Environment.Exit (1);
966 string val = args [++i];
967 int idx = val.IndexOf ('=');
968 if (idx > -1) {
969 string alias = val.Substring (0, idx);
970 string assembly = val.Substring (idx + 1);
971 AddExternAlias (alias, assembly);
972 return true;
975 references.Add (val);
976 return true;
978 case "-L":
979 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
980 if ((i + 1) >= args.Length){
981 Usage ();
982 Environment.Exit (1);
984 link_paths.Add (args [++i]);
985 return true;
987 case "--nostdlib":
988 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
989 RootContext.StdLib = false;
990 return true;
992 case "--fatal":
993 Report.Fatal = true;
994 return true;
996 case "--nowarn":
997 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
998 if ((i + 1) >= args.Length){
999 Usage ();
1000 Environment.Exit (1);
1002 int warn = 0;
1004 try {
1005 warn = Int32.Parse (args [++i]);
1006 } catch {
1007 Usage ();
1008 Environment.Exit (1);
1010 Report.SetIgnoreWarning (warn);
1011 return true;
1013 case "--wlevel":
1014 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1015 if ((i + 1) >= args.Length){
1016 Report.Error (
1017 1900,
1018 "--wlevel requires a value from 0 to 4");
1019 Environment.Exit (1);
1022 SetWarningLevel (args [++i]);
1023 return true;
1025 case "--mcs-debug":
1026 if ((i + 1) >= args.Length){
1027 Report.Error (5, "--mcs-debug requires an argument");
1028 Environment.Exit (1);
1031 try {
1032 Report.DebugFlags = Int32.Parse (args [++i]);
1033 } catch {
1034 Report.Error (5, "Invalid argument to --mcs-debug");
1035 Environment.Exit (1);
1037 return true;
1039 case "--about":
1040 About ();
1041 return true;
1043 case "--recurse":
1044 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1045 if ((i + 1) >= args.Length){
1046 Report.Error (5, "--recurse requires an argument");
1047 Environment.Exit (1);
1049 ProcessSourceFiles (args [++i], true);
1050 return true;
1052 case "--timestamp":
1053 timestamps = true;
1054 last_time = first_time = DateTime.Now;
1055 return true;
1057 case "--debug": case "-g":
1058 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1059 want_debugging_support = true;
1060 return true;
1062 case "--noconfig":
1063 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1064 load_default_config = false;
1065 return true;
1068 return false;
1071 #if !SMCS_SOURCE
1072 public static string GetPackageFlags (string packages, bool fatal)
1074 ProcessStartInfo pi = new ProcessStartInfo ();
1075 pi.FileName = "pkg-config";
1076 pi.RedirectStandardOutput = true;
1077 pi.UseShellExecute = false;
1078 pi.Arguments = "--libs " + packages;
1079 Process p = null;
1080 try {
1081 p = Process.Start (pi);
1082 } catch (Exception e) {
1083 Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1084 if (fatal)
1085 Environment.Exit (1);
1086 p.Close ();
1087 return null;
1090 if (p.StandardOutput == null){
1091 Report.Warning (-27, 1, "Specified package did not return any information");
1092 p.Close ();
1093 return null;
1095 string pkgout = p.StandardOutput.ReadToEnd ();
1096 p.WaitForExit ();
1097 if (p.ExitCode != 0) {
1098 Report.Error (-27, "Error running pkg-config. Check the above output.");
1099 if (fatal)
1100 Environment.Exit (1);
1101 p.Close ();
1102 return null;
1104 p.Close ();
1106 return pkgout;
1108 #endif
1111 // This parses the -arg and /arg options to the compiler, even if the strings
1112 // in the following text use "/arg" on the strings.
1114 bool CSCParseOption (string option, ref string [] args)
1116 int idx = option.IndexOf (':');
1117 string arg, value;
1119 if (idx == -1){
1120 arg = option;
1121 value = "";
1122 } else {
1123 arg = option.Substring (0, idx);
1125 value = option.Substring (idx + 1);
1128 switch (arg.ToLower (CultureInfo.InvariantCulture)){
1129 case "/nologo":
1130 return true;
1132 case "/t":
1133 case "/target":
1134 switch (value){
1135 case "exe":
1136 RootContext.Target = Target.Exe;
1137 break;
1139 case "winexe":
1140 RootContext.Target = Target.WinExe;
1141 break;
1143 case "library":
1144 RootContext.Target = Target.Library;
1145 RootContext.TargetExt = ".dll";
1146 break;
1148 case "module":
1149 RootContext.Target = Target.Module;
1150 RootContext.TargetExt = ".netmodule";
1151 break;
1153 default:
1154 TargetUsage ();
1155 break;
1157 return true;
1159 case "/out":
1160 if (value.Length == 0){
1161 Usage ();
1162 Environment.Exit (1);
1164 OutputFile = value;
1165 return true;
1167 case "/o":
1168 case "/o+":
1169 case "/optimize":
1170 case "/optimize+":
1171 RootContext.Optimize = true;
1172 return true;
1174 case "/o-":
1175 case "/optimize-":
1176 RootContext.Optimize = false;
1177 return true;
1179 case "/incremental":
1180 case "/incremental+":
1181 case "/incremental-":
1182 // nothing.
1183 return true;
1185 case "/d":
1186 case "/define": {
1187 if (value.Length == 0){
1188 Usage ();
1189 Environment.Exit (1);
1192 foreach (string d in value.Split (argument_value_separator)) {
1193 if (!Tokenizer.IsValidIdentifier (d)) {
1194 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d);
1195 continue;
1197 RootContext.AddConditional (d);
1199 return true;
1202 case "/bugreport":
1204 // We should collect data, runtime, etc and store in the file specified
1206 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1207 return true;
1208 #if !SMCS_SOURCE
1209 case "/pkg": {
1210 string packages;
1212 if (value.Length == 0){
1213 Usage ();
1214 Environment.Exit (1);
1216 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1217 string pkgout = GetPackageFlags (packages, true);
1219 if (pkgout != null){
1220 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1221 Split (new Char [] { ' ', '\t'});
1222 args = AddArgs (args, xargs);
1225 return true;
1227 #endif
1228 case "/linkres":
1229 case "/linkresource":
1230 case "/res":
1231 case "/resource":
1232 if (embedded_resources == null)
1233 embedded_resources = new Resources ();
1235 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1236 string[] s = value.Split (argument_value_separator);
1237 switch (s.Length) {
1238 case 1:
1239 if (s[0].Length == 0)
1240 goto default;
1241 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1242 break;
1243 case 2:
1244 embedded_resources.Add (embeded, s [0], s [1]);
1245 break;
1246 case 3:
1247 if (s [2] != "public" && s [2] != "private") {
1248 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1249 return true;
1251 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1252 break;
1253 default:
1254 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1255 break;
1258 return true;
1260 case "/recurse":
1261 if (value.Length == 0){
1262 Report.Error (5, "-recurse requires an argument");
1263 Environment.Exit (1);
1265 ProcessSourceFiles (value, true);
1266 return true;
1268 case "/r":
1269 case "/reference": {
1270 if (value.Length == 0){
1271 Report.Error (5, "-reference requires an argument");
1272 Environment.Exit (1);
1275 string[] refs = value.Split (argument_value_separator);
1276 foreach (string r in refs){
1277 string val = r;
1278 int index = val.IndexOf ('=');
1279 if (index > -1) {
1280 string alias = r.Substring (0, index);
1281 string assembly = r.Substring (index + 1);
1282 AddExternAlias (alias, assembly);
1283 return true;
1286 if (val.Length != 0)
1287 references.Add (val);
1289 return true;
1291 case "/addmodule": {
1292 if (value.Length == 0){
1293 Report.Error (5, arg + " requires an argument");
1294 Environment.Exit (1);
1297 string[] refs = value.Split (argument_value_separator);
1298 foreach (string r in refs){
1299 modules.Add (r);
1301 return true;
1303 case "/win32res": {
1304 if (value.Length == 0) {
1305 Report.Error (5, arg + " requires an argument");
1306 Environment.Exit (1);
1309 if (win32IconFile != null)
1310 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1312 win32ResourceFile = value;
1313 return true;
1315 case "/win32icon": {
1316 if (value.Length == 0) {
1317 Report.Error (5, arg + " requires an argument");
1318 Environment.Exit (1);
1321 if (win32ResourceFile != null)
1322 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1324 win32IconFile = value;
1325 return true;
1327 case "/doc": {
1328 if (value.Length == 0){
1329 Report.Error (2006, arg + " requires an argument");
1330 Environment.Exit (1);
1332 RootContext.Documentation = new Documentation (value);
1333 return true;
1335 case "/lib": {
1336 string [] libdirs;
1338 if (value.Length == 0){
1339 Report.Error (5, "/lib requires an argument");
1340 Environment.Exit (1);
1343 libdirs = value.Split (argument_value_separator);
1344 foreach (string dir in libdirs)
1345 link_paths.Add (dir);
1346 return true;
1349 case "/debug-":
1350 want_debugging_support = false;
1351 return true;
1353 case "/debug":
1354 if (value == "full" || value == "")
1355 want_debugging_support = true;
1357 return true;
1359 case "/debug+":
1360 want_debugging_support = true;
1361 return true;
1363 case "/checked":
1364 case "/checked+":
1365 RootContext.Checked = true;
1366 return true;
1368 case "/checked-":
1369 RootContext.Checked = false;
1370 return true;
1372 case "/clscheck":
1373 case "/clscheck+":
1374 return true;
1376 case "/clscheck-":
1377 RootContext.VerifyClsCompliance = false;
1378 return true;
1380 case "/unsafe":
1381 case "/unsafe+":
1382 RootContext.Unsafe = true;
1383 return true;
1385 case "/unsafe-":
1386 RootContext.Unsafe = false;
1387 return true;
1389 case "/warnaserror":
1390 case "/warnaserror+":
1391 if (value.Length == 0) {
1392 Report.WarningsAreErrors = true;
1393 } else {
1394 foreach (string wid in value.Split (argument_value_separator))
1395 Report.AddWarningAsError (wid);
1397 return true;
1399 case "/warnaserror-":
1400 if (value.Length == 0) {
1401 Report.WarningsAreErrors = false;
1402 } else {
1403 foreach (string wid in value.Split (argument_value_separator))
1404 Report.RemoveWarningAsError (wid);
1406 return true;
1408 case "/warn":
1409 SetWarningLevel (value);
1410 return true;
1412 case "/nowarn": {
1413 string [] warns;
1415 if (value.Length == 0){
1416 Report.Error (5, "/nowarn requires an argument");
1417 Environment.Exit (1);
1420 warns = value.Split (argument_value_separator);
1421 foreach (string wc in warns){
1422 try {
1423 if (wc.Trim ().Length == 0)
1424 continue;
1426 int warn = Int32.Parse (wc);
1427 if (warn < 1) {
1428 throw new ArgumentOutOfRangeException("warn");
1430 Report.SetIgnoreWarning (warn);
1431 } catch {
1432 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1435 return true;
1438 case "/noconfig":
1439 load_default_config = false;
1440 return true;
1442 case "/platform":
1443 #if GMCS_SOURCE
1444 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1445 case "anycpu":
1446 RootContext.Platform = Platform.AnyCPU;
1447 break;
1448 case "x86":
1449 RootContext.Platform = Platform.X86;
1450 break;
1451 case "x64":
1452 RootContext.Platform = Platform.X64;
1453 break;
1454 case "itanium":
1455 RootContext.Platform = Platform.IA64;
1456 break;
1457 default:
1458 Report.Error (1672, "Invalid platform type for -platform. Valid options are `anycpu', `x86', `x64' or `itanium'");
1459 break;
1461 #endif
1462 return true;
1464 // We just ignore this.
1465 case "/errorreport":
1466 case "/filealign":
1467 return true;
1469 case "/help2":
1470 OtherFlags ();
1471 Environment.Exit(0);
1472 return true;
1474 case "/help":
1475 case "/?":
1476 Usage ();
1477 Environment.Exit (0);
1478 return true;
1480 case "/main":
1481 case "/m":
1482 if (value.Length == 0){
1483 Report.Error (5, arg + " requires an argument");
1484 Environment.Exit (1);
1486 RootContext.MainClass = value;
1487 return true;
1489 case "/nostdlib":
1490 case "/nostdlib+":
1491 RootContext.StdLib = false;
1492 return true;
1494 case "/nostdlib-":
1495 RootContext.StdLib = true;
1496 return true;
1498 case "/fullpaths":
1499 return true;
1501 case "/keyfile":
1502 if (value == String.Empty) {
1503 Report.Error (5, arg + " requires an argument");
1504 Environment.Exit (1);
1506 RootContext.StrongNameKeyFile = value;
1507 return true;
1508 case "/keycontainer":
1509 if (value == String.Empty) {
1510 Report.Error (5, arg + " requires an argument");
1511 Environment.Exit (1);
1513 RootContext.StrongNameKeyContainer = value;
1514 return true;
1515 case "/delaysign+":
1516 RootContext.StrongNameDelaySign = true;
1517 return true;
1518 case "/delaysign-":
1519 RootContext.StrongNameDelaySign = false;
1520 return true;
1522 case "/langversion":
1523 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1524 case "iso-1":
1525 RootContext.Version = LanguageVersion.ISO_1;
1526 return true;
1528 case "default":
1529 RootContext.Version = LanguageVersion.Default;
1530 #if GMCS_SOURCE
1531 RootContext.AddConditional ("__V2__");
1532 #endif
1533 return true;
1534 case "iso-2":
1535 RootContext.Version = LanguageVersion.ISO_2;
1536 return true;
1537 case "3":
1538 RootContext.Version = LanguageVersion.V_3;
1539 return true;
1540 case "future":
1541 RootContext.Version = LanguageVersion.Future;
1542 return true;
1545 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1546 return true;
1548 case "/codepage":
1549 switch (value) {
1550 case "utf8":
1551 encoding = new UTF8Encoding();
1552 break;
1553 case "reset":
1554 encoding = Encoding.Default;
1555 break;
1556 default:
1557 try {
1558 encoding = Encoding.GetEncoding (
1559 Int32.Parse (value));
1560 } catch {
1561 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1563 break;
1565 return true;
1568 return false;
1571 static void Error_WrongOption (string option)
1573 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1576 static string [] AddArgs (string [] args, string [] extra_args)
1578 string [] new_args;
1579 new_args = new string [extra_args.Length + args.Length];
1581 // if args contains '--' we have to take that into account
1582 // split args into first half and second half based on '--'
1583 // and add the extra_args before --
1584 int split_position = Array.IndexOf (args, "--");
1585 if (split_position != -1)
1587 Array.Copy (args, new_args, split_position);
1588 extra_args.CopyTo (new_args, split_position);
1589 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1591 else
1593 args.CopyTo (new_args, 0);
1594 extra_args.CopyTo (new_args, args.Length);
1597 return new_args;
1600 void AddExternAlias (string identifier, string assembly)
1602 if (assembly.Length == 0) {
1603 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1604 return;
1607 if (!IsExternAliasValid (identifier)) {
1608 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1609 return;
1612 // Could here hashtable throw an exception?
1613 external_aliases [identifier] = assembly;
1616 static bool IsExternAliasValid (string identifier)
1618 if (identifier.Length == 0)
1619 return false;
1620 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1621 return false;
1623 for (int i = 1; i < identifier.Length; i++) {
1624 char c = identifier [i];
1625 if (Char.IsLetter (c) || Char.IsDigit (c))
1626 continue;
1628 UnicodeCategory category = Char.GetUnicodeCategory (c);
1629 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1630 category != UnicodeCategory.SpacingCombiningMark ||
1631 category != UnicodeCategory.ConnectorPunctuation)
1632 return false;
1635 return true;
1639 // Main compilation method
1641 public bool Compile ()
1643 // TODO: Should be passed to parser as an argument
1644 RootContext.ToplevelTypes = new ModuleContainer (RootContext.Unsafe);
1646 Parse ();
1647 if (Report.Errors > 0)
1648 return false;
1650 if (tokenize || parse_only)
1651 return true;
1653 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1654 throw new InternalErrorException ("who set it?");
1656 ProcessDefaultConfig ();
1659 // Quick hack
1661 if (output_file == null){
1662 if (first_source == null){
1663 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1664 return false;
1667 int pos = first_source.LastIndexOf ('.');
1669 if (pos > 0)
1670 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1671 else
1672 output_file = first_source + RootContext.TargetExt;
1675 if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1676 return false;
1678 if (RootContext.Target == Target.Module) {
1679 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1680 if (module_only == null) {
1681 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1682 Environment.Exit (1);
1685 MethodInfo set_method = module_only.GetSetMethod (true);
1686 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1689 GlobalRootNamespace.Instance.AddModuleReference (RootContext.ToplevelTypes.Builder);
1692 // Load assemblies required
1694 if (timestamps)
1695 ShowTime ("Loading references");
1697 LoadReferences ();
1699 if (modules.Count > 0) {
1700 foreach (string module in modules)
1701 LoadModule (module);
1704 if (timestamps)
1705 ShowTime ("References loaded");
1707 if (!TypeManager.InitCoreTypes () || Report.Errors > 0)
1708 return false;
1710 TypeManager.InitOptionalCoreTypes ();
1712 if (timestamps)
1713 ShowTime (" Core Types done");
1716 // The second pass of the compiler
1718 if (timestamps)
1719 ShowTime ("Resolving tree");
1720 RootContext.ResolveTree ();
1722 if (Report.Errors > 0)
1723 return false;
1724 if (timestamps)
1725 ShowTime ("Populate tree");
1726 if (!RootContext.StdLib)
1727 RootContext.BootCorlib_PopulateCoreTypes ();
1728 RootContext.PopulateTypes ();
1730 if (Report.Errors == 0 &&
1731 RootContext.Documentation != null &&
1732 !RootContext.Documentation.OutputDocComment (
1733 output_file))
1734 return false;
1737 // Verify using aliases now
1739 NamespaceEntry.VerifyAllUsing ();
1741 if (Report.Errors > 0){
1742 return false;
1745 CodeGen.Assembly.Resolve ();
1747 if (RootContext.VerifyClsCompliance) {
1748 if (CodeGen.Assembly.IsClsCompliant) {
1749 AttributeTester.VerifyModulesClsCompliance ();
1750 TypeManager.LoadAllImportedTypes ();
1753 if (Report.Errors > 0)
1754 return false;
1757 // The code generator
1759 if (timestamps)
1760 ShowTime ("Emitting code");
1761 ShowTotalTime ("Total so far");
1762 RootContext.EmitCode ();
1763 if (timestamps)
1764 ShowTime (" done");
1766 if (Report.Errors > 0){
1767 return false;
1770 if (timestamps)
1771 ShowTime ("Closing types");
1773 RootContext.CloseTypes ();
1775 PEFileKinds k = PEFileKinds.ConsoleApplication;
1777 switch (RootContext.Target) {
1778 case Target.Library:
1779 case Target.Module:
1780 k = PEFileKinds.Dll; break;
1781 case Target.Exe:
1782 k = PEFileKinds.ConsoleApplication; break;
1783 case Target.WinExe:
1784 k = PEFileKinds.WindowApplication; break;
1787 if (RootContext.NeedsEntryPoint) {
1788 Method ep = RootContext.EntryPoint;
1790 if (ep == null) {
1791 if (RootContext.MainClass != null) {
1792 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1793 if (main_cont == null) {
1794 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1795 return false;
1798 if (!(main_cont is ClassOrStruct)) {
1799 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1800 return false;
1803 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1804 return false;
1807 if (Report.Errors == 0)
1808 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1809 output_file);
1810 return false;
1813 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1814 } else if (RootContext.MainClass != null) {
1815 Report.Error (2017, "Cannot specify -main if building a module or library");
1818 if (embedded_resources != null){
1819 if (RootContext.Target == Target.Module) {
1820 Report.Error (1507, "Cannot link resource file when building a module");
1821 return false;
1824 embedded_resources.Emit ();
1828 // Add Win32 resources
1831 if (win32ResourceFile != null) {
1832 try {
1833 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1834 } catch (ArgumentException) {
1835 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1837 } else {
1838 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1841 if (win32IconFile != null) {
1842 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1843 if (define_icon == null) {
1844 Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1845 } else {
1846 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1850 if (Report.Errors > 0)
1851 return false;
1853 CodeGen.Save (output_file, want_debugging_support);
1854 if (timestamps) {
1855 ShowTime ("Saved output");
1856 ShowTotalTime ("Total");
1859 Timer.ShowTimers ();
1861 if (Report.ExpectedError != 0) {
1862 if (Report.Errors == 0) {
1863 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1864 "No other errors reported.");
1866 Environment.Exit (2);
1867 } else {
1868 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1869 "However, other errors were reported.");
1871 Environment.Exit (1);
1875 return false;
1878 #if DEBUGME
1879 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1880 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1881 #endif
1882 return (Report.Errors == 0);
1886 class Resources
1888 interface IResource
1890 void Emit ();
1891 string FileName { get; }
1894 class EmbededResource : IResource
1896 static MethodInfo embed_res;
1898 static EmbededResource () {
1899 Type[] argst = new Type [] {
1900 typeof (string), typeof (string), typeof (ResourceAttributes)
1903 embed_res = typeof (AssemblyBuilder).GetMethod (
1904 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1905 null, CallingConventions.Any, argst, null);
1907 if (embed_res == null) {
1908 Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1912 readonly object[] args;
1914 public EmbededResource (string name, string file, bool isPrivate)
1916 args = new object [3];
1917 args [0] = name;
1918 args [1] = file;
1919 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1922 public void Emit()
1924 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1927 public string FileName {
1928 get {
1929 return (string)args [1];
1934 class LinkedResource : IResource
1936 readonly string file;
1937 readonly string name;
1938 readonly ResourceAttributes attribute;
1940 public LinkedResource (string name, string file, bool isPrivate)
1942 this.name = name;
1943 this.file = file;
1944 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1947 public void Emit ()
1949 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1952 public string FileName {
1953 get {
1954 return file;
1960 IDictionary embedded_resources = new HybridDictionary ();
1962 public void Add (bool embeded, string file, string name)
1964 Add (embeded, file, name, false);
1967 public void Add (bool embeded, string file, string name, bool isPrivate)
1969 if (embedded_resources.Contains (name)) {
1970 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1971 return;
1973 IResource r = embeded ?
1974 (IResource) new EmbededResource (name, file, isPrivate) :
1975 new LinkedResource (name, file, isPrivate);
1977 embedded_resources.Add (name, r);
1980 public void Emit ()
1982 foreach (IResource r in embedded_resources.Values) {
1983 if (!File.Exists (r.FileName)) {
1984 Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1985 continue;
1988 r.Emit ();
1994 // This is the only public entry point
1996 public class CompilerCallableEntryPoint : MarshalByRefObject {
1997 public static bool InvokeCompiler (string [] args, TextWriter error)
1999 Report.Stderr = error;
2000 try {
2001 Driver d = Driver.Create (args, true);
2002 if (d == null)
2003 return false;
2005 return d.Compile () && Report.Errors == 0;
2007 finally {
2008 Report.Stderr = Console.Error;
2009 Reset ();
2013 public static int[] AllWarningNumbers {
2014 get {
2015 return Report.AllWarnings;
2019 public static void Reset ()
2021 Reset (true);
2024 public static void PartialReset ()
2026 Reset (false);
2029 public static void Reset (bool full_flag)
2031 Driver.Reset ();
2032 RootContext.Reset (full_flag);
2033 Location.Reset ();
2034 Report.Reset ();
2035 TypeManager.Reset ();
2036 PredefinedAttributes.Reset ();
2037 TypeHandle.Reset ();
2039 if (full_flag)
2040 GlobalRootNamespace.Reset ();
2042 NamespaceEntry.Reset ();
2043 CodeGen.Reset ();
2044 Attribute.Reset ();
2045 AttributeTester.Reset ();
2046 AnonymousTypeClass.Reset ();
2047 AnonymousMethodBody.Reset ();
2048 AnonymousMethodStorey.Reset ();
2049 SymbolWriter.Reset ();
2050 Switch.Reset ();
2051 Linq.QueryBlock.TransparentParameter.Reset ();
2052 Convert.Reset ();
2053 TypeInfo.Reset ();