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