Fix bug #566087.
[mcs.git] / mcs / driver.cs
blob3674bd6ce81292db2306a2181b2610e1ec388f98
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.Generic;
20 using System.IO;
21 using System.Text;
22 using System.Globalization;
23 using System.Diagnostics;
25 public enum Target {
26 Library, Exe, Module, WinExe
29 public enum Platform {
30 AnyCPU, X86, X64, IA64
33 /// <summary>
34 /// The compiler driver.
35 /// </summary>
36 class Driver
39 // Assemblies references to be linked. Initialized with
40 // mscorlib.dll here.
41 List<string> references;
44 // If any of these fail, we ignore the problem. This is so
45 // that we can list all the assemblies in Windows and not fail
46 // if they are missing on Linux.
48 List<string> soft_references;
50 //
51 // External aliases for assemblies.
53 Dictionary<string, string> external_aliases;
56 // Modules to be linked
58 List<string> modules;
60 // Lookup paths
61 List<string> link_paths;
63 // Whether we want to only run the tokenizer
64 bool tokenize;
66 string first_source;
68 bool want_debugging_support;
69 bool parse_only;
70 bool timestamps;
71 bool fatal_errors;
74 // Whether to load the initial config file (what CSC.RSP has by default)
75 //
76 bool load_default_config = true;
79 // A list of resource files
81 Resources embedded_resources;
82 string win32ResourceFile;
83 string win32IconFile;
86 // Output file
88 static string output_file;
91 // Last time we took the time
93 DateTime last_time, first_time;
96 // Encoding.
98 Encoding encoding;
100 readonly CompilerContext ctx;
102 static readonly char[] argument_value_separator = new char [] { ';', ',' };
104 static public void Reset ()
106 output_file = null;
109 private Driver (CompilerContext ctx)
111 this.ctx = ctx;
112 encoding = Encoding.Default;
115 public static Driver Create (string[] args, bool require_files, ReportPrinter printer)
117 Driver d = new Driver (new CompilerContext (new Report (printer)));
119 if (!d.ParseArguments (args, require_files))
120 return null;
122 return d;
125 Report Report {
126 get { return ctx.Report; }
129 void ShowTime (string msg)
131 if (!timestamps)
132 return;
134 DateTime now = DateTime.Now;
135 TimeSpan span = now - last_time;
136 last_time = now;
138 Console.WriteLine (
139 "[{0:00}:{1:000}] {2}",
140 (int) span.TotalSeconds, span.Milliseconds, msg);
143 void ShowTotalTime (string msg)
145 if (!timestamps)
146 return;
148 DateTime now = DateTime.Now;
149 TimeSpan span = now - first_time;
150 last_time = now;
152 Console.WriteLine (
153 "[{0:00}:{1:000}] {2}",
154 (int) span.TotalSeconds, span.Milliseconds, msg);
157 void tokenize_file (CompilationUnit file, CompilerContext ctx)
159 Stream input;
161 try {
162 input = File.OpenRead (file.Name);
163 } catch {
164 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
165 return;
168 using (input){
169 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
170 Tokenizer lexer = new Tokenizer (reader, file, ctx);
171 int token, tokens = 0, errors = 0;
173 while ((token = lexer.token ()) != Token.EOF){
174 tokens++;
175 if (token == Token.ERROR)
176 errors++;
178 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
181 return;
184 void Parse (CompilationUnit file)
186 Stream input;
188 try {
189 input = File.OpenRead (file.Name);
190 } catch {
191 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
192 return;
195 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
197 // Check 'MZ' header
198 if (reader.Read () == 77 && reader.Read () == 90) {
199 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
200 input.Close ();
201 return;
204 reader.Position = 0;
205 Parse (reader, file);
206 reader.Dispose ();
207 input.Close ();
210 void Parse (SeekableStreamReader reader, CompilationUnit file)
212 CSharpParser parser = new CSharpParser (reader, file, ctx);
213 parser.parse ();
216 static void OtherFlags ()
218 Console.WriteLine (
219 "Other flags in the compiler\n" +
220 " --fatal Makes errors fatal\n" +
221 " --parse Only parses the source file\n" +
222 " --typetest Tests the tokenizer's built-in type parser\n" +
223 " --stacktrace Shows stack trace at error location\n" +
224 " --timestamp Displays time stamps of various compiler events\n" +
225 " --expect-error X Expect that error X will be encountered\n" +
226 " -v Verbose parsing (for debugging the parser)\n" +
227 " --mcs-debug X Sets MCS debugging level to X\n");
230 static void Usage ()
232 Console.WriteLine (
233 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
234 "mcs [options] source-files\n" +
235 " --about About the Mono C# compiler\n" +
236 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
237 " -checked[+|-] Sets default aritmetic overflow context\n" +
238 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
239 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
240 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
241 " -debug[+|-], -g Generate debugging information\n" +
242 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
243 " -doc:FILE Process documentation comments to XML file\n" +
244 " -help Lists all compiler options (short: -?)\n" +
245 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
246 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
247 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, Default, or Future\n" +
248 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
249 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
250 " -noconfig Disables implicitly referenced assemblies\n" +
251 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
252 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
253 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
254 " -out:FILE Specifies output assembly name\n" +
255 #if !SMCS_SOURCE
256 " -pkg:P1[,Pn] References packages P1..Pn\n" +
257 #endif
258 " -platform:ARCH Specifies the target platform of the output assembly\n" +
259 " ARCH can be one of: anycpu, x86, x64 or itanium\n" +
260 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
261 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
262 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
263 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
264 " KIND can be one of: exe, winexe, library, module\n" +
265 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
266 " -warnaserror[+|-] Treats all warnings as errors\n" +
267 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
268 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
269 " -help2 Shows internal compiler options\n" +
270 "\n" +
271 "Resources:\n" +
272 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
273 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
274 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
275 " -win32icon:FILE Use this icon for the output\n" +
276 " @file Read response file for more options\n\n" +
277 "Options can be of the form -option or /option");
280 void TargetUsage ()
282 Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
285 static void About ()
287 Console.WriteLine (
288 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
289 "The compiler source code is released under the terms of the \n"+
290 "MIT X11 or GNU GPL licenses\n\n" +
292 "For more information on Mono, visit the project Web site\n" +
293 " http://www.mono-project.com\n\n" +
295 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
296 Environment.Exit (0);
299 public static int Main (string[] args)
301 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
302 var crp = new ConsoleReportPrinter ();
303 Driver d = Driver.Create (args, true, crp);
304 if (d == null)
305 return 1;
307 crp.Fatal = d.fatal_errors;
309 if (d.Compile () && d.Report.Errors == 0) {
310 if (d.Report.Warnings > 0) {
311 Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
313 Environment.Exit (0);
314 return 0;
318 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
319 d.Report.Errors, d.Report.Warnings);
320 Environment.Exit (1);
321 return 1;
324 public void LoadAssembly (string assembly, bool soft)
326 LoadAssembly (assembly, null, soft);
329 void Error6 (string name, string log)
331 if (log != null && log.Length > 0)
332 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
333 Report.Error (6, "cannot find metadata file `{0}'", name);
336 void Error9 (string type, string filename, string log)
338 if (log != null && log.Length > 0)
339 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
340 Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
343 void BadAssembly (string filename, string log)
345 MethodInfo adder_method = AssemblyClass.AddModule_Method;
347 if (adder_method != null) {
348 AssemblyName an = new AssemblyName ();
349 an.Name = ".temp";
350 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
351 try {
352 object m = null;
353 try {
354 m = adder_method.Invoke (ab, new object [] { filename });
355 } catch (TargetInvocationException ex) {
356 throw ex.InnerException;
359 if (m != null) {
360 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
361 Path.GetFileName (filename));
362 return;
364 } catch (FileNotFoundException) {
365 // did the file get deleted during compilation? who cares? swallow the exception
366 } catch (BadImageFormatException) {
367 // swallow exception
368 } catch (FileLoadException) {
369 // swallow exception
372 Error9 ("assembly", filename, log);
375 public void LoadAssembly (string assembly, string alias, bool soft)
377 Assembly a = null;
378 string total_log = "";
380 try {
381 try {
382 char[] path_chars = { '/', '\\' };
384 if (assembly.IndexOfAny (path_chars) != -1) {
385 a = Assembly.LoadFrom (assembly);
386 } else {
387 string ass = assembly;
388 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
389 ass = assembly.Substring (0, assembly.Length - 4);
390 a = Assembly.Load (ass);
392 } catch (FileNotFoundException) {
393 bool err = !soft;
394 foreach (string dir in link_paths) {
395 string full_path = Path.Combine (dir, assembly);
396 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
397 full_path += ".dll";
399 try {
400 a = Assembly.LoadFrom (full_path);
401 err = false;
402 break;
403 } catch (FileNotFoundException ff) {
404 if (soft)
405 return;
406 total_log += ff.FusionLog;
409 if (err) {
410 Error6 (assembly, total_log);
411 return;
415 // Extern aliased refs require special handling
416 if (alias == null)
417 GlobalRootNamespace.Instance.AddAssemblyReference (a);
418 else
419 GlobalRootNamespace.Instance.DefineRootNamespace (alias, a, ctx);
421 } catch (BadImageFormatException f) {
422 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
423 BadAssembly (f.FileName, f.FusionLog);
424 } catch (FileLoadException f) {
425 // ... while .NET 1.1 throws this
426 BadAssembly (f.FileName, f.FusionLog);
430 public void LoadModule (string module)
432 Module m = null;
433 string total_log = "";
435 try {
436 try {
437 m = CodeGen.Assembly.AddModule (module);
438 } catch (FileNotFoundException) {
439 bool err = true;
440 foreach (string dir in link_paths) {
441 string full_path = Path.Combine (dir, module);
442 if (!module.EndsWith (".netmodule"))
443 full_path += ".netmodule";
445 try {
446 m = CodeGen.Assembly.AddModule (full_path);
447 err = false;
448 break;
449 } catch (FileNotFoundException ff) {
450 total_log += ff.FusionLog;
453 if (err) {
454 Error6 (module, total_log);
455 return;
459 GlobalRootNamespace.Instance.AddModuleReference (m);
461 } catch (BadImageFormatException f) {
462 Error9 ("module", f.FileName, f.FusionLog);
463 } catch (FileLoadException f) {
464 Error9 ("module", f.FileName, f.FusionLog);
468 /// <summary>
469 /// Loads all assemblies referenced on the command line
470 /// </summary>
471 public void LoadReferences ()
473 link_paths.Add (GetSystemDir ());
474 link_paths.Add (Directory.GetCurrentDirectory ());
477 // Load Core Library for default compilation
479 if (RootContext.StdLib)
480 LoadAssembly ("mscorlib", false);
482 foreach (string r in soft_references)
483 LoadAssembly (r, true);
485 foreach (string r in references)
486 LoadAssembly (r, false);
488 foreach (var entry in external_aliases)
489 LoadAssembly (entry.Value, entry.Key, false);
491 GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
494 static string [] LoadArgs (string file)
496 StreamReader f;
497 var args = new List<string> ();
498 string line;
499 try {
500 f = new StreamReader (file);
501 } catch {
502 return null;
505 StringBuilder sb = new StringBuilder ();
507 while ((line = f.ReadLine ()) != null){
508 int t = line.Length;
510 for (int i = 0; i < t; i++){
511 char c = line [i];
513 if (c == '"' || c == '\''){
514 char end = c;
516 for (i++; i < t; i++){
517 c = line [i];
519 if (c == end)
520 break;
521 sb.Append (c);
523 } else if (c == ' '){
524 if (sb.Length > 0){
525 args.Add (sb.ToString ());
526 sb.Length = 0;
528 } else
529 sb.Append (c);
531 if (sb.Length > 0){
532 args.Add (sb.ToString ());
533 sb.Length = 0;
537 return args.ToArray ();
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 (Report, f);
588 bool ParseArguments (string[] args, bool require_files)
590 references = new List<string> ();
591 external_aliases = new Dictionary<string, string> ();
592 soft_references = new List<string> ();
593 modules = new List<string> (2);
594 link_paths = new List<string> ();
596 List<string> 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 List<string> ();
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 var cu = Location.SourceFiles;
694 for (int i = 0; i < cu.Count; ++i) {
695 if (tokenize) {
696 tokenize_file (cu [i], ctx);
697 } else {
698 Parse (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 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.Printer.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 (ctx);
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 (ctx);
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 fatal_errors = 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, Report report)
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 string conditional = d.Trim ();
1194 if (!Tokenizer.IsValidIdentifier (conditional)) {
1195 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
1196 continue;
1198 RootContext.AddConditional (conditional);
1200 return true;
1203 case "/bugreport":
1205 // We should collect data, runtime, etc and store in the file specified
1207 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1208 return true;
1209 #if !SMCS_SOURCE
1210 case "/pkg": {
1211 string packages;
1213 if (value.Length == 0){
1214 Usage ();
1215 Environment.Exit (1);
1217 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1218 string pkgout = GetPackageFlags (packages, true, Report);
1220 if (pkgout != null){
1221 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1222 Split (new Char [] { ' ', '\t'});
1223 args = AddArgs (args, xargs);
1226 return true;
1228 #endif
1229 case "/linkres":
1230 case "/linkresource":
1231 case "/res":
1232 case "/resource":
1233 if (embedded_resources == null)
1234 embedded_resources = new Resources (ctx);
1236 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1237 string[] s = value.Split (argument_value_separator);
1238 switch (s.Length) {
1239 case 1:
1240 if (s[0].Length == 0)
1241 goto default;
1242 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1243 break;
1244 case 2:
1245 embedded_resources.Add (embeded, s [0], s [1]);
1246 break;
1247 case 3:
1248 if (s [2] != "public" && s [2] != "private") {
1249 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1250 return true;
1252 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1253 break;
1254 default:
1255 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1256 break;
1259 return true;
1261 case "/recurse":
1262 if (value.Length == 0){
1263 Report.Error (5, "-recurse requires an argument");
1264 Environment.Exit (1);
1266 ProcessSourceFiles (value, true);
1267 return true;
1269 case "/r":
1270 case "/reference": {
1271 if (value.Length == 0){
1272 Report.Error (5, "-reference requires an argument");
1273 Environment.Exit (1);
1276 string[] refs = value.Split (argument_value_separator);
1277 foreach (string r in refs){
1278 string val = r;
1279 int index = val.IndexOf ('=');
1280 if (index > -1) {
1281 string alias = r.Substring (0, index);
1282 string assembly = r.Substring (index + 1);
1283 AddExternAlias (alias, assembly);
1284 return true;
1287 if (val.Length != 0)
1288 references.Add (val);
1290 return true;
1292 case "/addmodule": {
1293 if (value.Length == 0){
1294 Report.Error (5, arg + " requires an argument");
1295 Environment.Exit (1);
1298 string[] refs = value.Split (argument_value_separator);
1299 foreach (string r in refs){
1300 modules.Add (r);
1302 return true;
1304 case "/win32res": {
1305 if (value.Length == 0) {
1306 Report.Error (5, arg + " requires an argument");
1307 Environment.Exit (1);
1310 if (win32IconFile != null)
1311 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1313 win32ResourceFile = value;
1314 return true;
1316 case "/win32icon": {
1317 if (value.Length == 0) {
1318 Report.Error (5, arg + " requires an argument");
1319 Environment.Exit (1);
1322 if (win32ResourceFile != null)
1323 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1325 win32IconFile = value;
1326 return true;
1328 case "/doc": {
1329 if (value.Length == 0){
1330 Report.Error (2006, arg + " requires an argument");
1331 Environment.Exit (1);
1333 RootContext.Documentation = new Documentation (value);
1334 return true;
1336 case "/lib": {
1337 string [] libdirs;
1339 if (value.Length == 0){
1340 Report.Error (5, "/lib requires an argument");
1341 Environment.Exit (1);
1344 libdirs = value.Split (argument_value_separator);
1345 foreach (string dir in libdirs)
1346 link_paths.Add (dir);
1347 return true;
1350 case "/debug-":
1351 want_debugging_support = false;
1352 return true;
1354 case "/debug":
1355 if (value == "full" || value == "")
1356 want_debugging_support = true;
1358 return true;
1360 case "/debug+":
1361 want_debugging_support = true;
1362 return true;
1364 case "/checked":
1365 case "/checked+":
1366 RootContext.Checked = true;
1367 return true;
1369 case "/checked-":
1370 RootContext.Checked = false;
1371 return true;
1373 case "/clscheck":
1374 case "/clscheck+":
1375 return true;
1377 case "/clscheck-":
1378 RootContext.VerifyClsCompliance = false;
1379 return true;
1381 case "/unsafe":
1382 case "/unsafe+":
1383 RootContext.Unsafe = true;
1384 return true;
1386 case "/unsafe-":
1387 RootContext.Unsafe = false;
1388 return true;
1390 case "/warnaserror":
1391 case "/warnaserror+":
1392 if (value.Length == 0) {
1393 Report.WarningsAreErrors = true;
1394 } else {
1395 foreach (string wid in value.Split (argument_value_separator))
1396 Report.AddWarningAsError (wid);
1398 return true;
1400 case "/warnaserror-":
1401 if (value.Length == 0) {
1402 Report.WarningsAreErrors = false;
1403 } else {
1404 foreach (string wid in value.Split (argument_value_separator))
1405 Report.RemoveWarningAsError (wid);
1407 return true;
1409 case "/warn":
1410 SetWarningLevel (value);
1411 return true;
1413 case "/nowarn": {
1414 string [] warns;
1416 if (value.Length == 0){
1417 Report.Error (5, "/nowarn requires an argument");
1418 Environment.Exit (1);
1421 warns = value.Split (argument_value_separator);
1422 foreach (string wc in warns){
1423 try {
1424 if (wc.Trim ().Length == 0)
1425 continue;
1427 int warn = Int32.Parse (wc);
1428 if (warn < 1) {
1429 throw new ArgumentOutOfRangeException("warn");
1431 Report.SetIgnoreWarning (warn);
1432 } catch {
1433 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1436 return true;
1439 case "/noconfig":
1440 load_default_config = false;
1441 return true;
1443 case "/platform":
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;
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;
1527 case "default":
1528 RootContext.Version = LanguageVersion.Default;
1529 RootContext.AddConditional ("__V2__");
1530 return true;
1531 case "iso-2":
1532 RootContext.Version = LanguageVersion.ISO_2;
1533 return true;
1534 case "3":
1535 RootContext.Version = LanguageVersion.V_3;
1536 return true;
1537 case "future":
1538 RootContext.Version = LanguageVersion.Future;
1539 return true;
1542 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1543 return true;
1545 case "/codepage":
1546 switch (value) {
1547 case "utf8":
1548 encoding = new UTF8Encoding();
1549 break;
1550 case "reset":
1551 encoding = Encoding.Default;
1552 break;
1553 default:
1554 try {
1555 encoding = Encoding.GetEncoding (
1556 Int32.Parse (value));
1557 } catch {
1558 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1560 break;
1562 return true;
1565 return false;
1568 void Error_WrongOption (string option)
1570 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1573 static string [] AddArgs (string [] args, string [] extra_args)
1575 string [] new_args;
1576 new_args = new string [extra_args.Length + args.Length];
1578 // if args contains '--' we have to take that into account
1579 // split args into first half and second half based on '--'
1580 // and add the extra_args before --
1581 int split_position = Array.IndexOf (args, "--");
1582 if (split_position != -1)
1584 Array.Copy (args, new_args, split_position);
1585 extra_args.CopyTo (new_args, split_position);
1586 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1588 else
1590 args.CopyTo (new_args, 0);
1591 extra_args.CopyTo (new_args, args.Length);
1594 return new_args;
1597 void AddExternAlias (string identifier, string assembly)
1599 if (assembly.Length == 0) {
1600 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1601 return;
1604 if (!IsExternAliasValid (identifier)) {
1605 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1606 return;
1609 // Could here hashtable throw an exception?
1610 external_aliases [identifier] = assembly;
1613 static bool IsExternAliasValid (string identifier)
1615 if (identifier.Length == 0)
1616 return false;
1617 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1618 return false;
1620 for (int i = 1; i < identifier.Length; i++) {
1621 char c = identifier [i];
1622 if (Char.IsLetter (c) || Char.IsDigit (c))
1623 continue;
1625 UnicodeCategory category = Char.GetUnicodeCategory (c);
1626 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1627 category != UnicodeCategory.SpacingCombiningMark ||
1628 category != UnicodeCategory.ConnectorPunctuation)
1629 return false;
1632 return true;
1636 // Main compilation method
1638 public bool Compile ()
1640 // TODO: Should be passed to parser as an argument
1641 RootContext.ToplevelTypes = new ModuleCompiled (ctx, RootContext.Unsafe);
1643 Parse ();
1644 if (Report.Errors > 0)
1645 return false;
1647 if (tokenize || parse_only)
1648 return true;
1650 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1651 throw new InternalErrorException ("who set it?");
1653 ProcessDefaultConfig ();
1656 // Quick hack
1658 if (output_file == null){
1659 if (first_source == null){
1660 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1661 return false;
1664 int pos = first_source.LastIndexOf ('.');
1666 if (pos > 0)
1667 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1668 else
1669 output_file = first_source + RootContext.TargetExt;
1672 if (!CodeGen.Init (output_file, output_file, want_debugging_support, ctx))
1673 return false;
1675 if (RootContext.Target == Target.Module) {
1676 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1677 if (module_only == null) {
1678 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1679 Environment.Exit (1);
1682 MethodInfo set_method = module_only.GetSetMethod (true);
1683 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1686 GlobalRootNamespace.Instance.AddModuleReference (RootContext.ToplevelTypes.Builder);
1689 // Load assemblies required
1691 if (timestamps)
1692 ShowTime ("Loading references");
1694 LoadReferences ();
1696 if (modules.Count > 0) {
1697 foreach (string module in modules)
1698 LoadModule (module);
1701 if (timestamps)
1702 ShowTime ("References loaded");
1704 if (!TypeManager.InitCoreTypes (ctx) || Report.Errors > 0)
1705 return false;
1707 TypeManager.InitOptionalCoreTypes (ctx);
1709 if (timestamps)
1710 ShowTime (" Core Types done");
1713 // The second pass of the compiler
1715 if (timestamps)
1716 ShowTime ("Resolving tree");
1717 RootContext.ResolveTree ();
1719 if (Report.Errors > 0)
1720 return false;
1721 if (timestamps)
1722 ShowTime ("Populate tree");
1723 if (!RootContext.StdLib)
1724 RootContext.BootCorlib_PopulateCoreTypes ();
1725 RootContext.PopulateTypes ();
1727 if (Report.Errors == 0 &&
1728 RootContext.Documentation != null &&
1729 !RootContext.Documentation.OutputDocComment (
1730 output_file, Report))
1731 return false;
1734 // Verify using aliases now
1736 NamespaceEntry.VerifyAllUsing ();
1738 if (Report.Errors > 0){
1739 return false;
1742 CodeGen.Assembly.Resolve ();
1744 if (RootContext.VerifyClsCompliance) {
1745 if (CodeGen.Assembly.IsClsCompliant) {
1746 AttributeTester.VerifyModulesClsCompliance (ctx);
1747 TypeManager.LoadAllImportedTypes ();
1750 if (Report.Errors > 0)
1751 return false;
1754 // The code generator
1756 if (timestamps)
1757 ShowTime ("Emitting code");
1758 ShowTotalTime ("Total so far");
1759 RootContext.EmitCode ();
1760 if (timestamps)
1761 ShowTime (" done");
1763 if (Report.Errors > 0){
1764 return false;
1767 if (timestamps)
1768 ShowTime ("Closing types");
1770 RootContext.CloseTypes ();
1772 PEFileKinds k = PEFileKinds.ConsoleApplication;
1774 switch (RootContext.Target) {
1775 case Target.Library:
1776 case Target.Module:
1777 k = PEFileKinds.Dll; break;
1778 case Target.Exe:
1779 k = PEFileKinds.ConsoleApplication; break;
1780 case Target.WinExe:
1781 k = PEFileKinds.WindowApplication; break;
1784 if (RootContext.NeedsEntryPoint) {
1785 Method ep = RootContext.EntryPoint;
1787 if (ep == null) {
1788 if (RootContext.MainClass != null) {
1789 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1790 if (main_cont == null) {
1791 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1792 return false;
1795 if (!(main_cont is ClassOrStruct)) {
1796 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1797 return false;
1800 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1801 return false;
1804 if (Report.Errors == 0)
1805 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1806 output_file);
1807 return false;
1810 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1811 } else if (RootContext.MainClass != null) {
1812 Report.Error (2017, "Cannot specify -main if building a module or library");
1815 if (embedded_resources != null){
1816 if (RootContext.Target == Target.Module) {
1817 Report.Error (1507, "Cannot link resource file when building a module");
1818 return false;
1821 embedded_resources.Emit ();
1825 // Add Win32 resources
1828 if (win32ResourceFile != null) {
1829 try {
1830 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1831 } catch (ArgumentException) {
1832 Report.RuntimeMissingSupport (Location.Null, "resource embedding ");
1834 } else {
1835 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1838 if (win32IconFile != null) {
1839 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1840 if (define_icon == null) {
1841 Report.RuntimeMissingSupport (Location.Null, "resource embedding");
1842 } else {
1843 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1847 if (Report.Errors > 0)
1848 return false;
1850 CodeGen.Save (output_file, want_debugging_support, Report);
1851 if (timestamps) {
1852 ShowTime ("Saved output");
1853 ShowTotalTime ("Total");
1856 Timer.ShowTimers ();
1858 #if DEBUGME
1859 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1860 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1861 #endif
1862 return (Report.Errors == 0);
1866 class Resources
1868 interface IResource
1870 void Emit (CompilerContext cc);
1871 string FileName { get; }
1874 class EmbededResource : IResource
1876 static MethodInfo embed_res;
1877 readonly object[] args;
1879 public EmbededResource (string name, string file, bool isPrivate)
1881 args = new object [3];
1882 args [0] = name;
1883 args [1] = file;
1884 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1887 public void Emit (CompilerContext cc)
1889 if (embed_res == null) {
1890 var argst = new [] {
1891 typeof (string), typeof (string), typeof (ResourceAttributes)
1894 embed_res = typeof (AssemblyBuilder).GetMethod (
1895 "EmbedResourceFile", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
1896 null, CallingConventions.Any, argst, null);
1898 if (embed_res == null) {
1899 cc.Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1903 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1906 public string FileName {
1907 get {
1908 return (string)args [1];
1913 class LinkedResource : IResource
1915 readonly string file;
1916 readonly string name;
1917 readonly ResourceAttributes attribute;
1919 public LinkedResource (string name, string file, bool isPrivate)
1921 this.name = name;
1922 this.file = file;
1923 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1926 public void Emit (CompilerContext cc)
1928 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1931 public string FileName {
1932 get {
1933 return file;
1939 Dictionary<string, IResource> embedded_resources = new Dictionary<string, IResource> ();
1940 readonly CompilerContext ctx;
1942 public Resources (CompilerContext ctx)
1944 this.ctx = ctx;
1947 public void Add (bool embeded, string file, string name)
1949 Add (embeded, file, name, false);
1952 public void Add (bool embeded, string file, string name, bool isPrivate)
1954 if (embedded_resources.ContainsKey (name)) {
1955 ctx.Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1956 return;
1958 IResource r = embeded ?
1959 (IResource) new EmbededResource (name, file, isPrivate) :
1960 new LinkedResource (name, file, isPrivate);
1962 embedded_resources.Add (name, r);
1965 public void Emit ()
1967 foreach (IResource r in embedded_resources.Values) {
1968 if (!File.Exists (r.FileName)) {
1969 ctx.Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1970 continue;
1973 r.Emit (ctx);
1979 // This is the only public entry point
1981 public class CompilerCallableEntryPoint : MarshalByRefObject {
1982 public static bool InvokeCompiler (string [] args, TextWriter error)
1984 try {
1985 StreamReportPrinter srp = new StreamReportPrinter (error);
1986 Driver d = Driver.Create (args, true, srp);
1987 if (d == null)
1988 return false;
1990 return d.Compile () && srp.ErrorsCount == 0;
1991 } finally {
1992 Reset ();
1996 public static int[] AllWarningNumbers {
1997 get {
1998 return Report.AllWarnings;
2002 public static void Reset ()
2004 Reset (true);
2007 public static void PartialReset ()
2009 Reset (false);
2012 public static void Reset (bool full_flag)
2014 Driver.Reset ();
2015 CSharpParser.yacc_verbose_flag = 0;
2016 RootContext.Reset (full_flag);
2017 Location.Reset ();
2018 TypeManager.Reset ();
2019 PredefinedAttributes.Reset ();
2020 TypeHandle.Reset ();
2022 if (full_flag)
2023 GlobalRootNamespace.Reset ();
2025 NamespaceEntry.Reset ();
2026 CodeGen.Reset ();
2027 Attribute.Reset ();
2028 AttributeTester.Reset ();
2029 AnonymousTypeClass.Reset ();
2030 AnonymousMethodBody.Reset ();
2031 AnonymousMethodStorey.Reset ();
2032 SymbolWriter.Reset ();
2033 Switch.Reset ();
2034 Linq.QueryBlock.TransparentParameter.Reset ();
2035 Convert.Reset ();
2036 TypeInfo.Reset ();
2037 DynamicExpressionStatement.Reset ();