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