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