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