(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / mcs / driver.cs
blob29850d83cb7c171a5854f488274465833e32b516
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
9 //
11 namespace Mono.CSharp
13 using System;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Collections;
17 using System.IO;
18 using System.Text;
19 using System.Globalization;
20 using System.Diagnostics;
22 public enum Target {
23 Library, Exe, Module, WinExe
26 /// <summary>
27 /// The compiler driver.
28 /// </summary>
29 public class Driver
33 // Assemblies references to be linked. Initialized with
34 // mscorlib.dll here.
35 static ArrayList references;
38 // If any of these fail, we ignore the problem. This is so
39 // that we can list all the assemblies in Windows and not fail
40 // if they are missing on Linux.
42 static ArrayList soft_references;
45 // Modules to be linked
47 static ArrayList modules;
49 // Lookup paths
50 static ArrayList link_paths;
52 // Whether we want Yacc to output its progress
53 static bool yacc_verbose = false;
55 // Whether we want to only run the tokenizer
56 static bool tokenize = false;
58 static string first_source;
60 static bool want_debugging_support = false;
62 static bool parse_only = false;
63 static bool timestamps = false;
64 static bool pause = false;
65 static bool show_counters = false;
66 public static bool parser_verbose = false;
69 // Whether to load the initial config file (what CSC.RSP has by default)
70 //
71 static bool load_default_config = true;
73 static Hashtable response_file_list;
76 // A list of resource files
78 static ArrayList resources;
79 static ArrayList embedded_resources;
80 static string win32ResourceFile;
81 static string win32IconFile;
84 // An array of the defines from the command line
86 static ArrayList defines;
89 // Output file
91 static string output_file = null;
94 // Last time we took the time
96 static DateTime last_time, first_time;
99 // Encoding: ISO-Latin1 is 28591
101 static Encoding encoding;
104 // Whether the user has specified a different encoder manually
106 static bool using_default_encoder = true;
108 public static void ShowTime (string msg)
110 if (!timestamps)
111 return;
113 DateTime now = DateTime.Now;
114 TimeSpan span = now - last_time;
115 last_time = now;
117 Console.WriteLine (
118 "[{0:00}:{1:000}] {2}",
119 (int) span.TotalSeconds, span.Milliseconds, msg);
122 public static void ShowTotalTime (string msg)
124 if (!timestamps)
125 return;
127 DateTime now = DateTime.Now;
128 TimeSpan span = now - first_time;
129 last_time = now;
131 Console.WriteLine (
132 "[{0:00}:{1:000}] {2}",
133 (int) span.TotalSeconds, span.Milliseconds, msg);
136 static void tokenize_file (SourceFile file)
138 Stream input;
140 try {
141 input = File.OpenRead (file.Name);
142 } catch {
143 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
144 return;
147 using (input){
148 SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
149 Tokenizer lexer = new Tokenizer (reader, file, defines);
150 int token, tokens = 0, errors = 0;
152 while ((token = lexer.token ()) != Token.EOF){
153 tokens++;
154 if (token == Token.ERROR)
155 errors++;
157 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
160 return;
163 // MonoTODO("Change error code for aborted compilation to something reasonable")]
164 static void parse (SourceFile file)
166 CSharpParser parser;
167 Stream input;
169 try {
170 input = File.OpenRead (file.Name);
171 } catch {
172 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
173 return;
176 SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
178 parser = new CSharpParser (reader, file, defines);
179 parser.yacc_verbose_flag = yacc_verbose;
180 try {
181 parser.parse ();
182 } catch (Exception ex) {
183 Report.Error(666, "Compilation aborted: " + ex);
184 } finally {
185 input.Close ();
189 static void OtherFlags ()
191 Console.WriteLine (
192 "Other flags in the compiler\n" +
193 " --fatal Makes errors fatal\n" +
194 " --parse Only parses the source file\n" +
195 " --stacktrace Shows stack trace at error location\n" +
196 " --timestamp Displays time stamps of various compiler events\n" +
197 " -2 Enables experimental C# features\n" +
198 " -v Verbose parsing (for debugging the parser)\n" +
199 " --mcs-debug X Sets MCS debugging level to X\n");
202 static void Usage ()
204 Console.WriteLine (
205 "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
206 "mcs [options] source-files\n" +
207 " --about About the Mono C# compiler\n" +
208 " -addmodule:MODULE Adds the module to the generated assembly\n" +
209 " -checked[+|-] Set default context to checked\n" +
210 " -codepage:ID Sets code page to the one in ID\n" +
211 " (number, `utf8' or `reset')\n" +
212 " -clscheck[+|-] Disables CLS Compliance verifications" + Environment.NewLine +
213 " -define:S1[;S2] Defines one or more symbols (short: /d:)\n" +
214 " -debug[+|-] Generate debugging information\n" +
215 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
216 " -doc:FILE XML Documentation file to generate\n" +
217 " -g Generate debugging information\n" +
218 " -keycontainer:NAME The key pair container used to strongname the assembly\n" +
219 " -keyfile:FILE The strongname key file used to strongname the assembly\n" +
220 " -langversion:TEXT Specifies language version modes: ISO-1 or Default" + Environment.NewLine +
221 " -lib:PATH1,PATH2 Adds the paths to the assembly link path\n" +
222 " -main:class Specified the class that contains the entry point\n" +
223 " -noconfig[+|-] Disables implicit references to assemblies\n" +
224 " -nostdlib[+|-] Does not load core libraries\n" +
225 " -nowarn:W1[,W2] Disables one or more warnings\n" +
226 " -out:FNAME Specifies output file\n" +
227 " -pkg:P1[,Pn] References packages P1..Pn\n" +
228 " --expect-error X Expect that error X will be encountered\n" +
229 " -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" +
230 " -reference:ASS References the specified assembly (-r:ASS)\n" +
231 " -target:KIND Specifies the target (KIND is one of: exe, winexe,\n" +
232 " library, module), (short: /t:)\n" +
233 " -unsafe[+|-] Allows unsafe code\n" +
234 " -warnaserror[+|-] Treat warnings as errors\n" +
235 " -warn:LEVEL Sets warning level (the highest is 4, the default is 2)\n" +
236 " -help2 Show other help flags\n" +
237 "\n" +
238 "Resources:\n" +
239 " -linkresource:FILE[,ID] Links FILE as a resource\n" +
240 " -resource:FILE[,ID] Embed FILE as a resource\n" +
241 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
242 " -win32icon:FILE Use this icon for the output\n" +
243 " @file Read response file for more options\n\n" +
244 "Options can be of the form -option or /option");
247 static void TargetUsage ()
249 Report.Error (2019, "Valid options for -target: are exe, winexe, library or module");
252 static void About ()
254 Console.WriteLine (
255 "The Mono C# compiler is (C) 2001, 2002, 2003 Ximian, Inc.\n\n" +
256 "The compiler source code is released under the terms of the GNU GPL\n\n" +
258 "For more information on Mono, visit the project Web site\n" +
259 " http://www.go-mono.com\n\n" +
261 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig and Marek Safar");
262 Environment.Exit (0);
265 public static int counter1, counter2;
267 public static int Main (string[] args)
269 bool ok = MainDriver (args);
271 if (ok && Report.Errors == 0) {
272 Console.Write("Compilation succeeded");
273 if (Report.Warnings > 0) {
274 Console.Write(" - {0} warning(s)", Report.Warnings);
276 Console.WriteLine();
277 if (show_counters){
278 Console.WriteLine ("Counter1: " + counter1);
279 Console.WriteLine ("Counter2: " + counter2);
281 if (pause)
282 Console.ReadLine ();
283 return 0;
284 } else {
285 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
286 Report.Errors, Report.Warnings);
287 return 1;
291 static public void LoadAssembly (string assembly, bool soft)
293 Assembly a;
294 string total_log = "";
296 try {
297 char[] path_chars = { '/', '\\' };
299 if (assembly.IndexOfAny (path_chars) != -1) {
300 a = Assembly.LoadFrom (assembly);
301 } else {
302 string ass = assembly;
303 if (ass.EndsWith (".dll"))
304 ass = assembly.Substring (0, assembly.Length - 4);
305 a = Assembly.Load (ass);
307 TypeManager.AddAssembly (a);
309 } catch (FileNotFoundException){
310 foreach (string dir in link_paths){
311 string full_path = Path.Combine (dir, assembly);
312 if (!assembly.EndsWith (".dll"))
313 full_path += ".dll";
315 try {
316 a = Assembly.LoadFrom (full_path);
317 TypeManager.AddAssembly (a);
318 return;
319 } catch (FileNotFoundException ff) {
320 total_log += ff.FusionLog;
321 continue;
324 if (!soft) {
325 Report.Error (6, "Cannot find assembly `" + assembly + "'" );
326 Console.WriteLine ("Log: \n" + total_log);
328 } catch (BadImageFormatException f) {
329 Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
330 } catch (FileLoadException f){
331 Report.Error(6, "Cannot load assembly " + f.FusionLog);
332 } catch (ArgumentNullException){
333 Report.Error(6, "Cannot load assembly (null argument)");
337 static public void LoadModule (MethodInfo adder_method, string module)
339 Module m;
340 string total_log = "";
342 try {
343 try {
344 m = (Module)adder_method.Invoke (CodeGen.Assembly.Builder, new object [] { module });
346 catch (TargetInvocationException ex) {
347 throw ex.InnerException;
349 TypeManager.AddModule (m);
352 catch (FileNotFoundException){
353 foreach (string dir in link_paths){
354 string full_path = Path.Combine (dir, module);
355 if (!module.EndsWith (".netmodule"))
356 full_path += ".netmodule";
358 try {
359 try {
360 m = (Module)adder_method.Invoke (CodeGen.Assembly.Builder, new object [] { full_path });
362 catch (TargetInvocationException ex) {
363 throw ex.InnerException;
365 TypeManager.AddModule (m);
366 return;
367 } catch (FileNotFoundException ff) {
368 total_log += ff.FusionLog;
369 continue;
372 Report.Error (6, "Cannot find module `" + module + "'" );
373 Console.WriteLine ("Log: \n" + total_log);
374 } catch (BadImageFormatException f) {
375 Report.Error(6, "Cannot load module (bad file format)" + f.FusionLog);
376 } catch (FileLoadException f){
377 Report.Error(6, "Cannot load module " + f.FusionLog);
378 } catch (ArgumentNullException){
379 Report.Error(6, "Cannot load module (null argument)");
383 /// <summary>
384 /// Loads all assemblies referenced on the command line
385 /// </summary>
386 static public void LoadReferences ()
388 foreach (string r in references)
389 LoadAssembly (r, false);
391 foreach (string r in soft_references)
392 LoadAssembly (r, true);
394 return;
397 static void SetupDefaultDefines ()
399 defines = new ArrayList ();
400 defines.Add ("__MonoCS__");
403 static string [] LoadArgs (string file)
405 StreamReader f;
406 ArrayList args = new ArrayList ();
407 string line;
408 try {
409 f = new StreamReader (file);
410 } catch {
411 return null;
414 StringBuilder sb = new StringBuilder ();
416 while ((line = f.ReadLine ()) != null){
417 int t = line.Length;
419 for (int i = 0; i < t; i++){
420 char c = line [i];
422 if (c == '"' || c == '\''){
423 char end = c;
425 for (i++; i < t; i++){
426 c = line [i];
428 if (c == end)
429 break;
430 sb.Append (c);
432 } else if (c == ' '){
433 if (sb.Length > 0){
434 args.Add (sb.ToString ());
435 sb.Length = 0;
437 } else
438 sb.Append (c);
440 if (sb.Length > 0){
441 args.Add (sb.ToString ());
442 sb.Length = 0;
446 string [] ret_value = new string [args.Count];
447 args.CopyTo (ret_value, 0);
449 return ret_value;
453 // Returns the directory where the system assemblies are installed
455 static string GetSystemDir ()
457 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
459 foreach (Assembly a in assemblies){
460 string codebase = a.Location;
461 string fn = System.IO.Path.GetFileName (codebase);
462 if (fn == "corlib.dll" || fn == "mscorlib.dll"){
463 return codebase.Substring (0, codebase.LastIndexOf (System.IO.Path.DirectorySeparatorChar));
467 Report.Error (-15, "Can not compute my system path");
468 return "";
472 // Given a path specification, splits the path from the file/pattern
474 static void SplitPathAndPattern (string spec, out string path, out string pattern)
476 int p = spec.LastIndexOf ('/');
477 if (p != -1){
479 // Windows does not like /file.cs, switch that to:
480 // "\", "file.cs"
482 if (p == 0){
483 path = "\\";
484 pattern = spec.Substring (1);
485 } else {
486 path = spec.Substring (0, p);
487 pattern = spec.Substring (p + 1);
489 return;
492 p = spec.LastIndexOf ('\\');
493 if (p != -1){
494 path = spec.Substring (0, p);
495 pattern = spec.Substring (p + 1);
496 return;
499 path = ".";
500 pattern = spec;
503 static void ProcessFile (string f)
505 if (first_source == null)
506 first_source = f;
508 Location.AddFile (f);
511 static void ProcessFiles ()
513 Location.Initialize ();
515 foreach (SourceFile file in Location.SourceFiles) {
516 if (tokenize) {
517 tokenize_file (file);
518 } else {
519 parse (file);
524 static void CompileFiles (string spec, bool recurse)
526 string path, pattern;
528 SplitPathAndPattern (spec, out path, out pattern);
529 if (pattern.IndexOf ('*') == -1){
530 ProcessFile (spec);
531 return;
534 string [] files = null;
535 try {
536 files = Directory.GetFiles (path, pattern);
537 } catch (System.IO.DirectoryNotFoundException) {
538 Report.Error (2001, "Source file `" + spec + "' could not be found");
539 return;
540 } catch (System.IO.IOException){
541 Report.Error (2001, "Source file `" + spec + "' could not be found");
542 return;
544 foreach (string f in files) {
545 ProcessFile (f);
548 if (!recurse)
549 return;
551 string [] dirs = null;
553 try {
554 dirs = Directory.GetDirectories (path);
555 } catch {
558 foreach (string d in dirs) {
560 // Don't include path in this string, as each
561 // directory entry already does
562 CompileFiles (d + "/" + pattern, true);
566 static void DefineDefaultConfig ()
569 // For now the "default config" is harcoded into the compiler
570 // we can move this outside later
572 string [] default_config = {
573 "System",
574 "System.Xml",
575 #if false
577 // Is it worth pre-loading all this stuff?
579 "Accessibility",
580 "System.Configuration.Install",
581 "System.Data",
582 "System.Design",
583 "System.DirectoryServices",
584 "System.Drawing.Design",
585 "System.Drawing",
586 "System.EnterpriseServices",
587 "System.Management",
588 "System.Messaging",
589 "System.Runtime.Remoting",
590 "System.Runtime.Serialization.Formatters.Soap",
591 "System.Security",
592 "System.ServiceProcess",
593 "System.Web",
594 "System.Web.RegularExpressions",
595 "System.Web.Services",
596 "System.Windows.Forms"
597 #endif
600 int p = 0;
601 foreach (string def in default_config)
602 soft_references.Insert (p++, def);
605 static void SetOutputFile (string name)
607 output_file = name;
610 static void SetWarningLevel (string s)
612 int level = 0;
614 try {
615 level = Int32.Parse (s);
616 } catch {
617 Report.Error (
618 1900,
619 "--wlevel requires a value from 0 to 4");
620 Environment.Exit (1);
622 if (level < 0 || level > 4){
623 Report.Error (1900, "Warning level must be 0 to 4");
624 Environment.Exit (1);
626 RootContext.WarningLevel = level;
627 TestWarningConflict ();
630 static void TestWarningConflict ()
632 if (RootContext.WarningLevel == 0 && Report.WarningsAreErrors) {
633 Report.Error (1901, "Conflicting options specified: Warning level 0; Treat warnings as errors");
634 Environment.Exit (1);
638 static void SetupV2 ()
640 RootContext.Version = LanguageVersion.Default;
641 defines.Add ("__V2__");
644 static void Version ()
646 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
647 Console.WriteLine ("Mono C# compiler version {0}", version);
648 Environment.Exit (0);
652 // Currently handles the Unix-like command line options, but will be
653 // deprecated in favor of the CSCParseOption, which will also handle the
654 // options that start with a dash in the future.
656 static bool UnixParseOption (string arg, ref string [] args, ref int i)
658 switch (arg){
659 case "-vv":
660 parser_verbose = true;
661 return true;
663 case "-v":
664 yacc_verbose = true;
665 return true;
667 case "--version":
668 Version ();
669 return true;
671 case "--parse":
672 parse_only = true;
673 return true;
675 case "--main": case "-m":
676 if ((i + 1) >= args.Length){
677 Usage ();
678 Environment.Exit (1);
680 RootContext.MainClass = args [++i];
681 return true;
683 case "--unsafe":
684 RootContext.Unsafe = true;
685 return true;
687 case "/?": case "/h": case "/help":
688 case "--help":
689 Usage ();
690 Environment.Exit (0);
691 return true;
693 case "--define":
694 if ((i + 1) >= args.Length){
695 Usage ();
696 Environment.Exit (1);
698 defines.Add (args [++i]);
699 return true;
701 case "--show-counters":
702 show_counters = true;
703 return true;
705 case "--expect-error": {
706 int code = 0;
708 try {
709 code = Int32.Parse (
710 args [++i], NumberStyles.AllowLeadingSign);
711 Report.ExpectedError = code;
712 } catch {
713 Report.Error (-14, "Invalid number specified");
715 return true;
718 case "--tokenize":
719 tokenize = true;
720 return true;
722 case "-o":
723 case "--output":
724 if ((i + 1) >= args.Length){
725 Usage ();
726 Environment.Exit (1);
728 SetOutputFile (args [++i]);
729 return true;
731 case "--checked":
732 RootContext.Checked = true;
733 return true;
735 case "--stacktrace":
736 Report.Stacktrace = true;
737 return true;
739 case "--linkresource":
740 case "--linkres":
741 if ((i + 1) >= args.Length){
742 Usage ();
743 Report.Error (5, "Missing argument to --linkres");
744 Environment.Exit (1);
746 if (resources == null)
747 resources = new ArrayList ();
749 resources.Add (args [++i]);
750 return true;
752 case "--resource":
753 case "--res":
754 if ((i + 1) >= args.Length){
755 Usage ();
756 Report.Error (5, "Missing argument to --resource");
757 Environment.Exit (1);
759 if (embedded_resources == null)
760 embedded_resources = new ArrayList ();
762 embedded_resources.Add (args [++i]);
763 return true;
765 case "--target":
766 if ((i + 1) >= args.Length){
767 Environment.Exit (1);
768 return true;
771 string type = args [++i];
772 switch (type){
773 case "library":
774 RootContext.Target = Target.Library;
775 RootContext.TargetExt = ".dll";
776 break;
778 case "exe":
779 RootContext.Target = Target.Exe;
780 break;
782 case "winexe":
783 RootContext.Target = Target.WinExe;
784 break;
786 case "module":
787 RootContext.Target = Target.Module;
788 RootContext.TargetExt = ".dll";
789 break;
790 default:
791 TargetUsage ();
792 Environment.Exit (1);
793 break;
795 return true;
797 case "-r":
798 if ((i + 1) >= args.Length){
799 Usage ();
800 Environment.Exit (1);
803 references.Add (args [++i]);
804 return true;
806 case "-L":
807 if ((i + 1) >= args.Length){
808 Usage ();
809 Environment.Exit (1);
811 link_paths.Add (args [++i]);
812 return true;
814 case "--nostdlib":
815 RootContext.StdLib = false;
816 return true;
818 case "--fatal":
819 Report.Fatal = true;
820 return true;
822 case "--werror":
823 Report.WarningsAreErrors = true;
824 TestWarningConflict();
825 return true;
827 case "--nowarn":
828 if ((i + 1) >= args.Length){
829 Usage ();
830 Environment.Exit (1);
832 int warn = 0;
834 try {
835 warn = Int32.Parse (args [++i]);
836 } catch {
837 Usage ();
838 Environment.Exit (1);
840 Report.SetIgnoreWarning (warn);
841 return true;
843 case "--wlevel":
844 if ((i + 1) >= args.Length){
845 Report.Error (
846 1900,
847 "--wlevel requires a value from 0 to 4");
848 Environment.Exit (1);
851 SetWarningLevel (args [++i]);
852 return true;
854 case "--mcs-debug":
855 if ((i + 1) >= args.Length){
856 Report.Error (5, "--mcs-debug requires an argument");
857 Environment.Exit (1);
860 try {
861 Report.DebugFlags = Int32.Parse (args [++i]);
862 } catch {
863 Report.Error (5, "Invalid argument to --mcs-debug");
864 Environment.Exit (1);
866 return true;
868 case "--about":
869 About ();
870 return true;
872 case "--recurse":
873 if ((i + 1) >= args.Length){
874 Report.Error (5, "--recurse requires an argument");
875 Environment.Exit (1);
877 CompileFiles (args [++i], true);
878 return true;
880 case "--timestamp":
881 timestamps = true;
882 last_time = first_time = DateTime.Now;
883 return true;
885 case "--pause":
886 pause = true;
887 return true;
889 case "--debug": case "-g":
890 want_debugging_support = true;
891 return true;
893 case "--noconfig":
894 load_default_config = false;
895 return true;
898 return false;
902 // Currently it is very basic option parsing, but eventually, this will
903 // be the complete option parser
905 static bool CSCParseOption (string option, ref string [] args, ref int i)
907 int idx = option.IndexOf (':');
908 string arg, value;
910 if (idx == -1){
911 arg = option;
912 value = "";
913 } else {
914 arg = option.Substring (0, idx);
916 value = option.Substring (idx + 1);
919 switch (arg){
920 case "/nologo":
921 return true;
923 case "/t":
924 case "/target":
925 switch (value){
926 case "exe":
927 RootContext.Target = Target.Exe;
928 break;
930 case "winexe":
931 RootContext.Target = Target.WinExe;
932 break;
934 case "library":
935 RootContext.Target = Target.Library;
936 RootContext.TargetExt = ".dll";
937 break;
939 case "module":
940 RootContext.Target = Target.Module;
941 RootContext.TargetExt = ".netmodule";
942 break;
944 default:
945 TargetUsage ();
946 Environment.Exit (1);
947 break;
949 return true;
951 case "/out":
952 if (value == ""){
953 Usage ();
954 Environment.Exit (1);
956 SetOutputFile (value);
957 return true;
959 case "/optimize":
960 case "/optimize+":
961 case "/optimize-":
962 case "/incremental":
963 case "/incremental+":
964 case "/incremental-":
965 // nothing.
966 return true;
968 case "/d":
969 case "/define": {
970 string [] defs;
972 if (value == ""){
973 Usage ();
974 Environment.Exit (1);
977 defs = value.Split (new Char [] {';', ','});
978 foreach (string d in defs){
979 defines.Add (d);
981 return true;
984 case "/linkres":
985 case "/linkresource":
986 if (value == ""){
987 Report.Error (5, arg + " requires an argument");
988 Environment.Exit (1);
990 if (resources == null)
991 resources = new ArrayList ();
993 resources.Add (value);
994 return true;
996 case "/pkg": {
997 string packages;
999 if (value == ""){
1000 Usage ();
1001 Environment.Exit (1);
1003 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1005 ProcessStartInfo pi = new ProcessStartInfo ();
1006 pi.FileName = "pkg-config";
1007 pi.RedirectStandardOutput = true;
1008 pi.UseShellExecute = false;
1009 pi.Arguments = "--libs " + packages;
1010 Process p = null;
1011 try {
1012 p = Process.Start (pi);
1013 } catch (Exception e) {
1014 Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1015 Environment.Exit (1);
1018 if (p.StandardOutput == null){
1019 Report.Warning (-27, "Specified package did not return any information");
1020 return true;
1022 string pkgout = p.StandardOutput.ReadToEnd ();
1023 p.WaitForExit ();
1024 if (p.ExitCode != 0) {
1025 Report.Error (-27, "Error running pkg-config. Check the above output.");
1026 Environment.Exit (1);
1029 if (pkgout != null){
1030 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1031 Split (new Char [] { ' ', '\t'});
1032 args = AddArgs (args, xargs);
1035 p.Close ();
1036 return true;
1039 case "/res":
1040 case "/resource":
1041 if (value == ""){
1042 Report.Error (5, "-resource requires an argument");
1043 Environment.Exit (1);
1045 if (embedded_resources == null)
1046 embedded_resources = new ArrayList ();
1048 if (embedded_resources.Contains (value)) {
1049 Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
1051 else if (value.IndexOf (',') != -1 && embedded_resources.Contains (value.Split (',')[1])) {
1052 Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
1054 else {
1055 embedded_resources.Add (value);
1057 return true;
1059 case "/recurse":
1060 if (value == ""){
1061 Report.Error (5, "-recurse requires an argument");
1062 Environment.Exit (1);
1064 CompileFiles (value, true);
1065 return true;
1067 case "/r":
1068 case "/reference": {
1069 if (value == ""){
1070 Report.Error (5, "-reference requires an argument");
1071 Environment.Exit (1);
1074 string [] refs = value.Split (new char [] { ';', ',' });
1075 foreach (string r in refs){
1076 references.Add (r);
1078 return true;
1080 case "/addmodule": {
1081 if (value == ""){
1082 Report.Error (5, arg + " requires an argument");
1083 Environment.Exit (1);
1086 string [] refs = value.Split (new char [] { ';', ',' });
1087 foreach (string r in refs){
1088 modules.Add (r);
1090 return true;
1092 case "/win32res": {
1093 if (value == "") {
1094 Report.Error (5, arg + " requires an argument");
1095 Environment.Exit (1);
1098 win32ResourceFile = value;
1099 return true;
1101 case "/win32icon": {
1102 if (value == "") {
1103 Report.Error (5, arg + " requires an argument");
1104 Environment.Exit (1);
1107 win32IconFile = value;
1108 return true;
1110 case "/doc": {
1111 if (value == ""){
1112 Report.Error (5, arg + " requires an argument");
1113 Environment.Exit (1);
1115 // TODO handle the /doc argument to generate xml doc
1116 return true;
1118 case "/lib": {
1119 string [] libdirs;
1121 if (value == ""){
1122 Report.Error (5, "/lib requires an argument");
1123 Environment.Exit (1);
1126 libdirs = value.Split (new Char [] { ',' });
1127 foreach (string dir in libdirs)
1128 link_paths.Add (dir);
1129 return true;
1132 case "/debug-":
1133 want_debugging_support = false;
1134 return true;
1136 case "/debug":
1137 case "/debug+":
1138 want_debugging_support = true;
1139 return true;
1141 case "/checked":
1142 case "/checked+":
1143 RootContext.Checked = true;
1144 return true;
1146 case "/checked-":
1147 RootContext.Checked = false;
1148 return true;
1150 case "/clscheck":
1151 case "/clscheck+":
1152 return true;
1154 case "/clscheck-":
1155 RootContext.VerifyClsCompliance = false;
1156 return true;
1158 case "/unsafe":
1159 case "/unsafe+":
1160 RootContext.Unsafe = true;
1161 return true;
1163 case "/unsafe-":
1164 RootContext.Unsafe = false;
1165 return true;
1167 case "/warnaserror":
1168 case "/warnaserror+":
1169 Report.WarningsAreErrors = true;
1170 TestWarningConflict();
1171 return true;
1173 case "/warnaserror-":
1174 Report.WarningsAreErrors = false;
1175 return true;
1177 case "/warn":
1178 SetWarningLevel (value);
1179 return true;
1181 case "/nowarn": {
1182 string [] warns;
1184 if (value == ""){
1185 Report.Error (5, "/nowarn requires an argument");
1186 Environment.Exit (1);
1189 warns = value.Split (new Char [] {','});
1190 foreach (string wc in warns){
1191 try {
1192 int warn = Int32.Parse (wc);
1193 if (warn < 1) {
1194 throw new ArgumentOutOfRangeException("warn");
1196 Report.SetIgnoreWarning (warn);
1197 } catch {
1198 Report.Error (1904, String.Format("'{0}' is not a valid warning number", wc));
1199 Environment.Exit (1);
1202 return true;
1205 case "/noconfig-":
1206 load_default_config = true;
1207 return true;
1209 case "/noconfig":
1210 case "/noconfig+":
1211 load_default_config = false;
1212 return true;
1214 case "/help2":
1215 OtherFlags ();
1216 Environment.Exit(0);
1217 return true;
1219 case "/help":
1220 case "/?":
1221 Usage ();
1222 Environment.Exit (0);
1223 return true;
1225 case "/main":
1226 case "/m":
1227 if (value == ""){
1228 Report.Error (5, arg + " requires an argument");
1229 Environment.Exit (1);
1231 RootContext.MainClass = value;
1232 return true;
1234 case "/nostdlib":
1235 case "/nostdlib+":
1236 RootContext.StdLib = false;
1237 return true;
1239 case "/nostdlib-":
1240 RootContext.StdLib = true;
1241 return true;
1243 case "/fullpaths":
1244 return true;
1246 case "/keyfile":
1247 if (value == String.Empty) {
1248 Report.Error (5, arg + " requires an argument");
1249 Environment.Exit (1);
1251 RootContext.StrongNameKeyFile = value;
1252 return true;
1253 case "/keycontainer":
1254 if (value == String.Empty) {
1255 Report.Error (5, arg + " requires an argument");
1256 Environment.Exit (1);
1258 RootContext.StrongNameKeyContainer = value;
1259 return true;
1260 case "/delaysign+":
1261 RootContext.StrongNameDelaySign = true;
1262 return true;
1263 case "/delaysign-":
1264 RootContext.StrongNameDelaySign = false;
1265 return true;
1267 case "/v2":
1268 case "/2":
1269 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1270 SetupV2 ();
1271 return true;
1273 case "/langversion":
1274 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1275 case "iso-1":
1276 RootContext.Version = LanguageVersion.ISO_1;
1277 return true;
1279 case "default":
1280 SetupV2 ();
1281 return true;
1283 Report.Error (1617, "Invalid option '{0}' for /langversion; must be ISO-1 or Default", value);
1284 Environment.Exit (1);
1285 return false;
1287 case "/codepage":
1288 int cp = -1;
1290 if (value == "utf8"){
1291 encoding = new UTF8Encoding();
1292 using_default_encoder = false;
1293 return true;
1295 if (value == "reset"){
1297 // 28591 is the code page for ISO-8859-1 encoding.
1299 cp = 28591;
1300 using_default_encoder = true;
1303 try {
1304 cp = Int32.Parse (value);
1305 encoding = Encoding.GetEncoding (cp);
1306 using_default_encoder = false;
1307 } catch {
1308 Report.Error (2016, String.Format("Code page '{0}' is invalid or not installed", cp));
1309 Environment.Exit (1);
1311 return true;
1314 //Report.Error (2007, String.Format ("Unrecognized command-line option: '{0}'", option));
1315 //Environment.Exit (1);
1316 return false;
1319 static string [] AddArgs (string [] args, string [] extra_args)
1321 string [] new_args;
1323 new_args = new string [extra_args.Length + args.Length];
1324 args.CopyTo (new_args, 0);
1325 extra_args.CopyTo (new_args, args.Length);
1327 return new_args;
1330 /// <summary>
1331 /// Parses the arguments, and drives the compilation
1332 /// process.
1333 /// </summary>
1335 /// <remarks>
1336 /// TODO: Mostly structured to debug the compiler
1337 /// now, needs to be turned into a real driver soon.
1338 /// </remarks>
1339 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1340 internal static bool MainDriver (string [] args)
1342 int i;
1343 bool parsing_options = true;
1345 try {
1346 encoding = Encoding.GetEncoding (28591);
1347 } catch {
1348 Console.WriteLine ("Error: could not load encoding 28591, trying 1252");
1349 encoding = Encoding.GetEncoding (1252);
1352 references = new ArrayList ();
1353 soft_references = new ArrayList ();
1354 modules = new ArrayList ();
1355 link_paths = new ArrayList ();
1357 SetupDefaultDefines ();
1360 // Setup defaults
1362 // This is not required because Assembly.Load knows about this
1363 // path.
1366 for (i = 0; i < args.Length; i++){
1367 string arg = args [i];
1368 if (arg == "")
1369 continue;
1371 if (arg.StartsWith ("@")){
1372 string [] extra_args;
1373 string response_file = arg.Substring (1);
1375 if (response_file_list == null)
1376 response_file_list = new Hashtable ();
1378 if (response_file_list.Contains (response_file)){
1379 Report.Error (
1380 1515, "Response file `" + response_file +
1381 "' specified multiple times");
1382 Environment.Exit (1);
1385 response_file_list.Add (response_file, response_file);
1387 extra_args = LoadArgs (response_file);
1388 if (extra_args == null){
1389 Report.Error (2011, "Unable to open response file: " +
1390 response_file);
1391 return false;
1394 args = AddArgs (args, extra_args);
1395 continue;
1398 if (parsing_options){
1399 if (arg == "--"){
1400 parsing_options = false;
1401 continue;
1404 if (arg.StartsWith ("-")){
1405 if (UnixParseOption (arg, ref args, ref i))
1406 continue;
1408 // Try a -CSCOPTION
1409 string csc_opt = "/" + arg.Substring (1);
1410 if (CSCParseOption (csc_opt, ref args, ref i))
1411 continue;
1412 } else {
1413 if (arg.StartsWith ("/")){
1414 if (CSCParseOption (arg, ref args, ref i))
1415 continue;
1420 CompileFiles (arg, false);
1423 ProcessFiles ();
1425 if (tokenize)
1426 return true;
1429 // If we are an exe, require a source file for the entry point
1431 if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe){
1432 if (first_source == null){
1433 Report.Error (2008, "No files to compile were specified");
1434 return false;
1440 // If there is nothing to put in the assembly, and we are not a library
1442 if (first_source == null && embedded_resources == null && resources == null){
1443 Report.Error (2008, "No files to compile were specified");
1444 return false;
1447 if (Report.Errors > 0)
1448 return false;
1450 if (parse_only)
1451 return true;
1453 Tokenizer.Cleanup ();
1456 // Load Core Library for default compilation
1458 if (RootContext.StdLib)
1459 references.Insert (0, "mscorlib");
1461 if (load_default_config)
1462 DefineDefaultConfig ();
1464 if (Report.Errors > 0){
1465 return false;
1469 // Load assemblies required
1471 if (timestamps)
1472 ShowTime ("Loading references");
1473 link_paths.Add (GetSystemDir ());
1474 link_paths.Add (Directory.GetCurrentDirectory ());
1475 LoadReferences ();
1477 if (timestamps)
1478 ShowTime (" References loaded");
1480 if (Report.Errors > 0){
1481 return false;
1485 // Quick hack
1487 if (output_file == null){
1488 int pos = first_source.LastIndexOf ('.');
1490 if (pos > 0)
1491 output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1492 else
1493 output_file = first_source + RootContext.TargetExt;
1496 CodeGen.Init (output_file, output_file, want_debugging_support);
1498 if (RootContext.Target == Target.Module) {
1499 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1500 if (module_only == null) {
1501 Report.Error (0, new Location (-1), "Cannot use /target:module on this runtime: try the Mono runtime instead.");
1502 Environment.Exit (1);
1505 MethodInfo set_method = module_only.GetSetMethod (true);
1506 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1509 TypeManager.AddModule (CodeGen.Module.Builder);
1511 if (modules.Count > 0) {
1512 MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1513 if (adder_method == null) {
1514 Report.Error (0, new Location (-1), "Cannot use /addmodule on this runtime: Try the Mono runtime instead.");
1515 Environment.Exit (1);
1518 foreach (string module in modules)
1519 LoadModule (adder_method, module);
1522 TypeManager.ComputeNamespaces ();
1525 // Before emitting, we need to get the core
1526 // types emitted from the user defined types
1527 // or from the system ones.
1529 if (timestamps)
1530 ShowTime ("Initializing Core Types");
1531 if (!RootContext.StdLib){
1532 RootContext.ResolveCore ();
1533 if (Report.Errors > 0)
1534 return false;
1537 TypeManager.InitCoreTypes ();
1538 if (timestamps)
1539 ShowTime (" Core Types done");
1542 // The second pass of the compiler
1544 if (timestamps)
1545 ShowTime ("Resolving tree");
1546 RootContext.ResolveTree ();
1547 if (Report.Errors > 0)
1548 return false;
1549 if (timestamps)
1550 ShowTime ("Populate tree");
1551 if (!RootContext.StdLib)
1552 RootContext.BootCorlib_PopulateCoreTypes ();
1554 RootContext.PopulateTypes ();
1555 RootContext.DefineTypes ();
1557 TypeManager.InitCodeHelpers ();
1560 // Verify using aliases now
1562 Namespace.VerifyUsing ();
1564 if (Report.Errors > 0){
1565 return false;
1568 if (RootContext.VerifyClsCompliance) {
1569 CodeGen.Assembly.ResolveClsCompliance ();
1570 if (CodeGen.Assembly.IsClsCompliant) {
1571 AttributeTester.VerifyModulesClsCompliance ();
1572 TypeManager.LoadAllImportedTypes ();
1573 AttributeTester.VerifyTopLevelNameClsCompliance ();
1578 // The code generator
1580 if (timestamps)
1581 ShowTime ("Emitting code");
1582 ShowTotalTime ("Total so far");
1583 RootContext.EmitCode ();
1584 if (timestamps)
1585 ShowTime (" done");
1587 if (Report.Errors > 0){
1588 return false;
1591 if (timestamps)
1592 ShowTime ("Closing types");
1594 RootContext.CloseTypes ();
1596 PEFileKinds k = PEFileKinds.ConsoleApplication;
1598 switch (RootContext.Target) {
1599 case Target.Library:
1600 case Target.Module:
1601 k = PEFileKinds.Dll; break;
1602 case Target.Exe:
1603 k = PEFileKinds.ConsoleApplication; break;
1604 case Target.WinExe:
1605 k = PEFileKinds.WindowApplication; break;
1608 if (RootContext.NeedsEntryPoint) {
1609 MethodInfo ep = RootContext.EntryPoint;
1611 if (ep == null) {
1612 if (RootContext.MainClass != null) {
1613 object main_cont = RootContext.Tree.Decls [RootContext.MainClass];
1614 if (main_cont == null) {
1615 Report.Error (1555, output_file, "Could not find '{0}' specified for Main method", RootContext.MainClass);
1616 return false;
1619 if (!(main_cont is ClassOrStruct)) {
1620 Report.Error (1556, output_file, "'{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1621 return false;
1625 if (Report.Errors == 0)
1626 Report.Error (5001, "Program " + output_file +
1627 " does not have an entry point defined");
1628 return false;
1631 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1632 } else if (RootContext.MainClass != null) {
1633 Report.Error (2017, "Can not specify -main: when building module or library");
1637 // Add the resources
1639 if (resources != null){
1640 foreach (string spec in resources){
1641 string file, res;
1642 int cp;
1644 cp = spec.IndexOf (',');
1645 if (cp != -1){
1646 file = spec.Substring (0, cp);
1647 res = spec.Substring (cp + 1);
1648 } else
1649 file = res = spec;
1651 CodeGen.Assembly.Builder.AddResourceFile (res, file);
1655 if (embedded_resources != null){
1656 object[] margs = new object [2];
1657 Type[] argst = new Type [2];
1658 argst [0] = argst [1] = typeof (string);
1660 MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod (
1661 "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1662 null, CallingConventions.Any, argst, null);
1664 if (embed_res == null) {
1665 Report.Warning (0, new Location (-1),
1666 "Cannot embed resources on this runtime: try the Mono runtime instead.");
1667 } else {
1668 foreach (string spec in embedded_resources) {
1669 int cp;
1671 cp = spec.IndexOf (',');
1672 if (cp != -1){
1673 margs [0] = spec.Substring (cp + 1);
1674 margs [1] = spec.Substring (0, cp);
1675 } else {
1676 margs [1] = spec;
1677 margs [0] = Path.GetFileName (spec);
1680 if (File.Exists ((string) margs [1]))
1681 embed_res.Invoke (CodeGen.Assembly.Builder, margs);
1682 else {
1683 Report.Error (1566, "Can not find the resource " + margs [1]);
1690 // Add Win32 resources
1693 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1695 if (win32ResourceFile != null) {
1696 try {
1697 CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1699 catch (ArgumentException) {
1700 Report.Warning (0, new Location (-1), "Cannot embed win32 resources on this runtime: try the Mono runtime instead.");
1704 if (win32IconFile != null) {
1705 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1706 if (define_icon == null) {
1707 Report.Warning (0, new Location (-1), "Cannot embed icon resource on this runtime: try the Mono runtime instead.");
1709 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1712 if (Report.Errors > 0)
1713 return false;
1715 CodeGen.Save (output_file);
1716 if (timestamps) {
1717 ShowTime ("Saved output");
1718 ShowTotalTime ("Total");
1721 Timer.ShowTimers ();
1723 if (Report.ExpectedError != 0) {
1724 if (Report.Errors == 0) {
1725 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1726 "No other errors reported.");
1728 Environment.Exit (2);
1729 } else {
1730 Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1731 "However, other errors were reported.");
1733 Environment.Exit (1);
1737 return false;
1740 #if DEBUGME
1741 Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1742 Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1743 #endif
1744 return (Report.Errors == 0);
1750 // This is the only public entry point
1752 public class CompilerCallableEntryPoint : MarshalByRefObject {
1753 static bool used = false;
1755 public bool InvokeCompiler (string [] args)
1757 if (used)
1758 Reset ();
1759 bool ok = Driver.MainDriver (args);
1760 return ok && Report.Errors == 0;
1763 public void Reset ()