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