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
38 public enum RuntimeVersion
47 Library, Exe, Module, WinExe
60 public class CompilerSettings
63 public Platform Platform;
64 public string TargetExt;
65 public bool VerifyClsCompliance;
67 public LanguageVersion Version;
68 public bool EnhancedWarnings;
69 public bool LoadDefaultReferences;
70 public string SdkVersion;
72 public string StrongNameKeyFile;
73 public string StrongNameKeyContainer;
74 public bool StrongNameDelaySign;
78 public bool WarningsAreErrors;
79 public int WarningLevel;
82 // Assemblies references to be loaded
84 public List<string> AssemblyReferences;
87 // External aliases for assemblies
89 public List<Tuple<string, string>> AssemblyReferencesAliases;
91 public List<KeyValuePair<string, string>> PathMap;
94 // Modules to be embedded
96 public List<string> Modules;
99 // Lookup paths for referenced assemblies
101 public List<string> ReferencesLookupPaths;
106 public Encoding Encoding;
109 // If set, enable XML documentation generation
111 public string DocumentationFile;
113 public string MainClass;
118 public string OutputFile;
121 // The default compiler checked state
126 // If true, the compiler is operating in statement mode,
127 // this currently turns local variable declaration into
128 // static variables of a class
130 public bool StatementMode; // TODO: SUPER UGLY
133 // Whether to allow Unsafe code
137 public string Win32ResourceFile;
138 public string Win32IconFile;
141 // A list of resource files for embedding
143 public List<AssemblyResource> Resources;
145 public bool GenerateDebugInfo;
147 #region Compiler debug flags only
148 public bool ParseOnly, TokenizeOnly, Timestamps;
149 public int DebugFlags;
150 public int VerboseParserFlag;
151 public int FatalCounter;
152 public bool Stacktrace;
153 public bool BreakOnInternalError;
156 public List<string> GetResourceStrings;
158 public bool ShowFullPaths;
161 // Whether we are being linked against the standard libraries.
162 // This is only used to tell whether `System.Object' should
163 // have a base class or not.
167 public RuntimeVersion StdLibRuntimeVersion;
169 public string RuntimeMetadataVersion;
171 public bool WriteMetadataOnly;
173 readonly List<string> conditional_symbols;
175 readonly List<SourceFile> source_files;
177 List<int> warnings_as_error;
178 List<int> warnings_only;
179 HashSet<int> warning_ignore_table;
181 public CompilerSettings ()
186 Platform = Platform.AnyCPU;
187 Version = LanguageVersion.Default;
188 VerifyClsCompliance = true;
189 Encoding = Encoding.UTF8;
190 LoadDefaultReferences = true;
191 StdLibRuntimeVersion = RuntimeVersion.v4;
194 // Default to 1 or mdb files would be platform speficic
197 AssemblyReferences = new List<string> ();
198 AssemblyReferencesAliases = new List<Tuple<string, string>> ();
199 Modules = new List<string> ();
200 ReferencesLookupPaths = new List<string> ();
202 conditional_symbols = new List<string> ();
204 // Add default mcs define
206 conditional_symbols.Add ("__MonoCS__");
208 source_files = new List<SourceFile> ();
213 public SourceFile FirstSourceFile {
215 return source_files.Count > 0 ? source_files [0] : null;
219 public bool HasKeyFileOrContainer {
221 return StrongNameKeyFile != null || StrongNameKeyContainer != null;
225 public bool NeedsEntryPoint {
227 return Target == Target.Exe || Target == Target.WinExe;
231 public List<SourceFile> SourceFiles {
239 public void AddConditionalSymbol (string symbol)
241 if (!conditional_symbols.Contains (symbol))
242 conditional_symbols.Add (symbol);
245 public void AddWarningAsError (int id)
247 if (warnings_as_error == null)
248 warnings_as_error = new List<int> ();
250 warnings_as_error.Add (id);
253 public void AddWarningOnly (int id)
255 if (warnings_only == null)
256 warnings_only = new List<int> ();
258 warnings_only.Add (id);
261 public bool IsConditionalSymbolDefined (string symbol)
263 return conditional_symbols.Contains (symbol);
266 public bool IsWarningAsError (int code)
268 bool is_error = WarningsAreErrors;
270 // Check specific list
271 if (warnings_as_error != null)
272 is_error |= warnings_as_error.Contains (code);
274 // Ignore excluded warnings
275 if (warnings_only != null && warnings_only.Contains (code))
281 public bool IsWarningEnabled (int code, int level)
283 if (WarningLevel < level)
286 return !IsWarningDisabledGlobally (code);
289 public bool IsWarningDisabledGlobally (int code)
291 return warning_ignore_table != null && warning_ignore_table.Contains (code);
294 public void SetIgnoreWarning (int code)
296 if (warning_ignore_table == null)
297 warning_ignore_table = new HashSet<int> ();
299 warning_ignore_table.Add (code);
303 public class CommandLineParser
313 static readonly char[] argument_value_separator = { ';', ',' };
314 static readonly char[] numeric_value_separator = { ';', ',', ' ' };
316 readonly TextWriter output;
317 readonly Report report;
320 Dictionary<string, int> source_file_index;
322 public event Func<string[], int, int> UnknownOptionHandler;
324 CompilerSettings parser_settings;
326 public CommandLineParser (TextWriter errorOutput)
327 : this (errorOutput, Console.Out)
331 public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
333 var rp = new StreamReportPrinter (errorOutput);
335 parser_settings = new CompilerSettings ();
336 report = new Report (new CompilerContext (parser_settings, rp), rp);
337 this.output = messagesOutput;
340 public bool HasBeenStopped {
342 return stop_argument;
349 "The Turbo C# compiler is Copyright 2001-2011, Novell, Inc. 2011-2016 Xamarin Inc, 2016-2017 Microsoft Corp\n\n" +
350 "The compiler source code is released under the terms of the \n" +
351 "MIT X11 or GNU GPL licenses\n\n" +
353 "For more information on Mono, visit the project Web site\n" +
354 " http://www.mono-project.com\n\n" +
356 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
359 public CompilerSettings ParseArguments (string[] args)
361 CompilerSettings settings = new CompilerSettings ();
362 if (!ParseArguments (settings, args))
368 public bool ParseArguments (CompilerSettings settings, string[] args)
370 if (settings == null)
371 throw new ArgumentNullException ("settings");
373 List<string> response_file_list = null;
374 bool parsing_options = true;
375 stop_argument = false;
376 source_file_index = new Dictionary<string, int> ();
378 for (int i = 0; i < args.Length; i++) {
379 string arg = args[i];
385 string response_file = arg.Substring (1);
387 if (response_file_list == null)
388 response_file_list = new List<string> ();
390 if (response_file_list.Contains (response_file)) {
391 report.Error (1515, "Response file `{0}' specified multiple times", response_file);
395 response_file_list.Add (response_file);
397 extra_args = LoadArgs (response_file);
398 if (extra_args == null) {
399 report.Error (2011, "Unable to open response file: " + response_file);
403 args = AddArgs (args, extra_args);
407 if (parsing_options) {
409 parsing_options = false;
413 bool dash_opt = arg[0] == '-';
414 bool slash_opt = arg[0] == '/';
416 switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
417 case ParseResult.Error:
418 case ParseResult.Success:
420 case ParseResult.Stop:
421 stop_argument = true;
423 case ParseResult.UnknownOption:
424 if (UnknownOptionHandler != null) {
425 var ret = UnknownOptionHandler (args, i);
435 if (dash_opt || slash_opt) {
437 string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
438 switch (ParseOption (csc_opt, ref args, settings)) {
439 case ParseResult.Error:
440 case ParseResult.Success:
442 case ParseResult.UnknownOption:
443 // Need to skip `/home/test.cs' however /test.cs is considered as error
444 if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
447 if (UnknownOptionHandler != null) {
448 var ret = UnknownOptionHandler (args, i);
455 Error_WrongOption (arg);
458 case ParseResult.Stop:
459 stop_argument = true;
465 ProcessSourceFiles (arg, false, settings.SourceFiles);
468 return report.Errors == 0;
471 void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
473 string path, pattern;
475 SplitPathAndPattern (spec, out path, out pattern);
476 if (pattern.IndexOf ('*') == -1) {
477 AddSourceFile (spec, sourceFiles);
483 files = Directory.GetFiles (path, pattern);
484 } catch (System.IO.DirectoryNotFoundException) {
485 report.Error (2001, "Source file `" + spec + "' could not be found");
487 } catch (System.IO.IOException) {
488 report.Error (2001, "Source file `" + spec + "' could not be found");
491 foreach (string f in files) {
492 AddSourceFile (f, sourceFiles);
498 string[] dirs = null;
501 dirs = Directory.GetDirectories (path);
505 foreach (string d in dirs) {
507 // Don't include path in this string, as each
508 // directory entry already does
509 ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
513 static string[] AddArgs (string[] args, string[] extra_args)
516 new_args = new string[extra_args.Length + args.Length];
518 // if args contains '--' we have to take that into account
519 // split args into first half and second half based on '--'
520 // and add the extra_args before --
521 int split_position = Array.IndexOf (args, "--");
522 if (split_position != -1) {
523 Array.Copy (args, new_args, split_position);
524 extra_args.CopyTo (new_args, split_position);
525 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
527 args.CopyTo (new_args, 0);
528 extra_args.CopyTo (new_args, args.Length);
534 void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
536 if (assembly.Length == 0) {
537 report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
541 if (!IsExternAliasValid (alias)) {
542 report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
546 settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
549 void AddResource (AssemblyResource res, CompilerSettings settings)
551 if (settings.Resources == null) {
552 settings.Resources = new List<AssemblyResource> ();
553 settings.Resources.Add (res);
557 if (settings.Resources.Contains (res)) {
558 report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
562 settings.Resources.Add (res);
565 void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
567 string path = Path.GetFullPath (fileName);
570 if (source_file_index.TryGetValue (path, out index)) {
571 string other_name = sourceFiles[index - 1].Name;
572 if (fileName.Equals (other_name))
573 report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
575 report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
580 var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
581 sourceFiles.Add (unit);
582 source_file_index.Add (path, unit.Index);
585 public bool ProcessWarningsList (string text, Action<int> action)
587 foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
589 if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
590 warning = warning.Substring (2);
593 if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
603 void Error_RequiresArgument (string option)
605 report.Error (2006, "Missing argument for `{0}' option", option);
608 void Error_RequiresFileName (string option)
610 report.Error (2005, "Missing file specification for `{0}' option", option);
613 void Error_WrongOption (string option)
615 report.Error (2007, "Unrecognized command-line option: `{0}'", option);
618 static bool IsExternAliasValid (string identifier)
620 return Tokenizer.IsValidIdentifier (identifier);
623 static string[] LoadArgs (string file)
626 var args = new List<string> ();
629 f = new StreamReader (file);
634 StringBuilder sb = new StringBuilder ();
636 while ((line = f.ReadLine ()) != null) {
639 for (int i = 0; i < t; i++) {
642 if (c == '"' || c == '\'') {
645 for (i++; i < t; i++) {
652 } else if (c == ' ') {
654 args.Add (sb.ToString ());
661 args.Add (sb.ToString ());
666 return args.ToArray ();
672 "Other flags in the compiler\n" +
673 " --fatal[=COUNT] Makes error after COUNT fatal\n" +
674 " --lint Enhanced warnings\n" +
675 " --metadata-only Produced assembly will contain metadata only\n" +
676 " --parse Only parses the source file\n" +
677 " --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
678 " --stacktrace Shows stack trace at error location\n" +
679 " --timestamp Displays time stamps of various compiler events\n" +
680 " -v Verbose parsing (for debugging the parser)\n" +
681 " --mcs-debug X Sets MCS debugging level to X\n" +
682 " --break-on-ice Breaks compilation on internal compiler error");
686 // This parses the -arg and /arg options to the compiler, even if the strings
687 // in the following text use "/arg" on the strings.
689 ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
691 int idx = option.IndexOf (':');
698 arg = option.Substring (0, idx);
700 value = option.Substring (idx + 1);
703 switch (arg.ToLowerInvariant ()) {
705 return ParseResult.Success;
711 settings.Target = Target.Exe;
715 settings.Target = Target.WinExe;
719 settings.Target = Target.Library;
720 settings.TargetExt = ".dll";
724 settings.Target = Target.Module;
725 settings.TargetExt = ".netmodule";
729 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
730 return ParseResult.Error;
732 return ParseResult.Success;
735 if (value.Length == 0) {
736 Error_RequiresFileName (option);
737 return ParseResult.Error;
739 settings.OutputFile = value;
740 return ParseResult.Success;
746 settings.Optimize = true;
747 return ParseResult.Success;
751 settings.Optimize = false;
752 return ParseResult.Success;
754 // TODO: Not supported by csc 3.5+
756 case "/incremental+":
757 case "/incremental-":
759 return ParseResult.Success;
763 if (value.Length == 0) {
764 Error_RequiresArgument (option);
765 return ParseResult.Error;
768 foreach (string d in value.Split (argument_value_separator)) {
769 string conditional = d.Trim ();
770 if (!Tokenizer.IsValidIdentifier (conditional)) {
771 report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
775 settings.AddConditionalSymbol (conditional);
777 return ParseResult.Success;
782 // We should collect data, runtime, etc and store in the file specified
784 output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
785 return ParseResult.Success;
790 if (value.Length == 0) {
791 Error_RequiresArgument (option);
792 return ParseResult.Error;
794 packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
795 string pkgout = Driver.GetPackageFlags (packages, report);
798 return ParseResult.Error;
800 string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
801 args = AddArgs (args, xargs);
802 return ParseResult.Success;
806 case "/linkresource":
809 AssemblyResource res = null;
810 string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
813 if (s[0].Length == 0)
815 res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
818 res = new AssemblyResource (s[0], s[1]);
821 if (s[2] != "public" && s[2] != "private") {
822 report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
823 return ParseResult.Error;
825 res = new AssemblyResource (s[0], s[1], s[2] == "private");
828 report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
829 return ParseResult.Error;
833 res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
834 AddResource (res, settings);
837 return ParseResult.Success;
840 if (value.Length == 0) {
841 Error_RequiresFileName (option);
842 return ParseResult.Error;
844 ProcessSourceFiles (value, true, settings.SourceFiles);
845 return ParseResult.Success;
849 if (value.Length == 0) {
850 Error_RequiresFileName (option);
851 return ParseResult.Error;
854 string[] refs = value.Split (argument_value_separator);
855 foreach (string r in refs) {
860 int index = val.IndexOf ('=');
862 string alias = r.Substring (0, index);
863 string assembly = r.Substring (index + 1);
864 AddAssemblyReference (alias, assembly, settings);
865 if (refs.Length != 1) {
866 report.Error (2034, "Cannot specify multiple aliases using single /reference option");
867 return ParseResult.Error;
870 settings.AssemblyReferences.Add (val);
873 return ParseResult.Success;
876 if (value.Length == 0) {
877 Error_RequiresFileName (option);
878 return ParseResult.Error;
881 string[] refs = value.Split (argument_value_separator);
882 foreach (string r in refs) {
883 settings.Modules.Add (r);
885 return ParseResult.Success;
888 if (value.Length == 0) {
889 Error_RequiresFileName (option);
890 return ParseResult.Error;
893 if (settings.Win32IconFile != null)
894 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
896 settings.Win32ResourceFile = value;
897 return ParseResult.Success;
900 if (value.Length == 0) {
901 Error_RequiresFileName (option);
902 return ParseResult.Error;
905 if (settings.Win32ResourceFile != null)
906 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
908 settings.Win32IconFile = value;
909 return ParseResult.Success;
912 if (value.Length == 0) {
913 Error_RequiresFileName (option);
914 return ParseResult.Error;
917 settings.DocumentationFile = value;
918 return ParseResult.Success;
923 if (value.Length == 0) {
924 return ParseResult.Error;
927 libdirs = value.Split (argument_value_separator);
928 foreach (string dir in libdirs)
929 settings.ReferencesLookupPaths.Add (dir);
930 return ParseResult.Success;
934 settings.GenerateDebugInfo = false;
935 return ParseResult.Success;
938 if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || value.Equals ("portable", StringComparison.OrdinalIgnoreCase) || idx < 0) {
939 settings.GenerateDebugInfo = true;
940 return ParseResult.Success;
943 if (value.Length > 0) {
944 report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
946 Error_RequiresArgument (option);
949 return ParseResult.Error;
952 settings.GenerateDebugInfo = true;
953 return ParseResult.Success;
957 settings.Checked = true;
958 return ParseResult.Success;
961 settings.Checked = false;
962 return ParseResult.Success;
966 settings.VerifyClsCompliance = true;
967 return ParseResult.Success;
970 settings.VerifyClsCompliance = false;
971 return ParseResult.Success;
975 settings.Unsafe = true;
976 return ParseResult.Success;
979 settings.Unsafe = false;
980 return ParseResult.Success;
983 case "/warnaserror+":
984 if (value.Length == 0) {
985 settings.WarningsAreErrors = true;
986 parser_settings.WarningsAreErrors = true;
988 if (!ProcessWarningsList (value, settings.AddWarningAsError))
989 return ParseResult.Error;
991 return ParseResult.Success;
993 case "/warnaserror-":
994 if (value.Length == 0) {
995 settings.WarningsAreErrors = false;
997 if (!ProcessWarningsList (value, settings.AddWarningOnly))
998 return ParseResult.Error;
1000 return ParseResult.Success;
1004 if (value.Length == 0) {
1005 Error_RequiresArgument (option);
1006 return ParseResult.Error;
1009 SetWarningLevel (value, settings);
1010 return ParseResult.Success;
1013 if (value.Length == 0) {
1014 Error_RequiresArgument (option);
1015 return ParseResult.Error;
1018 if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
1019 return ParseResult.Error;
1021 return ParseResult.Success;
1024 settings.LoadDefaultReferences = false;
1025 return ParseResult.Success;
1028 if (value.Length == 0) {
1029 Error_RequiresArgument (option);
1030 return ParseResult.Error;
1033 switch (value.ToLowerInvariant ()) {
1035 settings.Platform = Platform.Arm;
1038 settings.Platform = Platform.AnyCPU;
1041 settings.Platform = Platform.X86;
1044 settings.Platform = Platform.X64;
1047 settings.Platform = Platform.IA64;
1049 case "anycpu32bitpreferred":
1050 settings.Platform = Platform.AnyCPU32Preferred;
1053 report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
1055 return ParseResult.Error;
1058 return ParseResult.Success;
1061 if (value.Length == 0) {
1062 Error_RequiresArgument (option);
1063 return ParseResult.Error;
1066 settings.SdkVersion = value;
1067 return ParseResult.Success;
1069 // We just ignore this.
1070 case "/errorreport":
1072 if (value.Length == 0) {
1073 Error_RequiresArgument (option);
1074 return ParseResult.Error;
1077 return ParseResult.Success;
1079 case "/helpinternal":
1081 return ParseResult.Stop;
1086 return ParseResult.Stop;
1090 if (value.Length == 0) {
1091 Error_RequiresArgument (option);
1092 return ParseResult.Error;
1094 settings.MainClass = value;
1095 return ParseResult.Success;
1099 settings.StdLib = false;
1100 return ParseResult.Success;
1103 settings.StdLib = true;
1104 return ParseResult.Success;
1107 settings.ShowFullPaths = true;
1108 return ParseResult.Success;
1111 if (value.Length == 0) {
1112 Error_RequiresFileName (option);
1113 return ParseResult.Error;
1116 settings.StrongNameKeyFile = value;
1117 return ParseResult.Success;
1119 case "/keycontainer":
1120 if (value.Length == 0) {
1121 Error_RequiresArgument (option);
1122 return ParseResult.Error;
1125 settings.StrongNameKeyContainer = value;
1126 return ParseResult.Success;
1130 settings.StrongNameDelaySign = true;
1131 return ParseResult.Success;
1134 settings.StrongNameDelaySign = false;
1135 return ParseResult.Success;
1137 case "/langversion":
1138 if (value.Length == 0) {
1139 Error_RequiresArgument (option);
1140 return ParseResult.Error;
1143 switch (value.ToLowerInvariant ()) {
1146 settings.Version = LanguageVersion.ISO_1;
1147 return ParseResult.Success;
1149 settings.Version = LanguageVersion.Default;
1150 return ParseResult.Success;
1153 settings.Version = LanguageVersion.ISO_2;
1154 return ParseResult.Success;
1156 settings.Version = LanguageVersion.V_3;
1157 return ParseResult.Success;
1159 settings.Version = LanguageVersion.V_4;
1160 return ParseResult.Success;
1162 settings.Version = LanguageVersion.V_5;
1163 return ParseResult.Success;
1165 settings.Version = LanguageVersion.V_6;
1166 return ParseResult.Success;
1168 settings.Version = LanguageVersion.V_7;
1169 return ParseResult.Success;
1170 case "experimental":
1171 settings.Version = LanguageVersion.Experimental;
1172 return ParseResult.Success;
1175 report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', Default or value in range 1 to 7", value);
1176 return ParseResult.Error;
1179 if (value.Length == 0) {
1180 Error_RequiresArgument (option);
1181 return ParseResult.Error;
1186 settings.Encoding = Encoding.UTF8;
1189 settings.Encoding = Encoding.Default;
1193 settings.Encoding = Encoding.GetEncoding (int.Parse (value));
1195 report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1197 return ParseResult.Error;
1199 return ParseResult.Success;
1201 case "/runtimemetadataversion":
1202 if (value.Length == 0) {
1203 Error_RequiresArgument (option);
1204 return ParseResult.Error;
1207 settings.RuntimeMetadataVersion = value;
1208 return ParseResult.Success;
1211 if (value.Length == 0) {
1212 return ParseResult.Success;
1215 foreach (var pair in value.Split (',')) {
1216 var kv = pair.Split ('=');
1217 if (kv.Length != 2) {
1218 report.Error (8101, "The pathmap option was incorrectly formatted");
1219 return ParseResult.Error;
1222 if (settings.PathMap == null)
1223 settings.PathMap = new List<KeyValuePair<string, string>> ();
1225 var key = kv [0].TrimEnd (Path.DirectorySeparatorChar);
1226 var path = kv [1].TrimEnd (Path.DirectorySeparatorChar);
1227 if (key.Length == 0 || path.Length == 0)
1228 report.Error (8101, "The pathmap option was incorrectly formatted");
1230 settings.PathMap.Add (new KeyValuePair<string, string> (key, path));
1233 return ParseResult.Success;
1235 // csc options that we don't support
1238 case "/baseaddress":
1239 case "/deterministic":
1240 case "/deterministic+":
1241 case "/deterministic-":
1242 case "/errorendlocation":
1245 case "/highentropyva":
1246 case "/highentropyva+":
1247 case "/highentropyva-":
1249 case "/moduleassemblyname":
1250 case "/nowin32manifest":
1252 case "/preferreduilang":
1254 case "/publicsign+":
1255 case "/publicsign-":
1256 case "/reportanalyzer":
1258 case "/sqmsessionguid":
1259 case "/subsystemversion":
1261 case "/win32manifest":
1262 return ParseResult.Success;
1265 return ParseResult.UnknownOption;
1270 // Currently handles the Unix-like command line options, but will be
1271 // deprecated in favor of the CSCParseOption, which will also handle the
1272 // options that start with a dash in the future.
1274 ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
1278 settings.VerboseParserFlag++;
1279 return ParseResult.Success;
1283 return ParseResult.Stop;
1286 settings.ParseOnly = true;
1287 return ParseResult.Success;
1289 case "--main": case "-m":
1290 report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
1291 if ((i + 1) >= args.Length){
1292 Error_RequiresArgument (arg);
1293 return ParseResult.Error;
1295 settings.MainClass = args[++i];
1296 return ParseResult.Success;
1299 report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
1300 settings.Unsafe = true;
1301 return ParseResult.Success;
1303 case "/?": case "/h": case "/help":
1306 return ParseResult.Stop;
1309 report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
1310 if ((i + 1) >= args.Length){
1311 Error_RequiresArgument (arg);
1312 return ParseResult.Error;
1315 settings.AddConditionalSymbol (args [++i]);
1316 return ParseResult.Success;
1319 settings.TokenizeOnly = true;
1320 return ParseResult.Success;
1324 report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
1325 if ((i + 1) >= args.Length){
1326 Error_RequiresArgument (arg);
1327 return ParseResult.Error;
1329 settings.OutputFile = args[++i];
1330 return ParseResult.Success;
1333 report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
1334 settings.Checked = true;
1335 return ParseResult.Success;
1337 case "--stacktrace":
1338 settings.Stacktrace = true;
1339 return ParseResult.Success;
1341 case "--linkresource":
1343 report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
1344 if ((i + 1) >= args.Length){
1345 Error_RequiresArgument (arg);
1346 return ParseResult.Error;
1349 AddResource (new AssemblyResource (args[++i], args[i]), settings);
1350 return ParseResult.Success;
1354 report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
1355 if ((i + 1) >= args.Length){
1356 Error_RequiresArgument (arg);
1357 return ParseResult.Error;
1360 AddResource (new AssemblyResource (args[++i], args[i], true), settings);
1361 return ParseResult.Success;
1364 report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
1365 if ((i + 1) >= args.Length){
1366 Error_RequiresArgument (arg);
1367 return ParseResult.Error;
1370 string type = args [++i];
1373 settings.Target = Target.Library;
1374 settings.TargetExt = ".dll";
1378 settings.Target = Target.Exe;
1382 settings.Target = Target.WinExe;
1386 settings.Target = Target.Module;
1387 settings.TargetExt = ".dll";
1390 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
1393 return ParseResult.Success;
1396 report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
1397 if ((i + 1) >= args.Length){
1398 Error_RequiresArgument (arg);
1399 return ParseResult.Error;
1402 string val = args [++i];
1403 int idx = val.IndexOf ('=');
1405 string alias = val.Substring (0, idx);
1406 string assembly = val.Substring (idx + 1);
1407 AddAssemblyReference (alias, assembly, settings);
1408 return ParseResult.Success;
1411 settings.AssemblyReferences.Add (val);
1412 return ParseResult.Success;
1415 report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
1416 if ((i + 1) >= args.Length){
1417 Error_RequiresArgument (arg);
1418 return ParseResult.Error;
1420 settings.ReferencesLookupPaths.Add (args [++i]);
1421 return ParseResult.Success;
1424 settings.EnhancedWarnings = true;
1425 return ParseResult.Success;
1428 report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
1429 settings.StdLib = false;
1430 return ParseResult.Success;
1433 report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1434 if ((i + 1) >= args.Length){
1435 Error_RequiresArgument (arg);
1436 return ParseResult.Error;
1441 warn = int.Parse (args [++i]);
1444 Environment.Exit (1);
1446 settings.SetIgnoreWarning (warn);
1447 return ParseResult.Success;
1450 report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1451 if ((i + 1) >= args.Length){
1452 Error_RequiresArgument (arg);
1453 return ParseResult.Error;
1456 SetWarningLevel (args [++i], settings);
1457 return ParseResult.Success;
1460 if ((i + 1) >= args.Length){
1461 Error_RequiresArgument (arg);
1462 return ParseResult.Error;
1466 settings.DebugFlags = int.Parse (args [++i]);
1468 Error_RequiresArgument (arg);
1469 return ParseResult.Error;
1472 return ParseResult.Success;
1476 return ParseResult.Stop;
1479 report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1480 if ((i + 1) >= args.Length){
1481 Error_RequiresArgument (arg);
1482 return ParseResult.Error;
1484 ProcessSourceFiles (args [++i], true, settings.SourceFiles);
1485 return ParseResult.Success;
1488 settings.Timestamps = true;
1489 return ParseResult.Success;
1491 case "--debug": case "-g":
1492 report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1493 settings.GenerateDebugInfo = true;
1494 return ParseResult.Success;
1497 report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1498 settings.LoadDefaultReferences = false;
1499 return ParseResult.Success;
1501 case "--metadata-only":
1502 settings.WriteMetadataOnly = true;
1503 return ParseResult.Success;
1505 case "--break-on-ice":
1506 settings.BreakOnInternalError = true;
1507 return ParseResult.Success;
1510 if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
1512 if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
1513 int.TryParse (arg.Substring (8), out fatal);
1515 settings.FatalCounter = fatal;
1516 return ParseResult.Success;
1518 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
1519 string version = arg.Substring (10);
1524 settings.StdLibRuntimeVersion = RuntimeVersion.v1;
1528 settings.StdLibRuntimeVersion = RuntimeVersion.v2;
1532 settings.StdLibRuntimeVersion = RuntimeVersion.v4;
1535 return ParseResult.Success;
1538 if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
1539 string file = arg.Substring (21).Trim ();
1540 if (file.Length < 1) {
1541 Error_RequiresArgument (arg);
1542 return ParseResult.Error;
1545 if (settings.GetResourceStrings == null)
1546 settings.GetResourceStrings = new List<string> ();
1548 settings.GetResourceStrings.Add (file);
1549 return ParseResult.Success;
1552 return ParseResult.UnknownOption;
1556 void SetWarningLevel (string s, CompilerSettings settings)
1561 level = int.Parse (s);
1564 if (level < 0 || level > 4) {
1565 report.Error (1900, "Warning level must be in the range 0-4");
1568 settings.WarningLevel = level;
1572 // Given a path specification, splits the path from the file/pattern
1574 static void SplitPathAndPattern (string spec, out string path, out string pattern)
1576 int p = spec.LastIndexOf ('/');
1579 // Windows does not like /file.cs, switch that to:
1584 pattern = spec.Substring (1);
1586 path = spec.Substring (0, p);
1587 pattern = spec.Substring (p + 1);
1592 p = spec.LastIndexOf ('\\');
1594 path = spec.Substring (0, p);
1595 pattern = spec.Substring (p + 1);
1606 "Turbo C# compiler, Copyright 2001-2011 Novell, Inc., 2011-2016 Xamarin, Inc, 2016-2017 Microsoft Corp\n" +
1607 "mcs [options] source-files\n" +
1608 " --about About the Mono C# compiler\n" +
1609 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
1610 " -checked[+|-] Sets default aritmetic overflow context\n" +
1611 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
1612 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
1613 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
1614 " -debug[+|-], -g Generate debugging information\n" +
1615 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
1616 " -doc:FILE Process documentation comments to XML file\n" +
1617 " -fullpaths Any issued error or warning uses absolute file path\n" +
1618 " -help Lists all compiler options (short: -?)\n" +
1619 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
1620 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
1621 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, 4, 5, 6, Default or Experimental\n" +
1622 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
1623 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
1624 " -noconfig Disables implicitly referenced assemblies\n" +
1625 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
1626 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
1627 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
1628 " -out:FILE Specifies output assembly name\n" +
1629 " -pathmap:K=V[,Kn=Vn] Sets a mapping for source path names used in generated output\n" +
1630 " -pkg:P1[,Pn] References packages P1..Pn\n" +
1631 " -platform:ARCH Specifies the target platform of the output assembly\n" +
1632 " ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
1633 " x86, x64 or itanium. The default is anycpu.\n" +
1634 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
1635 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
1636 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
1637 " -sdk:VERSION Specifies SDK version of referenced assemblies\n" +
1638 " VERSION can be one of: 2, 4, 4.5 (default) or a custom value\n" +
1639 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
1640 " KIND can be one of: exe, winexe, library, module\n" +
1641 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
1642 " -warnaserror[+|-] Treats all warnings as errors\n" +
1643 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
1644 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
1645 " -helpinternal Shows internal and advanced compiler options\n" +
1648 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
1649 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
1650 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
1651 " -win32icon:FILE Use this icon for the output\n" +
1652 " @file Read response file for more options\n\n" +
1653 "Options can be of the form -option or /option");
1658 string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
1659 output.WriteLine ("Mono C# compiler version {0}", version);
1663 public class RootContext
1666 // Contains the parsed tree
1668 static ModuleContainer root;
1670 static public ModuleContainer ToplevelTypes {
1671 get { return root; }
1672 set { root = value; }