2010-05-31 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / driver.cs
blob2ec21ee01647a1c28bb7747d10f5d4da2915c7bc
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 internal int 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[=COUNT] Makes errors after COUNT fatal\n" +
221 " --lint Enhanced warnings\n" +
222 " --parse Only parses the source file\n" +
223 " --stacktrace Shows stack trace at error location\n" +
224 " --timestamp Displays time stamps of various compiler events\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 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";
301 var crp = new ConsoleReportPrinter ();
302 Driver d = Driver.Create (args, true, crp);
303 if (d == null)
304 return 1;
306 crp.Fatal = d.fatal_errors;
308 if (d.Compile () && d.Report.Errors == 0) {
309 if (d.Report.Warnings > 0) {
310 Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
312 Environment.Exit (0);
313 return 0;
317 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
318 d.Report.Errors, d.Report.Warnings);
319 Environment.Exit (1);
320 return 1;
323 public void LoadAssembly (string assembly, bool soft)
325 LoadAssembly (assembly, null, soft);
328 void Error6 (string name, string log)
330 if (log != null && log.Length > 0)
331 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
332 Report.Error (6, "cannot find metadata file `{0}'", name);
335 void Error9 (string type, string filename, string log)
337 if (log != null && log.Length > 0)
338 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
339 Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
342 void BadAssembly (string filename, string log)
344 MethodInfo adder_method = AssemblyClass.AddModule_Method;
346 if (adder_method != null) {
347 AssemblyName an = new AssemblyName ();
348 an.Name = ".temp";
349 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
350 try {
351 object m = null;
352 try {
353 m = adder_method.Invoke (ab, new object [] { filename });
354 } catch (TargetInvocationException ex) {
355 throw ex.InnerException;
358 if (m != null) {
359 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
360 Path.GetFileName (filename));
361 return;
363 } catch (FileNotFoundException) {
364 // did the file get deleted during compilation? who cares? swallow the exception
365 } catch (BadImageFormatException) {
366 // swallow exception
367 } catch (FileLoadException) {
368 // swallow exception
371 Error9 ("assembly", filename, log);
374 public void LoadAssembly (string assembly, string alias, bool soft)
376 Assembly a = null;
377 string total_log = "";
379 try {
380 try {
381 char[] path_chars = { '/', '\\' };
383 if (assembly.IndexOfAny (path_chars) != -1) {
384 a = Assembly.LoadFrom (assembly);
385 } else {
386 string ass = assembly;
387 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
388 ass = assembly.Substring (0, assembly.Length - 4);
389 a = Assembly.Load (ass);
391 } catch (FileNotFoundException) {
392 bool err = !soft;
393 foreach (string dir in link_paths) {
394 string full_path = Path.Combine (dir, assembly);
395 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
396 full_path += ".dll";
398 try {
399 a = Assembly.LoadFrom (full_path);
400 err = false;
401 break;
402 } catch (FileNotFoundException ff) {
403 if (soft)
404 return;
405 total_log += ff.FusionLog;
408 if (err) {
409 Error6 (assembly, total_log);
410 return;
414 // Extern aliased refs require special handling
415 if (alias == null)
416 GlobalRootNamespace.Instance.AddAssemblyReference (a);
417 else
418 GlobalRootNamespace.Instance.DefineRootNamespace (alias, a, ctx);
420 } catch (BadImageFormatException f) {
421 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
422 BadAssembly (f.FileName, f.FusionLog);
423 } catch (FileLoadException f) {
424 // ... while .NET 1.1 throws this
425 BadAssembly (f.FileName, f.FusionLog);
429 public void LoadModule (string module)
431 Module m = null;
432 string total_log = "";
434 try {
435 try {
436 m = CodeGen.Assembly.AddModule (module);
437 } catch (FileNotFoundException) {
438 bool err = true;
439 foreach (string dir in link_paths) {
440 string full_path = Path.Combine (dir, module);
441 if (!module.EndsWith (".netmodule"))
442 full_path += ".netmodule";
444 try {
445 m = CodeGen.Assembly.AddModule (full_path);
446 err = false;
447 break;
448 } catch (FileNotFoundException ff) {
449 total_log += ff.FusionLog;
452 if (err) {
453 Error6 (module, total_log);
454 return;
458 GlobalRootNamespace.Instance.AddModuleReference (m);
460 } catch (BadImageFormatException f) {
461 Error9 ("module", f.FileName, f.FusionLog);
462 } catch (FileLoadException f) {
463 Error9 ("module", f.FileName, f.FusionLog);
467 /// <summary>
468 /// Loads all assemblies referenced on the command line
469 /// </summary>
470 public void LoadReferences ()
472 link_paths.Add (GetSystemDir ());
473 link_paths.Add (Directory.GetCurrentDirectory ());
476 // Load Core Library for default compilation
478 if (RootContext.StdLib)
479 LoadAssembly ("mscorlib", false);
481 foreach (string r in soft_references)
482 LoadAssembly (r, true);
484 foreach (string r in references)
485 LoadAssembly (r, false);
487 foreach (var entry in external_aliases)
488 LoadAssembly (entry.Value, entry.Key, false);
490 GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
493 static string [] LoadArgs (string file)
495 StreamReader f;
496 var args = new List<string> ();
497 string line;
498 try {
499 f = new StreamReader (file);
500 } catch {
501 return null;
504 StringBuilder sb = new StringBuilder ();
506 while ((line = f.ReadLine ()) != null){
507 int t = line.Length;
509 for (int i = 0; i < t; i++){
510 char c = line [i];
512 if (c == '"' || c == '\''){
513 char end = c;
515 for (i++; i < t; i++){
516 c = line [i];
518 if (c == end)
519 break;
520 sb.Append (c);
522 } else if (c == ' '){
523 if (sb.Length > 0){
524 args.Add (sb.ToString ());
525 sb.Length = 0;
527 } else
528 sb.Append (c);
530 if (sb.Length > 0){
531 args.Add (sb.ToString ());
532 sb.Length = 0;
536 return args.ToArray ();
540 // Returns the directory where the system assemblies are installed
542 static string GetSystemDir ()
544 return Path.GetDirectoryName (typeof (object).Assembly.Location);
548 // Given a path specification, splits the path from the file/pattern
550 static void SplitPathAndPattern (string spec, out string path, out string pattern)
552 int p = spec.LastIndexOf ('/');
553 if (p != -1){
555 // Windows does not like /file.cs, switch that to:
556 // "\", "file.cs"
558 if (p == 0){
559 path = "\\";
560 pattern = spec.Substring (1);
561 } else {
562 path = spec.Substring (0, p);
563 pattern = spec.Substring (p + 1);
565 return;
568 p = spec.LastIndexOf ('\\');
569 if (p != -1){
570 path = spec.Substring (0, p);
571 pattern = spec.Substring (p + 1);
572 return;
575 path = ".";
576 pattern = spec;
579 void AddSourceFile (string f)
581 if (first_source == null)
582 first_source = f;
584 Location.AddFile (Report, f);
587 bool ParseArguments (string[] args, bool require_files)
589 references = new List<string> ();
590 external_aliases = new Dictionary<string, string> ();
591 soft_references = new List<string> ();
592 modules = new List<string> (2);
593 link_paths = new List<string> ();
595 List<string> response_file_list = null;
596 bool parsing_options = true;
598 for (int i = 0; i < args.Length; i++) {
599 string arg = args [i];
600 if (arg.Length == 0)
601 continue;
603 if (arg [0] == '@') {
604 string [] extra_args;
605 string response_file = arg.Substring (1);
607 if (response_file_list == null)
608 response_file_list = new List<string> ();
610 if (response_file_list.Contains (response_file)) {
611 Report.Error (
612 1515, "Response file `" + response_file +
613 "' specified multiple times");
614 return false;
617 response_file_list.Add (response_file);
619 extra_args = LoadArgs (response_file);
620 if (extra_args == null) {
621 Report.Error (2011, "Unable to open response file: " +
622 response_file);
623 return false;
626 args = AddArgs (args, extra_args);
627 continue;
630 if (parsing_options) {
631 if (arg == "--") {
632 parsing_options = false;
633 continue;
636 if (arg [0] == '-') {
637 if (UnixParseOption (arg, ref args, ref i))
638 continue;
640 // Try a -CSCOPTION
641 string csc_opt = "/" + arg.Substring (1);
642 if (CSCParseOption (csc_opt, ref args))
643 continue;
645 Error_WrongOption (arg);
646 return false;
648 if (arg [0] == '/') {
649 if (CSCParseOption (arg, ref args))
650 continue;
652 // Need to skip `/home/test.cs' however /test.cs is considered as error
653 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
654 Error_WrongOption (arg);
655 return false;
660 ProcessSourceFiles (arg, false);
663 if (require_files == false)
664 return true;
667 // If we are an exe, require a source file for the entry point
669 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
670 if (first_source == null) {
671 Report.Error (2008, "No files to compile were specified");
672 return false;
678 // If there is nothing to put in the assembly, and we are not a library
680 if (first_source == null && embedded_resources == null) {
681 Report.Error (2008, "No files to compile were specified");
682 return false;
685 return true;
688 public void Parse ()
690 Location.Initialize ();
692 var cu = Location.SourceFiles;
693 for (int i = 0; i < cu.Count; ++i) {
694 if (tokenize) {
695 tokenize_file (cu [i], ctx);
696 } else {
697 Parse (cu [i]);
702 void ProcessSourceFiles (string spec, bool recurse)
704 string path, pattern;
706 SplitPathAndPattern (spec, out path, out pattern);
707 if (pattern.IndexOf ('*') == -1){
708 AddSourceFile (spec);
709 return;
712 string [] files = null;
713 try {
714 files = Directory.GetFiles (path, pattern);
715 } catch (System.IO.DirectoryNotFoundException) {
716 Report.Error (2001, "Source file `" + spec + "' could not be found");
717 return;
718 } catch (System.IO.IOException){
719 Report.Error (2001, "Source file `" + spec + "' could not be found");
720 return;
722 foreach (string f in files) {
723 AddSourceFile (f);
726 if (!recurse)
727 return;
729 string [] dirs = null;
731 try {
732 dirs = Directory.GetDirectories (path);
733 } catch {
736 foreach (string d in dirs) {
738 // Don't include path in this string, as each
739 // directory entry already does
740 ProcessSourceFiles (d + "/" + pattern, true);
744 public void ProcessDefaultConfig ()
746 if (!load_default_config)
747 return;
750 // For now the "default config" is harcoded into the compiler
751 // we can move this outside later
753 string [] default_config = {
754 "System",
755 "System.Xml",
756 #if NET_2_1
757 "System.Net",
758 "System.Windows",
759 "System.Windows.Browser",
760 #endif
761 #if false
763 // Is it worth pre-loading all this stuff?
765 "Accessibility",
766 "System.Configuration.Install",
767 "System.Data",
768 "System.Design",
769 "System.DirectoryServices",
770 "System.Drawing.Design",
771 "System.Drawing",
772 "System.EnterpriseServices",
773 "System.Management",
774 "System.Messaging",
775 "System.Runtime.Remoting",
776 "System.Runtime.Serialization.Formatters.Soap",
777 "System.Security",
778 "System.ServiceProcess",
779 "System.Web",
780 "System.Web.RegularExpressions",
781 "System.Web.Services",
782 "System.Windows.Forms"
783 #endif
786 soft_references.AddRange (default_config);
788 if (RootContext.Version > LanguageVersion.ISO_2)
789 soft_references.Add ("System.Core");
790 if (RootContext.Version > LanguageVersion.V_3)
791 soft_references.Add ("Microsoft.CSharp");
794 public static string OutputFile
796 set {
797 output_file = value;
799 get {
800 return Path.GetFileName (output_file);
804 void SetWarningLevel (string s)
806 int level = -1;
808 try {
809 level = Int32.Parse (s);
810 } catch {
812 if (level < 0 || level > 4){
813 Report.Error (1900, "Warning level must be in the range 0-4");
814 return;
816 Report.WarningLevel = level;
819 static void Version ()
821 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
822 Console.WriteLine ("Mono C# compiler version {0}", version);
823 Environment.Exit (0);
827 // Currently handles the Unix-like command line options, but will be
828 // deprecated in favor of the CSCParseOption, which will also handle the
829 // options that start with a dash in the future.
831 bool UnixParseOption (string arg, ref string [] args, ref int i)
833 switch (arg){
834 case "-v":
835 CSharpParser.yacc_verbose_flag++;
836 return true;
838 case "--version":
839 Version ();
840 return true;
842 case "--parse":
843 parse_only = true;
844 return true;
846 case "--main": case "-m":
847 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
848 if ((i + 1) >= args.Length){
849 Usage ();
850 Environment.Exit (1);
852 RootContext.MainClass = args [++i];
853 return true;
855 case "--unsafe":
856 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
857 RootContext.Unsafe = true;
858 return true;
860 case "/?": case "/h": case "/help":
861 case "--help":
862 Usage ();
863 Environment.Exit (0);
864 return true;
866 case "--define":
867 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
868 if ((i + 1) >= args.Length){
869 Usage ();
870 Environment.Exit (1);
872 RootContext.AddConditional (args [++i]);
873 return true;
875 case "--tokenize":
876 tokenize = true;
877 return true;
879 case "-o":
880 case "--output":
881 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
882 if ((i + 1) >= args.Length){
883 Usage ();
884 Environment.Exit (1);
886 OutputFile = args [++i];
887 return true;
889 case "--checked":
890 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
891 RootContext.Checked = true;
892 return true;
894 case "--stacktrace":
895 Report.Printer.Stacktrace = true;
896 return true;
898 case "--linkresource":
899 case "--linkres":
900 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
901 if ((i + 1) >= args.Length){
902 Usage ();
903 Report.Error (5, "Missing argument to --linkres");
904 Environment.Exit (1);
906 if (embedded_resources == null)
907 embedded_resources = new Resources (ctx);
909 embedded_resources.Add (false, args [++i], args [i]);
910 return true;
912 case "--resource":
913 case "--res":
914 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
915 if ((i + 1) >= args.Length){
916 Usage ();
917 Report.Error (5, "Missing argument to --resource");
918 Environment.Exit (1);
920 if (embedded_resources == null)
921 embedded_resources = new Resources (ctx);
923 embedded_resources.Add (true, args [++i], args [i]);
924 return true;
926 case "--target":
927 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
928 if ((i + 1) >= args.Length){
929 Environment.Exit (1);
930 return true;
933 string type = args [++i];
934 switch (type){
935 case "library":
936 RootContext.Target = Target.Library;
937 RootContext.TargetExt = ".dll";
938 break;
940 case "exe":
941 RootContext.Target = Target.Exe;
942 break;
944 case "winexe":
945 RootContext.Target = Target.WinExe;
946 break;
948 case "module":
949 RootContext.Target = Target.Module;
950 RootContext.TargetExt = ".dll";
951 break;
952 default:
953 TargetUsage ();
954 break;
956 return true;
958 case "-r":
959 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
960 if ((i + 1) >= args.Length){
961 Usage ();
962 Environment.Exit (1);
965 string val = args [++i];
966 int idx = val.IndexOf ('=');
967 if (idx > -1) {
968 string alias = val.Substring (0, idx);
969 string assembly = val.Substring (idx + 1);
970 AddExternAlias (alias, assembly);
971 return true;
974 references.Add (val);
975 return true;
977 case "-L":
978 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
979 if ((i + 1) >= args.Length){
980 Usage ();
981 Environment.Exit (1);
983 link_paths.Add (args [++i]);
984 return true;
986 case "--lint":
987 RootContext.EnhancedWarnings = true;
988 return true;
990 case "--nostdlib":
991 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
992 RootContext.StdLib = false;
993 return true;
995 case "--nowarn":
996 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
997 if ((i + 1) >= args.Length){
998 Usage ();
999 Environment.Exit (1);
1001 int warn = 0;
1003 try {
1004 warn = Int32.Parse (args [++i]);
1005 } catch {
1006 Usage ();
1007 Environment.Exit (1);
1009 Report.SetIgnoreWarning (warn);
1010 return true;
1012 case "--wlevel":
1013 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1014 if ((i + 1) >= args.Length){
1015 Report.Error (
1016 1900,
1017 "--wlevel requires a value from 0 to 4");
1018 Environment.Exit (1);
1021 SetWarningLevel (args [++i]);
1022 return true;
1024 case "--mcs-debug":
1025 if ((i + 1) >= args.Length){
1026 Report.Error (5, "--mcs-debug requires an argument");
1027 Environment.Exit (1);
1030 try {
1031 Report.DebugFlags = Int32.Parse (args [++i]);
1032 } catch {
1033 Report.Error (5, "Invalid argument to --mcs-debug");
1034 Environment.Exit (1);
1036 return true;
1038 case "--about":
1039 About ();
1040 return true;
1042 case "--recurse":
1043 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1044 if ((i + 1) >= args.Length){
1045 Report.Error (5, "--recurse requires an argument");
1046 Environment.Exit (1);
1048 ProcessSourceFiles (args [++i], true);
1049 return true;
1051 case "--timestamp":
1052 timestamps = true;
1053 last_time = first_time = DateTime.Now;
1054 return true;
1056 case "--debug": case "-g":
1057 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1058 want_debugging_support = true;
1059 return true;
1061 case "--noconfig":
1062 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1063 load_default_config = false;
1064 return true;
1066 default:
1067 if (arg.StartsWith ("--fatal")){
1068 if (arg.StartsWith ("--fatal=")){
1069 if (!Int32.TryParse (arg.Substring (8), out fatal_errors))
1070 fatal_errors = 1;
1071 } else
1072 fatal_errors = 1;
1073 return true;
1075 break;
1078 return false;
1081 #if !SMCS_SOURCE
1082 public static string GetPackageFlags (string packages, bool fatal, Report report)
1084 ProcessStartInfo pi = new ProcessStartInfo ();
1085 pi.FileName = "pkg-config";
1086 pi.RedirectStandardOutput = true;
1087 pi.UseShellExecute = false;
1088 pi.Arguments = "--libs " + packages;
1089 Process p = null;
1090 try {
1091 p = Process.Start (pi);
1092 } catch (Exception e) {
1093 report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1094 if (fatal)
1095 Environment.Exit (1);
1096 p.Close ();
1097 return null;
1100 if (p.StandardOutput == null){
1101 report.Warning (-27, 1, "Specified package did not return any information");
1102 p.Close ();
1103 return null;
1105 string pkgout = p.StandardOutput.ReadToEnd ();
1106 p.WaitForExit ();
1107 if (p.ExitCode != 0) {
1108 report.Error (-27, "Error running pkg-config. Check the above output.");
1109 if (fatal)
1110 Environment.Exit (1);
1111 p.Close ();
1112 return null;
1114 p.Close ();
1116 return pkgout;
1118 #endif
1121 // This parses the -arg and /arg options to the compiler, even if the strings
1122 // in the following text use "/arg" on the strings.
1124 bool CSCParseOption (string option, ref string [] args)
1126 int idx = option.IndexOf (':');
1127 string arg, value;
1129 if (idx == -1){
1130 arg = option;
1131 value = "";
1132 } else {
1133 arg = option.Substring (0, idx);
1135 value = option.Substring (idx + 1);
1138 switch (arg.ToLower (CultureInfo.InvariantCulture)){
1139 case "/nologo":
1140 return true;
1142 case "/t":
1143 case "/target":
1144 switch (value){
1145 case "exe":
1146 RootContext.Target = Target.Exe;
1147 break;
1149 case "winexe":
1150 RootContext.Target = Target.WinExe;
1151 break;
1153 case "library":
1154 RootContext.Target = Target.Library;
1155 RootContext.TargetExt = ".dll";
1156 break;
1158 case "module":
1159 RootContext.Target = Target.Module;
1160 RootContext.TargetExt = ".netmodule";
1161 break;
1163 default:
1164 TargetUsage ();
1165 break;
1167 return true;
1169 case "/out":
1170 if (value.Length == 0){
1171 Usage ();
1172 Environment.Exit (1);
1174 OutputFile = value;
1175 return true;
1177 case "/o":
1178 case "/o+":
1179 case "/optimize":
1180 case "/optimize+":
1181 RootContext.Optimize = true;
1182 return true;
1184 case "/o-":
1185 case "/optimize-":
1186 RootContext.Optimize = false;
1187 return true;
1189 // TODO: Not supported by csc 3.5+
1190 case "/incremental":
1191 case "/incremental+":
1192 case "/incremental-":
1193 // nothing.
1194 return true;
1196 case "/d":
1197 case "/define": {
1198 if (value.Length == 0){
1199 Usage ();
1200 Environment.Exit (1);
1203 foreach (string d in value.Split (argument_value_separator)) {
1204 string conditional = d.Trim ();
1205 if (!Tokenizer.IsValidIdentifier (conditional)) {
1206 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
1207 continue;
1209 RootContext.AddConditional (conditional);
1211 return true;
1214 case "/bugreport":
1216 // We should collect data, runtime, etc and store in the file specified
1218 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1219 return true;
1220 #if !SMCS_SOURCE
1221 case "/pkg": {
1222 string packages;
1224 if (value.Length == 0){
1225 Usage ();
1226 Environment.Exit (1);
1228 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1229 string pkgout = GetPackageFlags (packages, true, Report);
1231 if (pkgout != null){
1232 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1233 Split (new Char [] { ' ', '\t'});
1234 args = AddArgs (args, xargs);
1237 return true;
1239 #endif
1240 case "/linkres":
1241 case "/linkresource":
1242 case "/res":
1243 case "/resource":
1244 if (embedded_resources == null)
1245 embedded_resources = new Resources (ctx);
1247 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1248 string[] s = value.Split (argument_value_separator);
1249 switch (s.Length) {
1250 case 1:
1251 if (s[0].Length == 0)
1252 goto default;
1253 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1254 break;
1255 case 2:
1256 embedded_resources.Add (embeded, s [0], s [1]);
1257 break;
1258 case 3:
1259 if (s [2] != "public" && s [2] != "private") {
1260 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1261 return true;
1263 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1264 break;
1265 default:
1266 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1267 break;
1270 return true;
1272 case "/recurse":
1273 if (value.Length == 0){
1274 Report.Error (5, "-recurse requires an argument");
1275 Environment.Exit (1);
1277 ProcessSourceFiles (value, true);
1278 return true;
1280 case "/r":
1281 case "/reference": {
1282 if (value.Length == 0){
1283 Report.Error (5, "-reference requires an argument");
1284 Environment.Exit (1);
1287 string[] refs = value.Split (argument_value_separator);
1288 foreach (string r in refs){
1289 string val = r;
1290 int index = val.IndexOf ('=');
1291 if (index > -1) {
1292 string alias = r.Substring (0, index);
1293 string assembly = r.Substring (index + 1);
1294 AddExternAlias (alias, assembly);
1295 return true;
1298 if (val.Length != 0)
1299 references.Add (val);
1301 return true;
1303 case "/addmodule": {
1304 if (value.Length == 0){
1305 Report.Error (5, arg + " requires an argument");
1306 Environment.Exit (1);
1309 string[] refs = value.Split (argument_value_separator);
1310 foreach (string r in refs){
1311 modules.Add (r);
1313 return true;
1315 case "/win32res": {
1316 if (value.Length == 0) {
1317 Report.Error (5, arg + " requires an argument");
1318 Environment.Exit (1);
1321 if (win32IconFile != null)
1322 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1324 win32ResourceFile = value;
1325 return true;
1327 case "/win32icon": {
1328 if (value.Length == 0) {
1329 Report.Error (5, arg + " requires an argument");
1330 Environment.Exit (1);
1333 if (win32ResourceFile != null)
1334 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1336 win32IconFile = value;
1337 return true;
1339 case "/doc": {
1340 if (value.Length == 0){
1341 Report.Error (2006, arg + " requires an argument");
1342 Environment.Exit (1);
1344 RootContext.Documentation = new Documentation (value);
1345 return true;
1347 case "/lib": {
1348 string [] libdirs;
1350 if (value.Length == 0){
1351 Report.Error (5, "/lib requires an argument");
1352 Environment.Exit (1);
1355 libdirs = value.Split (argument_value_separator);
1356 foreach (string dir in libdirs)
1357 link_paths.Add (dir);
1358 return true;
1361 case "/debug-":
1362 want_debugging_support = false;
1363 return true;
1365 case "/debug":
1366 if (value == "full" || value == "")
1367 want_debugging_support = true;
1369 return true;
1371 case "/debug+":
1372 want_debugging_support = true;
1373 return true;
1375 case "/checked":
1376 case "/checked+":
1377 RootContext.Checked = true;
1378 return true;
1380 case "/checked-":
1381 RootContext.Checked = false;
1382 return true;
1384 case "/clscheck":
1385 case "/clscheck+":
1386 return true;
1388 case "/clscheck-":
1389 RootContext.VerifyClsCompliance = false;
1390 return true;
1392 case "/unsafe":
1393 case "/unsafe+":
1394 RootContext.Unsafe = true;
1395 return true;
1397 case "/unsafe-":
1398 RootContext.Unsafe = false;
1399 return true;
1401 case "/warnaserror":
1402 case "/warnaserror+":
1403 if (value.Length == 0) {
1404 Report.WarningsAreErrors = true;
1405 } else {
1406 foreach (string wid in value.Split (argument_value_separator))
1407 Report.AddWarningAsError (wid);
1409 return true;
1411 case "/warnaserror-":
1412 if (value.Length == 0) {
1413 Report.WarningsAreErrors = false;
1414 } else {
1415 foreach (string wid in value.Split (argument_value_separator))
1416 Report.RemoveWarningAsError (wid);
1418 return true;
1420 case "/warn":
1421 SetWarningLevel (value);
1422 return true;
1424 case "/nowarn": {
1425 string [] warns;
1427 if (value.Length == 0){
1428 Report.Error (5, "/nowarn requires an argument");
1429 Environment.Exit (1);
1432 warns = value.Split (argument_value_separator);
1433 foreach (string wc in warns){
1434 try {
1435 if (wc.Trim ().Length == 0)
1436 continue;
1438 int warn = Int32.Parse (wc);
1439 if (warn < 1) {
1440 throw new ArgumentOutOfRangeException("warn");
1442 Report.SetIgnoreWarning (warn);
1443 } catch {
1444 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1447 return true;
1450 case "/noconfig":
1451 load_default_config = false;
1452 return true;
1454 case "/platform":
1455 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1456 case "anycpu":
1457 RootContext.Platform = Platform.AnyCPU;
1458 break;
1459 case "x86":
1460 RootContext.Platform = Platform.X86;
1461 break;
1462 case "x64":
1463 RootContext.Platform = Platform.X64;
1464 break;
1465 case "itanium":
1466 RootContext.Platform = Platform.IA64;
1467 break;
1468 default:
1469 Report.Error (1672, "Invalid platform type for -platform. Valid options are `anycpu', `x86', `x64' or `itanium'");
1470 break;
1473 return true;
1475 // We just ignore this.
1476 case "/errorreport":
1477 case "/filealign":
1478 return true;
1480 case "/help2":
1481 OtherFlags ();
1482 Environment.Exit(0);
1483 return true;
1485 case "/help":
1486 case "/?":
1487 Usage ();
1488 Environment.Exit (0);
1489 return true;
1491 case "/main":
1492 case "/m":
1493 if (value.Length == 0){
1494 Report.Error (5, arg + " requires an argument");
1495 Environment.Exit (1);
1497 RootContext.MainClass = value;
1498 return true;
1500 case "/nostdlib":
1501 case "/nostdlib+":
1502 RootContext.StdLib = false;
1503 return true;
1505 case "/nostdlib-":
1506 RootContext.StdLib = true;
1507 return true;
1509 case "/fullpaths":
1510 return true;
1512 case "/keyfile":
1513 if (value == String.Empty) {
1514 Report.Error (5, arg + " requires an argument");
1515 Environment.Exit (1);
1517 RootContext.StrongNameKeyFile = value;
1518 return true;
1519 case "/keycontainer":
1520 if (value == String.Empty) {
1521 Report.Error (5, arg + " requires an argument");
1522 Environment.Exit (1);
1524 RootContext.StrongNameKeyContainer = value;
1525 return true;
1526 case "/delaysign+":
1527 RootContext.StrongNameDelaySign = true;
1528 return true;
1529 case "/delaysign-":
1530 RootContext.StrongNameDelaySign = false;
1531 return true;
1533 case "/langversion":
1534 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1535 case "iso-1":
1536 RootContext.Version = LanguageVersion.ISO_1;
1537 return true;
1538 case "default":
1539 RootContext.Version = LanguageVersion.Default;
1540 RootContext.AddConditional ("__V2__");
1541 return true;
1542 case "iso-2":
1543 RootContext.Version = LanguageVersion.ISO_2;
1544 return true;
1545 case "3":
1546 RootContext.Version = LanguageVersion.V_3;
1547 return true;
1548 case "future":
1549 RootContext.Version = LanguageVersion.Future;
1550 return true;
1553 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1554 return true;
1556 case "/codepage":
1557 switch (value) {
1558 case "utf8":
1559 encoding = new UTF8Encoding();
1560 break;
1561 case "reset":
1562 encoding = Encoding.Default;
1563 break;
1564 default:
1565 try {
1566 encoding = Encoding.GetEncoding (
1567 Int32.Parse (value));
1568 } catch {
1569 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1571 break;
1573 return true;
1576 return false;
1579 void Error_WrongOption (string option)
1581 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1584 static string [] AddArgs (string [] args, string [] extra_args)
1586 string [] new_args;
1587 new_args = new string [extra_args.Length + args.Length];
1589 // if args contains '--' we have to take that into account
1590 // split args into first half and second half based on '--'
1591 // and add the extra_args before --
1592 int split_position = Array.IndexOf (args, "--");
1593 if (split_position != -1)
1595 Array.Copy (args, new_args, split_position);
1596 extra_args.CopyTo (new_args, split_position);
1597 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1599 else
1601 args.CopyTo (new_args, 0);
1602 extra_args.CopyTo (new_args, args.Length);
1605 return new_args;
1608 void AddExternAlias (string identifier, string assembly)
1610 if (assembly.Length == 0) {
1611 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1612 return;
1615 if (!IsExternAliasValid (identifier)) {
1616 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1617 return;
1620 // Could here hashtable throw an exception?
1621 external_aliases [identifier] = assembly;
1624 static bool IsExternAliasValid (string identifier)
1626 if (identifier.Length == 0)
1627 return false;
1628 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1629 return false;
1631 for (int i = 1; i < identifier.Length; i++) {
1632 char c = identifier [i];
1633 if (Char.IsLetter (c) || Char.IsDigit (c))
1634 continue;
1636 UnicodeCategory category = Char.GetUnicodeCategory (c);
1637 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1638 category != UnicodeCategory.SpacingCombiningMark ||
1639 category != UnicodeCategory.ConnectorPunctuation)
1640 return false;
1643 return true;
1647 // Main compilation method
1649 public bool Compile ()
1651 // TODO: Should be passed to parser as an argument
1652 RootContext.ToplevelTypes = new ModuleCompiled (ctx, RootContext.Unsafe);
1653 var ctypes = TypeManager.InitCoreTypes ();
1654 TypeManager.InitExpressionTypes ();
1656 Parse ();
1657 if (Report.Errors > 0)
1658 return false;
1660 if (tokenize || parse_only)
1661 return true;
1663 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1664 throw new InternalErrorException ("who set it?");
1666 ProcessDefaultConfig ();
1669 // Quick hack
1671 if (output_file == null){
1672 if (first_source == null){
1673 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1674 return false;
1677 int pos = first_source.LastIndexOf ('.');
1679 if (pos > 0)
1680 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1681 else
1682 output_file = first_source + RootContext.TargetExt;
1685 if (!CodeGen.Init (output_file, output_file, want_debugging_support, ctx))
1686 return false;
1688 if (RootContext.Target == Target.Module) {
1689 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1690 if (module_only == null) {
1691 Report.RuntimeMissingSupport (Location.Null, "/target:module");
1692 Environment.Exit (1);
1695 MethodInfo set_method = module_only.GetSetMethod (true);
1696 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1699 GlobalRootNamespace.Instance.AddModuleReference (RootContext.ToplevelTypes.Builder);
1702 // Load assemblies required
1704 if (timestamps)
1705 ShowTime ("Loading references");
1707 Import.Initialize ();
1708 LoadReferences ();
1710 if (modules.Count > 0) {
1711 foreach (string module in modules)
1712 LoadModule (module);
1715 if (timestamps)
1716 ShowTime ("References loaded");
1718 if (!TypeManager.InitCoreTypes (ctx, ctypes))
1719 return false;
1721 TypeManager.InitOptionalCoreTypes (ctx);
1723 if (timestamps)
1724 ShowTime (" Core Types done");
1727 // The second pass of the compiler
1729 if (timestamps)
1730 ShowTime ("Resolving tree");
1731 RootContext.ResolveTree ();
1733 if (Report.Errors > 0)
1734 return false;
1735 if (timestamps)
1736 ShowTime ("Populate tree");
1738 RootContext.PopulateTypes ();
1740 if (Report.Errors == 0 &&
1741 RootContext.Documentation != null &&
1742 !RootContext.Documentation.OutputDocComment (
1743 output_file, Report))
1744 return false;
1747 // Verify using aliases now
1749 NamespaceEntry.VerifyAllUsing ();
1751 if (Report.Errors > 0){
1752 return false;
1755 CodeGen.Assembly.Resolve ();
1757 if (RootContext.VerifyClsCompliance) {
1758 if (CodeGen.Assembly.IsClsCompliant) {
1759 AttributeTester.VerifyModulesClsCompliance (ctx);
1762 if (Report.Errors > 0)
1763 return false;
1766 // The code generator
1768 if (timestamps)
1769 ShowTime ("Emitting code");
1770 ShowTotalTime ("Total so far");
1771 RootContext.EmitCode ();
1772 if (timestamps)
1773 ShowTime (" done");
1775 if (Report.Errors > 0){
1776 return false;
1779 if (timestamps)
1780 ShowTime ("Closing types");
1782 RootContext.CloseTypes ();
1784 PEFileKinds k = PEFileKinds.ConsoleApplication;
1786 switch (RootContext.Target) {
1787 case Target.Library:
1788 case Target.Module:
1789 k = PEFileKinds.Dll; break;
1790 case Target.Exe:
1791 k = PEFileKinds.ConsoleApplication; break;
1792 case Target.WinExe:
1793 k = PEFileKinds.WindowApplication; break;
1796 if (RootContext.NeedsEntryPoint) {
1797 Method ep = RootContext.EntryPoint;
1799 if (ep == null) {
1800 if (RootContext.MainClass != null) {
1801 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1802 if (main_cont == null) {
1803 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1804 return false;
1807 if (!(main_cont is ClassOrStruct)) {
1808 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1809 return false;
1812 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1813 return false;
1816 if (Report.Errors == 0)
1817 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1818 output_file);
1819 return false;
1822 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1823 } else if (RootContext.MainClass != null) {
1824 Report.Error (2017, "Cannot specify -main if building a module or library");
1827 if (embedded_resources != null){
1828 if (RootContext.Target == Target.Module) {
1829 Report.Error (1507, "Cannot link resource file when building a module");
1830 return false;
1833 embedded_resources.Emit ();
1837 // Add Win32 resources
1840 if (win32ResourceFile != null) {
1841 try {
1842 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1843 } catch (ArgumentException) {
1844 Report.RuntimeMissingSupport (Location.Null, "resource embedding ");
1846 } else {
1847 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1850 if (win32IconFile != null) {
1851 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1852 if (define_icon == null) {
1853 Report.RuntimeMissingSupport (Location.Null, "resource embedding");
1854 } else {
1855 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1859 if (Report.Errors > 0)
1860 return false;
1862 CodeGen.Save (output_file, want_debugging_support, Report);
1863 if (timestamps) {
1864 ShowTime ("Saved output");
1865 ShowTotalTime ("Total");
1868 Timer.ShowTimers ();
1870 #if DEBUGME
1871 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1872 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1873 #endif
1874 return (Report.Errors == 0);
1878 class Resources
1880 interface IResource
1882 void Emit (CompilerContext cc);
1883 string FileName { get; }
1886 class EmbededResource : IResource
1888 static MethodInfo embed_res;
1889 readonly object[] args;
1891 public EmbededResource (string name, string file, bool isPrivate)
1893 args = new object [3];
1894 args [0] = name;
1895 args [1] = file;
1896 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1899 public void Emit (CompilerContext cc)
1901 if (embed_res == null) {
1902 var argst = new [] {
1903 typeof (string), typeof (string), typeof (ResourceAttributes)
1906 embed_res = typeof (AssemblyBuilder).GetMethod (
1907 "EmbedResourceFile", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
1908 null, CallingConventions.Any, argst, null);
1910 if (embed_res == null) {
1911 cc.Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1915 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1918 public string FileName {
1919 get {
1920 return (string)args [1];
1925 class LinkedResource : IResource
1927 readonly string file;
1928 readonly string name;
1929 readonly ResourceAttributes attribute;
1931 public LinkedResource (string name, string file, bool isPrivate)
1933 this.name = name;
1934 this.file = file;
1935 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1938 public void Emit (CompilerContext cc)
1940 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1943 public string FileName {
1944 get {
1945 return file;
1951 Dictionary<string, IResource> embedded_resources = new Dictionary<string, IResource> ();
1952 readonly CompilerContext ctx;
1954 public Resources (CompilerContext ctx)
1956 this.ctx = ctx;
1959 public void Add (bool embeded, string file, string name)
1961 Add (embeded, file, name, false);
1964 public void Add (bool embeded, string file, string name, bool isPrivate)
1966 if (embedded_resources.ContainsKey (name)) {
1967 ctx.Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1968 return;
1970 IResource r = embeded ?
1971 (IResource) new EmbededResource (name, file, isPrivate) :
1972 new LinkedResource (name, file, isPrivate);
1974 embedded_resources.Add (name, r);
1977 public void Emit ()
1979 foreach (IResource r in embedded_resources.Values) {
1980 if (!File.Exists (r.FileName)) {
1981 ctx.Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1982 continue;
1985 r.Emit (ctx);
1991 // This is the only public entry point
1993 public class CompilerCallableEntryPoint : MarshalByRefObject {
1994 public static bool InvokeCompiler (string [] args, TextWriter error)
1996 try {
1997 StreamReportPrinter srp = new StreamReportPrinter (error);
1998 Driver d = Driver.Create (args, true, srp);
1999 if (d == null)
2000 return false;
2002 return d.Compile () && srp.ErrorsCount == 0;
2003 } finally {
2004 Reset ();
2008 public static int[] AllWarningNumbers {
2009 get {
2010 return Report.AllWarnings;
2014 public static void Reset ()
2016 Reset (true);
2019 public static void PartialReset ()
2021 Reset (false);
2024 public static void Reset (bool full_flag)
2026 Driver.Reset ();
2027 CSharpParser.yacc_verbose_flag = 0;
2028 Location.Reset ();
2030 if (!full_flag)
2031 return;
2033 RootContext.Reset (full_flag);
2034 TypeManager.Reset ();
2035 PredefinedAttributes.Reset ();
2036 ArrayContainer.Reset ();
2037 ReferenceContainer.Reset ();
2038 PointerContainer.Reset ();
2039 Parameter.Reset ();
2041 GlobalRootNamespace.Reset ();
2042 Unary.Reset ();
2043 Binary.Reset ();
2044 ConstantFold.Reset ();
2045 CastFromDecimal.Reset ();
2047 NamespaceEntry.Reset ();
2048 CodeGen.Reset ();
2049 Attribute.Reset ();
2050 AnonymousTypeClass.Reset ();
2051 AnonymousMethodBody.Reset ();
2052 AnonymousMethodStorey.Reset ();
2053 SymbolWriter.Reset ();
2054 Switch.Reset ();
2055 Linq.QueryBlock.TransparentParameter.Reset ();
2056 Convert.Reset ();
2057 TypeInfo.Reset ();
2058 DynamicExpressionStatement.Reset ();