2001-11-08 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10
11 namespace CIR
12 {
13         using System;
14         using System.Reflection;
15         using System.Reflection.Emit;
16         using System.Collections;
17         using System.IO;
18         using CIR;
19         using Generator;
20         using Mono.Languages;
21
22         /// <summary>
23         ///    The compiler driver.
24         /// </summary>
25         public class Driver
26         {
27
28                 enum Target {
29                         Library, Exe, Module, WinExe
30                 };
31                 
32                 //
33                 // Assemblies references to be linked.   Initialized with
34                 // mscorlib.dll here.
35                 ArrayList references;
36
37                 // Lookup paths
38                 ArrayList link_paths;
39
40                 RootContext context; 
41
42                 bool yacc_verbose = false;
43
44                 int error_count = 0;
45
46                 string first_source;
47
48                 Target target = Target.Exe;
49                 string target_ext = ".exe";
50
51                 bool parse_only = false;
52                 
53                 public int parse (string input_file)
54                 {
55                         CSharpParser parser;
56                         System.IO.Stream input;
57                         int errors;
58
59                         try {
60                                 input = System.IO.File.OpenRead (input_file);
61                         } catch {
62                                 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
63                                 return 1;
64                         }
65
66                         parser = new CSharpParser (context, input_file, input);
67                         parser.yacc_verbose = yacc_verbose;
68                         try {
69                                 errors = parser.parse ();\r
70                         } catch (Exception ex) {
71                                 Console.WriteLine (ex);
72                                 Console.WriteLine ("Compilation aborted");
73                                 return 1;
74                         }
75                         
76                         return errors;
77                 }
78                 
79                 public void Usage ()
80                 {
81                         Console.WriteLine (
82                                 "compiler [options] source-files\n\n" +
83                                 "-v           Verbose parsing\n"+
84                                 "-o           Specifies output file\n" +
85                                 "-L           Specifies path for loading assemblies\n" +
86                                 "--fatal      Makes errors fatal\n" + 
87                                 "--nostdlib   Does not load core libraries\n" +
88                                 "--target     Specifies the target (exe, winexe, library, module)\n" +
89                                 "--dumper     Specifies a tree dumper\n" +
90                                 "--parse      Only parses the source file\n" +
91                                 "--probe X L  Probes for the source to generate code X on line L\n" +
92                                 "--checked    Set default context to checked\n" +
93                                 "-r           References an assembly\n");
94                         
95                 }
96
97                 public ITreeDump lookup_dumper (string name)
98                 {
99                         if (name == "tree")
100                                 return new Generator.TreeDump ();
101                         
102                         //                      if (name == "il")
103                         // return new MSIL.Generator ();
104                         
105                         return null;
106                 }
107
108                 public static void error (string msg)
109                 {
110                         Console.WriteLine ("Error: " + msg);
111                 }
112
113                 public static void notice (string msg)
114                 {
115                         Console.WriteLine (msg);
116                 }
117                 
118                 public static int Main(string[] args)
119                 {
120                         Driver driver = new Driver (args);
121
122                         return driver.error_count;
123                 }
124
125                 public int LoadAssembly (string assembly)
126                 {
127                         Assembly a;
128                         string total_log = "";
129
130                         try {
131                                 a = Assembly.Load (assembly);
132                                 context.TypeManager.AddAssembly (a);
133                                 return 0;
134                         } catch (FileNotFoundException){
135                                 foreach (string dir in link_paths){
136                                         string full_path = dir + "/" + assembly;;
137
138                                         try {
139                                                 a = Assembly.LoadFrom (full_path);
140                                                 context.TypeManager.AddAssembly (a);
141                                                 return 0;
142                                         } catch (FileNotFoundException ff) {
143                                                 total_log += ff.FusionLog;
144                                                 continue;
145                                         }
146                                 }
147                         } catch (BadImageFormatException f) {
148                                 error ("// Bad file format while loading assembly");
149                                 error ("Log: " + f.FusionLog);
150                                 return 1;
151                         } catch (FileLoadException f){
152                                 error ("// File Load Exception: ");
153                                 error ("Log: " + f.FusionLog);
154                                 return 1;
155                         } catch (ArgumentNullException){
156                                 error ("// Argument Null exception ");
157                                 return 1;
158                         }
159                         
160                         Report.Error (6, "Can not find assembly `" + assembly + "'" );
161                         Console.WriteLine ("Log: \n" + total_log);
162
163                         return 0;
164                 }
165
166                 // <summary>
167                 //   Loads all assemblies referenced on the command line
168                 // </summary>
169                 public int LoadReferences ()
170                 {
171                         int errors = 0;
172                         
173                         foreach (string r in references){
174                                 errors += LoadAssembly (r);
175                         }
176
177                         return errors;
178                 }
179
180                 // <summary>
181                 //    Parses the arguments, and drives the compilation
182                 //    process.
183                 //
184                 //    TODO: Mostly structured to debug the compiler
185                 //    now, needs to be turned into a real driver soon.
186                 // </summary>
187                 public Driver (string [] args)
188                 {
189                         ITreeDump generator = null;
190                         int errors = 0, i;
191                         string output_file = null;
192
193                         context = new RootContext ();
194                         references = new ArrayList ();
195                         link_paths = new ArrayList ();
196
197                         //
198                         // Setup defaults
199                         //
200                         // This is not required because Assembly.Load knows about this
201                         // path.
202                         //
203                         // link_paths.Add ("file:///C:/WINNT/Microsoft.NET/Framework/v1.0.2914");
204                         
205                         for (i = 0; i < args.Length; i++){
206                                 string arg = args [i];
207                                 
208                                 try {
209                                         if (arg.StartsWith ("-")){
210                                                 if (arg == "-v"){
211                                                         yacc_verbose = true;
212                                                         continue;
213                                                 }
214                                                 
215                                                 if (arg.StartsWith ("--dumper")){
216                                                         generator = lookup_dumper (args [++i]);
217                                                         continue;
218                                                 }
219                                                 
220                                                 if (arg == "--parse"){
221                                                         parse_only = true;
222                                                         continue;
223                                                 }
224                                                 
225                                                 if (arg == "--probe"){
226                                                         int code, line;
227
228                                                         code = Int32.Parse (args [++i], 0);
229                                                         line = Int32.Parse (args [++i], 0);
230                                                         Report.SetProbe (code, line);
231                                                         continue;
232                                                 }
233                                                 
234                                                 if (arg == "-z"){
235                                                         generator.ParseOptions (args [++i]);
236                                                         continue;
237                                                 }
238                                                 
239                                                 if (arg == "-o" || arg == "--output"){
240                                                         try {
241                                                                 output_file = args [++i];
242                                                         } catch (Exception){
243                                                                 error ("Could not write to `"+args [i]);
244                                                                 error_count++;
245                                                                 return;
246                                                         }
247                                                         continue;
248                                                 }
249
250                                                 if (arg == "--checked"){
251                                                         context.Checked = true;
252                                                         continue;
253                                                 }
254                                                 
255                                                 if (arg == "--target"){
256                                                         string type = args [++i];
257                                                         
258                                                         switch (type){
259                                                         case "library":
260                                                                 target = Target.Library;
261                                                                 target_ext = ".dll";
262                                                                 break;
263                                                                 
264                                                         case "exe":
265                                                                 target = Target.Exe;
266                                                                 break;
267                                                                 
268                                                         case "winexe":
269                                                                 target = Target.WinExe;
270                                                                 break;
271                                                                 
272                                                         case "module":
273                                                                 target = Target.Module;
274                                                                 target_ext = ".dll";
275                                                                 break;
276                                                         }
277                                                         continue;
278                                                 }
279                                                 
280                                                 if (arg == "-r"){
281                                                         references.Add (args [++i]);
282                                                         continue;
283                                                 }
284                                                 
285                                                 if (arg == "-L"){
286                                                         link_paths.Add (args [++i]);
287                                                         continue;
288                                                 }
289                                                 
290                                                 if (arg == "--nostdlib"){
291                                                         context.StdLib = false;
292                                                         continue;
293                                                 }
294                                                 
295                                                 if (arg == "--fatal"){
296                                                         Report.Fatal = true;
297                                                         continue;
298                                                 }
299                                                 Usage ();
300                                                 error_count++;
301                                                 return;
302                                         }
303                                 } catch (System.IndexOutOfRangeException){
304                                         Usage ();
305                                         error_count++;
306                                         return;
307                                 } catch (System.FormatException) {
308                                         Usage ();
309                                         error_count++;
310                                         return;
311                                 }
312
313                                 if (first_source == null)
314                                         first_source = arg;
315
316                                 if (!arg.EndsWith (".cs")){
317                                         error ("Do not know how to compile " + arg);
318                                         errors++;
319                                         continue;
320                                 }
321                                 
322                                 errors += parse (arg);
323                         }
324
325                         if (first_source == null){
326                                 Report.Error (2008, "No files to compile were specified");
327                                 return;
328                         }
329
330                         if (Report.Errors > 0)
331                                 return;
332                         
333                         if (parse_only)
334                                 return;
335                         
336                         //
337                         // Load Core Library for default compilation
338                         //
339                         if (context.StdLib){
340                                 references.Insert (0, "mscorlib");
341                                 references.Insert (1, "System");
342                         }
343
344                         if (errors > 0){
345                                 error ("Parsing failed");
346                                 return;
347                         }
348
349                         //
350                         // Load assemblies required
351                         //
352                         errors += LoadReferences ();
353
354                         if (errors > 0){
355                                 error ("Could not load one or more assemblies");
356                                 return;
357                         }
358
359
360                         //
361                         // Dumping the parsed tree.
362                         //
363                         // This code generation interface is only here
364                         // for debugging the parser. 
365                         //
366                         if (generator != null){
367                                 if (output_file == null){
368                                         error ("Error: no output file specified");
369                                         return;
370                                 }
371
372                                 Stream output_stream = File.Create (output_file);
373                                 StreamWriter output = new StreamWriter (output_stream);
374                                 
375                                 errors += generator.Dump (context.Tree, output);
376
377                                 if (errors > 0){
378                                         error ("Compilation failed");
379                                         return;
380                                 } else
381                                         notice ("Compilation successful");
382
383                                 output.Flush ();
384                                 output.Close ();
385                         } 
386
387                         
388                         error_count = errors;
389
390                         //
391                         // Quick hack
392                         //
393                         if (output_file == null){
394                                 int pos = first_source.LastIndexOf (".");
395
396                                 output_file = first_source.Substring (0, pos) + target_ext;
397                         }
398
399                         context.CodeGen = new CodeGen (output_file, output_file);
400
401                         //
402                         // Before emitting, we need to get the core
403                         // types emitted from the user defined types
404                         // or from the system ones.
405                         //
406                         context.TypeManager.InitCoreTypes ();
407
408                         context.TypeManager.AddModule (context.CodeGen.ModuleBuilder);
409                         
410                         //
411                         // The second pass of the compiler
412                         //
413                         context.ResolveTree ();
414                         context.PopulateTypes ();
415                         
416                         if (Report.Errors > 0){
417                                 error ("Compilation failed");
418                                 return;
419                         }
420                         
421                         //
422                         // The code generator
423                         //
424                         context.EmitCode ();
425                         
426                         if (Report.Errors > 0){
427                                 error ("Compilation failed");
428                                 return;
429                         }
430                         
431                         context.CloseTypes ();
432
433                         PEFileKinds k = PEFileKinds.ConsoleApplication;
434                                 
435                         if (target == Target.Library || target == Target.Module)
436                                 k = PEFileKinds.Dll;
437                         else if (target == Target.Exe)
438                                 k = PEFileKinds.ConsoleApplication;
439                         else if (target == Target.WinExe)
440                                 k = PEFileKinds.WindowApplication;
441
442                         if (target == Target.Exe || target == Target.WinExe){
443                                 MethodInfo ep = context.EntryPoint;
444
445                                 if (ep == null){
446                                         Report.Error (5001, "Program " + output_file +
447                                                               " does not have an entry point defined");
448                                         return;
449                                 }
450                                 
451                                 context.CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
452                         }
453                         
454                         context.CodeGen.Save (output_file);
455
456                         if (Report.Errors > 0){
457                                 error ("Compilation failed");
458                                 return;
459                         } else if (Report.ProbeCode != 0){
460                                 error ("Failed to report code " + Report.ProbeCode);
461                                 Environment.Exit (124);
462                         }
463                 }
464
465         }
466 }