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
34 Default = LanguageVersion.V_6,
37 public enum RuntimeVersion
46 Library, Exe, Module, WinExe
59 public class CompilerSettings
62 public Platform Platform;
63 public string TargetExt;
64 public bool VerifyClsCompliance;
66 public LanguageVersion Version;
67 public bool EnhancedWarnings;
68 public bool LoadDefaultReferences;
69 public string SdkVersion;
71 public string StrongNameKeyFile;
72 public string StrongNameKeyContainer;
73 public bool StrongNameDelaySign;
77 public bool WarningsAreErrors;
78 public int WarningLevel;
81 // Assemblies references to be loaded
83 public List<string> AssemblyReferences;
86 // External aliases for assemblies
88 public List<Tuple<string, string>> AssemblyReferencesAliases;
90 public List<KeyValuePair<string, string>> PathMap;
93 // Modules to be embedded
95 public List<string> Modules;
98 // Lookup paths for referenced assemblies
100 public List<string> ReferencesLookupPaths;
105 public Encoding Encoding;
108 // If set, enable XML documentation generation
110 public string DocumentationFile;
112 public string MainClass;
117 public string OutputFile;
120 // The default compiler checked state
125 // If true, the compiler is operating in statement mode,
126 // this currently turns local variable declaration into
127 // static variables of a class
129 public bool StatementMode; // TODO: SUPER UGLY
132 // Whether to allow Unsafe code
136 public string Win32ResourceFile;
137 public string Win32IconFile;
140 // A list of resource files for embedding
142 public List<AssemblyResource> Resources;
144 public bool GenerateDebugInfo;
146 #region Compiler debug flags only
147 public bool ParseOnly, TokenizeOnly, Timestamps;
148 public int DebugFlags;
149 public int VerboseParserFlag;
150 public int FatalCounter;
151 public bool Stacktrace;
152 public bool BreakOnInternalError;
155 public List<string> GetResourceStrings;
157 public bool ShowFullPaths;
160 // Whether we are being linked against the standard libraries.
161 // This is only used to tell whether `System.Object' should
162 // have a base class or not.
166 public RuntimeVersion StdLibRuntimeVersion;
168 public string RuntimeMetadataVersion;
170 public bool WriteMetadataOnly;
172 readonly List<string> conditional_symbols;
174 readonly List<SourceFile> source_files;
176 List<int> warnings_as_error;
177 List<int> warnings_only;
178 HashSet<int> warning_ignore_table;
180 public CompilerSettings ()
185 Platform = Platform.AnyCPU;
186 Version = LanguageVersion.Default;
187 VerifyClsCompliance = true;
188 Encoding = Encoding.UTF8;
189 LoadDefaultReferences = true;
190 StdLibRuntimeVersion = RuntimeVersion.v4;
193 // Default to 1 or mdb files would be platform speficic
196 AssemblyReferences = new List<string> ();
197 AssemblyReferencesAliases = new List<Tuple<string, string>> ();
198 Modules = new List<string> ();
199 ReferencesLookupPaths = new List<string> ();
201 conditional_symbols = new List<string> ();
203 // Add default mcs define
205 conditional_symbols.Add ("__MonoCS__");
207 source_files = new List<SourceFile> ();
212 public SourceFile FirstSourceFile {
214 return source_files.Count > 0 ? source_files [0] : null;
218 public bool HasKeyFileOrContainer {
220 return StrongNameKeyFile != null || StrongNameKeyContainer != null;
224 public bool NeedsEntryPoint {
226 return Target == Target.Exe || Target == Target.WinExe;
230 public List<SourceFile> SourceFiles {
238 public void AddConditionalSymbol (string symbol)
240 if (!conditional_symbols.Contains (symbol))
241 conditional_symbols.Add (symbol);
244 public void AddWarningAsError (int id)
246 if (warnings_as_error == null)
247 warnings_as_error = new List<int> ();
249 warnings_as_error.Add (id);
252 public void AddWarningOnly (int id)
254 if (warnings_only == null)
255 warnings_only = new List<int> ();
257 warnings_only.Add (id);
260 public bool IsConditionalSymbolDefined (string symbol)
262 return conditional_symbols.Contains (symbol);
265 public bool IsWarningAsError (int code)
267 bool is_error = WarningsAreErrors;
269 // Check specific list
270 if (warnings_as_error != null)
271 is_error |= warnings_as_error.Contains (code);
273 // Ignore excluded warnings
274 if (warnings_only != null && warnings_only.Contains (code))
280 public bool IsWarningEnabled (int code, int level)
282 if (WarningLevel < level)
285 return !IsWarningDisabledGlobally (code);
288 public bool IsWarningDisabledGlobally (int code)
290 return warning_ignore_table != null && warning_ignore_table.Contains (code);
293 public void SetIgnoreWarning (int code)
295 if (warning_ignore_table == null)
296 warning_ignore_table = new HashSet<int> ();
298 warning_ignore_table.Add (code);
302 public class CommandLineParser
312 static readonly char[] argument_value_separator = { ';', ',' };
313 static readonly char[] numeric_value_separator = { ';', ',', ' ' };
315 readonly TextWriter output;
316 readonly Report report;
319 Dictionary<string, int> source_file_index;
321 public event Func<string[], int, int> UnknownOptionHandler;
323 CompilerSettings parser_settings;
325 public CommandLineParser (TextWriter errorOutput)
326 : this (errorOutput, Console.Out)
330 public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
332 var rp = new StreamReportPrinter (errorOutput);
334 parser_settings = new CompilerSettings ();
335 report = new Report (new CompilerContext (parser_settings, rp), rp);
336 this.output = messagesOutput;
339 public bool HasBeenStopped {
341 return stop_argument;
348 "The Mono C# compiler is Copyright 2001-2011, Novell, Inc. 2011-2016 Xamarin Inc, 2016-2017 Microsoft Corp\n\n" +
349 "The compiler source code is released under the terms of the \n" +
350 "MIT X11 or GNU GPL licenses\n\n" +
352 "For more information on Mono, visit the project Web site\n" +
353 " http://www.mono-project.com\n\n" +
355 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
358 public CompilerSettings ParseArguments (string[] args)
360 CompilerSettings settings = new CompilerSettings ();
361 if (!ParseArguments (settings, args))
367 public bool ParseArguments (CompilerSettings settings, string[] args)
369 if (settings == null)
370 throw new ArgumentNullException ("settings");
372 List<string> response_file_list = null;
373 bool parsing_options = true;
374 stop_argument = false;
375 source_file_index = new Dictionary<string, int> ();
377 for (int i = 0; i < args.Length; i++) {
378 string arg = args[i];
384 string response_file = arg.Substring (1);
386 if (response_file_list == null)
387 response_file_list = new List<string> ();
389 if (response_file_list.Contains (response_file)) {
390 report.Error (1515, "Response file `{0}' specified multiple times", response_file);
394 response_file_list.Add (response_file);
396 extra_args = LoadArgs (response_file);
397 if (extra_args == null) {
398 report.Error (2011, "Unable to open response file: " + response_file);
402 args = AddArgs (args, extra_args);
406 if (parsing_options) {
408 parsing_options = false;
412 bool dash_opt = arg[0] == '-';
413 bool slash_opt = arg[0] == '/';
415 switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
416 case ParseResult.Error:
417 case ParseResult.Success:
419 case ParseResult.Stop:
420 stop_argument = true;
422 case ParseResult.UnknownOption:
423 if (UnknownOptionHandler != null) {
424 var ret = UnknownOptionHandler (args, i);
434 if (dash_opt || slash_opt) {
436 string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
437 switch (ParseOption (csc_opt, ref args, settings)) {
438 case ParseResult.Error:
439 case ParseResult.Success:
441 case ParseResult.UnknownOption:
442 // Need to skip `/home/test.cs' however /test.cs is considered as error
443 if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
446 if (UnknownOptionHandler != null) {
447 var ret = UnknownOptionHandler (args, i);
454 Error_WrongOption (arg);
457 case ParseResult.Stop:
458 stop_argument = true;
464 ProcessSourceFiles (arg, false, settings.SourceFiles);
467 return report.Errors == 0;
470 void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
472 string path, pattern;
474 SplitPathAndPattern (spec, out path, out pattern);
475 if (pattern.IndexOf ('*') == -1) {
476 AddSourceFile (spec, sourceFiles);
482 files = Directory.GetFiles (path, pattern);
483 } catch (System.IO.DirectoryNotFoundException) {
484 report.Error (2001, "Source file `" + spec + "' could not be found");
486 } catch (System.IO.IOException) {
487 report.Error (2001, "Source file `" + spec + "' could not be found");
490 foreach (string f in files) {
491 AddSourceFile (f, sourceFiles);
497 string[] dirs = null;
500 dirs = Directory.GetDirectories (path);
504 foreach (string d in dirs) {
506 // Don't include path in this string, as each
507 // directory entry already does
508 ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
512 static string[] AddArgs (string[] args, string[] extra_args)
515 new_args = new string[extra_args.Length + args.Length];
517 // if args contains '--' we have to take that into account
518 // split args into first half and second half based on '--'
519 // and add the extra_args before --
520 int split_position = Array.IndexOf (args, "--");
521 if (split_position != -1) {
522 Array.Copy (args, new_args, split_position);
523 extra_args.CopyTo (new_args, split_position);
524 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
526 args.CopyTo (new_args, 0);
527 extra_args.CopyTo (new_args, args.Length);
533 void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
535 if (assembly.Length == 0) {
536 report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
540 if (!IsExternAliasValid (alias)) {
541 report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
545 settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
548 void AddResource (AssemblyResource res, CompilerSettings settings)
550 if (settings.Resources == null) {
551 settings.Resources = new List<AssemblyResource> ();
552 settings.Resources.Add (res);
556 if (settings.Resources.Contains (res)) {
557 report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
561 settings.Resources.Add (res);
564 void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
566 string path = Path.GetFullPath (fileName);
569 if (source_file_index.TryGetValue (path, out index)) {
570 string other_name = sourceFiles[index - 1].Name;
571 if (fileName.Equals (other_name))
572 report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
574 report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
579 var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
580 sourceFiles.Add (unit);
581 source_file_index.Add (path, unit.Index);
584 public bool ProcessWarningsList (string text, Action<int> action)
586 foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
588 if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
589 warning = warning.Substring (2);
592 if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
602 void Error_RequiresArgument (string option)
604 report.Error (2006, "Missing argument for `{0}' option", option);
607 void Error_RequiresFileName (string option)
609 report.Error (2005, "Missing file specification for `{0}' option", option);
612 void Error_WrongOption (string option)
614 report.Error (2007, "Unrecognized command-line option: `{0}'", option);
617 static bool IsExternAliasValid (string identifier)
619 return Tokenizer.IsValidIdentifier (identifier);
622 static string[] LoadArgs (string file)
625 var args = new List<string> ();
628 f = new StreamReader (file);
633 StringBuilder sb = new StringBuilder ();
635 while ((line = f.ReadLine ()) != null) {
638 for (int i = 0; i < t; i++) {
641 if (c == '"' || c == '\'') {
644 for (i++; i < t; i++) {
651 } else if (c == ' ') {
653 args.Add (sb.ToString ());
660 args.Add (sb.ToString ());
665 return args.ToArray ();
671 "Other flags in the compiler\n" +
672 " --fatal[=COUNT] Makes error after COUNT fatal\n" +
673 " --lint Enhanced warnings\n" +
674 " --metadata-only Produced assembly will contain metadata only\n" +
675 " --parse Only parses the source file\n" +
676 " --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
677 " --stacktrace Shows stack trace at error location\n" +
678 " --timestamp Displays time stamps of various compiler events\n" +
679 " -v Verbose parsing (for debugging the parser)\n" +
680 " --mcs-debug X Sets MCS debugging level to X\n" +
681 " --break-on-ice Breaks compilation on internal compiler error");
685 // This parses the -arg and /arg options to the compiler, even if the strings
686 // in the following text use "/arg" on the strings.
688 ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
690 int idx = option.IndexOf (':');
697 arg = option.Substring (0, idx);
699 value = option.Substring (idx + 1);
702 switch (arg.ToLowerInvariant ()) {
704 return ParseResult.Success;
710 settings.Target = Target.Exe;
714 settings.Target = Target.WinExe;
718 settings.Target = Target.Library;
719 settings.TargetExt = ".dll";
723 settings.Target = Target.Module;
724 settings.TargetExt = ".netmodule";
728 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
729 return ParseResult.Error;
731 return ParseResult.Success;
734 if (value.Length == 0) {
735 Error_RequiresFileName (option);
736 return ParseResult.Error;
738 settings.OutputFile = value;
739 return ParseResult.Success;
745 settings.Optimize = true;
746 return ParseResult.Success;
750 settings.Optimize = false;
751 return ParseResult.Success;
753 // TODO: Not supported by csc 3.5+
755 case "/incremental+":
756 case "/incremental-":
758 return ParseResult.Success;
762 if (value.Length == 0) {
763 Error_RequiresArgument (option);
764 return ParseResult.Error;
767 foreach (string d in value.Split (argument_value_separator)) {
768 string conditional = d.Trim ();
769 if (!Tokenizer.IsValidIdentifier (conditional)) {
770 report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
774 settings.AddConditionalSymbol (conditional);
776 return ParseResult.Success;
781 // We should collect data, runtime, etc and store in the file specified
783 output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
784 return ParseResult.Success;
789 if (value.Length == 0) {
790 Error_RequiresArgument (option);
791 return ParseResult.Error;
793 packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
794 string pkgout = Driver.GetPackageFlags (packages, report);
797 return ParseResult.Error;
799 string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
800 args = AddArgs (args, xargs);
801 return ParseResult.Success;
805 case "/linkresource":
808 AssemblyResource res = null;
809 string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
812 if (s[0].Length == 0)
814 res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
817 res = new AssemblyResource (s[0], s[1]);
820 if (s[2] != "public" && s[2] != "private") {
821 report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
822 return ParseResult.Error;
824 res = new AssemblyResource (s[0], s[1], s[2] == "private");
827 report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
828 return ParseResult.Error;
832 res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
833 AddResource (res, settings);
836 return ParseResult.Success;
839 if (value.Length == 0) {
840 Error_RequiresFileName (option);
841 return ParseResult.Error;
843 ProcessSourceFiles (value, true, settings.SourceFiles);
844 return ParseResult.Success;
848 if (value.Length == 0) {
849 Error_RequiresFileName (option);
850 return ParseResult.Error;
853 string[] refs = value.Split (argument_value_separator);
854 foreach (string r in refs) {
859 int index = val.IndexOf ('=');
861 string alias = r.Substring (0, index);
862 string assembly = r.Substring (index + 1);
863 AddAssemblyReference (alias, assembly, settings);
864 if (refs.Length != 1) {
865 report.Error (2034, "Cannot specify multiple aliases using single /reference option");
866 return ParseResult.Error;
869 settings.AssemblyReferences.Add (val);
872 return ParseResult.Success;
875 if (value.Length == 0) {
876 Error_RequiresFileName (option);
877 return ParseResult.Error;
880 string[] refs = value.Split (argument_value_separator);
881 foreach (string r in refs) {
882 settings.Modules.Add (r);
884 return ParseResult.Success;
887 if (value.Length == 0) {
888 Error_RequiresFileName (option);
889 return ParseResult.Error;
892 if (settings.Win32IconFile != null)
893 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
895 settings.Win32ResourceFile = value;
896 return ParseResult.Success;
899 if (value.Length == 0) {
900 Error_RequiresFileName (option);
901 return ParseResult.Error;
904 if (settings.Win32ResourceFile != null)
905 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
907 settings.Win32IconFile = value;
908 return ParseResult.Success;
911 if (value.Length == 0) {
912 Error_RequiresFileName (option);
913 return ParseResult.Error;
916 settings.DocumentationFile = value;
917 return ParseResult.Success;
922 if (value.Length == 0) {
923 return ParseResult.Error;
926 libdirs = value.Split (argument_value_separator);
927 foreach (string dir in libdirs)
928 settings.ReferencesLookupPaths.Add (dir);
929 return ParseResult.Success;
933 settings.GenerateDebugInfo = false;
934 return ParseResult.Success;
937 if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || value.Equals ("portable", StringComparison.OrdinalIgnoreCase) || idx < 0) {
938 settings.GenerateDebugInfo = true;
939 return ParseResult.Success;
942 if (value.Length > 0) {
943 report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
945 Error_RequiresArgument (option);
948 return ParseResult.Error;
951 settings.GenerateDebugInfo = true;
952 return ParseResult.Success;
956 settings.Checked = true;
957 return ParseResult.Success;
960 settings.Checked = false;
961 return ParseResult.Success;
965 settings.VerifyClsCompliance = true;
966 return ParseResult.Success;
969 settings.VerifyClsCompliance = false;
970 return ParseResult.Success;
974 settings.Unsafe = true;
975 return ParseResult.Success;
978 settings.Unsafe = false;
979 return ParseResult.Success;
982 case "/warnaserror+":
983 if (value.Length == 0) {
984 settings.WarningsAreErrors = true;
985 parser_settings.WarningsAreErrors = true;
987 if (!ProcessWarningsList (value, settings.AddWarningAsError))
988 return ParseResult.Error;
990 return ParseResult.Success;
992 case "/warnaserror-":
993 if (value.Length == 0) {
994 settings.WarningsAreErrors = false;
996 if (!ProcessWarningsList (value, settings.AddWarningOnly))
997 return ParseResult.Error;
999 return ParseResult.Success;
1003 if (value.Length == 0) {
1004 Error_RequiresArgument (option);
1005 return ParseResult.Error;
1008 SetWarningLevel (value, settings);
1009 return ParseResult.Success;
1012 if (value.Length == 0) {
1013 Error_RequiresArgument (option);
1014 return ParseResult.Error;
1017 if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
1018 return ParseResult.Error;
1020 return ParseResult.Success;
1023 settings.LoadDefaultReferences = false;
1024 return ParseResult.Success;
1027 if (value.Length == 0) {
1028 Error_RequiresArgument (option);
1029 return ParseResult.Error;
1032 switch (value.ToLowerInvariant ()) {
1034 settings.Platform = Platform.Arm;
1037 settings.Platform = Platform.AnyCPU;
1040 settings.Platform = Platform.X86;
1043 settings.Platform = Platform.X64;
1046 settings.Platform = Platform.IA64;
1048 case "anycpu32bitpreferred":
1049 settings.Platform = Platform.AnyCPU32Preferred;
1052 report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
1054 return ParseResult.Error;
1057 return ParseResult.Success;
1060 if (value.Length == 0) {
1061 Error_RequiresArgument (option);
1062 return ParseResult.Error;
1065 settings.SdkVersion = value;
1066 return ParseResult.Success;
1068 // We just ignore this.
1069 case "/errorreport":
1071 if (value.Length == 0) {
1072 Error_RequiresArgument (option);
1073 return ParseResult.Error;
1076 return ParseResult.Success;
1078 case "/helpinternal":
1080 return ParseResult.Stop;
1085 return ParseResult.Stop;
1089 if (value.Length == 0) {
1090 Error_RequiresArgument (option);
1091 return ParseResult.Error;
1093 settings.MainClass = value;
1094 return ParseResult.Success;
1098 settings.StdLib = false;
1099 return ParseResult.Success;
1102 settings.StdLib = true;
1103 return ParseResult.Success;
1106 settings.ShowFullPaths = true;
1107 return ParseResult.Success;
1110 if (value.Length == 0) {
1111 Error_RequiresFileName (option);
1112 return ParseResult.Error;
1115 settings.StrongNameKeyFile = value;
1116 return ParseResult.Success;
1118 case "/keycontainer":
1119 if (value.Length == 0) {
1120 Error_RequiresArgument (option);
1121 return ParseResult.Error;
1124 settings.StrongNameKeyContainer = value;
1125 return ParseResult.Success;
1129 settings.StrongNameDelaySign = true;
1130 return ParseResult.Success;
1133 settings.StrongNameDelaySign = false;
1134 return ParseResult.Success;
1136 case "/langversion":
1137 if (value.Length == 0) {
1138 Error_RequiresArgument (option);
1139 return ParseResult.Error;
1142 switch (value.ToLowerInvariant ()) {
1145 settings.Version = LanguageVersion.ISO_1;
1146 return ParseResult.Success;
1148 settings.Version = LanguageVersion.Default;
1149 return ParseResult.Success;
1152 settings.Version = LanguageVersion.ISO_2;
1153 return ParseResult.Success;
1155 settings.Version = LanguageVersion.V_3;
1156 return ParseResult.Success;
1158 settings.Version = LanguageVersion.V_4;
1159 return ParseResult.Success;
1161 settings.Version = LanguageVersion.V_5;
1162 return ParseResult.Success;
1164 settings.Version = LanguageVersion.V_6;
1165 return ParseResult.Success;
1166 case "experimental":
1167 settings.Version = LanguageVersion.Experimental;
1168 return ParseResult.Success;
1170 report.Warning (8000, 1, "Language version `future' is no longer supported");
1174 report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', Default or value in range 1 to 6", value);
1175 return ParseResult.Error;
1178 if (value.Length == 0) {
1179 Error_RequiresArgument (option);
1180 return ParseResult.Error;
1185 settings.Encoding = Encoding.UTF8;
1188 settings.Encoding = Encoding.Default;
1192 settings.Encoding = Encoding.GetEncoding (int.Parse (value));
1194 report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1196 return ParseResult.Error;
1198 return ParseResult.Success;
1200 case "/runtimemetadataversion":
1201 if (value.Length == 0) {
1202 Error_RequiresArgument (option);
1203 return ParseResult.Error;
1206 settings.RuntimeMetadataVersion = value;
1207 return ParseResult.Success;
1210 if (value.Length == 0) {
1211 return ParseResult.Success;
1214 foreach (var pair in value.Split (',')) {
1215 var kv = pair.Split ('=');
1216 if (kv.Length != 2) {
1217 report.Error (8101, "The pathmap option was incorrectly formatted");
1218 return ParseResult.Error;
1221 if (settings.PathMap == null)
1222 settings.PathMap = new List<KeyValuePair<string, string>> ();
1224 var key = kv [0].TrimEnd (Path.DirectorySeparatorChar);
1225 var path = kv [1].TrimEnd (Path.DirectorySeparatorChar);
1226 if (key.Length == 0 || path.Length == 0)
1227 report.Error (8101, "The pathmap option was incorrectly formatted");
1229 settings.PathMap.Add (new KeyValuePair<string, string> (key, path));
1232 return ParseResult.Success;
1234 // csc options that we don't support
1237 case "/baseaddress":
1238 case "/deterministic":
1239 case "/deterministic+":
1240 case "/deterministic-":
1241 case "/errorendlocation":
1244 case "/highentropyva":
1245 case "/highentropyva+":
1246 case "/highentropyva-":
1248 case "/moduleassemblyname":
1249 case "/nowin32manifest":
1251 case "/preferreduilang":
1253 case "/publicsign+":
1254 case "/publicsign-":
1255 case "/reportanalyzer":
1257 case "/sqmsessionguid":
1258 case "/subsystemversion":
1260 case "/win32manifest":
1261 return ParseResult.Success;
1264 return ParseResult.UnknownOption;
1269 // Currently handles the Unix-like command line options, but will be
1270 // deprecated in favor of the CSCParseOption, which will also handle the
1271 // options that start with a dash in the future.
1273 ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
1277 settings.VerboseParserFlag++;
1278 return ParseResult.Success;
1282 return ParseResult.Stop;
1285 settings.ParseOnly = true;
1286 return ParseResult.Success;
1288 case "--main": case "-m":
1289 report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
1290 if ((i + 1) >= args.Length){
1291 Error_RequiresArgument (arg);
1292 return ParseResult.Error;
1294 settings.MainClass = args[++i];
1295 return ParseResult.Success;
1298 report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
1299 settings.Unsafe = true;
1300 return ParseResult.Success;
1302 case "/?": case "/h": case "/help":
1305 return ParseResult.Stop;
1308 report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
1309 if ((i + 1) >= args.Length){
1310 Error_RequiresArgument (arg);
1311 return ParseResult.Error;
1314 settings.AddConditionalSymbol (args [++i]);
1315 return ParseResult.Success;
1318 settings.TokenizeOnly = true;
1319 return ParseResult.Success;
1323 report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
1324 if ((i + 1) >= args.Length){
1325 Error_RequiresArgument (arg);
1326 return ParseResult.Error;
1328 settings.OutputFile = args[++i];
1329 return ParseResult.Success;
1332 report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
1333 settings.Checked = true;
1334 return ParseResult.Success;
1336 case "--stacktrace":
1337 settings.Stacktrace = true;
1338 return ParseResult.Success;
1340 case "--linkresource":
1342 report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
1343 if ((i + 1) >= args.Length){
1344 Error_RequiresArgument (arg);
1345 return ParseResult.Error;
1348 AddResource (new AssemblyResource (args[++i], args[i]), settings);
1349 return ParseResult.Success;
1353 report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
1354 if ((i + 1) >= args.Length){
1355 Error_RequiresArgument (arg);
1356 return ParseResult.Error;
1359 AddResource (new AssemblyResource (args[++i], args[i], true), settings);
1360 return ParseResult.Success;
1363 report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
1364 if ((i + 1) >= args.Length){
1365 Error_RequiresArgument (arg);
1366 return ParseResult.Error;
1369 string type = args [++i];
1372 settings.Target = Target.Library;
1373 settings.TargetExt = ".dll";
1377 settings.Target = Target.Exe;
1381 settings.Target = Target.WinExe;
1385 settings.Target = Target.Module;
1386 settings.TargetExt = ".dll";
1389 report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
1392 return ParseResult.Success;
1395 report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
1396 if ((i + 1) >= args.Length){
1397 Error_RequiresArgument (arg);
1398 return ParseResult.Error;
1401 string val = args [++i];
1402 int idx = val.IndexOf ('=');
1404 string alias = val.Substring (0, idx);
1405 string assembly = val.Substring (idx + 1);
1406 AddAssemblyReference (alias, assembly, settings);
1407 return ParseResult.Success;
1410 settings.AssemblyReferences.Add (val);
1411 return ParseResult.Success;
1414 report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
1415 if ((i + 1) >= args.Length){
1416 Error_RequiresArgument (arg);
1417 return ParseResult.Error;
1419 settings.ReferencesLookupPaths.Add (args [++i]);
1420 return ParseResult.Success;
1423 settings.EnhancedWarnings = true;
1424 return ParseResult.Success;
1427 report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
1428 settings.StdLib = false;
1429 return ParseResult.Success;
1432 report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1433 if ((i + 1) >= args.Length){
1434 Error_RequiresArgument (arg);
1435 return ParseResult.Error;
1440 warn = int.Parse (args [++i]);
1443 Environment.Exit (1);
1445 settings.SetIgnoreWarning (warn);
1446 return ParseResult.Success;
1449 report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1450 if ((i + 1) >= args.Length){
1451 Error_RequiresArgument (arg);
1452 return ParseResult.Error;
1455 SetWarningLevel (args [++i], settings);
1456 return ParseResult.Success;
1459 if ((i + 1) >= args.Length){
1460 Error_RequiresArgument (arg);
1461 return ParseResult.Error;
1465 settings.DebugFlags = int.Parse (args [++i]);
1467 Error_RequiresArgument (arg);
1468 return ParseResult.Error;
1471 return ParseResult.Success;
1475 return ParseResult.Stop;
1478 report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1479 if ((i + 1) >= args.Length){
1480 Error_RequiresArgument (arg);
1481 return ParseResult.Error;
1483 ProcessSourceFiles (args [++i], true, settings.SourceFiles);
1484 return ParseResult.Success;
1487 settings.Timestamps = true;
1488 return ParseResult.Success;
1490 case "--debug": case "-g":
1491 report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1492 settings.GenerateDebugInfo = true;
1493 return ParseResult.Success;
1496 report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1497 settings.LoadDefaultReferences = false;
1498 return ParseResult.Success;
1500 case "--metadata-only":
1501 settings.WriteMetadataOnly = true;
1502 return ParseResult.Success;
1504 case "--break-on-ice":
1505 settings.BreakOnInternalError = true;
1506 return ParseResult.Success;
1509 if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
1511 if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
1512 int.TryParse (arg.Substring (8), out fatal);
1514 settings.FatalCounter = fatal;
1515 return ParseResult.Success;
1517 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
1518 string version = arg.Substring (10);
1523 settings.StdLibRuntimeVersion = RuntimeVersion.v1;
1527 settings.StdLibRuntimeVersion = RuntimeVersion.v2;
1531 settings.StdLibRuntimeVersion = RuntimeVersion.v4;
1534 return ParseResult.Success;
1537 if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
1538 string file = arg.Substring (21).Trim ();
1539 if (file.Length < 1) {
1540 Error_RequiresArgument (arg);
1541 return ParseResult.Error;
1544 if (settings.GetResourceStrings == null)
1545 settings.GetResourceStrings = new List<string> ();
1547 settings.GetResourceStrings.Add (file);
1548 return ParseResult.Success;
1551 return ParseResult.UnknownOption;
1555 void SetWarningLevel (string s, CompilerSettings settings)
1560 level = int.Parse (s);
1563 if (level < 0 || level > 4) {
1564 report.Error (1900, "Warning level must be in the range 0-4");
1567 settings.WarningLevel = level;
1571 // Given a path specification, splits the path from the file/pattern
1573 static void SplitPathAndPattern (string spec, out string path, out string pattern)
1575 int p = spec.LastIndexOf ('/');
1578 // Windows does not like /file.cs, switch that to:
1583 pattern = spec.Substring (1);
1585 path = spec.Substring (0, p);
1586 pattern = spec.Substring (p + 1);
1591 p = spec.LastIndexOf ('\\');
1593 path = spec.Substring (0, p);
1594 pattern = spec.Substring (p + 1);
1605 "Mono C# compiler, Copyright 2001-2011 Novell, Inc., 2011-2016 Xamarin, Inc, 2016-2017 Microsoft Corp\n" +
1606 "mcs [options] source-files\n" +
1607 " --about About the Mono C# compiler\n" +
1608 " -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
1609 " -checked[+|-] Sets default aritmetic overflow context\n" +
1610 " -clscheck[+|-] Disables CLS Compliance verifications\n" +
1611 " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
1612 " -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
1613 " -debug[+|-], -g Generate debugging information\n" +
1614 " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
1615 " -doc:FILE Process documentation comments to XML file\n" +
1616 " -fullpaths Any issued error or warning uses absolute file path\n" +
1617 " -help Lists all compiler options (short: -?)\n" +
1618 " -keycontainer:NAME The key pair container used to sign the output assembly\n" +
1619 " -keyfile:FILE The key file used to strongname the ouput assembly\n" +
1620 " -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, 4, 5, 6, Default or Experimental\n" +
1621 " -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
1622 " -main:CLASS Specifies the class with the Main method (short: -m)\n" +
1623 " -noconfig Disables implicitly referenced assemblies\n" +
1624 " -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
1625 " -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
1626 " -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
1627 " -out:FILE Specifies output assembly name\n" +
1628 " -pathmap:K=V[,Kn=Vn] Sets a mapping for source path names used in generated output\n" +
1629 " -pkg:P1[,Pn] References packages P1..Pn\n" +
1630 " -platform:ARCH Specifies the target platform of the output assembly\n" +
1631 " ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
1632 " x86, x64 or itanium. The default is anycpu.\n" +
1633 " -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
1634 " -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
1635 " -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
1636 " -sdk:VERSION Specifies SDK version of referenced assemblies\n" +
1637 " VERSION can be one of: 2, 4, 4.5 (default) or a custom value\n" +
1638 " -target:KIND Specifies the format of the output assembly (short: -t)\n" +
1639 " KIND can be one of: exe, winexe, library, module\n" +
1640 " -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
1641 " -warnaserror[+|-] Treats all warnings as errors\n" +
1642 " -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
1643 " -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
1644 " -helpinternal Shows internal and advanced compiler options\n" +
1647 " -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
1648 " -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
1649 " -win32res:FILE Specifies Win32 resource file (.res)\n" +
1650 " -win32icon:FILE Use this icon for the output\n" +
1651 " @file Read response file for more options\n\n" +
1652 "Options can be of the form -option or /option");
1657 string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
1658 output.WriteLine ("Mono C# compiler version {0}", version);
1662 public class RootContext
1665 // Contains the parsed tree
1667 static ModuleContainer root;
1669 static public ModuleContainer ToplevelTypes {
1670 get { return root; }
1671 set { root = value; }