2 // driver.cs: The compiler command line driver.
\r
4 // Author: Miguel de Icaza (miguel@gnu.org)
\r
6 // Licensed under the terms of the GNU GPL
\r
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
\r
14 using System.Reflection;
\r
15 using System.Reflection.Emit;
\r
16 using System.Collections;
\r
22 /// The compiler driver.
\r
28 Library, Exe, Module, WinExe
\r
32 // Assemblies references to be linked. Initialized with
\r
33 // mscorlib.dll here.
\r
34 ArrayList references;
\r
37 ArrayList link_paths;
\r
39 RootContext context;
\r
41 bool yacc_verbose = false;
\r
43 int error_count = 0;
\r
45 string first_source;
\r
47 Target target = Target.Exe;
\r
48 string target_ext = ".exe";
\r
50 bool parse_only = false;
\r
52 public int parse (string input_file)
\r
54 CSharpParser parser;
\r
55 System.IO.Stream input;
\r
59 input = System.IO.File.OpenRead (input_file);
\r
61 context.Report.Error (2001, "Source file '" + input_file + "' could not be parsed");
\r
65 parser = new CSharpParser (context, input_file, input);
\r
66 parser.yacc_verbose = yacc_verbose;
\r
68 errors = parser.parse ();
\r
69 } catch (Exception ex) {
\r
70 Console.WriteLine (ex);
\r
71 Console.WriteLine ("Compilation aborted");
\r
78 public void Usage ()
\r
81 "compiler [options] source-files\n\n" +
\r
82 "-v Verbose parsing\n"+
\r
83 "-o Specifies output file\n" +
\r
84 "-L Specifies path for loading assemblies\n" +
\r
85 "--nostdlib Does not load core libraries\n" +
\r
86 "--target Specifies the target (exe, winexe, library, module)\n" +
\r
87 "--dumper Specifies a tree dumper\n" +
\r
88 "--parse Only parses the source file\n" +
\r
89 "-r References an assembly\n");
\r
93 public ITreeDump lookup_dumper (string name)
\r
96 return new Generator.TreeDump ();
\r
98 // if (name == "il")
\r
99 // return new MSIL.Generator ();
\r
104 public static void error (string msg)
\r
106 Console.WriteLine ("Error: " + msg);
\r
109 public static void notice (string msg)
\r
111 Console.WriteLine (msg);
\r
114 public static int Main(string[] args)
\r
116 Driver driver = new Driver (args);
\r
118 return driver.error_count;
\r
121 public int LoadAssembly (string assembly)
\r
125 foreach (string dir in link_paths){
\r
126 string full_path = dir + "/" + assembly;
\r
129 a = Assembly.Load (assembly);
\r
130 } catch (FileNotFoundException f) {
\r
131 error ("// File not found: " + full_path);
\r
132 error ("Log: " + f.FusionLog);
\r
134 } catch (BadImageFormatException) {
\r
135 error ("// Bad file format: " + full_path);
\r
137 } catch (FileLoadException f){
\r
138 error ("// File Load Exception: " + full_path);
\r
139 error ("Log: " + f.FusionLog);
\r
141 } catch (ArgumentNullException){
\r
142 error ("// Argument Null exception " + full_path);
\r
146 context.TypeManager.AddAssembly (a);
\r
152 // Loads all assemblies referenced on the command line
\r
154 public int LoadReferences ()
\r
158 foreach (string r in references){
\r
159 errors += LoadAssembly (r);
\r
166 // Parses the arguments, and drives the compilation
\r
169 // TODO: Mostly structured to debug the compiler
\r
170 // now, needs to be turned into a real driver soon.
\r
172 public Driver (string [] args)
\r
174 ITreeDump generator = null;
\r
176 string output_file = null;
\r
178 context = new RootContext ();
\r
179 references = new ArrayList ();
\r
180 link_paths = new ArrayList ();
\r
185 link_paths.Add ("file:///C:/WINNT/Microsoft.NET/Framework/v1.0.2914");
\r
187 for (i = 0; i < args.Length; i++){
\r
188 string arg = args [i];
\r
190 if (arg.StartsWith ("-")){
\r
192 yacc_verbose = true;
\r
196 if (arg.StartsWith ("--dumper")){
\r
197 generator = lookup_dumper (args [++i]);
\r
201 if (arg == "--parse"){
\r
207 generator.ParseOptions (args [++i]);
\r
213 output_file = args [++i];
\r
214 } catch (Exception){
\r
215 error ("Could not write to `"+args [i]);
\r
222 if (arg == "--target"){
\r
223 string type = args [++i];
\r
227 target = Target.Library;
\r
228 target_ext = ".dll";
\r
232 target = Target.Exe;
\r
236 target = Target.WinExe;
\r
240 target = Target.Module;
\r
241 target_ext = ".dll";
\r
248 references.Add (args [++i]);
\r
253 link_paths.Add (args [++i]);
\r
257 if (arg == "--nostdlib"){
\r
258 context.StdLib = false;
\r
262 if (arg == "--fatal"){
\r
263 context.Report.Fatal = true;
\r
272 if (!arg.EndsWith (".cs")){
\r
274 error ("Do not know how to compile " + arg);
\r
279 if (first_source == null)
\r
280 first_source = arg;
\r
282 errors += parse (arg);
\r
285 if (first_source == null){
\r
286 context.Report.Error (2008, "No files to compile were specified");
\r
290 if (context.Report.Errors > 0)
\r
297 // Load Core Library for default compilation
\r
299 if (context.StdLib){
\r
300 references.Insert (0, "mscorlib");
\r
301 references.Insert (1, "System");
\r
305 error ("Parsing failed");
\r
308 notice ("Parsing successful");
\r
311 // Load assemblies required
\r
313 errors += LoadReferences ();
\r
316 error ("Could not load one or more assemblies");
\r
322 // Dumping the parsed tree.
\r
324 // This code generation interface is only here
\r
325 // for debugging the parser.
\r
327 if (generator != null){
\r
328 if (output_file == null){
\r
329 error ("Error: no output file specified");
\r
333 Stream output_stream = File.Create (output_file);
\r
334 StreamWriter output = new StreamWriter (output_stream);
\r
336 errors += generator.Dump (context.Tree, output);
\r
339 error ("Compilation failed");
\r
342 notice ("Compilation successful");
\r
349 error_count = errors;
\r
354 if (output_file == null){
\r
355 int pos = first_source.LastIndexOf (".");
\r
357 output_file = first_source.Substring (0, pos) + target_ext;
\r
360 context.CodeGen = new CodeGen (output_file, output_file);
\r
363 // The second pass of the compiler
\r
365 context.ResolveTree ();
\r
366 context.PopulateTypes ();
\r
369 // Before emitting, we need to get the core
\r
370 // types emitted from the user defined types
\r
371 // or from the system ones.
\r
373 context.TypeManager.InitCoreTypes ();
\r
376 // The code generator
\r
378 context.EmitCode ();
\r
380 if (context.Report.Errors > 0){
\r
381 error ("Compilation failed");
\r
385 context.CloseTypes ();
\r
387 PEFileKinds k = PEFileKinds.ConsoleApplication;
\r
389 if (target == Target.Library || target == Target.Module)
\r
390 k = PEFileKinds.Dll;
\r
391 else if (target == Target.Exe)
\r
392 k = PEFileKinds.ConsoleApplication;
\r
393 else if (target == Target.WinExe)
\r
394 k = PEFileKinds.WindowApplication;
\r
396 if (target == Target.Exe || target == Target.WinExe){
\r
397 MethodInfo ep = context.EntryPoint;
\r
400 context.Report.Error (5001, "Program " + output_file +
\r
401 " does not have an entry point defined");
\r
405 context.CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
\r
408 context.CodeGen.Save (context.Report, output_file);
\r
410 if (context.Report.Errors > 0){
\r
411 error ("Compilation failed");
\r
415 notice ("Success");
\r