2010-02-20 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / driver.cs
blob5a34c5521049c85ca03dca1c24b6dfbb5920fb32
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@gnu.org)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
14 namespace Mono.CSharp
16 using System;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Collections;
20 using System.Collections.Specialized;
21 using System.IO;
22 using System.Text;
23 using System.Globalization;
24 using System.Diagnostics;
26 public enum Target {
27 Library, Exe, Module, WinExe
30 public enum Platform {
31 AnyCPU, X86, X64, IA64
34 /// <summary>
35 /// The compiler driver.
36 /// </summary>
37 class Driver
40 // Assemblies references to be linked. Initialized with
41 // mscorlib.dll here.
42 ArrayList references;
45 // If any of these fail, we ignore the problem. This is so
46 // that we can list all the assemblies in Windows and not fail
47 // if they are missing on Linux.
49 ArrayList soft_references;
51 //
52 // External aliases for assemblies.
54 Hashtable external_aliases;
57 // Modules to be linked
59 ArrayList modules;
61 // Lookup paths
62 static ArrayList link_paths;
64 // Whether we want to only run the tokenizer
65 bool tokenize;
67 string first_source;
69 bool want_debugging_support;
70 bool parse_only;
71 bool timestamps;
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 input.Close ();
209 void Parse (SeekableStreamReader reader, CompilationUnit file)
211 CSharpParser parser = new CSharpParser (reader, file, ctx);
212 try {
213 parser.parse ();
214 } catch (Exception ex) {
215 Report.Error(589, parser.Lexer.Location,
216 "Compilation aborted in file `{0}', {1}", file.Name, ex);
220 static void OtherFlags ()
222 Console.WriteLine (
223 "Other flags in the compiler\n" +
224 " --fatal Makes errors fatal\n" +
225 " --lint Enhanced warnings\n" +
226 " --parse Only parses the source file\n" +
227 " --stacktrace Shows stack trace at error location\n" +
228 " --timestamp Displays time stamps of various compiler events\n" +
229 " -v Verbose parsing (for debugging the parser)\n" +
230 " --mcs-debug X Sets MCS debugging level to X\n");
233 static void Usage ()
235 Console.WriteLine (
236 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
237 "mcs [options] source-files\n" +
238 " --about About the Mono C# compiler\n" +
239 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
240 " -checked[+|-] Sets default aritmetic overflow context\n" +
241 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
242 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
243 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
244 " -debug[+|-], -g Generate debugging information\n" +
245 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
246 " -doc:FILE Process documentation comments to XML file\n" +
247 " -help Lists all compiler options (short: -?)\n" +
248 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
249 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
250 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, Default, or Future\n" +
251 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
252 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
253 " -noconfig Disables implicitly referenced assemblies\n" +
254 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
255 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
256 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
257 " -out:FILE Specifies output assembly name\n" +
258 #if !SMCS_SOURCE
259 " -pkg:P1[,Pn] References packages P1..Pn\n" +
260 #endif
261 " -platform:ARCH Specifies the target platform of the output assembly\n" +
262 " ARCH can be one of: anycpu, x86, x64 or itanium\n" +
263 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
264 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
265 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
266 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
267 " KIND can be one of: exe, winexe, library, module\n" +
268 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
269 " -warnaserror[+|-] Treats all warnings as errors\n" +
270 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
271 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
272 " -help2 Shows internal compiler options\n" +
273 "\n" +
274 "Resources:\n" +
275 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
276 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
277 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
278 " -win32icon:FILE Use this icon for the output\n" +
279 " @file Read response file for more options\n\n" +
280 "Options can be of the form -option or /option");
283 void TargetUsage ()
285 Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
288 static void About ()
290 Console.WriteLine (
291 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
292 "The compiler source code is released under the terms of the \n"+
293 "MIT X11 or GNU GPL licenses\n\n" +
295 "For more information on Mono, visit the project Web site\n" +
296 " http://www.mono-project.com\n\n" +
298 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
299 Environment.Exit (0);
302 public static int Main (string[] args)
304 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
306 Driver d = Driver.Create (args, true, new ConsoleReportPrinter ());
307 if (d == null)
308 return 1;
310 if (d.Compile () && d.Report.Errors == 0) {
311 if (d.Report.Warnings > 0) {
312 Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
314 Environment.Exit (0);
315 return 0;
319 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
320 d.Report.Errors, d.Report.Warnings);
321 Environment.Exit (1);
322 return 1;
325 public void LoadAssembly (string assembly, bool soft)
327 LoadAssembly (assembly, null, soft);
330 void Error6 (string name, string log)
332 if (log != null && log.Length > 0)
333 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
334 Report.Error (6, "cannot find metadata file `{0}'", name);
337 void Error9 (string type, string filename, string log)
339 if (log != null && log.Length > 0)
340 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
341 Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
344 void BadAssembly (string filename, string log)
346 MethodInfo adder_method = AssemblyClass.AddModule_Method;
348 if (adder_method != null) {
349 AssemblyName an = new AssemblyName ();
350 an.Name = ".temp";
351 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
352 try {
353 object m = null;
354 try {
355 m = adder_method.Invoke (ab, new object [] { filename });
356 } catch (TargetInvocationException ex) {
357 throw ex.InnerException;
360 if (m != null) {
361 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
362 Path.GetFileName (filename));
363 return;
365 } catch (FileNotFoundException) {
366 // did the file get deleted during compilation? who cares? swallow the exception
367 } catch (BadImageFormatException) {
368 // swallow exception
369 } catch (FileLoadException) {
370 // swallow exception
373 Error9 ("assembly", filename, log);
376 public void LoadAssembly (string assembly, string alias, bool soft)
378 Assembly a = null;
379 string total_log = "";
381 try {
382 try {
383 char[] path_chars = { '/', '\\' };
385 if (assembly.IndexOfAny (path_chars) != -1) {
386 a = Assembly.LoadFrom (assembly);
387 } else {
388 string ass = assembly;
389 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
390 ass = assembly.Substring (0, assembly.Length - 4);
391 a = Assembly.Load (ass);
393 } catch (FileNotFoundException) {
394 bool err = !soft;
395 foreach (string dir in link_paths) {
396 string full_path = Path.Combine (dir, assembly);
397 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
398 full_path += ".dll";
400 try {
401 a = Assembly.LoadFrom (full_path);
402 err = false;
403 break;
404 } catch (FileNotFoundException ff) {
405 if (soft)
406 return;
407 total_log += ff.FusionLog;
410 if (err) {
411 Error6 (assembly, total_log);
412 return;
416 // Extern aliased refs require special handling
417 if (alias == null)
418 GlobalRootNamespace.Instance.AddAssemblyReference (a);
419 else
420 GlobalRootNamespace.Instance.DefineRootNamespace (alias, a, ctx);
422 } catch (BadImageFormatException f) {
423 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
424 BadAssembly (f.FileName, f.FusionLog);
425 } catch (FileLoadException f) {
426 // ... while .NET 1.1 throws this
427 BadAssembly (f.FileName, f.FusionLog);
431 public void LoadModule (string module)
433 Module m = null;
434 string total_log = "";
436 try {
437 try {
438 m = CodeGen.Assembly.AddModule (module);
439 } catch (FileNotFoundException) {
440 bool err = true;
441 foreach (string dir in link_paths) {
442 string full_path = Path.Combine (dir, module);
443 if (!module.EndsWith (".netmodule"))
444 full_path += ".netmodule";
446 try {
447 m = CodeGen.Assembly.AddModule (full_path);
448 err = false;
449 break;
450 } catch (FileNotFoundException ff) {
451 total_log += ff.FusionLog;
454 if (err) {
455 Error6 (module, total_log);
456 return;
460 GlobalRootNamespace.Instance.AddModuleReference (m);
462 } catch (BadImageFormatException f) {
463 Error9 ("module", f.FileName, f.FusionLog);
464 } catch (FileLoadException f) {
465 Error9 ("module", f.FileName, f.FusionLog);
469 /// <summary>
470 /// Loads all assemblies referenced on the command line
471 /// </summary>
472 public void LoadReferences ()
474 link_paths.Add (GetSystemDir ());
475 link_paths.Add (Directory.GetCurrentDirectory ());
478 // Load Core Library for default compilation
480 if (RootContext.StdLib)
481 LoadAssembly ("mscorlib", false);
483 foreach (string r in soft_references)
484 LoadAssembly (r, true);
486 foreach (string r in references)
487 LoadAssembly (r, false);
489 foreach (DictionaryEntry entry in external_aliases)
490 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
492 GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
495 static string [] LoadArgs (string file)
497 StreamReader f;
498 ArrayList args = new ArrayList ();
499 string line;
500 try {
501 f = new StreamReader (file);
502 } catch {
503 return null;
506 StringBuilder sb = new StringBuilder ();
508 while ((line = f.ReadLine ()) != null){
509 int t = line.Length;
511 for (int i = 0; i < t; i++){
512 char c = line [i];
514 if (c == '"' || c == '\''){
515 char end = c;
517 for (i++; i < t; i++){
518 c = line [i];
520 if (c == end)
521 break;
522 sb.Append (c);
524 } else if (c == ' '){
525 if (sb.Length > 0){
526 args.Add (sb.ToString ());
527 sb.Length = 0;
529 } else
530 sb.Append (c);
532 if (sb.Length > 0){
533 args.Add (sb.ToString ());
534 sb.Length = 0;
538 string [] ret_value = new string [args.Count];
539 args.CopyTo (ret_value, 0);
541 return ret_value;
545 // Returns the directory where the system assemblies are installed
547 static string GetSystemDir ()
549 return Path.GetDirectoryName (typeof (object).Assembly.Location);
553 // Given a path specification, splits the path from the file/pattern
555 static void SplitPathAndPattern (string spec, out string path, out string pattern)
557 int p = spec.LastIndexOf ('/');
558 if (p != -1){
560 // Windows does not like /file.cs, switch that to:
561 // "\", "file.cs"
563 if (p == 0){
564 path = "\\";
565 pattern = spec.Substring (1);
566 } else {
567 path = spec.Substring (0, p);
568 pattern = spec.Substring (p + 1);
570 return;
573 p = spec.LastIndexOf ('\\');
574 if (p != -1){
575 path = spec.Substring (0, p);
576 pattern = spec.Substring (p + 1);
577 return;
580 path = ".";
581 pattern = spec;
584 void AddSourceFile (string f)
586 if (first_source == null)
587 first_source = f;
589 Location.AddFile (Report, f);
592 bool ParseArguments (string[] args, bool require_files)
594 references = new ArrayList ();
595 external_aliases = new Hashtable ();
596 soft_references = new ArrayList ();
597 modules = new ArrayList (2);
598 link_paths = new ArrayList ();
600 ArrayList response_file_list = null;
601 bool parsing_options = true;
603 for (int i = 0; i < args.Length; i++) {
604 string arg = args [i];
605 if (arg.Length == 0)
606 continue;
608 if (arg [0] == '@') {
609 string [] extra_args;
610 string response_file = arg.Substring (1);
612 if (response_file_list == null)
613 response_file_list = new ArrayList ();
615 if (response_file_list.Contains (response_file)) {
616 Report.Error (
617 1515, "Response file `" + response_file +
618 "' specified multiple times");
619 return false;
622 response_file_list.Add (response_file);
624 extra_args = LoadArgs (response_file);
625 if (extra_args == null) {
626 Report.Error (2011, "Unable to open response file: " +
627 response_file);
628 return false;
631 args = AddArgs (args, extra_args);
632 continue;
635 if (parsing_options) {
636 if (arg == "--") {
637 parsing_options = false;
638 continue;
641 if (arg [0] == '-') {
642 if (UnixParseOption (arg, ref args, ref i))
643 continue;
645 // Try a -CSCOPTION
646 string csc_opt = "/" + arg.Substring (1);
647 if (CSCParseOption (csc_opt, ref args))
648 continue;
650 Error_WrongOption (arg);
651 return false;
653 if (arg [0] == '/') {
654 if (CSCParseOption (arg, ref args))
655 continue;
657 // Need to skip `/home/test.cs' however /test.cs is considered as error
658 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
659 Error_WrongOption (arg);
660 return false;
665 ProcessSourceFiles (arg, false);
668 if (require_files == false)
669 return true;
672 // If we are an exe, require a source file for the entry point
674 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
675 if (first_source == null) {
676 Report.Error (2008, "No files to compile were specified");
677 return false;
683 // If there is nothing to put in the assembly, and we are not a library
685 if (first_source == null && embedded_resources == null) {
686 Report.Error (2008, "No files to compile were specified");
687 return false;
690 return true;
693 public void Parse ()
695 Location.Initialize ();
697 ArrayList cu = Location.SourceFiles;
698 for (int i = 0; i < cu.Count; ++i) {
699 if (tokenize) {
700 tokenize_file ((CompilationUnit) cu [i], ctx);
701 } else {
702 Parse ((CompilationUnit) cu [i]);
707 void ProcessSourceFiles (string spec, bool recurse)
709 string path, pattern;
711 SplitPathAndPattern (spec, out path, out pattern);
712 if (pattern.IndexOf ('*') == -1){
713 AddSourceFile (spec);
714 return;
717 string [] files = null;
718 try {
719 files = Directory.GetFiles (path, pattern);
720 } catch (System.IO.DirectoryNotFoundException) {
721 Report.Error (2001, "Source file `" + spec + "' could not be found");
722 return;
723 } catch (System.IO.IOException){
724 Report.Error (2001, "Source file `" + spec + "' could not be found");
725 return;
727 foreach (string f in files) {
728 AddSourceFile (f);
731 if (!recurse)
732 return;
734 string [] dirs = null;
736 try {
737 dirs = Directory.GetDirectories (path);
738 } catch {
741 foreach (string d in dirs) {
743 // Don't include path in this string, as each
744 // directory entry already does
745 ProcessSourceFiles (d + "/" + pattern, true);
749 public void ProcessDefaultConfig ()
751 if (!load_default_config)
752 return;
755 // For now the "default config" is harcoded into the compiler
756 // we can move this outside later
758 string [] default_config = {
759 "System",
760 "System.Xml",
761 #if NET_2_1
762 "System.Net",
763 "System.Windows",
764 "System.Windows.Browser",
765 #endif
766 #if false
768 // Is it worth pre-loading all this stuff?
770 "Accessibility",
771 "System.Configuration.Install",
772 "System.Data",
773 "System.Design",
774 "System.DirectoryServices",
775 "System.Drawing.Design",
776 "System.Drawing",
777 "System.EnterpriseServices",
778 "System.Management",
779 "System.Messaging",
780 "System.Runtime.Remoting",
781 "System.Runtime.Serialization.Formatters.Soap",
782 "System.Security",
783 "System.ServiceProcess",
784 "System.Web",
785 "System.Web.RegularExpressions",
786 "System.Web.Services",
787 "System.Windows.Forms"
788 #endif
791 soft_references.AddRange (default_config);
793 if (RootContext.Version > LanguageVersion.ISO_2)
794 soft_references.Add ("System.Core");
795 if (RootContext.Version > LanguageVersion.V_3)
796 soft_references.Add ("Microsoft.CSharp");
799 public static string OutputFile
801 set {
802 output_file = value;
804 get {
805 return Path.GetFileName (output_file);
809 void SetWarningLevel (string s)
811 int level = -1;
813 try {
814 level = Int32.Parse (s);
815 } catch {
817 if (level < 0 || level > 4){
818 Report.Error (1900, "Warning level must be in the range 0-4");
819 return;
821 Report.WarningLevel = level;
824 static void Version ()
826 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
827 Console.WriteLine ("Mono C# compiler version {0}", version);
828 Environment.Exit (0);
832 // Currently handles the Unix-like command line options, but will be
833 // deprecated in favor of the CSCParseOption, which will also handle the
834 // options that start with a dash in the future.
836 bool UnixParseOption (string arg, ref string [] args, ref int i)
838 switch (arg){
839 case "-v":
840 CSharpParser.yacc_verbose_flag++;
841 return true;
843 case "--version":
844 Version ();
845 return true;
847 case "--parse":
848 parse_only = true;
849 return true;
851 case "--main": case "-m":
852 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
853 if ((i + 1) >= args.Length){
854 Usage ();
855 Environment.Exit (1);
857 RootContext.MainClass = args [++i];
858 return true;
860 case "--unsafe":
861 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
862 RootContext.Unsafe = true;
863 return true;
865 case "/?": case "/h": case "/help":
866 case "--help":
867 Usage ();
868 Environment.Exit (0);
869 return true;
871 case "--define":
872 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
873 if ((i + 1) >= args.Length){
874 Usage ();
875 Environment.Exit (1);
877 RootContext.AddConditional (args [++i]);
878 return true;
880 case "--tokenize":
881 tokenize = true;
882 return true;
884 case "-o":
885 case "--output":
886 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
887 if ((i + 1) >= args.Length){
888 Usage ();
889 Environment.Exit (1);
891 OutputFile = args [++i];
892 return true;
894 case "--checked":
895 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
896 RootContext.Checked = true;
897 return true;
899 case "--stacktrace":
900 Report.Printer.Stacktrace = true;
901 return true;
903 case "--linkresource":
904 case "--linkres":
905 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
906 if ((i + 1) >= args.Length){
907 Usage ();
908 Report.Error (5, "Missing argument to --linkres");
909 Environment.Exit (1);
911 if (embedded_resources == null)
912 embedded_resources = new Resources (ctx);
914 embedded_resources.Add (false, args [++i], args [i]);
915 return true;
917 case "--resource":
918 case "--res":
919 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
920 if ((i + 1) >= args.Length){
921 Usage ();
922 Report.Error (5, "Missing argument to --resource");
923 Environment.Exit (1);
925 if (embedded_resources == null)
926 embedded_resources = new Resources (ctx);
928 embedded_resources.Add (true, args [++i], args [i]);
929 return true;
931 case "--target":
932 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
933 if ((i + 1) >= args.Length){
934 Environment.Exit (1);
935 return true;
938 string type = args [++i];
939 switch (type){
940 case "library":
941 RootContext.Target = Target.Library;
942 RootContext.TargetExt = ".dll";
943 break;
945 case "exe":
946 RootContext.Target = Target.Exe;
947 break;
949 case "winexe":
950 RootContext.Target = Target.WinExe;
951 break;
953 case "module":
954 RootContext.Target = Target.Module;
955 RootContext.TargetExt = ".dll";
956 break;
957 default:
958 TargetUsage ();
959 break;
961 return true;
963 case "-r":
964 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
965 if ((i + 1) >= args.Length){
966 Usage ();
967 Environment.Exit (1);
970 string val = args [++i];
971 int idx = val.IndexOf ('=');
972 if (idx > -1) {
973 string alias = val.Substring (0, idx);
974 string assembly = val.Substring (idx + 1);
975 AddExternAlias (alias, assembly);
976 return true;
979 references.Add (val);
980 return true;
982 case "-L":
983 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
984 if ((i + 1) >= args.Length){
985 Usage ();
986 Environment.Exit (1);
988 link_paths.Add (args [++i]);
989 return true;
991 case "--lint":
992 RootContext.EnhancedWarnings = true;
993 return true;
995 case "--nostdlib":
996 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
997 RootContext.StdLib = false;
998 return true;
1000 case "--fatal":
1001 Report.Fatal = true;
1002 return true;
1004 case "--nowarn":
1005 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1006 if ((i + 1) >= args.Length){
1007 Usage ();
1008 Environment.Exit (1);
1010 int warn = 0;
1012 try {
1013 warn = Int32.Parse (args [++i]);
1014 } catch {
1015 Usage ();
1016 Environment.Exit (1);
1018 Report.SetIgnoreWarning (warn);
1019 return true;
1021 case "--wlevel":
1022 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1023 if ((i + 1) >= args.Length){
1024 Report.Error (
1025 1900,
1026 "--wlevel requires a value from 0 to 4");
1027 Environment.Exit (1);
1030 SetWarningLevel (args [++i]);
1031 return true;
1033 case "--mcs-debug":
1034 if ((i + 1) >= args.Length){
1035 Report.Error (5, "--mcs-debug requires an argument");
1036 Environment.Exit (1);
1039 try {
1040 Report.DebugFlags = Int32.Parse (args [++i]);
1041 } catch {
1042 Report.Error (5, "Invalid argument to --mcs-debug");
1043 Environment.Exit (1);
1045 return true;
1047 case "--about":
1048 About ();
1049 return true;
1051 case "--recurse":
1052 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1053 if ((i + 1) >= args.Length){
1054 Report.Error (5, "--recurse requires an argument");
1055 Environment.Exit (1);
1057 ProcessSourceFiles (args [++i], true);
1058 return true;
1060 case "--timestamp":
1061 timestamps = true;
1062 last_time = first_time = DateTime.Now;
1063 return true;
1065 case "--debug": case "-g":
1066 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1067 want_debugging_support = true;
1068 return true;
1070 case "--noconfig":
1071 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1072 load_default_config = false;
1073 return true;
1076 return false;
1079 #if !SMCS_SOURCE
1080 public static string GetPackageFlags (string packages, bool fatal, Report report)
1082 ProcessStartInfo pi = new ProcessStartInfo ();
1083 pi.FileName = "pkg-config";
1084 pi.RedirectStandardOutput = true;
1085 pi.UseShellExecute = false;
1086 pi.Arguments = "--libs " + packages;
1087 Process p = null;
1088 try {
1089 p = Process.Start (pi);
1090 } catch (Exception e) {
1091 report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1092 if (fatal)
1093 Environment.Exit (1);
1094 p.Close ();
1095 return null;
1098 if (p.StandardOutput == null){
1099 report.Warning (-27, 1, "Specified package did not return any information");
1100 p.Close ();
1101 return null;
1103 string pkgout = p.StandardOutput.ReadToEnd ();
1104 p.WaitForExit ();
1105 if (p.ExitCode != 0) {
1106 report.Error (-27, "Error running pkg-config. Check the above output.");
1107 if (fatal)
1108 Environment.Exit (1);
1109 p.Close ();
1110 return null;
1112 p.Close ();
1114 return pkgout;
1116 #endif
1119 // This parses the -arg and /arg options to the compiler, even if the strings
1120 // in the following text use "/arg" on the strings.
1122 bool CSCParseOption (string option, ref string [] args)
1124 int idx = option.IndexOf (':');
1125 string arg, value;
1127 if (idx == -1){
1128 arg = option;
1129 value = "";
1130 } else {
1131 arg = option.Substring (0, idx);
1133 value = option.Substring (idx + 1);
1136 switch (arg.ToLower (CultureInfo.InvariantCulture)){
1137 case "/nologo":
1138 return true;
1140 case "/t":
1141 case "/target":
1142 switch (value){
1143 case "exe":
1144 RootContext.Target = Target.Exe;
1145 break;
1147 case "winexe":
1148 RootContext.Target = Target.WinExe;
1149 break;
1151 case "library":
1152 RootContext.Target = Target.Library;
1153 RootContext.TargetExt = ".dll";
1154 break;
1156 case "module":
1157 RootContext.Target = Target.Module;
1158 RootContext.TargetExt = ".netmodule";
1159 break;
1161 default:
1162 TargetUsage ();
1163 break;
1165 return true;
1167 case "/out":
1168 if (value.Length == 0){
1169 Usage ();
1170 Environment.Exit (1);
1172 OutputFile = value;
1173 return true;
1175 case "/o":
1176 case "/o+":
1177 case "/optimize":
1178 case "/optimize+":
1179 RootContext.Optimize = true;
1180 return true;
1182 case "/o-":
1183 case "/optimize-":
1184 RootContext.Optimize = false;
1185 return true;
1187 // TODO: Not supported by csc 3.5+
1188 case "/incremental":
1189 case "/incremental+":
1190 case "/incremental-":
1191 // nothing.
1192 return true;
1194 case "/d":
1195 case "/define": {
1196 if (value.Length == 0){
1197 Usage ();
1198 Environment.Exit (1);
1201 foreach (string d in value.Split (argument_value_separator)) {
1202 string conditional = d.Trim ();
1203 if (!Tokenizer.IsValidIdentifier (conditional)) {
1204 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
1205 continue;
1207 RootContext.AddConditional (conditional);
1209 return true;
1212 case "/bugreport":
1214 // We should collect data, runtime, etc and store in the file specified
1216 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1217 return true;
1218 #if !SMCS_SOURCE
1219 case "/pkg": {
1220 string packages;
1222 if (value.Length == 0){
1223 Usage ();
1224 Environment.Exit (1);
1226 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1227 string pkgout = GetPackageFlags (packages, true, Report);
1229 if (pkgout != null){
1230 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1231 Split (new Char [] { ' ', '\t'});
1232 args = AddArgs (args, xargs);
1235 return true;
1237 #endif
1238 case "/linkres":
1239 case "/linkresource":
1240 case "/res":
1241 case "/resource":
1242 if (embedded_resources == null)
1243 embedded_resources = new Resources (ctx);
1245 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1246 string[] s = value.Split (argument_value_separator);
1247 switch (s.Length) {
1248 case 1:
1249 if (s[0].Length == 0)
1250 goto default;
1251 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1252 break;
1253 case 2:
1254 embedded_resources.Add (embeded, s [0], s [1]);
1255 break;
1256 case 3:
1257 if (s [2] != "public" && s [2] != "private") {
1258 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1259 return true;
1261 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1262 break;
1263 default:
1264 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1265 break;
1268 return true;
1270 case "/recurse":
1271 if (value.Length == 0){
1272 Report.Error (5, "-recurse requires an argument");
1273 Environment.Exit (1);
1275 ProcessSourceFiles (value, true);
1276 return true;
1278 case "/r":
1279 case "/reference": {
1280 if (value.Length == 0){
1281 Report.Error (5, "-reference requires an argument");
1282 Environment.Exit (1);
1285 string[] refs = value.Split (argument_value_separator);
1286 foreach (string r in refs){
1287 string val = r;
1288 int index = val.IndexOf ('=');
1289 if (index > -1) {
1290 string alias = r.Substring (0, index);
1291 string assembly = r.Substring (index + 1);
1292 AddExternAlias (alias, assembly);
1293 return true;
1296 if (val.Length != 0)
1297 references.Add (val);
1299 return true;
1301 case "/addmodule": {
1302 if (value.Length == 0){
1303 Report.Error (5, arg + " requires an argument");
1304 Environment.Exit (1);
1307 string[] refs = value.Split (argument_value_separator);
1308 foreach (string r in refs){
1309 modules.Add (r);
1311 return true;
1313 case "/win32res": {
1314 if (value.Length == 0) {
1315 Report.Error (5, arg + " requires an argument");
1316 Environment.Exit (1);
1319 if (win32IconFile != null)
1320 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1322 win32ResourceFile = value;
1323 return true;
1325 case "/win32icon": {
1326 if (value.Length == 0) {
1327 Report.Error (5, arg + " requires an argument");
1328 Environment.Exit (1);
1331 if (win32ResourceFile != null)
1332 Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1334 win32IconFile = value;
1335 return true;
1337 case "/doc": {
1338 if (value.Length == 0){
1339 Report.Error (2006, arg + " requires an argument");
1340 Environment.Exit (1);
1342 RootContext.Documentation = new Documentation (value);
1343 return true;
1345 case "/lib": {
1346 string [] libdirs;
1348 if (value.Length == 0){
1349 Report.Error (5, "/lib requires an argument");
1350 Environment.Exit (1);
1353 libdirs = value.Split (argument_value_separator);
1354 foreach (string dir in libdirs)
1355 link_paths.Add (dir);
1356 return true;
1359 case "/debug-":
1360 want_debugging_support = false;
1361 return true;
1363 case "/debug":
1364 if (value == "full" || value == "")
1365 want_debugging_support = true;
1367 return true;
1369 case "/debug+":
1370 want_debugging_support = true;
1371 return true;
1373 case "/checked":
1374 case "/checked+":
1375 RootContext.Checked = true;
1376 return true;
1378 case "/checked-":
1379 RootContext.Checked = false;
1380 return true;
1382 case "/clscheck":
1383 case "/clscheck+":
1384 return true;
1386 case "/clscheck-":
1387 RootContext.VerifyClsCompliance = false;
1388 return true;
1390 case "/unsafe":
1391 case "/unsafe+":
1392 RootContext.Unsafe = true;
1393 return true;
1395 case "/unsafe-":
1396 RootContext.Unsafe = false;
1397 return true;
1399 case "/warnaserror":
1400 case "/warnaserror+":
1401 if (value.Length == 0) {
1402 Report.WarningsAreErrors = true;
1403 } else {
1404 foreach (string wid in value.Split (argument_value_separator))
1405 Report.AddWarningAsError (wid);
1407 return true;
1409 case "/warnaserror-":
1410 if (value.Length == 0) {
1411 Report.WarningsAreErrors = false;
1412 } else {
1413 foreach (string wid in value.Split (argument_value_separator))
1414 Report.RemoveWarningAsError (wid);
1416 return true;
1418 case "/warn":
1419 SetWarningLevel (value);
1420 return true;
1422 case "/nowarn": {
1423 string [] warns;
1425 if (value.Length == 0){
1426 Report.Error (5, "/nowarn requires an argument");
1427 Environment.Exit (1);
1430 warns = value.Split (argument_value_separator);
1431 foreach (string wc in warns){
1432 try {
1433 if (wc.Trim ().Length == 0)
1434 continue;
1436 int warn = Int32.Parse (wc);
1437 if (warn < 1) {
1438 throw new ArgumentOutOfRangeException("warn");
1440 Report.SetIgnoreWarning (warn);
1441 } catch {
1442 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1445 return true;
1448 case "/noconfig":
1449 load_default_config = false;
1450 return true;
1452 case "/platform":
1453 #if GMCS_SOURCE
1454 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1455 case "anycpu":
1456 RootContext.Platform = Platform.AnyCPU;
1457 break;
1458 case "x86":
1459 RootContext.Platform = Platform.X86;
1460 break;
1461 case "x64":
1462 RootContext.Platform = Platform.X64;
1463 break;
1464 case "itanium":
1465 RootContext.Platform = Platform.IA64;
1466 break;
1467 default:
1468 Report.Error (1672, "Invalid platform type for -platform. Valid options are `anycpu', `x86', `x64' or `itanium'");
1469 break;
1471 #endif
1472 return true;
1474 // We just ignore this.
1475 case "/errorreport":
1476 case "/filealign":
1477 return true;
1479 case "/help2":
1480 OtherFlags ();
1481 Environment.Exit(0);
1482 return true;
1484 case "/help":
1485 case "/?":
1486 Usage ();
1487 Environment.Exit (0);
1488 return true;
1490 case "/main":
1491 case "/m":
1492 if (value.Length == 0){
1493 Report.Error (5, arg + " requires an argument");
1494 Environment.Exit (1);
1496 RootContext.MainClass = value;
1497 return true;
1499 case "/nostdlib":
1500 case "/nostdlib+":
1501 RootContext.StdLib = false;
1502 return true;
1504 case "/nostdlib-":
1505 RootContext.StdLib = true;
1506 return true;
1508 case "/fullpaths":
1509 return true;
1511 case "/keyfile":
1512 if (value == String.Empty) {
1513 Report.Error (5, arg + " requires an argument");
1514 Environment.Exit (1);
1516 RootContext.StrongNameKeyFile = value;
1517 return true;
1518 case "/keycontainer":
1519 if (value == String.Empty) {
1520 Report.Error (5, arg + " requires an argument");
1521 Environment.Exit (1);
1523 RootContext.StrongNameKeyContainer = value;
1524 return true;
1525 case "/delaysign+":
1526 RootContext.StrongNameDelaySign = true;
1527 return true;
1528 case "/delaysign-":
1529 RootContext.StrongNameDelaySign = false;
1530 return true;
1532 case "/langversion":
1533 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1534 case "iso-1":
1535 RootContext.Version = LanguageVersion.ISO_1;
1536 return true;
1538 case "default":
1539 RootContext.Version = LanguageVersion.Default;
1540 #if GMCS_SOURCE
1541 RootContext.AddConditional ("__V2__");
1542 #endif
1543 return true;
1544 case "iso-2":
1545 RootContext.Version = LanguageVersion.ISO_2;
1546 return true;
1547 case "3":
1548 RootContext.Version = LanguageVersion.V_3;
1549 return true;
1550 case "future":
1551 RootContext.Version = LanguageVersion.Future;
1552 return true;
1555 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1556 return true;
1558 case "/codepage":
1559 switch (value) {
1560 case "utf8":
1561 encoding = new UTF8Encoding();
1562 break;
1563 case "reset":
1564 encoding = Encoding.Default;
1565 break;
1566 default:
1567 try {
1568 encoding = Encoding.GetEncoding (
1569 Int32.Parse (value));
1570 } catch {
1571 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1573 break;
1575 return true;
1578 return false;
1581 void Error_WrongOption (string option)
1583 Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1586 static string [] AddArgs (string [] args, string [] extra_args)
1588 string [] new_args;
1589 new_args = new string [extra_args.Length + args.Length];
1591 // if args contains '--' we have to take that into account
1592 // split args into first half and second half based on '--'
1593 // and add the extra_args before --
1594 int split_position = Array.IndexOf (args, "--");
1595 if (split_position != -1)
1597 Array.Copy (args, new_args, split_position);
1598 extra_args.CopyTo (new_args, split_position);
1599 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1601 else
1603 args.CopyTo (new_args, 0);
1604 extra_args.CopyTo (new_args, args.Length);
1607 return new_args;
1610 void AddExternAlias (string identifier, string assembly)
1612 if (assembly.Length == 0) {
1613 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1614 return;
1617 if (!IsExternAliasValid (identifier)) {
1618 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1619 return;
1622 // Could here hashtable throw an exception?
1623 external_aliases [identifier] = assembly;
1626 static bool IsExternAliasValid (string identifier)
1628 if (identifier.Length == 0)
1629 return false;
1630 if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1631 return false;
1633 for (int i = 1; i < identifier.Length; i++) {
1634 char c = identifier [i];
1635 if (Char.IsLetter (c) || Char.IsDigit (c))
1636 continue;
1638 UnicodeCategory category = Char.GetUnicodeCategory (c);
1639 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1640 category != UnicodeCategory.SpacingCombiningMark ||
1641 category != UnicodeCategory.ConnectorPunctuation)
1642 return false;
1645 return true;
1649 // Main compilation method
1651 public bool Compile ()
1653 // TODO: Should be passed to parser as an argument
1654 RootContext.ToplevelTypes = new ModuleContainer (ctx, RootContext.Unsafe);
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 LoadReferences ();
1709 if (modules.Count > 0) {
1710 foreach (string module in modules)
1711 LoadModule (module);
1714 if (timestamps)
1715 ShowTime ("References loaded");
1717 if (!TypeManager.InitCoreTypes (ctx) || Report.Errors > 0)
1718 return false;
1720 TypeManager.InitOptionalCoreTypes (ctx);
1722 if (timestamps)
1723 ShowTime (" Core Types done");
1726 // The second pass of the compiler
1728 if (timestamps)
1729 ShowTime ("Resolving tree");
1730 RootContext.ResolveTree ();
1732 if (Report.Errors > 0)
1733 return false;
1734 if (timestamps)
1735 ShowTime ("Populate tree");
1736 if (!RootContext.StdLib)
1737 RootContext.BootCorlib_PopulateCoreTypes ();
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);
1760 TypeManager.LoadAllImportedTypes ();
1763 if (Report.Errors > 0)
1764 return false;
1767 // The code generator
1769 if (timestamps)
1770 ShowTime ("Emitting code");
1771 ShowTotalTime ("Total so far");
1772 RootContext.EmitCode ();
1773 if (timestamps)
1774 ShowTime (" done");
1776 if (Report.Errors > 0){
1777 return false;
1780 if (timestamps)
1781 ShowTime ("Closing types");
1783 RootContext.CloseTypes ();
1785 PEFileKinds k = PEFileKinds.ConsoleApplication;
1787 switch (RootContext.Target) {
1788 case Target.Library:
1789 case Target.Module:
1790 k = PEFileKinds.Dll; break;
1791 case Target.Exe:
1792 k = PEFileKinds.ConsoleApplication; break;
1793 case Target.WinExe:
1794 k = PEFileKinds.WindowApplication; break;
1797 if (RootContext.NeedsEntryPoint) {
1798 Method ep = RootContext.EntryPoint;
1800 if (ep == null) {
1801 if (RootContext.MainClass != null) {
1802 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1803 if (main_cont == null) {
1804 Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
1805 return false;
1808 if (!(main_cont is ClassOrStruct)) {
1809 Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1810 return false;
1813 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1814 return false;
1817 if (Report.Errors == 0)
1818 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1819 output_file);
1820 return false;
1823 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1824 } else if (RootContext.MainClass != null) {
1825 Report.Error (2017, "Cannot specify -main if building a module or library");
1828 if (embedded_resources != null){
1829 if (RootContext.Target == Target.Module) {
1830 Report.Error (1507, "Cannot link resource file when building a module");
1831 return false;
1834 embedded_resources.Emit ();
1838 // Add Win32 resources
1841 if (win32ResourceFile != null) {
1842 try {
1843 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1844 } catch (ArgumentException) {
1845 Report.RuntimeMissingSupport (Location.Null, "resource embedding ");
1847 } else {
1848 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1851 if (win32IconFile != null) {
1852 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1853 if (define_icon == null) {
1854 Report.RuntimeMissingSupport (Location.Null, "resource embedding");
1855 } else {
1856 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1860 if (Report.Errors > 0)
1861 return false;
1863 CodeGen.Save (output_file, want_debugging_support, Report);
1864 if (timestamps) {
1865 ShowTime ("Saved output");
1866 ShowTotalTime ("Total");
1869 Timer.ShowTimers ();
1871 #if DEBUGME
1872 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1873 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1874 #endif
1875 return (Report.Errors == 0);
1879 class Resources
1881 interface IResource
1883 void Emit ();
1884 string FileName { get; }
1887 class EmbededResource : IResource
1889 static MethodInfo embed_res;
1891 static EmbededResource () {
1892 Type[] argst = new Type [] {
1893 typeof (string), typeof (string), typeof (ResourceAttributes)
1896 embed_res = typeof (AssemblyBuilder).GetMethod (
1897 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1898 null, CallingConventions.Any, argst, null);
1900 if (embed_res == null) {
1901 RootContext.ToplevelTypes.Compiler.Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1905 readonly object[] args;
1907 public EmbededResource (string name, string file, bool isPrivate)
1909 args = new object [3];
1910 args [0] = name;
1911 args [1] = file;
1912 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1915 public void Emit()
1917 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1920 public string FileName {
1921 get {
1922 return (string)args [1];
1927 class LinkedResource : IResource
1929 readonly string file;
1930 readonly string name;
1931 readonly ResourceAttributes attribute;
1933 public LinkedResource (string name, string file, bool isPrivate)
1935 this.name = name;
1936 this.file = file;
1937 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1940 public void Emit ()
1942 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1945 public string FileName {
1946 get {
1947 return file;
1953 IDictionary embedded_resources = new HybridDictionary ();
1954 readonly CompilerContext ctx;
1956 public Resources (CompilerContext ctx)
1958 this.ctx = ctx;
1961 public void Add (bool embeded, string file, string name)
1963 Add (embeded, file, name, false);
1966 public void Add (bool embeded, string file, string name, bool isPrivate)
1968 if (embedded_resources.Contains (name)) {
1969 ctx.Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1970 return;
1972 IResource r = embeded ?
1973 (IResource) new EmbededResource (name, file, isPrivate) :
1974 new LinkedResource (name, file, isPrivate);
1976 embedded_resources.Add (name, r);
1979 public void Emit ()
1981 foreach (IResource r in embedded_resources.Values) {
1982 if (!File.Exists (r.FileName)) {
1983 ctx.Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1984 continue;
1987 r.Emit ();
1993 // This is the only public entry point
1995 public class CompilerCallableEntryPoint : MarshalByRefObject {
1996 public static bool InvokeCompiler (string [] args, TextWriter error)
1998 try {
1999 StreamReportPrinter srp = new StreamReportPrinter (error);
2000 Driver d = Driver.Create (args, true, srp);
2001 if (d == null)
2002 return false;
2004 return d.Compile () && srp.ErrorsCount == 0;
2005 } finally {
2006 Reset ();
2010 public static int[] AllWarningNumbers {
2011 get {
2012 return Report.AllWarnings;
2016 public static void Reset ()
2018 Reset (true);
2021 public static void PartialReset ()
2023 Reset (false);
2026 public static void Reset (bool full_flag)
2028 Driver.Reset ();
2029 RootContext.Reset (full_flag);
2030 Location.Reset ();
2031 TypeManager.Reset ();
2032 PredefinedAttributes.Reset ();
2033 TypeHandle.Reset ();
2035 if (full_flag)
2036 GlobalRootNamespace.Reset ();
2038 NamespaceEntry.Reset ();
2039 CodeGen.Reset ();
2040 Attribute.Reset ();
2041 AttributeTester.Reset ();
2042 AnonymousTypeClass.Reset ();
2043 AnonymousMethodBody.Reset ();
2044 AnonymousMethodStorey.Reset ();
2045 SymbolWriter.Reset ();
2046 Switch.Reset ();
2047 Linq.QueryBlock.TransparentParameter.Reset ();
2048 Convert.Reset ();
2049 TypeInfo.Reset ();
2050 DynamicExpressionStatement.Reset ();