2 // settings.cs: All compiler settings
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 // Ravi Pratap (ravi@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
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;
19 using System.Globalization;
22 namespace Mono.CSharp {
24 public enum LanguageVersion
41 public enum RuntimeVersion
50 Library, Exe, Module, WinExe
63 public class CompilerSettings
66 public Platform Platform;
67 public string TargetExt;
68 public bool VerifyClsCompliance;
70 public LanguageVersion Version;
71 public bool EnhancedWarnings;
72 public bool LoadDefaultReferences;
73 public string SdkVersion;
75 public string StrongNameKeyFile;
76 public string StrongNameKeyContainer;
77 public bool StrongNameDelaySign;
81 public bool WarningsAreErrors;
82 public int WarningLevel;
85 // Assemblies references to be loaded
87 public List<string> AssemblyReferences;
90 // External aliases for assemblies
92 public List<Tuple<string, string>> AssemblyReferencesAliases;
94 public List<KeyValuePair<string, string>> PathMap;
97 // Modules to be embedded
99 public List<string> Modules;
102 // Lookup paths for referenced assemblies
104 public List<string> ReferencesLookupPaths;
109 public Encoding Encoding;
112 // If set, enable XML documentation generation
114 public string DocumentationFile;
116 public string MainClass;
121 public string OutputFile;
124 // The default compiler checked state
129 // If true, the compiler is operating in statement mode,
130 // this currently turns local variable declaration into
131 // static variables of a class
133 public bool StatementMode; // TODO: SUPER UGLY
136 // Whether to allow Unsafe code
140 public string Win32ResourceFile;
141 public string Win32IconFile;
144 // A list of resource files for embedding
146 public List<AssemblyResource> Resources;
148 public bool GenerateDebugInfo;
150 #region Compiler debug flags only
151 public bool ParseOnly, TokenizeOnly, Timestamps;
152 public int DebugFlags;
153 public int VerboseParserFlag;
154 public int FatalCounter;
155 public bool Stacktrace;
156 public bool BreakOnInternalError;
159 public List<string> GetResourceStrings;
161 public bool ShowFullPaths;
164 // Whether we are being linked against the standard libraries.
165 // This is only used to tell whether `System.Object' should
166 // have a base class or not.
170 public RuntimeVersion StdLibRuntimeVersion;
172 public string RuntimeMetadataVersion;
174 public bool WriteMetadataOnly;
176 readonly List<string> conditional_symbols;
178 readonly List<SourceFile> source_files;
180 List<int> warnings_as_error;
181 List<int> warnings_only;
182 HashSet<int> warning_ignore_table;
184 public CompilerSettings ()
189 Platform = Platform.AnyCPU;
190 Version = LanguageVersion.Default;
191 VerifyClsCompliance = true;
192 Encoding = Encoding.UTF8;
193 LoadDefaultReferences = true;
194 StdLibRuntimeVersion = RuntimeVersion.v4;
197 // Default to 1 or mdb files would be platform speficic
200 AssemblyReferences = new List<string> ();
201 AssemblyReferencesAliases = new List<Tuple<string, string>> ();
202 Modules = new List<string> ();
203 ReferencesLookupPaths = new List<string> ();
205 conditional_symbols = new List<string> ();
207 // Add default mcs define
209 conditional_symbols.Add ("__MonoCS__");
211 source_files = new List<SourceFile> ();
216 public SourceFile FirstSourceFile {
218 return source_files.Count > 0 ? source_files [0] : null;
222 public bool HasKeyFileOrContainer {
224 return StrongNameKeyFile != null || StrongNameKeyContainer != null;
228 public bool NeedsEntryPoint {
230 return Target == Target.Exe || Target == Target.WinExe;
234 public List<SourceFile> SourceFiles {
242 public void AddConditionalSymbol (string symbol)
244 if (!conditional_symbols.Contains (symbol))
245 conditional_symbols.Add (symbol);
248 public void AddWarningAsError (int id)
250 if (warnings_as_error == null)
251 warnings_as_error = new List<int> ();
253 warnings_as_error.Add (id);
256 public void AddWarningOnly (int id)
258 if (warnings_only == null)
259 warnings_only = new List<int> ();
261 warnings_only.Add (id);
264 public bool IsConditionalSymbolDefined (string symbol)
266 return conditional_symbols.Contains (symbol);
269 public bool IsWarningAsError (int code)
271 bool is_error = WarningsAreErrors;
273 // Check specific list
274 if (warnings_as_error != null)
275 is_error |= warnings_as_error.Contains (code);
277 // Ignore excluded warnings
278 if (warnings_only != null && warnings_only.Contains (code))
284 public bool IsWarningEnabled (int code, int level)
286 if (WarningLevel < level)
289 return !IsWarningDisabledGlobally (code);
292 public bool IsWarningDisabledGlobally (int code)
294 return warning_ignore_table != null && warning_ignore_table.Contains (code);
297 public void SetIgnoreWarning (int code)
299 if (warning_ignore_table == null)
300 warning_ignore_table = new HashSet<int> ();
302 warning_ignore_table.Add (code);
306 public class CommandLineParser
316 static readonly char[] argument_value_separator = { ';', ',' };
317 static readonly char[] numeric_value_separator = { ';', ',', ' ' };
319 readonly TextWriter output;
320 readonly Report report;
323 Dictionary<string, int> source_file_index;
325 public event Func<string[], int, int> UnknownOptionHandler;
327 CompilerSettings parser_settings;
329 public CommandLineParser (TextWriter errorOutput)
330 : this (errorOutput, Console.Out)
334 public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
336 var rp = new StreamReportPrinter (errorOutput);
338 parser_settings = new CompilerSettings ();
339 report = new Report (new CompilerContext (parser_settings, rp), rp);
340 this.output = messagesOutput;
343 public bool HasBeenStopped {
345 return stop_argument;
352 "The Turbo C# compiler is Copyright 2001-2011, Novell, Inc. 2011-2016 Xamarin Inc, 2016-2017 Microsoft Corp\n\n" +
353 "The compiler source code is released under the terms of the \n" +
354 "MIT X11 or GNU GPL licenses\n\n" +
356 "For more information on Mono, visit the project Web site\n" +
357 " http://www.mono-project.com\n\n" +
359 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
362 public CompilerSettings ParseArguments (string[] args)
364 CompilerSettings settings = new CompilerSettings ();
365 if (!ParseArguments (settings, args))
371 public bool ParseArguments (CompilerSettings settings, string[] args)
373 if (settings == null)
374 throw new ArgumentNullException ("settings");
376 List<string> response_file_list = null;
377 bool parsing_options = true;
378 stop_argument = false;
379 source_file_index = new Dictionary<string, int> ();
381 for (int i = 0; i < args.Length; i++) {
382 string arg = args[i];
388 string response_file = arg.Substring (1);
390 if (response_file_list == null)
391 response_file_list = new List<string> ();
393 if (response_file_list.Contains (response_file)) {
394 report.Error (1515, "Response file `{0}' specified multiple times", response_file);
398 response_file_list.Add (response_file);
400 extra_args = LoadArgs (response_file);
401 if (extra_args == null) {
402 report.Error (2011, "Unable to open response file: " + response_file);
406 args = AddArgs (args, extra_args);
410 if (parsing_options) {
412 parsing_options = false;
416 bool dash_opt = arg[0] == '-';
417 bool slash_opt = arg[0] == '/';
419 switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
420 case ParseResult.Error:
421 case ParseResult.Success:
423 case ParseResult.Stop:
424 stop_argument = true;
426 case ParseResult.UnknownOption:
427 if (UnknownOptionHandler != null) {
428 var ret = UnknownOptionHandler (args, i);
438 if (dash_opt || slash_opt) {
440 string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
441 switch (ParseOption (csc_opt, ref args, settings)) {
442 case ParseResult.Error:
443 case ParseResult.Success:
445 case ParseResult.UnknownOption:
446 // Need to skip `/home/test.cs' however /test.cs is considered as error
447 if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
450 if (UnknownOptionHandler != null) {
451 var ret = UnknownOptionHandler (args, i);
458 Error_WrongOption (arg);
461 case ParseResult.Stop:
462 stop_argument = true;
468 ProcessSourceFiles (arg, false, settings.SourceFiles);
471 return report.Errors == 0;
474 void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
476 string path, pattern;
478 SplitPathAndPattern (spec, out path, out pattern);
479 if (pattern.IndexOf ('*') == -1) {
480 AddSourceFile (spec, sourceFiles);
486 files = Directory.GetFiles (path, pattern);
487 } catch (System.IO.DirectoryNotFoundException) {
488 report.Error (2001, "Source file `" + spec + "' could not be found");
490 } catch (System.IO.IOException) {
491 report.Error (2001, "Source file `" + spec + "' could not be found");
494 foreach (string f in files) {
495 AddSourceFile (f, sourceFiles);
501 string[] dirs = null;
504 dirs = Directory.GetDirectories (path);
508 foreach (string d in dirs) {
510 // Don't include path in this string, as each
511 // directory entry already does
512 ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
516 static string[] AddArgs (string[] args, string[] extra_args)
519 new_args = new string[extra_args.Length + args.Length];
521 // if args contains '--' we have to take that into account
522 // split args into first half and second half based on '--'
523 // and add the extra_args before --
524 int split_position = Array.IndexOf (args, "--");
525 if (split_position != -1) {
526 Array.Copy (args, new_args, split_position);
527 extra_args.CopyTo (new_args, split_position);
528 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
530 args.CopyTo (new_args, 0);
531 extra_args.CopyTo (new_args, args.Length);
537 void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
539 if (assembly.Length == 0) {
540 report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
544 if (!IsExternAliasValid (alias)) {
545 report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
549 settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
552 void AddResource (AssemblyResource res, CompilerSettings settings)
554 if (settings.Resources == null) {
555 settings.Resources = new List<AssemblyResource> ();
556 settings.Resources.Add (res);
560 if (settings.Resources.Contains (res)) {
561 report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
565 settings.Resources.Add (res);
568 void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
570 string path = Path.GetFullPath (fileName);
573 if (source_file_index.TryGetValue (path, out index)) {
574 string other_name = sourceFiles[index - 1].Name;
575 if (fileName.Equals (other_name))
576 report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
578 report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
583 var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
584 sourceFiles.Add (unit);
585 source_file_index.Add (path, unit.Index);
588 public bool ProcessWarningsList (string text, Action<int> action)
590 foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
592 if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
593 warning = warning.Substring (2);
596 if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
606 void Error_RequiresArgument (string option)
608 report.Error (2006, "Missing argument for `{0}' option", option);
611 void Error_RequiresFileName (string option)
613 report.Error (2005, "Missing file specification for `{0}' option", option);
616 void Error_WrongOption (string option)
618 report.Error (2007, "Unrecognized command-line option: `{0}'", option);
621 static bool IsExternAliasValid (string identifier)
623 return Tokenizer.IsValidIdentifier (identifier);
626 static string[] LoadArgs (string file)
629 var args = new List<string> ();
632 f = new StreamReader (file);
637 StringBuilder sb = new StringBuilder ();
639 while ((line = f.ReadLine ()) != null) {
642 for (int i = 0; i < t; i++) {
645 if (c == '"' || c == '\'') {
648 for (i++; i < t; i++) {
655 } else if (c == ' ') {
657 args.Add (sb.ToString ());
664 args.Add (sb.ToString ());
669 return args.ToArray ();
675 "Other flags in the compiler\n" +
676 " --fatal[=COUNT] Makes error after COUNT fatal\n" +
677 " --lint Enhanced warnings\n" +
678 " --metadata-only Produced assembly will contain metadata only\n" +
679 " --parse Only parses the source file\n" +
680 " --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
681 " --stacktrace Shows stack trace at error location\n" +
682 " --timestamp Displays time stamps of various compiler events\n" +
683 " -v Verbose parsing (for debugging the parser)\n" +
684 " --mcs-debug X Sets MCS debugging level to X\n" +
685 " --break-on-ice Breaks compilation on internal compiler error");
689 // This parses the -arg and /arg options to the compiler, even if the strings
690 // in the following text use "/arg" on the strings.
692 ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
694 int idx = option.IndexOf (':');
701 arg = option.Substring (0, idx);
703 value = option.Substring (idx + 1);
706 switch (arg.ToLowerInvariant ()) {
708 return ParseResult.Success;
714 settings.Target = Target.Exe;
718 settings.Target = Target.WinExe;
722 settings.Target = Target.Library;
723 settings.TargetExt = ".dll";
727 settings.Target = Target.Module;
728 settings.TargetExt = ".netmodule";
732 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
733 return ParseResult.Error;
735 return ParseResult.Success;
738 if (value.Length == 0) {
739 Error_RequiresFileName (option);
740 return ParseResult.Error;
742 settings.OutputFile = value;
743 return ParseResult.Success;
749 settings.Optimize = true;
750 return ParseResult.Success;
754 settings.Optimize = false;
755 return ParseResult.Success;
757 // TODO: Not supported by csc 3.5+
759 case "/incremental+":
760 case "/incremental-":
762 return ParseResult.Success;
766 if (value.Length == 0) {
767 Error_RequiresArgument (option);
768 return ParseResult.Error;
771 foreach (string d in value.Split (argument_value_separator)) {
772 string conditional = d.Trim ();
773 if (!Tokenizer.IsValidIdentifier (conditional)) {
774 report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
778 settings.AddConditionalSymbol (conditional);
780 return ParseResult.Success;
785 // We should collect data, runtime, etc and store in the file specified
787 output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
788 return ParseResult.Success;
793 if (value.Length == 0) {
794 Error_RequiresArgument (option);
795 return ParseResult.Error;
797 packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
798 string pkgout = Driver.GetPackageFlags (packages, report);
801 return ParseResult.Error;
803 string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
804 args = AddArgs (args, xargs);
805 return ParseResult.Success;
809 case "/linkresource":
812 AssemblyResource res = null;
813 string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
816 if (s[0].Length == 0)
818 res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
821 res = new AssemblyResource (s[0], s[1]);
824 if (s[2] != "public" && s[2] != "private") {
825 report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
826 return ParseResult.Error;
828 res = new AssemblyResource (s[0], s[1], s[2] == "private");
831 report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
832 return ParseResult.Error;
836 res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
837 AddResource (res, settings);
840 return ParseResult.Success;
843 if (value.Length == 0) {
844 Error_RequiresFileName (option);
845 return ParseResult.Error;
847 ProcessSourceFiles (value, true, settings.SourceFiles);
848 return ParseResult.Success;
852 if (value.Length == 0) {
853 Error_RequiresFileName (option);
854 return ParseResult.Error;
857 string[] refs = value.Split (argument_value_separator);
858 foreach (string r in refs) {
863 int index = val.IndexOf ('=');
865 string alias = r.Substring (0, index);
866 string assembly = r.Substring (index + 1);
867 AddAssemblyReference (alias, assembly, settings);
868 if (refs.Length != 1) {
869 report.Error (2034, "Cannot specify multiple aliases using single /reference option");
870 return ParseResult.Error;
873 settings.AssemblyReferences.Add (val);
876 return ParseResult.Success;
879 if (value.Length == 0) {
880 Error_RequiresFileName (option);
881 return ParseResult.Error;
884 string[] refs = value.Split (argument_value_separator);
885 foreach (string r in refs) {
886 settings.Modules.Add (r);
888 return ParseResult.Success;
891 if (value.Length == 0) {
892 Error_RequiresFileName (option);
893 return ParseResult.Error;
896 if (settings.Win32IconFile != null)
897 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
899 settings.Win32ResourceFile = value;
900 return ParseResult.Success;
903 if (value.Length == 0) {
904 Error_RequiresFileName (option);
905 return ParseResult.Error;
908 if (settings.Win32ResourceFile != null)
909 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
911 settings.Win32IconFile = value;
912 return ParseResult.Success;
915 if (value.Length == 0) {
916 Error_RequiresFileName (option);
917 return ParseResult.Error;
920 settings.DocumentationFile = value;
921 return ParseResult.Success;
926 if (value.Length == 0) {
927 return ParseResult.Error;
930 libdirs = value.Split (argument_value_separator);
931 foreach (string dir in libdirs)
932 settings.ReferencesLookupPaths.Add (dir);
933 return ParseResult.Success;
937 settings.GenerateDebugInfo = false;
938 return ParseResult.Success;
941 if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || value.Equals ("portable", StringComparison.OrdinalIgnoreCase) || idx < 0) {
942 settings.GenerateDebugInfo = true;
943 return ParseResult.Success;
946 if (value.Length > 0) {
947 report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
949 Error_RequiresArgument (option);
952 return ParseResult.Error;
955 settings.GenerateDebugInfo = true;
956 return ParseResult.Success;
960 settings.Checked = true;
961 return ParseResult.Success;
964 settings.Checked = false;
965 return ParseResult.Success;
969 settings.VerifyClsCompliance = true;
970 return ParseResult.Success;
973 settings.VerifyClsCompliance = false;
974 return ParseResult.Success;
978 settings.Unsafe = true;
979 return ParseResult.Success;
982 settings.Unsafe = false;
983 return ParseResult.Success;
986 case "/warnaserror+":
987 if (value.Length == 0) {
988 settings.WarningsAreErrors = true;
989 parser_settings.WarningsAreErrors = true;
991 if (!ProcessWarningsList (value, settings.AddWarningAsError))
992 return ParseResult.Error;
994 return ParseResult.Success;
996 case "/warnaserror-":
997 if (value.Length == 0) {
998 settings.WarningsAreErrors = false;
1000 if (!ProcessWarningsList (value, settings.AddWarningOnly))
1001 return ParseResult.Error;
1003 return ParseResult.Success;
1007 if (value.Length == 0) {
1008 Error_RequiresArgument (option);
1009 return ParseResult.Error;
1012 SetWarningLevel (value, settings);
1013 return ParseResult.Success;
1016 if (value.Length == 0) {
1017 Error_RequiresArgument (option);
1018 return ParseResult.Error;
1021 if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
1022 return ParseResult.Error;
1024 return ParseResult.Success;
1027 settings.LoadDefaultReferences = false;
1028 return ParseResult.Success;
1031 if (value.Length == 0) {
1032 Error_RequiresArgument (option);
1033 return ParseResult.Error;
1036 switch (value.ToLowerInvariant ()) {
1038 settings.Platform = Platform.Arm;
1041 settings.Platform = Platform.AnyCPU;
1044 settings.Platform = Platform.X86;
1047 settings.Platform = Platform.X64;
1050 settings.Platform = Platform.IA64;
1052 case "anycpu32bitpreferred":
1053 settings.Platform = Platform.AnyCPU32Preferred;
1056 report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
1058 return ParseResult.Error;
1061 return ParseResult.Success;
1064 if (value.Length == 0) {
1065 Error_RequiresArgument (option);
1066 return ParseResult.Error;
1069 settings.SdkVersion = value;
1070 return ParseResult.Success;
1072 // We just ignore this.
1073 case "/errorreport":
1075 if (value.Length == 0) {
1076 Error_RequiresArgument (option);
1077 return ParseResult.Error;
1080 return ParseResult.Success;
1082 case "/helpinternal":
1084 return ParseResult.Stop;
1089 return ParseResult.Stop;
1093 if (value.Length == 0) {
1094 Error_RequiresArgument (option);
1095 return ParseResult.Error;
1097 settings.MainClass = value;
1098 return ParseResult.Success;
1102 settings.StdLib = false;
1103 return ParseResult.Success;
1106 settings.StdLib = true;
1107 return ParseResult.Success;
1110 settings.ShowFullPaths = true;
1111 return ParseResult.Success;
1114 if (value.Length == 0) {
1115 Error_RequiresFileName (option);
1116 return ParseResult.Error;
1119 settings.StrongNameKeyFile = value;
1120 return ParseResult.Success;
1122 case "/keycontainer":
1123 if (value.Length == 0) {
1124 Error_RequiresArgument (option);
1125 return ParseResult.Error;
1128 settings.StrongNameKeyContainer = value;
1129 return ParseResult.Success;
1133 settings.StrongNameDelaySign = true;
1134 return ParseResult.Success;
1137 settings.StrongNameDelaySign = false;
1138 return ParseResult.Success;
1140 case "/langversion":
1141 if (value.Length == 0) {
1142 Error_RequiresArgument (option);
1143 return ParseResult.Error;
1146 switch (value.ToLowerInvariant ()) {
1150 settings.Version = LanguageVersion.ISO_1;
1151 return ParseResult.Success;
1153 settings.Version = LanguageVersion.Default;
1154 return ParseResult.Success;
1158 settings.Version = LanguageVersion.ISO_2;
1159 return ParseResult.Success;
1162 settings.Version = LanguageVersion.V_3;
1163 return ParseResult.Success;
1166 settings.Version = LanguageVersion.V_4;
1167 return ParseResult.Success;
1170 settings.Version = LanguageVersion.V_5;
1171 return ParseResult.Success;
1174 settings.Version = LanguageVersion.V_6;
1175 return ParseResult.Success;
1178 settings.Version = LanguageVersion.V_7;
1179 return ParseResult.Success;
1181 settings.Version = LanguageVersion.V_7_1;
1182 return ParseResult.Success;
1184 settings.Version = LanguageVersion.V_7_2;
1185 return ParseResult.Success;
1187 settings.Version = LanguageVersion.Latest;
1188 return ParseResult.Success;
1189 case "experimental":
1190 settings.Version = LanguageVersion.Experimental;
1191 return ParseResult.Success;
1194 if (value.StartsWith ("0", StringComparison.Ordinal)) {
1195 report.Error (8303, "Specified language version `{0}' cannot have leading zeroes", value);
1197 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);
1200 return ParseResult.Error;
1203 if (value.Length == 0) {
1204 Error_RequiresArgument (option);
1205 return ParseResult.Error;
1210 settings.Encoding = Encoding.UTF8;
1213 settings.Encoding = Encoding.Default;
1217 settings.Encoding = Encoding.GetEncoding (int.Parse (value));
1219 report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1221 return ParseResult.Error;
1223 return ParseResult.Success;
1225 case "/runtimemetadataversion":
1226 if (value.Length == 0) {
1227 Error_RequiresArgument (option);
1228 return ParseResult.Error;
1231 settings.RuntimeMetadataVersion = value;
1232 return ParseResult.Success;
1235 if (value.Length == 0) {
1236 return ParseResult.Success;
1239 foreach (var pair in value.Split (',')) {
1240 var kv = pair.Split ('=');
1241 if (kv.Length != 2) {
1242 report.Error (8101, "The pathmap option was incorrectly formatted");
1243 return ParseResult.Error;
1246 if (settings.PathMap == null)
1247 settings.PathMap = new List<KeyValuePair<string, string>> ();
1249 var key = kv [0].TrimEnd (Path.DirectorySeparatorChar);
1250 var path = kv [1].TrimEnd (Path.DirectorySeparatorChar);
1251 if (key.Length == 0 || path.Length == 0)
1252 report.Error (8101, "The pathmap option was incorrectly formatted");
1254 settings.PathMap.Add (new KeyValuePair<string, string> (key, path));
1257 return ParseResult.Success;
1259 // csc options that we don't support
1262 case "/baseaddress":
1263 case "/deterministic":
1264 case "/deterministic+":
1265 case "/deterministic-":
1266 case "/errorendlocation":
1269 case "/highentropyva":
1270 case "/highentropyva+":
1271 case "/highentropyva-":
1273 case "/moduleassemblyname":
1274 case "/nowin32manifest":
1276 case "/preferreduilang":
1278 case "/publicsign+":
1279 case "/publicsign-":
1280 case "/reportanalyzer":
1282 case "/sqmsessionguid":
1283 case "/subsystemversion":
1285 case "/win32manifest":
1286 return ParseResult.Success;
1289 return ParseResult.UnknownOption;
1294 // Currently handles the Unix-like command line options, but will be
1295 // deprecated in favor of the CSCParseOption, which will also handle the
1296 // options that start with a dash in the future.
1298 ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
1302 settings.VerboseParserFlag++;
1303 return ParseResult.Success;
1307 return ParseResult.Stop;
1310 settings.ParseOnly = true;
1311 return ParseResult.Success;
1313 case "--main": case "-m":
1314 report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
1315 if ((i + 1) >= args.Length){
1316 Error_RequiresArgument (arg);
1317 return ParseResult.Error;
1319 settings.MainClass = args[++i];
1320 return ParseResult.Success;
1323 report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
1324 settings.Unsafe = true;
1325 return ParseResult.Success;
1327 case "/?": case "/h": case "/help":
1330 return ParseResult.Stop;
1333 report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
1334 if ((i + 1) >= args.Length){
1335 Error_RequiresArgument (arg);
1336 return ParseResult.Error;
1339 settings.AddConditionalSymbol (args [++i]);
1340 return ParseResult.Success;
1343 settings.TokenizeOnly = true;
1344 return ParseResult.Success;
1348 report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
1349 if ((i + 1) >= args.Length){
1350 Error_RequiresArgument (arg);
1351 return ParseResult.Error;
1353 settings.OutputFile = args[++i];
1354 return ParseResult.Success;
1357 report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
1358 settings.Checked = true;
1359 return ParseResult.Success;
1361 case "--stacktrace":
1362 settings.Stacktrace = true;
1363 return ParseResult.Success;
1365 case "--linkresource":
1367 report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
1368 if ((i + 1) >= args.Length){
1369 Error_RequiresArgument (arg);
1370 return ParseResult.Error;
1373 AddResource (new AssemblyResource (args[++i], args[i]), settings);
1374 return ParseResult.Success;
1378 report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
1379 if ((i + 1) >= args.Length){
1380 Error_RequiresArgument (arg);
1381 return ParseResult.Error;
1384 AddResource (new AssemblyResource (args[++i], args[i], true), settings);
1385 return ParseResult.Success;
1388 report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
1389 if ((i + 1) >= args.Length){
1390 Error_RequiresArgument (arg);
1391 return ParseResult.Error;
1394 string type = args [++i];
1397 settings.Target = Target.Library;
1398 settings.TargetExt = ".dll";
1402 settings.Target = Target.Exe;
1406 settings.Target = Target.WinExe;
1410 settings.Target = Target.Module;
1411 settings.TargetExt = ".dll";
1414 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
1417 return ParseResult.Success;
1420 report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
1421 if ((i + 1) >= args.Length){
1422 Error_RequiresArgument (arg);
1423 return ParseResult.Error;
1426 string val = args [++i];
1427 int idx = val.IndexOf ('=');
1429 string alias = val.Substring (0, idx);
1430 string assembly = val.Substring (idx + 1);
1431 AddAssemblyReference (alias, assembly, settings);
1432 return ParseResult.Success;
1435 settings.AssemblyReferences.Add (val);
1436 return ParseResult.Success;
1439 report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
1440 if ((i + 1) >= args.Length){
1441 Error_RequiresArgument (arg);
1442 return ParseResult.Error;
1444 settings.ReferencesLookupPaths.Add (args [++i]);
1445 return ParseResult.Success;
1448 settings.EnhancedWarnings = true;
1449 return ParseResult.Success;
1452 report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
1453 settings.StdLib = false;
1454 return ParseResult.Success;
1457 report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1458 if ((i + 1) >= args.Length){
1459 Error_RequiresArgument (arg);
1460 return ParseResult.Error;
1465 warn = int.Parse (args [++i]);
1468 Environment.Exit (1);
1470 settings.SetIgnoreWarning (warn);
1471 return ParseResult.Success;
1474 report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1475 if ((i + 1) >= args.Length){
1476 Error_RequiresArgument (arg);
1477 return ParseResult.Error;
1480 SetWarningLevel (args [++i], settings);
1481 return ParseResult.Success;
1484 if ((i + 1) >= args.Length){
1485 Error_RequiresArgument (arg);
1486 return ParseResult.Error;
1490 settings.DebugFlags = int.Parse (args [++i]);
1492 Error_RequiresArgument (arg);
1493 return ParseResult.Error;
1496 return ParseResult.Success;
1500 return ParseResult.Stop;
1503 report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1504 if ((i + 1) >= args.Length){
1505 Error_RequiresArgument (arg);
1506 return ParseResult.Error;
1508 ProcessSourceFiles (args [++i], true, settings.SourceFiles);
1509 return ParseResult.Success;
1512 settings.Timestamps = true;
1513 return ParseResult.Success;
1515 case "--debug": case "-g":
1516 report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1517 settings.GenerateDebugInfo = true;
1518 return ParseResult.Success;
1521 report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1522 settings.LoadDefaultReferences = false;
1523 return ParseResult.Success;
1525 case "--metadata-only":
1526 settings.WriteMetadataOnly = true;
1527 return ParseResult.Success;
1529 case "--break-on-ice":
1530 settings.BreakOnInternalError = true;
1531 return ParseResult.Success;
1534 if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
1536 if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
1537 int.TryParse (arg.Substring (8), out fatal);
1539 settings.FatalCounter = fatal;
1540 return ParseResult.Success;
1542 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
1543 string version = arg.Substring (10);
1548 settings.StdLibRuntimeVersion = RuntimeVersion.v1;
1552 settings.StdLibRuntimeVersion = RuntimeVersion.v2;
1556 settings.StdLibRuntimeVersion = RuntimeVersion.v4;
1559 return ParseResult.Success;
1562 if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
1563 string file = arg.Substring (21).Trim ();
1564 if (file.Length < 1) {
1565 Error_RequiresArgument (arg);
1566 return ParseResult.Error;
1569 if (settings.GetResourceStrings == null)
1570 settings.GetResourceStrings = new List<string> ();
1572 settings.GetResourceStrings.Add (file);
1573 return ParseResult.Success;
1576 return ParseResult.UnknownOption;
1580 void SetWarningLevel (string s, CompilerSettings settings)
1585 level = int.Parse (s);
1588 if (level < 0 || level > 4) {
1589 report.Error (1900, "Warning level must be in the range 0-4");
1592 settings.WarningLevel = level;
1596 // Given a path specification, splits the path from the file/pattern
1598 static void SplitPathAndPattern (string spec, out string path, out string pattern)
1600 int p = spec.LastIndexOf ('/');
1603 // Windows does not like /file.cs, switch that to:
1608 pattern = spec.Substring (1);
1610 path = spec.Substring (0, p);
1611 pattern = spec.Substring (p + 1);
1616 p = spec.LastIndexOf ('\\');
1618 path = spec.Substring (0, p);
1619 pattern = spec.Substring (p + 1);
1630 "Turbo C# compiler, Copyright 2001-2011 Novell, Inc., 2011-2016 Xamarin, Inc, 2016-2017 Microsoft Corp\n" +
1631 "mcs [options] source-files\n" +
1632 " --about About the Mono C# compiler\n" +
1633 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
1634 " -checked[+|-] Sets default aritmetic overflow context\n" +
1635 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
1636 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
1637 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
1638 " -debug[+|-], -g Generate debugging information\n" +
1639 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
1640 " -doc:FILE Process documentation comments to XML file\n" +
1641 " -fullpaths Any issued error or warning uses absolute file path\n" +
1642 " -help Lists all compiler options (short: -?)\n" +
1643 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
1644 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
1645 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, 4, 5, 6, Default or Experimental\n" +
1646 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
1647 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
1648 " -noconfig Disables implicitly referenced assemblies\n" +
1649 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
1650 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
1651 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
1652 " -out:FILE Specifies output assembly name\n" +
1653 " -pathmap:K=V[,Kn=Vn] Sets a mapping for source path names used in generated output\n" +
1654 " -pkg:P1[,Pn] References packages P1..Pn\n" +
1655 " -platform:ARCH Specifies the target platform of the output assembly\n" +
1656 " ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
1657 " x86, x64 or itanium. The default is anycpu.\n" +
1658 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
1659 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
1660 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
1661 " -sdk:VERSION Specifies SDK version of referenced assemblies\n" +
1662 " VERSION can be one of: 2, 4, 4.5 (default) or a custom value\n" +
1663 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
1664 " KIND can be one of: exe, winexe, library, module\n" +
1665 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
1666 " -warnaserror[+|-] Treats all warnings as errors\n" +
1667 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
1668 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
1669 " -helpinternal Shows internal and advanced compiler options\n" +
1672 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
1673 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
1674 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
1675 " -win32icon:FILE Use this icon for the output\n" +
1676 " @file Read response file for more options\n\n" +
1677 "Options can be of the form -option or /option");
1682 string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
1683 output.WriteLine ("Mono C# compiler version {0}", version);
1687 public class RootContext
1690 // Contains the parsed tree
1692 static ModuleContainer root;
1694 static public ModuleContainer ToplevelTypes {
1695 get { return root; }
1696 set { root = value; }