[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / mcs / settings.cs
blob050c7efa40d446b3c850dd41ecd3e8cdc03f8552
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 V_7 = 7,
33 V_7_1 = 71,
34 V_7_2 = 72,
35 V_7_3 = 73,
36 Experimental = 100,
38 Default = V_7,
39 Latest = V_7_3
42 public enum RuntimeVersion
44 v1,
45 v2,
49 public enum Target
51 Library, Exe, Module, WinExe
54 public enum Platform
56 AnyCPU,
57 AnyCPU32Preferred,
58 Arm,
59 X86,
60 X64,
61 IA64
64 public class CompilerSettings
66 public Target Target;
67 public Platform Platform;
68 public string TargetExt;
69 public bool VerifyClsCompliance;
70 public bool Optimize;
71 public LanguageVersion Version;
72 public bool EnhancedWarnings;
73 public bool LoadDefaultReferences;
74 public string SdkVersion;
76 public string StrongNameKeyFile;
77 public string StrongNameKeyContainer;
78 public bool StrongNameDelaySign;
80 public int TabSize;
82 public bool WarningsAreErrors;
83 public int WarningLevel;
86 // Assemblies references to be loaded
88 public List<string> AssemblyReferences;
90 //
91 // External aliases for assemblies
93 public List<Tuple<string, string>> AssemblyReferencesAliases;
95 public List<KeyValuePair<string, string>> PathMap;
98 // Modules to be embedded
100 public List<string> Modules;
103 // Lookup paths for referenced assemblies
105 public List<string> ReferencesLookupPaths;
108 // Encoding.
110 public Encoding Encoding;
113 // If set, enable XML documentation generation
115 public string DocumentationFile;
117 public string MainClass;
120 // Output file
122 public string OutputFile;
125 // The default compiler checked state
127 public bool Checked;
130 // If true, the compiler is operating in statement mode,
131 // this currently turns local variable declaration into
132 // static variables of a class
134 public bool StatementMode; // TODO: SUPER UGLY
137 // Whether to allow Unsafe code
139 public bool Unsafe;
141 public string Win32ResourceFile;
142 public string Win32IconFile;
145 // A list of resource files for embedding
147 public List<AssemblyResource> Resources;
149 public bool GenerateDebugInfo;
151 #region Compiler debug flags only
152 public bool ParseOnly, TokenizeOnly, Timestamps;
153 public int DebugFlags;
154 public int VerboseParserFlag;
155 public int FatalCounter;
156 public bool Stacktrace;
157 public bool BreakOnInternalError;
158 #endregion
160 public List<string> GetResourceStrings;
162 public bool ShowFullPaths;
165 // Whether we are being linked against the standard libraries.
166 // This is only used to tell whether `System.Object' should
167 // have a base class or not.
169 public bool StdLib;
171 public RuntimeVersion StdLibRuntimeVersion;
173 public string RuntimeMetadataVersion;
175 public bool WriteMetadataOnly;
177 readonly List<string> conditional_symbols;
179 readonly List<SourceFile> source_files;
181 List<int> warnings_as_error;
182 List<int> warnings_only;
183 HashSet<int> warning_ignore_table;
185 public CompilerSettings ()
187 StdLib = true;
188 Target = Target.Exe;
189 TargetExt = ".exe";
190 Platform = Platform.AnyCPU;
191 Version = LanguageVersion.Default;
192 VerifyClsCompliance = true;
193 Encoding = Encoding.UTF8;
194 LoadDefaultReferences = true;
195 StdLibRuntimeVersion = RuntimeVersion.v4;
196 WarningLevel = 4;
198 // Default to 1 or mdb files would be platform speficic
199 TabSize = 1;
201 AssemblyReferences = new List<string> ();
202 AssemblyReferencesAliases = new List<Tuple<string, string>> ();
203 Modules = new List<string> ();
204 ReferencesLookupPaths = new List<string> ();
206 conditional_symbols = new List<string> ();
208 // Add default mcs define
210 conditional_symbols.Add ("__MonoCS__");
212 source_files = new List<SourceFile> ();
215 #region Properties
217 public SourceFile FirstSourceFile {
218 get {
219 return source_files.Count > 0 ? source_files [0] : null;
223 public bool HasKeyFileOrContainer {
224 get {
225 return StrongNameKeyFile != null || StrongNameKeyContainer != null;
229 public bool NeedsEntryPoint {
230 get {
231 return Target == Target.Exe || Target == Target.WinExe;
235 public List<SourceFile> SourceFiles {
236 get {
237 return source_files;
241 #endregion
243 public void AddConditionalSymbol (string symbol)
245 if (!conditional_symbols.Contains (symbol))
246 conditional_symbols.Add (symbol);
249 public void AddWarningAsError (int id)
251 if (warnings_as_error == null)
252 warnings_as_error = new List<int> ();
254 warnings_as_error.Add (id);
257 public void AddWarningOnly (int id)
259 if (warnings_only == null)
260 warnings_only = new List<int> ();
262 warnings_only.Add (id);
265 public bool IsConditionalSymbolDefined (string symbol)
267 return conditional_symbols.Contains (symbol);
270 public bool IsWarningAsError (int code)
272 bool is_error = WarningsAreErrors;
274 // Check specific list
275 if (warnings_as_error != null)
276 is_error |= warnings_as_error.Contains (code);
278 // Ignore excluded warnings
279 if (warnings_only != null && warnings_only.Contains (code))
280 is_error = false;
282 return is_error;
285 public bool IsWarningEnabled (int code, int level)
287 if (WarningLevel < level)
288 return false;
290 return !IsWarningDisabledGlobally (code);
293 public bool IsWarningDisabledGlobally (int code)
295 return warning_ignore_table != null && warning_ignore_table.Contains (code);
298 public void SetIgnoreWarning (int code)
300 if (warning_ignore_table == null)
301 warning_ignore_table = new HashSet<int> ();
303 warning_ignore_table.Add (code);
307 public class CommandLineParser
309 enum ParseResult
311 Success,
312 Error,
313 Stop,
314 UnknownOption
317 static readonly char[] argument_value_separator = { ';', ',' };
318 static readonly char[] numeric_value_separator = { ';', ',', ' ' };
320 readonly TextWriter output;
321 readonly Report report;
322 bool stop_argument;
324 Dictionary<string, int> source_file_index;
326 public event Func<string[], int, int> UnknownOptionHandler;
328 CompilerSettings parser_settings;
330 public CommandLineParser (TextWriter errorOutput)
331 : this (errorOutput, Console.Out)
335 public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
337 var rp = new StreamReportPrinter (errorOutput);
339 parser_settings = new CompilerSettings ();
340 report = new Report (new CompilerContext (parser_settings, rp), rp);
341 this.output = messagesOutput;
344 public bool HasBeenStopped {
345 get {
346 return stop_argument;
350 void About ()
352 output.WriteLine (
353 "The Turbo C# compiler is Copyright 2001-2011, Novell, Inc. 2011-2016 Xamarin Inc, 2016-2017 Microsoft Corp\n\n" +
354 "The compiler source code is released under the terms of the \n" +
355 "MIT X11 or GNU GPL licenses\n\n" +
357 "For more information on Mono, visit the project Web site\n" +
358 " http://www.mono-project.com\n\n" +
360 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
363 public CompilerSettings ParseArguments (string[] args)
365 CompilerSettings settings = new CompilerSettings ();
366 if (!ParseArguments (settings, args))
367 return null;
369 return settings;
372 public bool ParseArguments (CompilerSettings settings, string[] args)
374 if (settings == null)
375 throw new ArgumentNullException ("settings");
377 List<string> response_file_list = null;
378 bool parsing_options = true;
379 stop_argument = false;
380 source_file_index = new Dictionary<string, int> ();
382 for (int i = 0; i < args.Length; i++) {
383 string arg = args[i];
384 if (arg.Length == 0)
385 continue;
387 if (arg[0] == '@') {
388 string[] extra_args;
389 string response_file = arg.Substring (1);
391 if (response_file_list == null)
392 response_file_list = new List<string> ();
394 if (response_file_list.Contains (response_file)) {
395 report.Error (1515, "Response file `{0}' specified multiple times", response_file);
396 return false;
399 response_file_list.Add (response_file);
401 extra_args = LoadArgs (response_file);
402 if (extra_args == null) {
403 report.Error (2011, "Unable to open response file: " + response_file);
404 return false;
407 args = AddArgs (args, extra_args);
408 continue;
411 if (parsing_options) {
412 if (arg == "--") {
413 parsing_options = false;
414 continue;
417 bool dash_opt = arg[0] == '-';
418 bool slash_opt = arg[0] == '/';
419 if (dash_opt) {
420 switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
421 case ParseResult.Error:
422 case ParseResult.Success:
423 continue;
424 case ParseResult.Stop:
425 stop_argument = true;
426 return true;
427 case ParseResult.UnknownOption:
428 if (UnknownOptionHandler != null) {
429 var ret = UnknownOptionHandler (args, i);
430 if (ret != -1) {
431 i = ret;
432 continue;
435 break;
439 if (dash_opt || slash_opt) {
440 // Try a -CSCOPTION
441 string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
442 switch (ParseOption (csc_opt, ref args, settings)) {
443 case ParseResult.Error:
444 case ParseResult.Success:
445 continue;
446 case ParseResult.UnknownOption:
447 // Need to skip `/home/test.cs' however /test.cs is considered as error
448 if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
449 break;
451 if (UnknownOptionHandler != null) {
452 var ret = UnknownOptionHandler (args, i);
453 if (ret != -1) {
454 i = ret;
455 continue;
459 Error_WrongOption (arg);
460 return false;
462 case ParseResult.Stop:
463 stop_argument = true;
464 return true;
469 ProcessSourceFiles (arg, false, settings.SourceFiles);
472 return report.Errors == 0;
475 void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
477 string path, pattern;
479 SplitPathAndPattern (spec, out path, out pattern);
480 if (pattern.IndexOf ('*') == -1) {
481 AddSourceFile (spec, sourceFiles);
482 return;
485 string[] files;
486 try {
487 files = Directory.GetFiles (path, pattern);
488 } catch (System.IO.DirectoryNotFoundException) {
489 report.Error (2001, "Source file `" + spec + "' could not be found");
490 return;
491 } catch (System.IO.IOException) {
492 report.Error (2001, "Source file `" + spec + "' could not be found");
493 return;
495 foreach (string f in files) {
496 AddSourceFile (f, sourceFiles);
499 if (!recurse)
500 return;
502 string[] dirs = null;
504 try {
505 dirs = Directory.GetDirectories (path);
506 } catch {
509 foreach (string d in dirs) {
511 // Don't include path in this string, as each
512 // directory entry already does
513 ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
517 static string[] AddArgs (string[] args, string[] extra_args)
519 string[] new_args;
520 new_args = new string[extra_args.Length + args.Length];
522 // if args contains '--' we have to take that into account
523 // split args into first half and second half based on '--'
524 // and add the extra_args before --
525 int split_position = Array.IndexOf (args, "--");
526 if (split_position != -1) {
527 Array.Copy (args, new_args, split_position);
528 extra_args.CopyTo (new_args, split_position);
529 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
530 } else {
531 args.CopyTo (new_args, 0);
532 extra_args.CopyTo (new_args, args.Length);
535 return new_args;
538 void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
540 if (assembly.Length == 0) {
541 report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
542 return;
545 if (!IsExternAliasValid (alias)) {
546 report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
547 return;
550 settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
553 void AddResource (AssemblyResource res, CompilerSettings settings)
555 if (settings.Resources == null) {
556 settings.Resources = new List<AssemblyResource> ();
557 settings.Resources.Add (res);
558 return;
561 if (settings.Resources.Contains (res)) {
562 report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
563 return;
566 settings.Resources.Add (res);
569 void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
571 string path = Path.GetFullPath (fileName);
573 int index;
574 if (source_file_index.TryGetValue (path, out index)) {
575 string other_name = sourceFiles[index - 1].Name;
576 if (fileName.Equals (other_name))
577 report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
578 else
579 report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
581 return;
584 var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
585 sourceFiles.Add (unit);
586 source_file_index.Add (path, unit.Index);
589 public bool ProcessWarningsList (string text, Action<int> action)
591 foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
592 var warning = wid;
593 if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
594 warning = warning.Substring (2);
596 int id;
597 if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
598 continue;
601 action (id);
604 return true;
607 void Error_RequiresArgument (string option)
609 report.Error (2006, "Missing argument for `{0}' option", option);
612 void Error_RequiresFileName (string option)
614 report.Error (2005, "Missing file specification for `{0}' option", option);
617 void Error_WrongOption (string option)
619 report.Error (2007, "Unrecognized command-line option: `{0}'", option);
622 static bool IsExternAliasValid (string identifier)
624 return Tokenizer.IsValidIdentifier (identifier);
627 static string[] LoadArgs (string file)
629 StreamReader f;
630 var args = new List<string> ();
631 string line;
632 try {
633 f = new StreamReader (file);
634 } catch {
635 return null;
638 StringBuilder sb = new StringBuilder ();
640 while ((line = f.ReadLine ()) != null) {
641 int t = line.Length;
643 for (int i = 0; i < t; i++) {
644 char c = line[i];
646 if (c == '"' || c == '\'') {
647 char end = c;
649 for (i++; i < t; i++) {
650 c = line[i];
652 if (c == end)
653 break;
654 sb.Append (c);
656 } else if (c == ' ') {
657 if (sb.Length > 0) {
658 args.Add (sb.ToString ());
659 sb.Length = 0;
661 } else
662 sb.Append (c);
664 if (sb.Length > 0) {
665 args.Add (sb.ToString ());
666 sb.Length = 0;
670 return args.ToArray ();
673 void OtherFlags ()
675 output.WriteLine (
676 "Other flags in the compiler\n" +
677 " --fatal[=COUNT] Makes error after COUNT fatal\n" +
678 " --lint Enhanced warnings\n" +
679 " --metadata-only Produced assembly will contain metadata only\n" +
680 " --parse Only parses the source file\n" +
681 " --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
682 " --stacktrace Shows stack trace at error location\n" +
683 " --timestamp Displays time stamps of various compiler events\n" +
684 " -v Verbose parsing (for debugging the parser)\n" +
685 " --mcs-debug X Sets MCS debugging level to X\n" +
686 " --break-on-ice Breaks compilation on internal compiler error");
690 // This parses the -arg and /arg options to the compiler, even if the strings
691 // in the following text use "/arg" on the strings.
693 ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
695 int idx = option.IndexOf (':');
696 string arg, value;
698 if (idx == -1) {
699 arg = option;
700 value = "";
701 } else {
702 arg = option.Substring (0, idx);
704 value = option.Substring (idx + 1);
707 switch (arg.ToLowerInvariant ()) {
708 case "/nologo":
709 return ParseResult.Success;
711 case "/t":
712 case "/target":
713 switch (value) {
714 case "exe":
715 settings.Target = Target.Exe;
716 break;
718 case "winexe":
719 settings.Target = Target.WinExe;
720 break;
722 case "library":
723 settings.Target = Target.Library;
724 settings.TargetExt = ".dll";
725 break;
727 case "module":
728 settings.Target = Target.Module;
729 settings.TargetExt = ".netmodule";
730 break;
732 default:
733 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
734 return ParseResult.Error;
736 return ParseResult.Success;
738 case "/out":
739 if (value.Length == 0) {
740 Error_RequiresFileName (option);
741 return ParseResult.Error;
743 settings.OutputFile = value;
744 return ParseResult.Success;
746 case "/o":
747 case "/o+":
748 case "/optimize":
749 case "/optimize+":
750 settings.Optimize = true;
751 return ParseResult.Success;
753 case "/o-":
754 case "/optimize-":
755 settings.Optimize = false;
756 return ParseResult.Success;
758 // TODO: Not supported by csc 3.5+
759 case "/incremental":
760 case "/incremental+":
761 case "/incremental-":
762 // nothing.
763 return ParseResult.Success;
765 case "/d":
766 case "/define": {
767 if (value.Length == 0) {
768 Error_RequiresArgument (option);
769 return ParseResult.Error;
772 foreach (string d in value.Split (argument_value_separator)) {
773 string conditional = d.Trim ();
774 if (!Tokenizer.IsValidIdentifier (conditional)) {
775 report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
776 continue;
779 settings.AddConditionalSymbol (conditional);
781 return ParseResult.Success;
784 case "/bugreport":
786 // We should collect data, runtime, etc and store in the file specified
788 output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
789 return ParseResult.Success;
791 case "/pkg": {
792 string packages;
794 if (value.Length == 0) {
795 Error_RequiresArgument (option);
796 return ParseResult.Error;
798 packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
799 string pkgout = Driver.GetPackageFlags (packages, report);
801 if (pkgout == null)
802 return ParseResult.Error;
804 string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
805 args = AddArgs (args, xargs);
806 return ParseResult.Success;
809 case "/linkres":
810 case "/linkresource":
811 case "/res":
812 case "/resource":
813 AssemblyResource res = null;
814 string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
815 switch (s.Length) {
816 case 1:
817 if (s[0].Length == 0)
818 goto default;
819 res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
820 break;
821 case 2:
822 res = new AssemblyResource (s[0], s[1]);
823 break;
824 case 3:
825 if (s[2] != "public" && s[2] != "private") {
826 report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
827 return ParseResult.Error;
829 res = new AssemblyResource (s[0], s[1], s[2] == "private");
830 break;
831 default:
832 report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
833 return ParseResult.Error;
836 if (res != null) {
837 res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
838 AddResource (res, settings);
841 return ParseResult.Success;
843 case "/recurse":
844 if (value.Length == 0) {
845 Error_RequiresFileName (option);
846 return ParseResult.Error;
848 ProcessSourceFiles (value, true, settings.SourceFiles);
849 return ParseResult.Success;
851 case "/r":
852 case "/reference": {
853 if (value.Length == 0) {
854 Error_RequiresFileName (option);
855 return ParseResult.Error;
858 string[] refs = value.Split (argument_value_separator);
859 foreach (string r in refs) {
860 if (r.Length == 0)
861 continue;
863 string val = r;
864 int index = val.IndexOf ('=');
865 if (index > -1) {
866 string alias = r.Substring (0, index);
867 string assembly = r.Substring (index + 1);
868 AddAssemblyReference (alias, assembly, settings);
869 if (refs.Length != 1) {
870 report.Error (2034, "Cannot specify multiple aliases using single /reference option");
871 return ParseResult.Error;
873 } else {
874 settings.AssemblyReferences.Add (val);
877 return ParseResult.Success;
879 case "/addmodule": {
880 if (value.Length == 0) {
881 Error_RequiresFileName (option);
882 return ParseResult.Error;
885 string[] refs = value.Split (argument_value_separator);
886 foreach (string r in refs) {
887 settings.Modules.Add (r);
889 return ParseResult.Success;
891 case "/win32res": {
892 if (value.Length == 0) {
893 Error_RequiresFileName (option);
894 return ParseResult.Error;
897 if (settings.Win32IconFile != null)
898 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
900 settings.Win32ResourceFile = value;
901 return ParseResult.Success;
903 case "/win32icon": {
904 if (value.Length == 0) {
905 Error_RequiresFileName (option);
906 return ParseResult.Error;
909 if (settings.Win32ResourceFile != null)
910 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
912 settings.Win32IconFile = value;
913 return ParseResult.Success;
915 case "/doc": {
916 if (value.Length == 0) {
917 Error_RequiresFileName (option);
918 return ParseResult.Error;
921 settings.DocumentationFile = value;
922 return ParseResult.Success;
924 case "/lib": {
925 string[] libdirs;
927 if (value.Length == 0) {
928 return ParseResult.Error;
931 libdirs = value.Split (argument_value_separator);
932 foreach (string dir in libdirs)
933 settings.ReferencesLookupPaths.Add (dir);
934 return ParseResult.Success;
937 case "/debug-":
938 settings.GenerateDebugInfo = false;
939 return ParseResult.Success;
941 case "/debug":
942 if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || value.Equals ("portable", StringComparison.OrdinalIgnoreCase) || idx < 0) {
943 settings.GenerateDebugInfo = true;
944 return ParseResult.Success;
947 if (value.Length > 0) {
948 report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
949 } else {
950 Error_RequiresArgument (option);
953 return ParseResult.Error;
955 case "/debug+":
956 settings.GenerateDebugInfo = true;
957 return ParseResult.Success;
959 case "/checked":
960 case "/checked+":
961 settings.Checked = true;
962 return ParseResult.Success;
964 case "/checked-":
965 settings.Checked = false;
966 return ParseResult.Success;
968 case "/clscheck":
969 case "/clscheck+":
970 settings.VerifyClsCompliance = true;
971 return ParseResult.Success;
973 case "/clscheck-":
974 settings.VerifyClsCompliance = false;
975 return ParseResult.Success;
977 case "/unsafe":
978 case "/unsafe+":
979 settings.Unsafe = true;
980 return ParseResult.Success;
982 case "/unsafe-":
983 settings.Unsafe = false;
984 return ParseResult.Success;
986 case "/warnaserror":
987 case "/warnaserror+":
988 if (value.Length == 0) {
989 settings.WarningsAreErrors = true;
990 parser_settings.WarningsAreErrors = true;
991 } else {
992 if (!ProcessWarningsList (value, settings.AddWarningAsError))
993 return ParseResult.Error;
995 return ParseResult.Success;
997 case "/warnaserror-":
998 if (value.Length == 0) {
999 settings.WarningsAreErrors = false;
1000 } else {
1001 if (!ProcessWarningsList (value, settings.AddWarningOnly))
1002 return ParseResult.Error;
1004 return ParseResult.Success;
1006 case "/warn":
1007 case "/w":
1008 if (value.Length == 0) {
1009 Error_RequiresArgument (option);
1010 return ParseResult.Error;
1013 SetWarningLevel (value, settings);
1014 return ParseResult.Success;
1016 case "/nowarn":
1017 if (value.Length == 0) {
1018 Error_RequiresArgument (option);
1019 return ParseResult.Error;
1022 if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
1023 return ParseResult.Error;
1025 return ParseResult.Success;
1027 case "/noconfig":
1028 settings.LoadDefaultReferences = false;
1029 return ParseResult.Success;
1031 case "/platform":
1032 if (value.Length == 0) {
1033 Error_RequiresArgument (option);
1034 return ParseResult.Error;
1037 switch (value.ToLowerInvariant ()) {
1038 case "arm":
1039 settings.Platform = Platform.Arm;
1040 break;
1041 case "anycpu":
1042 settings.Platform = Platform.AnyCPU;
1043 break;
1044 case "x86":
1045 settings.Platform = Platform.X86;
1046 break;
1047 case "x64":
1048 settings.Platform = Platform.X64;
1049 break;
1050 case "itanium":
1051 settings.Platform = Platform.IA64;
1052 break;
1053 case "anycpu32bitpreferred":
1054 settings.Platform = Platform.AnyCPU32Preferred;
1055 break;
1056 default:
1057 report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
1058 value);
1059 return ParseResult.Error;
1062 return ParseResult.Success;
1064 case "/sdk":
1065 if (value.Length == 0) {
1066 Error_RequiresArgument (option);
1067 return ParseResult.Error;
1070 settings.SdkVersion = value;
1071 return ParseResult.Success;
1073 // We just ignore this.
1074 case "/errorreport":
1075 case "/filealign":
1076 if (value.Length == 0) {
1077 Error_RequiresArgument (option);
1078 return ParseResult.Error;
1081 return ParseResult.Success;
1083 case "/helpinternal":
1084 OtherFlags ();
1085 return ParseResult.Stop;
1087 case "/help":
1088 case "/?":
1089 Usage ();
1090 return ParseResult.Stop;
1092 case "/main":
1093 case "/m":
1094 if (value.Length == 0) {
1095 Error_RequiresArgument (option);
1096 return ParseResult.Error;
1098 settings.MainClass = value;
1099 return ParseResult.Success;
1101 case "/nostdlib":
1102 case "/nostdlib+":
1103 settings.StdLib = false;
1104 return ParseResult.Success;
1106 case "/nostdlib-":
1107 settings.StdLib = true;
1108 return ParseResult.Success;
1110 case "/fullpaths":
1111 settings.ShowFullPaths = true;
1112 return ParseResult.Success;
1114 case "/keyfile":
1115 if (value.Length == 0) {
1116 Error_RequiresFileName (option);
1117 return ParseResult.Error;
1120 settings.StrongNameKeyFile = value;
1121 return ParseResult.Success;
1123 case "/keycontainer":
1124 if (value.Length == 0) {
1125 Error_RequiresArgument (option);
1126 return ParseResult.Error;
1129 settings.StrongNameKeyContainer = value;
1130 return ParseResult.Success;
1132 case "/delaysign+":
1133 case "/delaysign":
1134 settings.StrongNameDelaySign = true;
1135 return ParseResult.Success;
1137 case "/delaysign-":
1138 settings.StrongNameDelaySign = false;
1139 return ParseResult.Success;
1141 case "/langversion":
1142 if (value.Length == 0) {
1143 Error_RequiresArgument (option);
1144 return ParseResult.Error;
1147 switch (value.ToLowerInvariant ()) {
1148 case "iso-1":
1149 case "1":
1150 case "1.0":
1151 settings.Version = LanguageVersion.ISO_1;
1152 return ParseResult.Success;
1153 case "default":
1154 settings.Version = LanguageVersion.Default;
1155 return ParseResult.Success;
1156 case "2":
1157 case "2.0":
1158 case "iso-2":
1159 settings.Version = LanguageVersion.ISO_2;
1160 return ParseResult.Success;
1161 case "3":
1162 case "3.0":
1163 settings.Version = LanguageVersion.V_3;
1164 return ParseResult.Success;
1165 case "4":
1166 case "4.0":
1167 settings.Version = LanguageVersion.V_4;
1168 return ParseResult.Success;
1169 case "5":
1170 case "5.0":
1171 settings.Version = LanguageVersion.V_5;
1172 return ParseResult.Success;
1173 case "6":
1174 case "6.0":
1175 settings.Version = LanguageVersion.V_6;
1176 return ParseResult.Success;
1177 case "7":
1178 case "7.0":
1179 settings.Version = LanguageVersion.V_7;
1180 return ParseResult.Success;
1181 case "7.1":
1182 settings.Version = LanguageVersion.V_7_1;
1183 return ParseResult.Success;
1184 case "7.2":
1185 settings.Version = LanguageVersion.V_7_2;
1186 return ParseResult.Success;
1187 case "latest":
1188 settings.Version = LanguageVersion.Latest;
1189 return ParseResult.Success;
1190 case "experimental":
1191 settings.Version = LanguageVersion.Experimental;
1192 return ParseResult.Success;
1195 if (value.StartsWith ("0", StringComparison.Ordinal)) {
1196 report.Error (8303, "Specified language version `{0}' cannot have leading zeroes", value);
1197 } else {
1198 report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', Default, Latest or value in range 1 to 7.2", value);
1201 return ParseResult.Error;
1203 case "/codepage":
1204 if (value.Length == 0) {
1205 Error_RequiresArgument (option);
1206 return ParseResult.Error;
1209 switch (value) {
1210 case "utf8":
1211 settings.Encoding = Encoding.UTF8;
1212 break;
1213 case "reset":
1214 settings.Encoding = Encoding.Default;
1215 break;
1216 default:
1217 try {
1218 settings.Encoding = Encoding.GetEncoding (int.Parse (value));
1219 } catch {
1220 report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1222 return ParseResult.Error;
1224 return ParseResult.Success;
1226 case "/runtimemetadataversion":
1227 if (value.Length == 0) {
1228 Error_RequiresArgument (option);
1229 return ParseResult.Error;
1232 settings.RuntimeMetadataVersion = value;
1233 return ParseResult.Success;
1235 case "/pathmap":
1236 if (value.Length == 0) {
1237 return ParseResult.Success;
1240 foreach (var pair in value.Split (',')) {
1241 var kv = pair.Split ('=');
1242 if (kv.Length != 2) {
1243 report.Error (8101, "The pathmap option was incorrectly formatted");
1244 return ParseResult.Error;
1247 if (settings.PathMap == null)
1248 settings.PathMap = new List<KeyValuePair<string, string>> ();
1250 var key = kv [0].TrimEnd (Path.DirectorySeparatorChar);
1251 var path = kv [1].TrimEnd (Path.DirectorySeparatorChar);
1252 if (key.Length == 0 || path.Length == 0)
1253 report.Error (8101, "The pathmap option was incorrectly formatted");
1255 settings.PathMap.Add (new KeyValuePair<string, string> (key, path));
1258 return ParseResult.Success;
1260 // csc options that we don't support
1261 case "/analyzer":
1262 case "/appconfig":
1263 case "/baseaddress":
1264 case "/deterministic":
1265 case "/deterministic+":
1266 case "/deterministic-":
1267 case "/errorendlocation":
1268 case "/errorlog":
1269 case "/features":
1270 case "/highentropyva":
1271 case "/highentropyva+":
1272 case "/highentropyva-":
1273 case "/link":
1274 case "/sourcelink":
1275 case "/moduleassemblyname":
1276 case "/nowin32manifest":
1277 case "/pdb":
1278 case "/preferreduilang":
1279 case "/publicsign":
1280 case "/publicsign+":
1281 case "/publicsign-":
1282 case "/reportanalyzer":
1283 case "/ruleset":
1284 case "/sqmsessionguid":
1285 case "/subsystemversion":
1286 case "/utf8output":
1287 case "/win32manifest":
1288 return ParseResult.Success;
1290 default:
1291 return ParseResult.UnknownOption;
1296 // Currently handles the Unix-like command line options, but will be
1297 // deprecated in favor of the CSCParseOption, which will also handle the
1298 // options that start with a dash in the future.
1300 ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
1302 switch (arg){
1303 case "-v":
1304 settings.VerboseParserFlag++;
1305 return ParseResult.Success;
1307 case "--version":
1308 Version ();
1309 return ParseResult.Stop;
1311 case "--parse":
1312 settings.ParseOnly = true;
1313 return ParseResult.Success;
1315 case "--main": case "-m":
1316 report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
1317 if ((i + 1) >= args.Length){
1318 Error_RequiresArgument (arg);
1319 return ParseResult.Error;
1321 settings.MainClass = args[++i];
1322 return ParseResult.Success;
1324 case "--unsafe":
1325 report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
1326 settings.Unsafe = true;
1327 return ParseResult.Success;
1329 case "/?": case "/h": case "/help":
1330 case "--help":
1331 Usage ();
1332 return ParseResult.Stop;
1334 case "--define":
1335 report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
1336 if ((i + 1) >= args.Length){
1337 Error_RequiresArgument (arg);
1338 return ParseResult.Error;
1341 settings.AddConditionalSymbol (args [++i]);
1342 return ParseResult.Success;
1344 case "--tokenize":
1345 settings.TokenizeOnly = true;
1346 return ParseResult.Success;
1348 case "-o":
1349 case "--output":
1350 report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
1351 if ((i + 1) >= args.Length){
1352 Error_RequiresArgument (arg);
1353 return ParseResult.Error;
1355 settings.OutputFile = args[++i];
1356 return ParseResult.Success;
1358 case "--checked":
1359 report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
1360 settings.Checked = true;
1361 return ParseResult.Success;
1363 case "--stacktrace":
1364 settings.Stacktrace = true;
1365 return ParseResult.Success;
1367 case "--linkresource":
1368 case "--linkres":
1369 report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
1370 if ((i + 1) >= args.Length){
1371 Error_RequiresArgument (arg);
1372 return ParseResult.Error;
1375 AddResource (new AssemblyResource (args[++i], args[i]), settings);
1376 return ParseResult.Success;
1378 case "--resource":
1379 case "--res":
1380 report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
1381 if ((i + 1) >= args.Length){
1382 Error_RequiresArgument (arg);
1383 return ParseResult.Error;
1386 AddResource (new AssemblyResource (args[++i], args[i], true), settings);
1387 return ParseResult.Success;
1389 case "--target":
1390 report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
1391 if ((i + 1) >= args.Length){
1392 Error_RequiresArgument (arg);
1393 return ParseResult.Error;
1396 string type = args [++i];
1397 switch (type){
1398 case "library":
1399 settings.Target = Target.Library;
1400 settings.TargetExt = ".dll";
1401 break;
1403 case "exe":
1404 settings.Target = Target.Exe;
1405 break;
1407 case "winexe":
1408 settings.Target = Target.WinExe;
1409 break;
1411 case "module":
1412 settings.Target = Target.Module;
1413 settings.TargetExt = ".dll";
1414 break;
1415 default:
1416 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
1417 break;
1419 return ParseResult.Success;
1421 case "-r":
1422 report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
1423 if ((i + 1) >= args.Length){
1424 Error_RequiresArgument (arg);
1425 return ParseResult.Error;
1428 string val = args [++i];
1429 int idx = val.IndexOf ('=');
1430 if (idx > -1) {
1431 string alias = val.Substring (0, idx);
1432 string assembly = val.Substring (idx + 1);
1433 AddAssemblyReference (alias, assembly, settings);
1434 return ParseResult.Success;
1437 settings.AssemblyReferences.Add (val);
1438 return ParseResult.Success;
1440 case "-L":
1441 report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
1442 if ((i + 1) >= args.Length){
1443 Error_RequiresArgument (arg);
1444 return ParseResult.Error;
1446 settings.ReferencesLookupPaths.Add (args [++i]);
1447 return ParseResult.Success;
1449 case "--lint":
1450 settings.EnhancedWarnings = true;
1451 return ParseResult.Success;
1453 case "--nostdlib":
1454 report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
1455 settings.StdLib = false;
1456 return ParseResult.Success;
1458 case "--nowarn":
1459 report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1460 if ((i + 1) >= args.Length){
1461 Error_RequiresArgument (arg);
1462 return ParseResult.Error;
1464 int warn = 0;
1466 try {
1467 warn = int.Parse (args [++i]);
1468 } catch {
1469 Usage ();
1470 Environment.Exit (1);
1472 settings.SetIgnoreWarning (warn);
1473 return ParseResult.Success;
1475 case "--wlevel":
1476 report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1477 if ((i + 1) >= args.Length){
1478 Error_RequiresArgument (arg);
1479 return ParseResult.Error;
1482 SetWarningLevel (args [++i], settings);
1483 return ParseResult.Success;
1485 case "--mcs-debug":
1486 if ((i + 1) >= args.Length){
1487 Error_RequiresArgument (arg);
1488 return ParseResult.Error;
1491 try {
1492 settings.DebugFlags = int.Parse (args [++i]);
1493 } catch {
1494 Error_RequiresArgument (arg);
1495 return ParseResult.Error;
1498 return ParseResult.Success;
1500 case "--about":
1501 About ();
1502 return ParseResult.Stop;
1504 case "--recurse":
1505 report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1506 if ((i + 1) >= args.Length){
1507 Error_RequiresArgument (arg);
1508 return ParseResult.Error;
1510 ProcessSourceFiles (args [++i], true, settings.SourceFiles);
1511 return ParseResult.Success;
1513 case "--timestamp":
1514 settings.Timestamps = true;
1515 return ParseResult.Success;
1517 case "--debug": case "-g":
1518 report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1519 settings.GenerateDebugInfo = true;
1520 return ParseResult.Success;
1522 case "--noconfig":
1523 report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1524 settings.LoadDefaultReferences = false;
1525 return ParseResult.Success;
1527 case "--metadata-only":
1528 settings.WriteMetadataOnly = true;
1529 return ParseResult.Success;
1531 case "--break-on-ice":
1532 settings.BreakOnInternalError = true;
1533 return ParseResult.Success;
1535 default:
1536 if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
1537 int fatal = 1;
1538 if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
1539 int.TryParse (arg.Substring (8), out fatal);
1541 settings.FatalCounter = fatal;
1542 return ParseResult.Success;
1544 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
1545 string version = arg.Substring (10);
1547 switch (version) {
1548 case "v1":
1549 case "V1":
1550 settings.StdLibRuntimeVersion = RuntimeVersion.v1;
1551 break;
1552 case "v2":
1553 case "V2":
1554 settings.StdLibRuntimeVersion = RuntimeVersion.v2;
1555 break;
1556 case "v4":
1557 case "V4":
1558 settings.StdLibRuntimeVersion = RuntimeVersion.v4;
1559 break;
1561 return ParseResult.Success;
1564 if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
1565 string file = arg.Substring (21).Trim ();
1566 if (file.Length < 1) {
1567 Error_RequiresArgument (arg);
1568 return ParseResult.Error;
1571 if (settings.GetResourceStrings == null)
1572 settings.GetResourceStrings = new List<string> ();
1574 settings.GetResourceStrings.Add (file);
1575 return ParseResult.Success;
1578 return ParseResult.UnknownOption;
1582 void SetWarningLevel (string s, CompilerSettings settings)
1584 int level = -1;
1586 try {
1587 level = int.Parse (s);
1588 } catch {
1590 if (level < 0 || level > 4) {
1591 report.Error (1900, "Warning level must be in the range 0-4");
1592 return;
1594 settings.WarningLevel = level;
1598 // Given a path specification, splits the path from the file/pattern
1600 static void SplitPathAndPattern (string spec, out string path, out string pattern)
1602 int p = spec.LastIndexOf ('/');
1603 if (p != -1) {
1605 // Windows does not like /file.cs, switch that to:
1606 // "\", "file.cs"
1608 if (p == 0) {
1609 path = "\\";
1610 pattern = spec.Substring (1);
1611 } else {
1612 path = spec.Substring (0, p);
1613 pattern = spec.Substring (p + 1);
1615 return;
1618 p = spec.LastIndexOf ('\\');
1619 if (p != -1) {
1620 path = spec.Substring (0, p);
1621 pattern = spec.Substring (p + 1);
1622 return;
1625 path = ".";
1626 pattern = spec;
1629 void Usage ()
1631 output.WriteLine (
1632 "Turbo C# compiler, Copyright 2001-2011 Novell, Inc., 2011-2016 Xamarin, Inc, 2016-2017 Microsoft Corp\n" +
1633 "mcs [options] source-files\n" +
1634 " --about About the Mono C# compiler\n" +
1635 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
1636 " -checked[+|-] Sets default aritmetic overflow context\n" +
1637 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
1638 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
1639 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
1640 " -debug[+|-], -g Generate debugging information\n" +
1641 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
1642 " -doc:FILE Process documentation comments to XML file\n" +
1643 " -fullpaths Any issued error or warning uses absolute file path\n" +
1644 " -help Lists all compiler options (short: -?)\n" +
1645 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
1646 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
1647 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, 4, 5, 6, Default or Experimental\n" +
1648 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
1649 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
1650 " -noconfig Disables implicitly referenced assemblies\n" +
1651 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
1652 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
1653 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
1654 " -out:FILE Specifies output assembly name\n" +
1655 " -pathmap:K=V[,Kn=Vn] Sets a mapping for source path names used in generated output\n" +
1656 " -pkg:P1[,Pn] References packages P1..Pn\n" +
1657 " -platform:ARCH Specifies the target platform of the output assembly\n" +
1658 " ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
1659 " x86, x64 or itanium. The default is anycpu.\n" +
1660 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
1661 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
1662 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
1663 " -sdk:VERSION Specifies SDK version of referenced assemblies\n" +
1664 " VERSION can be one of: 2, 4, 4.5, 4.x (default) or a custom value\n" +
1665 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
1666 " KIND can be one of: exe, winexe, library, module\n" +
1667 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
1668 " -warnaserror[+|-] Treats all warnings as errors\n" +
1669 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
1670 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
1671 " -helpinternal Shows internal and advanced compiler options\n" +
1672 "\n" +
1673 "Resources:\n" +
1674 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
1675 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
1676 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
1677 " -win32icon:FILE Use this icon for the output\n" +
1678 " @file Read response file for more options\n\n" +
1679 "Options can be of the form -option or /option");
1682 void Version ()
1684 string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
1685 output.WriteLine ("Mono C# compiler version {0}", version);
1689 public class RootContext
1692 // Contains the parsed tree
1694 static ModuleContainer root;
1696 static public ModuleContainer ToplevelTypes {
1697 get { return root; }
1698 set { root = value; }