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