[mcs] Fixes runtimemetadataversion option check
[mono-project.git] / mcs / mcs / settings.cs
blobc9725226126b5cee3e40327e62cd6d57211ba99d
1 //
2 // settings.cs: All compiler settings
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 // Ravi Pratap (ravi@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 //
9 // Dual licensed under the terms of the MIT X11 or GNU GPL
11 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
12 // Copyright 2004-2008 Novell, Inc
13 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
16 using System.Collections.Generic;
17 using System.IO;
18 using System.Text;
19 using System.Globalization;
20 using System;
22 namespace Mono.CSharp {
24 public enum LanguageVersion
26 ISO_1 = 1,
27 ISO_2 = 2,
28 V_3 = 3,
29 V_4 = 4,
30 V_5 = 5,
31 V_6 = 6,
32 Experimental = 100,
34 Default = LanguageVersion.V_6,
37 public enum RuntimeVersion
39 v1,
40 v2,
44 public enum Target
46 Library, Exe, Module, WinExe
49 public enum Platform
51 AnyCPU,
52 AnyCPU32Preferred,
53 Arm,
54 X86,
55 X64,
56 IA64
59 public class CompilerSettings
61 public Target Target;
62 public Platform Platform;
63 public string TargetExt;
64 public bool VerifyClsCompliance;
65 public bool Optimize;
66 public LanguageVersion Version;
67 public bool EnhancedWarnings;
68 public bool LoadDefaultReferences;
69 public string SdkVersion;
71 public string StrongNameKeyFile;
72 public string StrongNameKeyContainer;
73 public bool StrongNameDelaySign;
75 public int TabSize;
77 public bool WarningsAreErrors;
78 public int WarningLevel;
81 // Assemblies references to be loaded
83 public List<string> AssemblyReferences;
85 //
86 // External aliases for assemblies
88 public List<Tuple<string, string>> AssemblyReferencesAliases;
91 // Modules to be embedded
93 public List<string> Modules;
96 // Lookup paths for referenced assemblies
98 public List<string> ReferencesLookupPaths;
101 // Encoding.
103 public Encoding Encoding;
106 // If set, enable XML documentation generation
108 public string DocumentationFile;
110 public string MainClass;
113 // Output file
115 public string OutputFile;
118 // The default compiler checked state
120 public bool Checked;
123 // If true, the compiler is operating in statement mode,
124 // this currently turns local variable declaration into
125 // static variables of a class
127 public bool StatementMode; // TODO: SUPER UGLY
130 // Whether to allow Unsafe code
132 public bool Unsafe;
134 public string Win32ResourceFile;
135 public string Win32IconFile;
138 // A list of resource files for embedding
140 public List<AssemblyResource> Resources;
142 public bool GenerateDebugInfo;
144 #region Compiler debug flags only
145 public bool ParseOnly, TokenizeOnly, Timestamps;
146 public int DebugFlags;
147 public int VerboseParserFlag;
148 public int FatalCounter;
149 public bool Stacktrace;
150 public bool BreakOnInternalError;
151 #endregion
153 public List<string> GetResourceStrings;
155 public bool ShowFullPaths;
158 // Whether we are being linked against the standard libraries.
159 // This is only used to tell whether `System.Object' should
160 // have a base class or not.
162 public bool StdLib;
164 public RuntimeVersion StdLibRuntimeVersion;
166 public string RuntimeMetadataVersion;
168 public bool WriteMetadataOnly;
170 readonly List<string> conditional_symbols;
172 readonly List<SourceFile> source_files;
174 List<int> warnings_as_error;
175 List<int> warnings_only;
176 HashSet<int> warning_ignore_table;
178 public CompilerSettings ()
180 StdLib = true;
181 Target = Target.Exe;
182 TargetExt = ".exe";
183 Platform = Platform.AnyCPU;
184 Version = LanguageVersion.Default;
185 VerifyClsCompliance = true;
186 Encoding = Encoding.UTF8;
187 LoadDefaultReferences = true;
188 StdLibRuntimeVersion = RuntimeVersion.v4;
189 WarningLevel = 4;
191 // Default to 1 or mdb files would be platform speficic
192 TabSize = 1;
194 AssemblyReferences = new List<string> ();
195 AssemblyReferencesAliases = new List<Tuple<string, string>> ();
196 Modules = new List<string> ();
197 ReferencesLookupPaths = new List<string> ();
199 conditional_symbols = new List<string> ();
201 // Add default mcs define
203 conditional_symbols.Add ("__MonoCS__");
205 source_files = new List<SourceFile> ();
208 #region Properties
210 public SourceFile FirstSourceFile {
211 get {
212 return source_files.Count > 0 ? source_files [0] : null;
216 public bool HasKeyFileOrContainer {
217 get {
218 return StrongNameKeyFile != null || StrongNameKeyContainer != null;
222 public bool NeedsEntryPoint {
223 get {
224 return Target == Target.Exe || Target == Target.WinExe;
228 public List<SourceFile> SourceFiles {
229 get {
230 return source_files;
234 #endregion
236 public void AddConditionalSymbol (string symbol)
238 if (!conditional_symbols.Contains (symbol))
239 conditional_symbols.Add (symbol);
242 public void AddWarningAsError (int id)
244 if (warnings_as_error == null)
245 warnings_as_error = new List<int> ();
247 warnings_as_error.Add (id);
250 public void AddWarningOnly (int id)
252 if (warnings_only == null)
253 warnings_only = new List<int> ();
255 warnings_only.Add (id);
258 public bool IsConditionalSymbolDefined (string symbol)
260 return conditional_symbols.Contains (symbol);
263 public bool IsWarningAsError (int code)
265 bool is_error = WarningsAreErrors;
267 // Check specific list
268 if (warnings_as_error != null)
269 is_error |= warnings_as_error.Contains (code);
271 // Ignore excluded warnings
272 if (warnings_only != null && warnings_only.Contains (code))
273 is_error = false;
275 return is_error;
278 public bool IsWarningEnabled (int code, int level)
280 if (WarningLevel < level)
281 return false;
283 return !IsWarningDisabledGlobally (code);
286 public bool IsWarningDisabledGlobally (int code)
288 return warning_ignore_table != null && warning_ignore_table.Contains (code);
291 public void SetIgnoreWarning (int code)
293 if (warning_ignore_table == null)
294 warning_ignore_table = new HashSet<int> ();
296 warning_ignore_table.Add (code);
300 public class CommandLineParser
302 enum ParseResult
304 Success,
305 Error,
306 Stop,
307 UnknownOption
310 static readonly char[] argument_value_separator = { ';', ',' };
311 static readonly char[] numeric_value_separator = { ';', ',', ' ' };
313 readonly TextWriter output;
314 readonly Report report;
315 bool stop_argument;
317 Dictionary<string, int> source_file_index;
319 public event Func<string[], int, int> UnknownOptionHandler;
321 CompilerSettings parser_settings;
323 public CommandLineParser (TextWriter errorOutput)
324 : this (errorOutput, Console.Out)
328 public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
330 var rp = new StreamReportPrinter (errorOutput);
332 parser_settings = new CompilerSettings ();
333 report = new Report (new CompilerContext (parser_settings, rp), rp);
334 this.output = messagesOutput;
337 public bool HasBeenStopped {
338 get {
339 return stop_argument;
343 void About ()
345 output.WriteLine (
346 "The Mono C# compiler is Copyright 2001-2011, Novell, Inc.\n\n" +
347 "The compiler source code is released under the terms of the \n" +
348 "MIT X11 or GNU GPL licenses\n\n" +
350 "For more information on Mono, visit the project Web site\n" +
351 " http://www.mono-project.com\n\n" +
353 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
356 public CompilerSettings ParseArguments (string[] args)
358 CompilerSettings settings = new CompilerSettings ();
359 if (!ParseArguments (settings, args))
360 return null;
362 return settings;
365 public bool ParseArguments (CompilerSettings settings, string[] args)
367 if (settings == null)
368 throw new ArgumentNullException ("settings");
370 List<string> response_file_list = null;
371 bool parsing_options = true;
372 stop_argument = false;
373 source_file_index = new Dictionary<string, int> ();
375 for (int i = 0; i < args.Length; i++) {
376 string arg = args[i];
377 if (arg.Length == 0)
378 continue;
380 if (arg[0] == '@') {
381 string[] extra_args;
382 string response_file = arg.Substring (1);
384 if (response_file_list == null)
385 response_file_list = new List<string> ();
387 if (response_file_list.Contains (response_file)) {
388 report.Error (1515, "Response file `{0}' specified multiple times", response_file);
389 return false;
392 response_file_list.Add (response_file);
394 extra_args = LoadArgs (response_file);
395 if (extra_args == null) {
396 report.Error (2011, "Unable to open response file: " + response_file);
397 return false;
400 args = AddArgs (args, extra_args);
401 continue;
404 if (parsing_options) {
405 if (arg == "--") {
406 parsing_options = false;
407 continue;
410 bool dash_opt = arg[0] == '-';
411 bool slash_opt = arg[0] == '/';
412 if (dash_opt) {
413 switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
414 case ParseResult.Error:
415 case ParseResult.Success:
416 continue;
417 case ParseResult.Stop:
418 stop_argument = true;
419 return true;
420 case ParseResult.UnknownOption:
421 if (UnknownOptionHandler != null) {
422 var ret = UnknownOptionHandler (args, i);
423 if (ret != -1) {
424 i = ret;
425 continue;
428 break;
432 if (dash_opt || slash_opt) {
433 // Try a -CSCOPTION
434 string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
435 switch (ParseOption (csc_opt, ref args, settings)) {
436 case ParseResult.Error:
437 case ParseResult.Success:
438 continue;
439 case ParseResult.UnknownOption:
440 // Need to skip `/home/test.cs' however /test.cs is considered as error
441 if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
442 break;
444 if (UnknownOptionHandler != null) {
445 var ret = UnknownOptionHandler (args, i);
446 if (ret != -1) {
447 i = ret;
448 continue;
452 Error_WrongOption (arg);
453 return false;
455 case ParseResult.Stop:
456 stop_argument = true;
457 return true;
462 ProcessSourceFiles (arg, false, settings.SourceFiles);
465 return report.Errors == 0;
468 void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
470 string path, pattern;
472 SplitPathAndPattern (spec, out path, out pattern);
473 if (pattern.IndexOf ('*') == -1) {
474 AddSourceFile (spec, sourceFiles);
475 return;
478 string[] files;
479 try {
480 files = Directory.GetFiles (path, pattern);
481 } catch (System.IO.DirectoryNotFoundException) {
482 report.Error (2001, "Source file `" + spec + "' could not be found");
483 return;
484 } catch (System.IO.IOException) {
485 report.Error (2001, "Source file `" + spec + "' could not be found");
486 return;
488 foreach (string f in files) {
489 AddSourceFile (f, sourceFiles);
492 if (!recurse)
493 return;
495 string[] dirs = null;
497 try {
498 dirs = Directory.GetDirectories (path);
499 } catch {
502 foreach (string d in dirs) {
504 // Don't include path in this string, as each
505 // directory entry already does
506 ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
510 static string[] AddArgs (string[] args, string[] extra_args)
512 string[] new_args;
513 new_args = new string[extra_args.Length + args.Length];
515 // if args contains '--' we have to take that into account
516 // split args into first half and second half based on '--'
517 // and add the extra_args before --
518 int split_position = Array.IndexOf (args, "--");
519 if (split_position != -1) {
520 Array.Copy (args, new_args, split_position);
521 extra_args.CopyTo (new_args, split_position);
522 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
523 } else {
524 args.CopyTo (new_args, 0);
525 extra_args.CopyTo (new_args, args.Length);
528 return new_args;
531 void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
533 if (assembly.Length == 0) {
534 report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
535 return;
538 if (!IsExternAliasValid (alias)) {
539 report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
540 return;
543 settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
546 void AddResource (AssemblyResource res, CompilerSettings settings)
548 if (settings.Resources == null) {
549 settings.Resources = new List<AssemblyResource> ();
550 settings.Resources.Add (res);
551 return;
554 if (settings.Resources.Contains (res)) {
555 report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
556 return;
559 settings.Resources.Add (res);
562 void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
564 string path = Path.GetFullPath (fileName);
566 int index;
567 if (source_file_index.TryGetValue (path, out index)) {
568 string other_name = sourceFiles[index - 1].Name;
569 if (fileName.Equals (other_name))
570 report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
571 else
572 report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
574 return;
577 var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
578 sourceFiles.Add (unit);
579 source_file_index.Add (path, unit.Index);
582 public bool ProcessWarningsList (string text, Action<int> action)
584 foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
585 var warning = wid;
586 if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
587 warning = warning.Substring (2);
589 int id;
590 if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
591 continue;
594 action (id);
597 return true;
600 void Error_RequiresArgument (string option)
602 report.Error (2006, "Missing argument for `{0}' option", option);
605 void Error_RequiresFileName (string option)
607 report.Error (2005, "Missing file specification for `{0}' option", option);
610 void Error_WrongOption (string option)
612 report.Error (2007, "Unrecognized command-line option: `{0}'", option);
615 static bool IsExternAliasValid (string identifier)
617 return Tokenizer.IsValidIdentifier (identifier);
620 static string[] LoadArgs (string file)
622 StreamReader f;
623 var args = new List<string> ();
624 string line;
625 try {
626 f = new StreamReader (file);
627 } catch {
628 return null;
631 StringBuilder sb = new StringBuilder ();
633 while ((line = f.ReadLine ()) != null) {
634 int t = line.Length;
636 for (int i = 0; i < t; i++) {
637 char c = line[i];
639 if (c == '"' || c == '\'') {
640 char end = c;
642 for (i++; i < t; i++) {
643 c = line[i];
645 if (c == end)
646 break;
647 sb.Append (c);
649 } else if (c == ' ') {
650 if (sb.Length > 0) {
651 args.Add (sb.ToString ());
652 sb.Length = 0;
654 } else
655 sb.Append (c);
657 if (sb.Length > 0) {
658 args.Add (sb.ToString ());
659 sb.Length = 0;
663 return args.ToArray ();
666 void OtherFlags ()
668 output.WriteLine (
669 "Other flags in the compiler\n" +
670 " --fatal[=COUNT] Makes error after COUNT fatal\n" +
671 " --lint Enhanced warnings\n" +
672 " --metadata-only Produced assembly will contain metadata only\n" +
673 " --parse Only parses the source file\n" +
674 " --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
675 " --stacktrace Shows stack trace at error location\n" +
676 " --timestamp Displays time stamps of various compiler events\n" +
677 " -v Verbose parsing (for debugging the parser)\n" +
678 " --mcs-debug X Sets MCS debugging level to X\n" +
679 " --break-on-ice Breaks compilation on internal compiler error");
683 // This parses the -arg and /arg options to the compiler, even if the strings
684 // in the following text use "/arg" on the strings.
686 ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
688 int idx = option.IndexOf (':');
689 string arg, value;
691 if (idx == -1) {
692 arg = option;
693 value = "";
694 } else {
695 arg = option.Substring (0, idx);
697 value = option.Substring (idx + 1);
700 switch (arg.ToLowerInvariant ()) {
701 case "/nologo":
702 return ParseResult.Success;
704 case "/t":
705 case "/target":
706 switch (value) {
707 case "exe":
708 settings.Target = Target.Exe;
709 break;
711 case "winexe":
712 settings.Target = Target.WinExe;
713 break;
715 case "library":
716 settings.Target = Target.Library;
717 settings.TargetExt = ".dll";
718 break;
720 case "module":
721 settings.Target = Target.Module;
722 settings.TargetExt = ".netmodule";
723 break;
725 default:
726 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
727 return ParseResult.Error;
729 return ParseResult.Success;
731 case "/out":
732 if (value.Length == 0) {
733 Error_RequiresFileName (option);
734 return ParseResult.Error;
736 settings.OutputFile = value;
737 return ParseResult.Success;
739 case "/o":
740 case "/o+":
741 case "/optimize":
742 case "/optimize+":
743 settings.Optimize = true;
744 return ParseResult.Success;
746 case "/o-":
747 case "/optimize-":
748 settings.Optimize = false;
749 return ParseResult.Success;
751 // TODO: Not supported by csc 3.5+
752 case "/incremental":
753 case "/incremental+":
754 case "/incremental-":
755 // nothing.
756 return ParseResult.Success;
758 case "/d":
759 case "/define": {
760 if (value.Length == 0) {
761 Error_RequiresArgument (option);
762 return ParseResult.Error;
765 foreach (string d in value.Split (argument_value_separator)) {
766 string conditional = d.Trim ();
767 if (!Tokenizer.IsValidIdentifier (conditional)) {
768 report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
769 continue;
772 settings.AddConditionalSymbol (conditional);
774 return ParseResult.Success;
777 case "/bugreport":
779 // We should collect data, runtime, etc and store in the file specified
781 output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
782 return ParseResult.Success;
784 case "/pkg": {
785 string packages;
787 if (value.Length == 0) {
788 Error_RequiresArgument (option);
789 return ParseResult.Error;
791 packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
792 string pkgout = Driver.GetPackageFlags (packages, report);
794 if (pkgout == null)
795 return ParseResult.Error;
797 string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
798 args = AddArgs (args, xargs);
799 return ParseResult.Success;
802 case "/linkres":
803 case "/linkresource":
804 case "/res":
805 case "/resource":
806 AssemblyResource res = null;
807 string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
808 switch (s.Length) {
809 case 1:
810 if (s[0].Length == 0)
811 goto default;
812 res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
813 break;
814 case 2:
815 res = new AssemblyResource (s[0], s[1]);
816 break;
817 case 3:
818 if (s[2] != "public" && s[2] != "private") {
819 report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
820 return ParseResult.Error;
822 res = new AssemblyResource (s[0], s[1], s[2] == "private");
823 break;
824 default:
825 report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
826 return ParseResult.Error;
829 if (res != null) {
830 res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
831 AddResource (res, settings);
834 return ParseResult.Success;
836 case "/recurse":
837 if (value.Length == 0) {
838 Error_RequiresFileName (option);
839 return ParseResult.Error;
841 ProcessSourceFiles (value, true, settings.SourceFiles);
842 return ParseResult.Success;
844 case "/r":
845 case "/reference": {
846 if (value.Length == 0) {
847 Error_RequiresFileName (option);
848 return ParseResult.Error;
851 string[] refs = value.Split (argument_value_separator);
852 foreach (string r in refs) {
853 if (r.Length == 0)
854 continue;
856 string val = r;
857 int index = val.IndexOf ('=');
858 if (index > -1) {
859 string alias = r.Substring (0, index);
860 string assembly = r.Substring (index + 1);
861 AddAssemblyReference (alias, assembly, settings);
862 if (refs.Length != 1) {
863 report.Error (2034, "Cannot specify multiple aliases using single /reference option");
864 return ParseResult.Error;
866 } else {
867 settings.AssemblyReferences.Add (val);
870 return ParseResult.Success;
872 case "/addmodule": {
873 if (value.Length == 0) {
874 Error_RequiresFileName (option);
875 return ParseResult.Error;
878 string[] refs = value.Split (argument_value_separator);
879 foreach (string r in refs) {
880 settings.Modules.Add (r);
882 return ParseResult.Success;
884 case "/win32res": {
885 if (value.Length == 0) {
886 Error_RequiresFileName (option);
887 return ParseResult.Error;
890 if (settings.Win32IconFile != null)
891 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
893 settings.Win32ResourceFile = value;
894 return ParseResult.Success;
896 case "/win32icon": {
897 if (value.Length == 0) {
898 Error_RequiresFileName (option);
899 return ParseResult.Error;
902 if (settings.Win32ResourceFile != null)
903 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
905 settings.Win32IconFile = value;
906 return ParseResult.Success;
908 case "/doc": {
909 if (value.Length == 0) {
910 Error_RequiresFileName (option);
911 return ParseResult.Error;
914 settings.DocumentationFile = value;
915 return ParseResult.Success;
917 case "/lib": {
918 string[] libdirs;
920 if (value.Length == 0) {
921 return ParseResult.Error;
924 libdirs = value.Split (argument_value_separator);
925 foreach (string dir in libdirs)
926 settings.ReferencesLookupPaths.Add (dir);
927 return ParseResult.Success;
930 case "/debug-":
931 settings.GenerateDebugInfo = false;
932 return ParseResult.Success;
934 case "/debug":
935 if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || idx < 0) {
936 settings.GenerateDebugInfo = true;
937 return ParseResult.Success;
940 if (value.Length > 0) {
941 report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
942 } else {
943 Error_RequiresArgument (option);
946 return ParseResult.Error;
948 case "/debug+":
949 settings.GenerateDebugInfo = true;
950 return ParseResult.Success;
952 case "/checked":
953 case "/checked+":
954 settings.Checked = true;
955 return ParseResult.Success;
957 case "/checked-":
958 settings.Checked = false;
959 return ParseResult.Success;
961 case "/clscheck":
962 case "/clscheck+":
963 settings.VerifyClsCompliance = true;
964 return ParseResult.Success;
966 case "/clscheck-":
967 settings.VerifyClsCompliance = false;
968 return ParseResult.Success;
970 case "/unsafe":
971 case "/unsafe+":
972 settings.Unsafe = true;
973 return ParseResult.Success;
975 case "/unsafe-":
976 settings.Unsafe = false;
977 return ParseResult.Success;
979 case "/warnaserror":
980 case "/warnaserror+":
981 if (value.Length == 0) {
982 settings.WarningsAreErrors = true;
983 parser_settings.WarningsAreErrors = true;
984 } else {
985 if (!ProcessWarningsList (value, settings.AddWarningAsError))
986 return ParseResult.Error;
988 return ParseResult.Success;
990 case "/warnaserror-":
991 if (value.Length == 0) {
992 settings.WarningsAreErrors = false;
993 } else {
994 if (!ProcessWarningsList (value, settings.AddWarningOnly))
995 return ParseResult.Error;
997 return ParseResult.Success;
999 case "/warn":
1000 case "/w":
1001 if (value.Length == 0) {
1002 Error_RequiresArgument (option);
1003 return ParseResult.Error;
1006 SetWarningLevel (value, settings);
1007 return ParseResult.Success;
1009 case "/nowarn":
1010 if (value.Length == 0) {
1011 Error_RequiresArgument (option);
1012 return ParseResult.Error;
1015 if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
1016 return ParseResult.Error;
1018 return ParseResult.Success;
1020 case "/noconfig":
1021 settings.LoadDefaultReferences = false;
1022 return ParseResult.Success;
1024 case "/platform":
1025 if (value.Length == 0) {
1026 Error_RequiresArgument (option);
1027 return ParseResult.Error;
1030 switch (value.ToLowerInvariant ()) {
1031 case "arm":
1032 settings.Platform = Platform.Arm;
1033 break;
1034 case "anycpu":
1035 settings.Platform = Platform.AnyCPU;
1036 break;
1037 case "x86":
1038 settings.Platform = Platform.X86;
1039 break;
1040 case "x64":
1041 settings.Platform = Platform.X64;
1042 break;
1043 case "itanium":
1044 settings.Platform = Platform.IA64;
1045 break;
1046 case "anycpu32bitpreferred":
1047 settings.Platform = Platform.AnyCPU32Preferred;
1048 break;
1049 default:
1050 report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
1051 value);
1052 return ParseResult.Error;
1055 return ParseResult.Success;
1057 case "/sdk":
1058 if (value.Length == 0) {
1059 Error_RequiresArgument (option);
1060 return ParseResult.Error;
1063 settings.SdkVersion = value;
1064 return ParseResult.Success;
1066 // We just ignore this.
1067 case "/errorreport":
1068 case "/filealign":
1069 if (value.Length == 0) {
1070 Error_RequiresArgument (option);
1071 return ParseResult.Error;
1074 return ParseResult.Success;
1076 case "/helpinternal":
1077 OtherFlags ();
1078 return ParseResult.Stop;
1080 case "/help":
1081 case "/?":
1082 Usage ();
1083 return ParseResult.Stop;
1085 case "/main":
1086 case "/m":
1087 if (value.Length == 0) {
1088 Error_RequiresArgument (option);
1089 return ParseResult.Error;
1091 settings.MainClass = value;
1092 return ParseResult.Success;
1094 case "/nostdlib":
1095 case "/nostdlib+":
1096 settings.StdLib = false;
1097 return ParseResult.Success;
1099 case "/nostdlib-":
1100 settings.StdLib = true;
1101 return ParseResult.Success;
1103 case "/fullpaths":
1104 settings.ShowFullPaths = true;
1105 return ParseResult.Success;
1107 case "/keyfile":
1108 if (value.Length == 0) {
1109 Error_RequiresFileName (option);
1110 return ParseResult.Error;
1113 settings.StrongNameKeyFile = value;
1114 return ParseResult.Success;
1116 case "/keycontainer":
1117 if (value.Length == 0) {
1118 Error_RequiresArgument (option);
1119 return ParseResult.Error;
1122 settings.StrongNameKeyContainer = value;
1123 return ParseResult.Success;
1125 case "/delaysign+":
1126 case "/delaysign":
1127 settings.StrongNameDelaySign = true;
1128 return ParseResult.Success;
1130 case "/delaysign-":
1131 settings.StrongNameDelaySign = false;
1132 return ParseResult.Success;
1134 case "/langversion":
1135 if (value.Length == 0) {
1136 Error_RequiresArgument (option);
1137 return ParseResult.Error;
1140 switch (value.ToLowerInvariant ()) {
1141 case "iso-1":
1142 case "1":
1143 settings.Version = LanguageVersion.ISO_1;
1144 return ParseResult.Success;
1145 case "default":
1146 settings.Version = LanguageVersion.Default;
1147 return ParseResult.Success;
1148 case "2":
1149 case "iso-2":
1150 settings.Version = LanguageVersion.ISO_2;
1151 return ParseResult.Success;
1152 case "3":
1153 settings.Version = LanguageVersion.V_3;
1154 return ParseResult.Success;
1155 case "4":
1156 settings.Version = LanguageVersion.V_4;
1157 return ParseResult.Success;
1158 case "5":
1159 settings.Version = LanguageVersion.V_5;
1160 return ParseResult.Success;
1161 case "6":
1162 settings.Version = LanguageVersion.V_6;
1163 return ParseResult.Success;
1164 case "experimental":
1165 settings.Version = LanguageVersion.Experimental;
1166 return ParseResult.Success;
1167 case "future":
1168 report.Warning (8000, 1, "Language version `future' is no longer supported");
1169 goto case "6";
1172 report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', Default or value in range 1 to 6", value);
1173 return ParseResult.Error;
1175 case "/codepage":
1176 if (value.Length == 0) {
1177 Error_RequiresArgument (option);
1178 return ParseResult.Error;
1181 switch (value) {
1182 case "utf8":
1183 settings.Encoding = Encoding.UTF8;
1184 break;
1185 case "reset":
1186 settings.Encoding = Encoding.Default;
1187 break;
1188 default:
1189 try {
1190 settings.Encoding = Encoding.GetEncoding (int.Parse (value));
1191 } catch {
1192 report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1194 return ParseResult.Error;
1196 return ParseResult.Success;
1198 case "/runtimemetadataversion":
1199 if (value.Length == 0) {
1200 Error_RequiresArgument (option);
1201 return ParseResult.Error;
1204 settings.RuntimeMetadataVersion = value;
1205 return ParseResult.Success;
1207 // csc options that we don't support
1208 case "/analyzer":
1209 case "/appconfig":
1210 case "/baseaddress":
1211 case "/deterministic":
1212 case "/deterministic+":
1213 case "/deterministic-":
1214 case "/errorendlocation":
1215 case "/errorlog":
1216 case "/features":
1217 case "/highentropyva":
1218 case "/highentropyva+":
1219 case "/highentropyva-":
1220 case "/link":
1221 case "/moduleassemblyname":
1222 case "/nowin32manifest":
1223 case "/pathmap":
1224 case "/pdb":
1225 case "/preferreduilang":
1226 case "/publicsign":
1227 case "/publicsign+":
1228 case "/publicsign-":
1229 case "/reportanalyzer":
1230 case "/ruleset":
1231 case "/sqmsessionguid":
1232 case "/subsystemversion":
1233 case "/utf8output":
1234 case "/win32manifest":
1235 return ParseResult.Success;
1237 default:
1238 return ParseResult.UnknownOption;
1243 // Currently handles the Unix-like command line options, but will be
1244 // deprecated in favor of the CSCParseOption, which will also handle the
1245 // options that start with a dash in the future.
1247 ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
1249 switch (arg){
1250 case "-v":
1251 settings.VerboseParserFlag++;
1252 return ParseResult.Success;
1254 case "--version":
1255 Version ();
1256 return ParseResult.Stop;
1258 case "--parse":
1259 settings.ParseOnly = true;
1260 return ParseResult.Success;
1262 case "--main": case "-m":
1263 report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
1264 if ((i + 1) >= args.Length){
1265 Error_RequiresArgument (arg);
1266 return ParseResult.Error;
1268 settings.MainClass = args[++i];
1269 return ParseResult.Success;
1271 case "--unsafe":
1272 report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
1273 settings.Unsafe = true;
1274 return ParseResult.Success;
1276 case "/?": case "/h": case "/help":
1277 case "--help":
1278 Usage ();
1279 return ParseResult.Stop;
1281 case "--define":
1282 report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
1283 if ((i + 1) >= args.Length){
1284 Error_RequiresArgument (arg);
1285 return ParseResult.Error;
1288 settings.AddConditionalSymbol (args [++i]);
1289 return ParseResult.Success;
1291 case "--tokenize":
1292 settings.TokenizeOnly = true;
1293 return ParseResult.Success;
1295 case "-o":
1296 case "--output":
1297 report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
1298 if ((i + 1) >= args.Length){
1299 Error_RequiresArgument (arg);
1300 return ParseResult.Error;
1302 settings.OutputFile = args[++i];
1303 return ParseResult.Success;
1305 case "--checked":
1306 report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
1307 settings.Checked = true;
1308 return ParseResult.Success;
1310 case "--stacktrace":
1311 settings.Stacktrace = true;
1312 return ParseResult.Success;
1314 case "--linkresource":
1315 case "--linkres":
1316 report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
1317 if ((i + 1) >= args.Length){
1318 Error_RequiresArgument (arg);
1319 return ParseResult.Error;
1322 AddResource (new AssemblyResource (args[++i], args[i]), settings);
1323 return ParseResult.Success;
1325 case "--resource":
1326 case "--res":
1327 report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
1328 if ((i + 1) >= args.Length){
1329 Error_RequiresArgument (arg);
1330 return ParseResult.Error;
1333 AddResource (new AssemblyResource (args[++i], args[i], true), settings);
1334 return ParseResult.Success;
1336 case "--target":
1337 report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
1338 if ((i + 1) >= args.Length){
1339 Error_RequiresArgument (arg);
1340 return ParseResult.Error;
1343 string type = args [++i];
1344 switch (type){
1345 case "library":
1346 settings.Target = Target.Library;
1347 settings.TargetExt = ".dll";
1348 break;
1350 case "exe":
1351 settings.Target = Target.Exe;
1352 break;
1354 case "winexe":
1355 settings.Target = Target.WinExe;
1356 break;
1358 case "module":
1359 settings.Target = Target.Module;
1360 settings.TargetExt = ".dll";
1361 break;
1362 default:
1363 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
1364 break;
1366 return ParseResult.Success;
1368 case "-r":
1369 report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
1370 if ((i + 1) >= args.Length){
1371 Error_RequiresArgument (arg);
1372 return ParseResult.Error;
1375 string val = args [++i];
1376 int idx = val.IndexOf ('=');
1377 if (idx > -1) {
1378 string alias = val.Substring (0, idx);
1379 string assembly = val.Substring (idx + 1);
1380 AddAssemblyReference (alias, assembly, settings);
1381 return ParseResult.Success;
1384 settings.AssemblyReferences.Add (val);
1385 return ParseResult.Success;
1387 case "-L":
1388 report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
1389 if ((i + 1) >= args.Length){
1390 Error_RequiresArgument (arg);
1391 return ParseResult.Error;
1393 settings.ReferencesLookupPaths.Add (args [++i]);
1394 return ParseResult.Success;
1396 case "--lint":
1397 settings.EnhancedWarnings = true;
1398 return ParseResult.Success;
1400 case "--nostdlib":
1401 report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
1402 settings.StdLib = false;
1403 return ParseResult.Success;
1405 case "--nowarn":
1406 report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1407 if ((i + 1) >= args.Length){
1408 Error_RequiresArgument (arg);
1409 return ParseResult.Error;
1411 int warn = 0;
1413 try {
1414 warn = int.Parse (args [++i]);
1415 } catch {
1416 Usage ();
1417 Environment.Exit (1);
1419 settings.SetIgnoreWarning (warn);
1420 return ParseResult.Success;
1422 case "--wlevel":
1423 report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1424 if ((i + 1) >= args.Length){
1425 Error_RequiresArgument (arg);
1426 return ParseResult.Error;
1429 SetWarningLevel (args [++i], settings);
1430 return ParseResult.Success;
1432 case "--mcs-debug":
1433 if ((i + 1) >= args.Length){
1434 Error_RequiresArgument (arg);
1435 return ParseResult.Error;
1438 try {
1439 settings.DebugFlags = int.Parse (args [++i]);
1440 } catch {
1441 Error_RequiresArgument (arg);
1442 return ParseResult.Error;
1445 return ParseResult.Success;
1447 case "--about":
1448 About ();
1449 return ParseResult.Stop;
1451 case "--recurse":
1452 report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1453 if ((i + 1) >= args.Length){
1454 Error_RequiresArgument (arg);
1455 return ParseResult.Error;
1457 ProcessSourceFiles (args [++i], true, settings.SourceFiles);
1458 return ParseResult.Success;
1460 case "--timestamp":
1461 settings.Timestamps = true;
1462 return ParseResult.Success;
1464 case "--debug": case "-g":
1465 report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1466 settings.GenerateDebugInfo = true;
1467 return ParseResult.Success;
1469 case "--noconfig":
1470 report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1471 settings.LoadDefaultReferences = false;
1472 return ParseResult.Success;
1474 case "--metadata-only":
1475 settings.WriteMetadataOnly = true;
1476 return ParseResult.Success;
1478 case "--break-on-ice":
1479 settings.BreakOnInternalError = true;
1480 return ParseResult.Success;
1482 default:
1483 if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
1484 int fatal = 1;
1485 if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
1486 int.TryParse (arg.Substring (8), out fatal);
1488 settings.FatalCounter = fatal;
1489 return ParseResult.Success;
1491 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
1492 string version = arg.Substring (10);
1494 switch (version) {
1495 case "v1":
1496 case "V1":
1497 settings.StdLibRuntimeVersion = RuntimeVersion.v1;
1498 break;
1499 case "v2":
1500 case "V2":
1501 settings.StdLibRuntimeVersion = RuntimeVersion.v2;
1502 break;
1503 case "v4":
1504 case "V4":
1505 settings.StdLibRuntimeVersion = RuntimeVersion.v4;
1506 break;
1508 return ParseResult.Success;
1511 if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
1512 string file = arg.Substring (21).Trim ();
1513 if (file.Length < 1) {
1514 Error_RequiresArgument (arg);
1515 return ParseResult.Error;
1518 if (settings.GetResourceStrings == null)
1519 settings.GetResourceStrings = new List<string> ();
1521 settings.GetResourceStrings.Add (file);
1522 return ParseResult.Success;
1525 return ParseResult.UnknownOption;
1529 void SetWarningLevel (string s, CompilerSettings settings)
1531 int level = -1;
1533 try {
1534 level = int.Parse (s);
1535 } catch {
1537 if (level < 0 || level > 4) {
1538 report.Error (1900, "Warning level must be in the range 0-4");
1539 return;
1541 settings.WarningLevel = level;
1545 // Given a path specification, splits the path from the file/pattern
1547 static void SplitPathAndPattern (string spec, out string path, out string pattern)
1549 int p = spec.LastIndexOf ('/');
1550 if (p != -1) {
1552 // Windows does not like /file.cs, switch that to:
1553 // "\", "file.cs"
1555 if (p == 0) {
1556 path = "\\";
1557 pattern = spec.Substring (1);
1558 } else {
1559 path = spec.Substring (0, p);
1560 pattern = spec.Substring (p + 1);
1562 return;
1565 p = spec.LastIndexOf ('\\');
1566 if (p != -1) {
1567 path = spec.Substring (0, p);
1568 pattern = spec.Substring (p + 1);
1569 return;
1572 path = ".";
1573 pattern = spec;
1576 void Usage ()
1578 output.WriteLine (
1579 "Mono C# compiler, Copyright 2001-2011 Novell, Inc., Copyright 2011-2012 Xamarin, Inc\n" +
1580 "mcs [options] source-files\n" +
1581 " --about About the Mono C# compiler\n" +
1582 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
1583 " -checked[+|-] Sets default aritmetic overflow context\n" +
1584 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
1585 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
1586 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
1587 " -debug[+|-], -g Generate debugging information\n" +
1588 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
1589 " -doc:FILE Process documentation comments to XML file\n" +
1590 " -fullpaths Any issued error or warning uses absolute file path\n" +
1591 " -help Lists all compiler options (short: -?)\n" +
1592 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
1593 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
1594 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, 4, 5, Default or Experimental\n" +
1595 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
1596 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
1597 " -noconfig Disables implicitly referenced assemblies\n" +
1598 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
1599 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
1600 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
1601 " -out:FILE Specifies output assembly name\n" +
1602 " -pkg:P1[,Pn] References packages P1..Pn\n" +
1603 " -platform:ARCH Specifies the target platform of the output assembly\n" +
1604 " ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
1605 " x86, x64 or itanium. The default is anycpu.\n" +
1606 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
1607 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
1608 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
1609 " -sdk:VERSION Specifies SDK version of referenced assemblies\n" +
1610 " VERSION can be one of: 2, 4, 4.5 (default) or a custom value\n" +
1611 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
1612 " KIND can be one of: exe, winexe, library, module\n" +
1613 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
1614 " -warnaserror[+|-] Treats all warnings as errors\n" +
1615 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
1616 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
1617 " -helpinternal Shows internal and advanced compiler options\n" +
1618 "\n" +
1619 "Resources:\n" +
1620 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
1621 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
1622 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
1623 " -win32icon:FILE Use this icon for the output\n" +
1624 " @file Read response file for more options\n\n" +
1625 "Options can be of the form -option or /option");
1628 void Version ()
1630 string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
1631 output.WriteLine ("Mono C# compiler version {0}", version);
1635 public class RootContext
1638 // Contains the parsed tree
1640 static ModuleContainer root;
1642 static public ModuleContainer ToplevelTypes {
1643 get { return root; }
1644 set { root = value; }