Xamarin Public Jenkins (auto-signing) 0510252385 Imported Upstream version 5.20.0.180
Former-commit-id: ff953ca879339fe1e1211f7220f563e1342e66cb
2019-02-04 20:11:37 +00:00

1702 lines
44 KiB
C#

//
// settings.cs: All compiler settings
//
// Author: Miguel de Icaza (miguel@ximian.com)
// Ravi Pratap (ravi@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2008 Novell, Inc
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Globalization;
using System;
namespace Mono.CSharp {
public enum LanguageVersion
{
ISO_1 = 1,
ISO_2 = 2,
V_3 = 3,
V_4 = 4,
V_5 = 5,
V_6 = 6,
V_7 = 7,
V_7_1 = 71,
V_7_2 = 72,
V_7_3 = 73,
Experimental = 100,
Default = V_7,
Latest = V_7_3
}
public enum RuntimeVersion
{
v1,
v2,
v4
}
public enum Target
{
Library, Exe, Module, WinExe
}
public enum Platform
{
AnyCPU,
AnyCPU32Preferred,
Arm,
X86,
X64,
IA64
}
public class CompilerSettings
{
public Target Target;
public Platform Platform;
public string TargetExt;
public bool VerifyClsCompliance;
public bool Optimize;
public LanguageVersion Version;
public bool EnhancedWarnings;
public bool LoadDefaultReferences;
public string SdkVersion;
public string StrongNameKeyFile;
public string StrongNameKeyContainer;
public bool StrongNameDelaySign;
public int TabSize;
public bool WarningsAreErrors;
public int WarningLevel;
//
// Assemblies references to be loaded
//
public List<string> AssemblyReferences;
//
// External aliases for assemblies
//
public List<Tuple<string, string>> AssemblyReferencesAliases;
public List<KeyValuePair<string, string>> PathMap;
//
// Modules to be embedded
//
public List<string> Modules;
//
// Lookup paths for referenced assemblies
//
public List<string> ReferencesLookupPaths;
//
// Encoding.
//
public Encoding Encoding;
//
// If set, enable XML documentation generation
//
public string DocumentationFile;
public string MainClass;
//
// Output file
//
public string OutputFile;
//
// The default compiler checked state
//
public bool Checked;
//
// If true, the compiler is operating in statement mode,
// this currently turns local variable declaration into
// static variables of a class
//
public bool StatementMode; // TODO: SUPER UGLY
//
// Whether to allow Unsafe code
//
public bool Unsafe;
public string Win32ResourceFile;
public string Win32IconFile;
//
// A list of resource files for embedding
//
public List<AssemblyResource> Resources;
public bool GenerateDebugInfo;
#region Compiler debug flags only
public bool ParseOnly, TokenizeOnly, Timestamps;
public int DebugFlags;
public int VerboseParserFlag;
public int FatalCounter;
public bool Stacktrace;
public bool BreakOnInternalError;
#endregion
public List<string> GetResourceStrings;
public bool ShowFullPaths;
//
// Whether we are being linked against the standard libraries.
// This is only used to tell whether `System.Object' should
// have a base class or not.
//
public bool StdLib;
public RuntimeVersion StdLibRuntimeVersion;
public string RuntimeMetadataVersion;
public bool WriteMetadataOnly;
readonly List<string> conditional_symbols;
readonly List<SourceFile> source_files;
List<int> warnings_as_error;
List<int> warnings_only;
HashSet<int> warning_ignore_table;
public CompilerSettings ()
{
StdLib = true;
Target = Target.Exe;
TargetExt = ".exe";
Platform = Platform.AnyCPU;
Version = LanguageVersion.Default;
VerifyClsCompliance = true;
Encoding = Encoding.UTF8;
LoadDefaultReferences = true;
StdLibRuntimeVersion = RuntimeVersion.v4;
WarningLevel = 4;
// Default to 1 or mdb files would be platform speficic
TabSize = 1;
AssemblyReferences = new List<string> ();
AssemblyReferencesAliases = new List<Tuple<string, string>> ();
Modules = new List<string> ();
ReferencesLookupPaths = new List<string> ();
conditional_symbols = new List<string> ();
//
// Add default mcs define
//
conditional_symbols.Add ("__MonoCS__");
source_files = new List<SourceFile> ();
}
#region Properties
public SourceFile FirstSourceFile {
get {
return source_files.Count > 0 ? source_files [0] : null;
}
}
public bool HasKeyFileOrContainer {
get {
return StrongNameKeyFile != null || StrongNameKeyContainer != null;
}
}
public bool NeedsEntryPoint {
get {
return Target == Target.Exe || Target == Target.WinExe;
}
}
public List<SourceFile> SourceFiles {
get {
return source_files;
}
}
#endregion
public void AddConditionalSymbol (string symbol)
{
if (!conditional_symbols.Contains (symbol))
conditional_symbols.Add (symbol);
}
public void AddWarningAsError (int id)
{
if (warnings_as_error == null)
warnings_as_error = new List<int> ();
warnings_as_error.Add (id);
}
public void AddWarningOnly (int id)
{
if (warnings_only == null)
warnings_only = new List<int> ();
warnings_only.Add (id);
}
public bool IsConditionalSymbolDefined (string symbol)
{
return conditional_symbols.Contains (symbol);
}
public bool IsWarningAsError (int code)
{
bool is_error = WarningsAreErrors;
// Check specific list
if (warnings_as_error != null)
is_error |= warnings_as_error.Contains (code);
// Ignore excluded warnings
if (warnings_only != null && warnings_only.Contains (code))
is_error = false;
return is_error;
}
public bool IsWarningEnabled (int code, int level)
{
if (WarningLevel < level)
return false;
return !IsWarningDisabledGlobally (code);
}
public bool IsWarningDisabledGlobally (int code)
{
return warning_ignore_table != null && warning_ignore_table.Contains (code);
}
public void SetIgnoreWarning (int code)
{
if (warning_ignore_table == null)
warning_ignore_table = new HashSet<int> ();
warning_ignore_table.Add (code);
}
}
public class CommandLineParser
{
enum ParseResult
{
Success,
Error,
Stop,
UnknownOption
}
static readonly char[] argument_value_separator = { ';', ',' };
static readonly char[] numeric_value_separator = { ';', ',', ' ' };
readonly TextWriter output;
readonly Report report;
bool stop_argument;
Dictionary<string, int> source_file_index;
public event Func<string[], int, int> UnknownOptionHandler;
CompilerSettings parser_settings;
public CommandLineParser (TextWriter errorOutput)
: this (errorOutput, Console.Out)
{
}
public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
{
var rp = new StreamReportPrinter (errorOutput);
parser_settings = new CompilerSettings ();
report = new Report (new CompilerContext (parser_settings, rp), rp);
this.output = messagesOutput;
}
public bool HasBeenStopped {
get {
return stop_argument;
}
}
void About ()
{
output.WriteLine (
"The Turbo C# compiler is Copyright 2001-2011, Novell, Inc. 2011-2016 Xamarin Inc, 2016-2017 Microsoft Corp\n\n" +
"The compiler source code is released under the terms of the \n" +
"MIT X11 or GNU GPL licenses\n\n" +
"For more information on Mono, visit the project Web site\n" +
" http://www.mono-project.com\n\n" +
"The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
}
public CompilerSettings ParseArguments (string[] args)
{
CompilerSettings settings = new CompilerSettings ();
if (!ParseArguments (settings, args))
return null;
return settings;
}
public bool ParseArguments (CompilerSettings settings, string[] args)
{
if (settings == null)
throw new ArgumentNullException ("settings");
List<string> response_file_list = null;
bool parsing_options = true;
stop_argument = false;
source_file_index = new Dictionary<string, int> ();
for (int i = 0; i < args.Length; i++) {
string arg = args[i];
if (arg.Length == 0)
continue;
if (arg[0] == '@') {
string[] extra_args;
string response_file = arg.Substring (1);
if (response_file_list == null)
response_file_list = new List<string> ();
if (response_file_list.Contains (response_file)) {
report.Error (1515, "Response file `{0}' specified multiple times", response_file);
return false;
}
response_file_list.Add (response_file);
extra_args = LoadArgs (response_file);
if (extra_args == null) {
report.Error (2011, "Unable to open response file: " + response_file);
return false;
}
args = AddArgs (args, extra_args);
continue;
}
if (parsing_options) {
if (arg == "--") {
parsing_options = false;
continue;
}
bool dash_opt = arg[0] == '-';
bool slash_opt = arg[0] == '/';
if (dash_opt) {
switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
case ParseResult.Error:
case ParseResult.Success:
continue;
case ParseResult.Stop:
stop_argument = true;
return true;
case ParseResult.UnknownOption:
if (UnknownOptionHandler != null) {
var ret = UnknownOptionHandler (args, i);
if (ret != -1) {
i = ret;
continue;
}
}
break;
}
}
if (dash_opt || slash_opt) {
// Try a -CSCOPTION
string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
switch (ParseOption (csc_opt, ref args, settings)) {
case ParseResult.Error:
case ParseResult.Success:
continue;
case ParseResult.UnknownOption:
// Need to skip `/home/test.cs' however /test.cs is considered as error
if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
break;
if (UnknownOptionHandler != null) {
var ret = UnknownOptionHandler (args, i);
if (ret != -1) {
i = ret;
continue;
}
}
Error_WrongOption (arg);
return false;
case ParseResult.Stop:
stop_argument = true;
return true;
}
}
}
ProcessSourceFiles (arg, false, settings.SourceFiles);
}
return report.Errors == 0;
}
void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
{
string path, pattern;
SplitPathAndPattern (spec, out path, out pattern);
if (pattern.IndexOf ('*') == -1) {
AddSourceFile (spec, sourceFiles);
return;
}
string[] files;
try {
files = Directory.GetFiles (path, pattern);
} catch (System.IO.DirectoryNotFoundException) {
report.Error (2001, "Source file `" + spec + "' could not be found");
return;
} catch (System.IO.IOException) {
report.Error (2001, "Source file `" + spec + "' could not be found");
return;
}
foreach (string f in files) {
AddSourceFile (f, sourceFiles);
}
if (!recurse)
return;
string[] dirs = null;
try {
dirs = Directory.GetDirectories (path);
} catch {
}
foreach (string d in dirs) {
// Don't include path in this string, as each
// directory entry already does
ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
}
}
static string[] AddArgs (string[] args, string[] extra_args)
{
string[] new_args;
new_args = new string[extra_args.Length + args.Length];
// if args contains '--' we have to take that into account
// split args into first half and second half based on '--'
// and add the extra_args before --
int split_position = Array.IndexOf (args, "--");
if (split_position != -1) {
Array.Copy (args, new_args, split_position);
extra_args.CopyTo (new_args, split_position);
Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
} else {
args.CopyTo (new_args, 0);
extra_args.CopyTo (new_args, args.Length);
}
return new_args;
}
void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
{
if (assembly.Length == 0) {
report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
return;
}
if (!IsExternAliasValid (alias)) {
report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
return;
}
settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
}
void AddResource (AssemblyResource res, CompilerSettings settings)
{
if (settings.Resources == null) {
settings.Resources = new List<AssemblyResource> ();
settings.Resources.Add (res);
return;
}
if (settings.Resources.Contains (res)) {
report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
return;
}
settings.Resources.Add (res);
}
void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
{
string path = Path.GetFullPath (fileName);
int index;
if (source_file_index.TryGetValue (path, out index)) {
string other_name = sourceFiles[index - 1].Name;
if (fileName.Equals (other_name))
report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
else
report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
return;
}
var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
sourceFiles.Add (unit);
source_file_index.Add (path, unit.Index);
}
public bool ProcessWarningsList (string text, Action<int> action)
{
foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
var warning = wid;
if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
warning = warning.Substring (2);
int id;
if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
continue;
}
action (id);
}
return true;
}
void Error_RequiresArgument (string option)
{
report.Error (2006, "Missing argument for `{0}' option", option);
}
void Error_RequiresFileName (string option)
{
report.Error (2005, "Missing file specification for `{0}' option", option);
}
void Error_WrongOption (string option)
{
report.Error (2007, "Unrecognized command-line option: `{0}'", option);
}
static bool IsExternAliasValid (string identifier)
{
return Tokenizer.IsValidIdentifier (identifier);
}
static string[] LoadArgs (string file)
{
StreamReader f;
var args = new List<string> ();
string line;
try {
f = new StreamReader (file);
} catch {
return null;
}
StringBuilder sb = new StringBuilder ();
while ((line = f.ReadLine ()) != null) {
int t = line.Length;
for (int i = 0; i < t; i++) {
char c = line[i];
if (c == '"' || c == '\'') {
char end = c;
for (i++; i < t; i++) {
c = line[i];
if (c == end)
break;
sb.Append (c);
}
} else if (c == ' ') {
if (sb.Length > 0) {
args.Add (sb.ToString ());
sb.Length = 0;
}
} else
sb.Append (c);
}
if (sb.Length > 0) {
args.Add (sb.ToString ());
sb.Length = 0;
}
}
return args.ToArray ();
}
void OtherFlags ()
{
output.WriteLine (
"Other flags in the compiler\n" +
" --fatal[=COUNT] Makes error after COUNT fatal\n" +
" --lint Enhanced warnings\n" +
" --metadata-only Produced assembly will contain metadata only\n" +
" --parse Only parses the source file\n" +
" --runtime:VERSION Sets mscorlib.dll metadata version: v1, v2, v4\n" +
" --stacktrace Shows stack trace at error location\n" +
" --timestamp Displays time stamps of various compiler events\n" +
" -v Verbose parsing (for debugging the parser)\n" +
" --mcs-debug X Sets MCS debugging level to X\n" +
" --break-on-ice Breaks compilation on internal compiler error");
}
//
// This parses the -arg and /arg options to the compiler, even if the strings
// in the following text use "/arg" on the strings.
//
ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
{
int idx = option.IndexOf (':');
string arg, value;
if (idx == -1) {
arg = option;
value = "";
} else {
arg = option.Substring (0, idx);
value = option.Substring (idx + 1);
}
switch (arg.ToLowerInvariant ()) {
case "/nologo":
return ParseResult.Success;
case "/t":
case "/target":
switch (value) {
case "exe":
settings.Target = Target.Exe;
break;
case "winexe":
settings.Target = Target.WinExe;
break;
case "library":
settings.Target = Target.Library;
settings.TargetExt = ".dll";
break;
case "module":
settings.Target = Target.Module;
settings.TargetExt = ".netmodule";
break;
default:
report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
return ParseResult.Error;
}
return ParseResult.Success;
case "/out":
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
settings.OutputFile = value;
return ParseResult.Success;
case "/o":
case "/o+":
case "/optimize":
case "/optimize+":
settings.Optimize = true;
return ParseResult.Success;
case "/o-":
case "/optimize-":
settings.Optimize = false;
return ParseResult.Success;
// TODO: Not supported by csc 3.5+
case "/incremental":
case "/incremental+":
case "/incremental-":
// nothing.
return ParseResult.Success;
case "/d":
case "/define": {
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
foreach (string d in value.Split (argument_value_separator)) {
string conditional = d.Trim ();
if (!Tokenizer.IsValidIdentifier (conditional)) {
report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
continue;
}
settings.AddConditionalSymbol (conditional);
}
return ParseResult.Success;
}
case "/bugreport":
//
// We should collect data, runtime, etc and store in the file specified
//
output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
return ParseResult.Success;
case "/pkg": {
string packages;
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
string pkgout = Driver.GetPackageFlags (packages, report);
if (pkgout == null)
return ParseResult.Error;
string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
args = AddArgs (args, xargs);
return ParseResult.Success;
}
case "/linkres":
case "/linkresource":
case "/res":
case "/resource":
AssemblyResource res = null;
string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
switch (s.Length) {
case 1:
if (s[0].Length == 0)
goto default;
res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
break;
case 2:
res = new AssemblyResource (s[0], s[1]);
break;
case 3:
if (s[2] != "public" && s[2] != "private") {
report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
return ParseResult.Error;
}
res = new AssemblyResource (s[0], s[1], s[2] == "private");
break;
default:
report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
return ParseResult.Error;
}
if (res != null) {
res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
AddResource (res, settings);
}
return ParseResult.Success;
case "/recurse":
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
ProcessSourceFiles (value, true, settings.SourceFiles);
return ParseResult.Success;
case "/r":
case "/reference": {
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
string[] refs = value.Split (argument_value_separator);
foreach (string r in refs) {
if (r.Length == 0)
continue;
string val = r;
int index = val.IndexOf ('=');
if (index > -1) {
string alias = r.Substring (0, index);
string assembly = r.Substring (index + 1);
AddAssemblyReference (alias, assembly, settings);
if (refs.Length != 1) {
report.Error (2034, "Cannot specify multiple aliases using single /reference option");
return ParseResult.Error;
}
} else {
settings.AssemblyReferences.Add (val);
}
}
return ParseResult.Success;
}
case "/addmodule": {
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
string[] refs = value.Split (argument_value_separator);
foreach (string r in refs) {
settings.Modules.Add (r);
}
return ParseResult.Success;
}
case "/win32res": {
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
if (settings.Win32IconFile != null)
report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
settings.Win32ResourceFile = value;
return ParseResult.Success;
}
case "/win32icon": {
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
if (settings.Win32ResourceFile != null)
report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
settings.Win32IconFile = value;
return ParseResult.Success;
}
case "/doc": {
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
settings.DocumentationFile = value;
return ParseResult.Success;
}
case "/lib": {
string[] libdirs;
if (value.Length == 0) {
return ParseResult.Error;
}
libdirs = value.Split (argument_value_separator);
foreach (string dir in libdirs)
settings.ReferencesLookupPaths.Add (dir);
return ParseResult.Success;
}
case "/debug-":
settings.GenerateDebugInfo = false;
return ParseResult.Success;
case "/debug":
if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || value.Equals ("portable", StringComparison.OrdinalIgnoreCase) || idx < 0) {
settings.GenerateDebugInfo = true;
return ParseResult.Success;
}
if (value.Length > 0) {
report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
} else {
Error_RequiresArgument (option);
}
return ParseResult.Error;
case "/debug+":
settings.GenerateDebugInfo = true;
return ParseResult.Success;
case "/checked":
case "/checked+":
settings.Checked = true;
return ParseResult.Success;
case "/checked-":
settings.Checked = false;
return ParseResult.Success;
case "/clscheck":
case "/clscheck+":
settings.VerifyClsCompliance = true;
return ParseResult.Success;
case "/clscheck-":
settings.VerifyClsCompliance = false;
return ParseResult.Success;
case "/unsafe":
case "/unsafe+":
settings.Unsafe = true;
return ParseResult.Success;
case "/unsafe-":
settings.Unsafe = false;
return ParseResult.Success;
case "/warnaserror":
case "/warnaserror+":
if (value.Length == 0) {
settings.WarningsAreErrors = true;
parser_settings.WarningsAreErrors = true;
} else {
if (!ProcessWarningsList (value, settings.AddWarningAsError))
return ParseResult.Error;
}
return ParseResult.Success;
case "/warnaserror-":
if (value.Length == 0) {
settings.WarningsAreErrors = false;
} else {
if (!ProcessWarningsList (value, settings.AddWarningOnly))
return ParseResult.Error;
}
return ParseResult.Success;
case "/warn":
case "/w":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
SetWarningLevel (value, settings);
return ParseResult.Success;
case "/nowarn":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
return ParseResult.Error;
return ParseResult.Success;
case "/noconfig":
settings.LoadDefaultReferences = false;
return ParseResult.Success;
case "/platform":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
switch (value.ToLowerInvariant ()) {
case "arm":
settings.Platform = Platform.Arm;
break;
case "anycpu":
settings.Platform = Platform.AnyCPU;
break;
case "x86":
settings.Platform = Platform.X86;
break;
case "x64":
settings.Platform = Platform.X64;
break;
case "itanium":
settings.Platform = Platform.IA64;
break;
case "anycpu32bitpreferred":
settings.Platform = Platform.AnyCPU32Preferred;
break;
default:
report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
value);
return ParseResult.Error;
}
return ParseResult.Success;
case "/sdk":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
settings.SdkVersion = value;
return ParseResult.Success;
// We just ignore this.
case "/errorreport":
case "/filealign":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
return ParseResult.Success;
case "/helpinternal":
OtherFlags ();
return ParseResult.Stop;
case "/help":
case "/?":
Usage ();
return ParseResult.Stop;
case "/main":
case "/m":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
settings.MainClass = value;
return ParseResult.Success;
case "/nostdlib":
case "/nostdlib+":
settings.StdLib = false;
return ParseResult.Success;
case "/nostdlib-":
settings.StdLib = true;
return ParseResult.Success;
case "/fullpaths":
settings.ShowFullPaths = true;
return ParseResult.Success;
case "/keyfile":
if (value.Length == 0) {
Error_RequiresFileName (option);
return ParseResult.Error;
}
settings.StrongNameKeyFile = value;
return ParseResult.Success;
case "/keycontainer":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
settings.StrongNameKeyContainer = value;
return ParseResult.Success;
case "/delaysign+":
case "/delaysign":
settings.StrongNameDelaySign = true;
return ParseResult.Success;
case "/delaysign-":
settings.StrongNameDelaySign = false;
return ParseResult.Success;
case "/langversion":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
switch (value.ToLowerInvariant ()) {
case "iso-1":
case "1":
case "1.0":
settings.Version = LanguageVersion.ISO_1;
return ParseResult.Success;
case "default":
settings.Version = LanguageVersion.Default;
return ParseResult.Success;
case "2":
case "2.0":
case "iso-2":
settings.Version = LanguageVersion.ISO_2;
return ParseResult.Success;
case "3":
case "3.0":
settings.Version = LanguageVersion.V_3;
return ParseResult.Success;
case "4":
case "4.0":
settings.Version = LanguageVersion.V_4;
return ParseResult.Success;
case "5":
case "5.0":
settings.Version = LanguageVersion.V_5;
return ParseResult.Success;
case "6":
case "6.0":
settings.Version = LanguageVersion.V_6;
return ParseResult.Success;
case "7":
case "7.0":
settings.Version = LanguageVersion.V_7;
return ParseResult.Success;
case "7.1":
settings.Version = LanguageVersion.V_7_1;
return ParseResult.Success;
case "7.2":
settings.Version = LanguageVersion.V_7_2;
return ParseResult.Success;
case "latest":
settings.Version = LanguageVersion.Latest;
return ParseResult.Success;
case "experimental":
settings.Version = LanguageVersion.Experimental;
return ParseResult.Success;
}
if (value.StartsWith ("0", StringComparison.Ordinal)) {
report.Error (8303, "Specified language version `{0}' cannot have leading zeroes", value);
} else {
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);
}
return ParseResult.Error;
case "/codepage":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
switch (value) {
case "utf8":
settings.Encoding = Encoding.UTF8;
break;
case "reset":
settings.Encoding = Encoding.Default;
break;
default:
try {
settings.Encoding = Encoding.GetEncoding (int.Parse (value));
} catch {
report.Error (2016, "Code page `{0}' is invalid or not installed", value);
}
return ParseResult.Error;
}
return ParseResult.Success;
case "/runtimemetadataversion":
if (value.Length == 0) {
Error_RequiresArgument (option);
return ParseResult.Error;
}
settings.RuntimeMetadataVersion = value;
return ParseResult.Success;
case "/pathmap":
if (value.Length == 0) {
return ParseResult.Success;
}
foreach (var pair in value.Split (',')) {
var kv = pair.Split ('=');
if (kv.Length != 2) {
report.Error (8101, "The pathmap option was incorrectly formatted");
return ParseResult.Error;
}
if (settings.PathMap == null)
settings.PathMap = new List<KeyValuePair<string, string>> ();
var key = kv [0].TrimEnd (Path.DirectorySeparatorChar);
var path = kv [1].TrimEnd (Path.DirectorySeparatorChar);
if (key.Length == 0 || path.Length == 0)
report.Error (8101, "The pathmap option was incorrectly formatted");
settings.PathMap.Add (new KeyValuePair<string, string> (key, path));
}
return ParseResult.Success;
// csc options that we don't support
case "/analyzer":
case "/appconfig":
case "/baseaddress":
case "/deterministic":
case "/deterministic+":
case "/deterministic-":
case "/errorendlocation":
case "/errorlog":
case "/features":
case "/highentropyva":
case "/highentropyva+":
case "/highentropyva-":
case "/link":
case "/sourcelink":
case "/moduleassemblyname":
case "/nowin32manifest":
case "/pdb":
case "/preferreduilang":
case "/publicsign":
case "/publicsign+":
case "/publicsign-":
case "/reportanalyzer":
case "/ruleset":
case "/sqmsessionguid":
case "/subsystemversion":
case "/utf8output":
case "/win32manifest":
return ParseResult.Success;
default:
return ParseResult.UnknownOption;
}
}
//
// Currently handles the Unix-like command line options, but will be
// deprecated in favor of the CSCParseOption, which will also handle the
// options that start with a dash in the future.
//
ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
{
switch (arg){
case "-v":
settings.VerboseParserFlag++;
return ParseResult.Success;
case "--version":
Version ();
return ParseResult.Stop;
case "--parse":
settings.ParseOnly = true;
return ParseResult.Success;
case "--main": case "-m":
report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
settings.MainClass = args[++i];
return ParseResult.Success;
case "--unsafe":
report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
settings.Unsafe = true;
return ParseResult.Success;
case "/?": case "/h": case "/help":
case "--help":
Usage ();
return ParseResult.Stop;
case "--define":
report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
settings.AddConditionalSymbol (args [++i]);
return ParseResult.Success;
case "--tokenize":
settings.TokenizeOnly = true;
return ParseResult.Success;
case "-o":
case "--output":
report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
settings.OutputFile = args[++i];
return ParseResult.Success;
case "--checked":
report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
settings.Checked = true;
return ParseResult.Success;
case "--stacktrace":
settings.Stacktrace = true;
return ParseResult.Success;
case "--linkresource":
case "--linkres":
report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
AddResource (new AssemblyResource (args[++i], args[i]), settings);
return ParseResult.Success;
case "--resource":
case "--res":
report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
AddResource (new AssemblyResource (args[++i], args[i], true), settings);
return ParseResult.Success;
case "--target":
report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
string type = args [++i];
switch (type){
case "library":
settings.Target = Target.Library;
settings.TargetExt = ".dll";
break;
case "exe":
settings.Target = Target.Exe;
break;
case "winexe":
settings.Target = Target.WinExe;
break;
case "module":
settings.Target = Target.Module;
settings.TargetExt = ".dll";
break;
default:
report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
break;
}
return ParseResult.Success;
case "-r":
report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
string val = args [++i];
int idx = val.IndexOf ('=');
if (idx > -1) {
string alias = val.Substring (0, idx);
string assembly = val.Substring (idx + 1);
AddAssemblyReference (alias, assembly, settings);
return ParseResult.Success;
}
settings.AssemblyReferences.Add (val);
return ParseResult.Success;
case "-L":
report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
settings.ReferencesLookupPaths.Add (args [++i]);
return ParseResult.Success;
case "--lint":
settings.EnhancedWarnings = true;
return ParseResult.Success;
case "--nostdlib":
report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
settings.StdLib = false;
return ParseResult.Success;
case "--nowarn":
report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
int warn = 0;
try {
warn = int.Parse (args [++i]);
} catch {
Usage ();
Environment.Exit (1);
}
settings.SetIgnoreWarning (warn);
return ParseResult.Success;
case "--wlevel":
report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
SetWarningLevel (args [++i], settings);
return ParseResult.Success;
case "--mcs-debug":
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
try {
settings.DebugFlags = int.Parse (args [++i]);
} catch {
Error_RequiresArgument (arg);
return ParseResult.Error;
}
return ParseResult.Success;
case "--about":
About ();
return ParseResult.Stop;
case "--recurse":
report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
if ((i + 1) >= args.Length){
Error_RequiresArgument (arg);
return ParseResult.Error;
}
ProcessSourceFiles (args [++i], true, settings.SourceFiles);
return ParseResult.Success;
case "--timestamp":
settings.Timestamps = true;
return ParseResult.Success;
case "--debug": case "-g":
report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
settings.GenerateDebugInfo = true;
return ParseResult.Success;
case "--noconfig":
report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
settings.LoadDefaultReferences = false;
return ParseResult.Success;
case "--metadata-only":
settings.WriteMetadataOnly = true;
return ParseResult.Success;
case "--break-on-ice":
settings.BreakOnInternalError = true;
return ParseResult.Success;
default:
if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
int fatal = 1;
if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
int.TryParse (arg.Substring (8), out fatal);
settings.FatalCounter = fatal;
return ParseResult.Success;
}
if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
string version = arg.Substring (10);
switch (version) {
case "v1":
case "V1":
settings.StdLibRuntimeVersion = RuntimeVersion.v1;
break;
case "v2":
case "V2":
settings.StdLibRuntimeVersion = RuntimeVersion.v2;
break;
case "v4":
case "V4":
settings.StdLibRuntimeVersion = RuntimeVersion.v4;
break;
}
return ParseResult.Success;
}
if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
string file = arg.Substring (21).Trim ();
if (file.Length < 1) {
Error_RequiresArgument (arg);
return ParseResult.Error;
}
if (settings.GetResourceStrings == null)
settings.GetResourceStrings = new List<string> ();
settings.GetResourceStrings.Add (file);
return ParseResult.Success;
}
return ParseResult.UnknownOption;
}
}
void SetWarningLevel (string s, CompilerSettings settings)
{
int level = -1;
try {
level = int.Parse (s);
} catch {
}
if (level < 0 || level > 4) {
report.Error (1900, "Warning level must be in the range 0-4");
return;
}
settings.WarningLevel = level;
}
//
// Given a path specification, splits the path from the file/pattern
//
static void SplitPathAndPattern (string spec, out string path, out string pattern)
{
int p = spec.LastIndexOf ('/');
if (p != -1) {
//
// Windows does not like /file.cs, switch that to:
// "\", "file.cs"
//
if (p == 0) {
path = "\\";
pattern = spec.Substring (1);
} else {
path = spec.Substring (0, p);
pattern = spec.Substring (p + 1);
}
return;
}
p = spec.LastIndexOf ('\\');
if (p != -1) {
path = spec.Substring (0, p);
pattern = spec.Substring (p + 1);
return;
}
path = ".";
pattern = spec;
}
void Usage ()
{
output.WriteLine (
"Turbo C# compiler, Copyright 2001-2011 Novell, Inc., 2011-2016 Xamarin, Inc, 2016-2017 Microsoft Corp\n" +
"mcs [options] source-files\n" +
" --about About the Mono C# compiler\n" +
" -addmodule:M1[,Mn] Adds the module to the generated assembly\n" +
" -checked[+|-] Sets default aritmetic overflow context\n" +
" -clscheck[+|-] Disables CLS Compliance verifications\n" +
" -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
" -define:S1[;S2] Defines one or more conditional symbols (short: -d)\n" +
" -debug[+|-], -g Generate debugging information\n" +
" -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
" -doc:FILE Process documentation comments to XML file\n" +
" -fullpaths Any issued error or warning uses absolute file path\n" +
" -help Lists all compiler options (short: -?)\n" +
" -keycontainer:NAME The key pair container used to sign the output assembly\n" +
" -keyfile:FILE The key file used to strongname the ouput assembly\n" +
" -langversion:TEXT Specifies language version: ISO-1, ISO-2, 3, 4, 5, 6, Default or Experimental\n" +
" -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
" -main:CLASS Specifies the class with the Main method (short: -m)\n" +
" -noconfig Disables implicitly referenced assemblies\n" +
" -nostdlib[+|-] Does not reference mscorlib.dll library\n" +
" -nowarn:W1[,Wn] Suppress one or more compiler warnings\n" +
" -optimize[+|-] Enables advanced compiler optimizations (short: -o)\n" +
" -out:FILE Specifies output assembly name\n" +
" -pathmap:K=V[,Kn=Vn] Sets a mapping for source path names used in generated output\n" +
" -pkg:P1[,Pn] References packages P1..Pn\n" +
" -platform:ARCH Specifies the target platform of the output assembly\n" +
" ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
" x86, x64 or itanium. The default is anycpu.\n" +
" -recurse:SPEC Recursively compiles files according to SPEC pattern\n" +
" -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
" -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +
" -sdk:VERSION Specifies SDK version of referenced assemblies\n" +
" VERSION can be one of: 2, 4, 4.5 (default) or a custom value\n" +
" -target:KIND Specifies the format of the output assembly (short: -t)\n" +
" KIND can be one of: exe, winexe, library, module\n" +
" -unsafe[+|-] Allows to compile code which uses unsafe keyword\n" +
" -warnaserror[+|-] Treats all warnings as errors\n" +
" -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
" -warn:0-4 Sets warning level, the default is 4 (short -w:)\n" +
" -helpinternal Shows internal and advanced compiler options\n" +
"\n" +
"Resources:\n" +
" -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
" -resource:FILE[,ID] Embed FILE as a resource (short: -res)\n" +
" -win32res:FILE Specifies Win32 resource file (.res)\n" +
" -win32icon:FILE Use this icon for the output\n" +
" @file Read response file for more options\n\n" +
"Options can be of the form -option or /option");
}
void Version ()
{
string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
output.WriteLine ("Mono C# compiler version {0}", version);
}
}
public class RootContext
{
//
// Contains the parsed tree
//
static ModuleContainer root;
static public ModuleContainer ToplevelTypes {
get { return root; }
set { root = value; }
}
}
}