// Licensed under the terms of the GNU GPL
//
// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc
//
namespace Mono.CSharp
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
+ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Globalization;
+ using System.Xml;
public enum Target {
Library, Exe, Module, WinExe
// Lookup paths
static ArrayList link_paths;
- // Whether we want Yacc to output its progress
- static bool yacc_verbose = false;
-
// Whether we want to only run the tokenizer
static bool tokenize = false;
static bool timestamps = false;
static bool pause = false;
static bool show_counters = false;
- public static bool parser_verbose = false;
//
// Whether to load the initial config file (what CSC.RSP has by default)
//
static bool using_default_encoder = true;
- //
- // The system version we are using, if not specified on the commandline we
- // will use the same version as corlib for looking for libraries in the GAC.
- //
- static string sys_version;
-
public static void ShowTime (string msg)
{
if (!timestamps)
SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
parser = new CSharpParser (reader, file, defines);
- parser.yacc_verbose_flag = yacc_verbose;
try {
parser.parse ();
} catch (Exception ex) {
}
}
+ static void OtherFlags ()
+ {
+ Console.WriteLine (
+ "Other flags in the compiler\n" +
+ " --fatal Makes errors fatal\n" +
+ " --parse Only parses the source file\n" +
+ " --stacktrace Shows stack trace at error location\n" +
+ " --timestamp Displays time stamps of various compiler events\n" +
+ " -2 Enables experimental C# features\n" +
+ " -v Verbose parsing (for debugging the parser)\n" +
+ " --mcs-debug X Sets MCS debugging level to X\n");
+ }
+
static void Usage ()
{
Console.WriteLine (
"Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
"mcs [options] source-files\n" +
" --about About the Mono C# compiler\n" +
+ " -addmodule:MODULE Adds the module to the generated assembly\n" +
" -checked[+|-] Set default context to checked\n" +
" -codepage:ID Sets code page to the one in ID\n" +
" (number, `utf8' or `reset')\n" +
" -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
" -doc:FILE XML Documentation file to generate\n" +
" -g Generate debugging information\n" +
- " --fatal Makes errors fatal\n" +
" -keycontainer:NAME The key pair container used to strongname the assembly\n" +
" -keyfile:FILE The strongname key file used to strongname the assembly\n" +
+ " -langversion:TEXT Specifies language version modes: ISO-1 or Default" + Environment.NewLine +
" -lib:PATH1,PATH2 Adds the paths to the assembly link path\n" +
" -main:class Specified the class that contains the entry point\n" +
" -noconfig[+|-] Disables implicit references to assemblies\n" +
" -nostdlib[+|-] Does not load core libraries\n" +
" -nowarn:W1[,W2] Disables one or more warnings\n" +
+ " -optimize[+|-] Enables code optimalizations" + Environment.NewLine +
" -out:FNAME Specifies output file\n" +
- " --parse Only parses the source file\n" +
+ " -pkg:P1[,Pn] References packages P1..Pn\n" +
" --expect-error X Expect that error X will be encountered\n" +
" -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" +
" -reference:ASS References the specified assembly (-r:ASS)\n" +
- " --stacktrace Shows stack trace at error location\n" +
" -target:KIND Specifies the target (KIND is one of: exe, winexe,\n" +
" library, module), (short: /t:)\n" +
- " --timestamp Displays time stamps of various compiler events\n" +
" -unsafe[+|-] Allows unsafe code\n" +
" -warnaserror[+|-] Treat warnings as errors\n" +
" -warn:LEVEL Sets warning level (the highest is 4, the default is 2)\n" +
- " -v Verbose parsing (for debugging the parser)\n" +
- " -2 Enables experimental C# features\n" +
+ " -help2 Show other help flags\n" +
"\n" +
"Resources:\n" +
" -linkresource:FILE[,ID] Links FILE as a resource\n" +
" -resource:FILE[,ID] Embed FILE as a resource\n" +
" -win32res:FILE Specifies Win32 resource file (.res)\n" +
" -win32icon:FILE Use this icon for the output\n" +
- " --mcs-debug X Sets MCS debugging level to X\n" +
" @file Read response file for more options\n\n" +
"Options can be of the form -option or /option");
}
"For more information on Mono, visit the project Web site\n" +
" http://www.go-mono.com\n\n" +
- "The compiler was written by Miguel de Icaza, Ravi Pratap and Martin Baulig");
+ "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath");
Environment.Exit (0);
}
public static int Main (string[] args)
{
- RootContext.V2 = true;
+ RootContext.Version = LanguageVersion.Default;
bool ok = MainDriver (args);
if (ok && Report.Errors == 0) {
- Console.Write("Compilation succeeded");
if (Report.Warnings > 0) {
- Console.Write(" - {0} warning(s)", Report.Warnings);
+ Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
}
- Console.WriteLine();
if (show_counters){
Console.WriteLine ("Counter1: " + counter1);
Console.WriteLine ("Counter2: " + counter2);
string total_log = "";
try {
- char[] path_chars = { '/', '\\', '.' };
+ char[] path_chars = { '/', '\\' };
if (assembly.IndexOfAny (path_chars) != -1) {
a = Assembly.LoadFrom (assembly);
} else {
- a = LoadAssemblyFromGac (assembly);
- if (a == null)
- a = Assembly.Load (assembly);
+ string ass = assembly;
+ if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
+ ass = assembly.Substring (0, assembly.Length - 4);
+ a = Assembly.Load (ass);
}
TypeManager.AddAssembly (a);
} catch (FileNotFoundException){
foreach (string dir in link_paths){
string full_path = Path.Combine (dir, assembly);
- if (!assembly.EndsWith (".dll"))
+ if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
full_path += ".dll";
try {
}
}
- static Assembly LoadAssemblyFromGac (string name)
- {
- PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath",
- BindingFlags.Static|BindingFlags.NonPublic);
-
- if (gac == null)
- return null;
-
- MethodInfo gac_get = gac.GetGetMethod (true);
- string use_name = name;
- string asmb_path;
- string [] canidates;
-
- if (name.EndsWith (".dll"))
- use_name = name.Substring (0, name.Length - 4);
-
- asmb_path = Path.Combine ((string) gac_get.Invoke (null, null), use_name);
-
- if (!Directory.Exists (asmb_path))
- return null;
-
- canidates = Directory.GetDirectories (asmb_path, GetSysVersion () + "*");
- if (canidates.Length == 0)
- canidates = Directory.GetDirectories (asmb_path);
- if (canidates.Length == 0)
- return null;
- try {
- Assembly a = Assembly.LoadFrom (Path.Combine (canidates [0], use_name + ".dll"));
- return a;
- } catch (Exception e) {
- return null;
- }
- }
-
- static string GetSysVersion ()
- {
- if (sys_version != null)
- return sys_version;
- sys_version = typeof (object).Assembly.GetName ().Version.ToString ();
- return sys_version;
- }
-
static public void LoadModule (MethodInfo adder_method, string module)
{
Module m;
static void SetupV2 ()
{
- RootContext.V2 = true;
+ RootContext.Version = LanguageVersion.Default;
defines.Add ("__V2__");
}
static bool UnixParseOption (string arg, ref string [] args, ref int i)
{
switch (arg){
- case "-vv":
- parser_verbose = true;
- return true;
-
case "-v":
- yacc_verbose = true;
+ CSharpParser.yacc_verbose_flag++;
return true;
case "--version":
case "/optimize":
case "/optimize+":
+ RootContext.Optimize = true;
+ return true;
+
case "/optimize-":
+ RootContext.Optimize = false;
+ return true;
+
case "/incremental":
case "/incremental+":
case "/incremental-":
resources.Add (value);
return true;
+ case "/pkg": {
+ string packages;
+
+ if (value == ""){
+ Usage ();
+ Environment.Exit (1);
+ }
+ packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
+
+ ProcessStartInfo pi = new ProcessStartInfo ();
+ pi.FileName = "pkg-config";
+ pi.RedirectStandardOutput = true;
+ pi.UseShellExecute = false;
+ pi.Arguments = "--libs " + packages;
+ Process p = null;
+ try {
+ p = Process.Start (pi);
+ } catch (Exception e) {
+ Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
+ Environment.Exit (1);
+ }
+
+ if (p.StandardOutput == null){
+ Report.Warning (-27, "Specified package did not return any information");
+ return true;
+ }
+ string pkgout = p.StandardOutput.ReadToEnd ();
+ p.WaitForExit ();
+ if (p.ExitCode != 0) {
+ Report.Error (-27, "Error running pkg-config. Check the above output.");
+ Environment.Exit (1);
+ }
+
+ if (pkgout != null){
+ string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
+ Split (new Char [] { ' ', '\t'});
+ args = AddArgs (args, xargs);
+ }
+
+ p.Close ();
+ return true;
+ }
+
case "/res":
case "/resource":
if (value == ""){
- Report.Error (5, arg + " requires an argument");
+ Report.Error (5, "-resource requires an argument");
Environment.Exit (1);
}
if (embedded_resources == null)
embedded_resources = new ArrayList ();
+ if (embedded_resources.Contains (value)) {
+ Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
+ }
+ else if (value.IndexOf (',') != -1 && embedded_resources.Contains (value.Split (',')[1])) {
+ Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
+ }
+ else {
embedded_resources.Add (value);
+ }
return true;
case "/recurse":
if (value == ""){
- Report.Error (5, "/recurse requires an argument");
+ Report.Error (5, "-recurse requires an argument");
Environment.Exit (1);
}
CompileFiles (value, true);
case "/r":
case "/reference": {
if (value == ""){
- Report.Error (5, arg + " requires an argument");
+ Report.Error (5, "-reference requires an argument");
Environment.Exit (1);
}
}
case "/doc": {
if (value == ""){
- Report.Error (5, arg + " requires an argument");
+ Report.Error (2006, arg + " requires an argument");
Environment.Exit (1);
}
- // TODO handle the /doc argument to generate xml doc
+ RootContext.Documentation = new Documentation (value);
return true;
}
case "/lib": {
link_paths.Add (dir);
return true;
}
+
+ case "/debug-":
+ want_debugging_support = false;
+ return true;
case "/debug":
case "/debug+":
load_default_config = false;
return true;
+ case "/help2":
+ OtherFlags ();
+ Environment.Exit(0);
+ return true;
+
case "/help":
case "/?":
Usage ();
case "/v2":
case "/2":
+ Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
SetupV2 ();
return true;
+ case "/langversion":
+ switch (value.ToLower (CultureInfo.InvariantCulture)) {
+ case "iso-1":
+ RootContext.Version = LanguageVersion.ISO_1;
+ return true;
+
+ case "default":
+ SetupV2 ();
+ return true;
+ }
+ Report.Error (1617, "Invalid option '{0}' for /langversion; must be ISO-1 or Default", value);
+ Environment.Exit (1);
+ return false;
+
case "/codepage":
int cp = -1;
return false;
}
+ 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;
+ }
+
/// <summary>
/// Parses the arguments, and drives the compilation
/// process.
int i;
bool parsing_options = true;
- Console.WriteLine ("ALPHA SOFTWARE: Mono C# Compiler {0} for Generics",
- Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
try {
encoding = Encoding.GetEncoding (28591);
} catch {
// path.
//
- int argc = args.Length;
- for (i = 0; i < argc; i++){
+ for (i = 0; i < args.Length; i++){
string arg = args [i];
+ if (arg == "")
+ continue;
if (arg.StartsWith ("@")){
- string [] new_args, extra_args;
+ string [] extra_args;
string response_file = arg.Substring (1);
if (response_file_list == null)
return false;
}
- new_args = new string [extra_args.Length + argc];
- args.CopyTo (new_args, 0);
- extra_args.CopyTo (new_args, argc);
- args = new_args;
- argc = new_args.Length;
+ args = AddArgs (args, extra_args);
continue;
}
if (tokenize)
return true;
+ //
+ // This will point to the NamespaceEntry of the last file that was parsed, and may
+ // not be meaningful when resolving classes from other files. So, reset it to prevent
+ // silent bugs.
+ //
+ RootContext.Tree.Types.NamespaceEntry = null;
+
//
// If we are an exe, require a source file for the entry point
//
if (timestamps)
ShowTime ("Loading references");
link_paths.Add (GetSystemDir ());
+ link_paths.Add (Directory.GetCurrentDirectory ());
LoadReferences ();
if (timestamps)
Environment.Exit (1);
}
- module_only.SetValue (CodeGen.Assembly.Builder, true, null);
+ MethodInfo set_method = module_only.GetSetMethod (true);
+ set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
}
TypeManager.AddModule (CodeGen.Module.Builder);
if (timestamps)
ShowTime ("Resolving tree");
RootContext.ResolveTree ();
+
if (Report.Errors > 0)
return false;
if (timestamps)
RootContext.PopulateTypes ();
RootContext.DefineTypes ();
+ if (RootContext.Documentation != null &&
+ !RootContext.Documentation.OutputDocComment (
+ output_file))
+ return false;
+
TypeManager.InitCodeHelpers ();
//
if (RootContext.VerifyClsCompliance) {
CodeGen.Assembly.ResolveClsCompliance ();
+ if (CodeGen.Assembly.IsClsCompliant) {
AttributeTester.VerifyModulesClsCompliance ();
TypeManager.LoadAllImportedTypes ();
+ AttributeTester.VerifyTopLevelNameClsCompliance ();
+ }
}
//
MethodInfo ep = RootContext.EntryPoint;
if (ep == null) {
+ if (RootContext.MainClass != null) {
+ DeclSpace main_cont = RootContext.Tree.Decls [RootContext.MainClass] as DeclSpace;
+ if (main_cont == null) {
+ Report.Error (1555, output_file, "Could not find '{0}' specified for Main method", RootContext.MainClass);
+ return false;
+ }
+
+ if (!(main_cont is ClassOrStruct)) {
+ Report.Error (1556, output_file, "'{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
+ return false;
+ }
+
+ Report.Error (1558, main_cont.Location, "'{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
+ return false;
+ }
+
if (Report.Errors == 0)
Report.Error (5001, "Program " + output_file +
" does not have an entry point defined");
margs [1] = spec.Substring (0, cp);
} else {
margs [1] = spec;
- margs [0] = spec.Replace ('/','.').Replace ('\\', '.');
+ margs [0] = Path.GetFileName (spec);
}
if (File.Exists ((string) margs [1]))
#endif
return (Report.Errors == 0);
}
-
}
//