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