2 // driver.cs: The compiler command line driver.
5 // Miguel de Icaza (miguel@gnu.org)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
12 // Copyright 2011 Xamarin Inc
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Collections.Generic;
21 using System.Globalization;
22 using System.Diagnostics;
27 /// The compiler driver.
31 readonly CompilerContext ctx;
33 public Driver (CompilerContext ctx)
44 void tokenize_file (SourceFile sourceFile, ModuleContainer module)
49 input = File.OpenRead (sourceFile.Name);
51 Report.Error (2001, "Source file `" + sourceFile.Name + "' could not be found");
56 SeekableStreamReader reader = new SeekableStreamReader (input, ctx.Settings.Encoding);
57 var file = new CompilationSourceFile (module, sourceFile);
59 Tokenizer lexer = new Tokenizer (reader, file);
60 int token, tokens = 0, errors = 0;
62 while ((token = lexer.token ()) != Token.EOF){
64 if (token == Token.ERROR)
67 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
73 void Parse (ModuleContainer module)
75 bool tokenize_only = module.Compiler.Settings.TokenizeOnly;
76 var sources = module.Compiler.SourceFiles;
78 Location.Initialize (sources);
80 for (int i = 0; i < sources.Count; ++i) {
82 tokenize_file (sources[i], module);
84 Parse (sources[i], module);
89 public void Parse (SourceFile file, ModuleContainer module)
94 input = File.OpenRead (file.Name);
96 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
101 if (input.ReadByte () == 77 && input.ReadByte () == 90) {
103 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
109 SeekableStreamReader reader = new SeekableStreamReader (input, ctx.Settings.Encoding);
111 Parse (reader, file, module);
116 public static void Parse (SeekableStreamReader reader, SourceFile sourceFile, ModuleContainer module)
118 var file = new CompilationSourceFile (module, sourceFile);
119 module.AddTypeContainer (file);
121 CSharpParser parser = new CSharpParser (reader, file);
125 public static int Main (string[] args)
127 Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
129 CommandLineParser cmd = new CommandLineParser (Console.Out);
130 var settings = cmd.ParseArguments (args);
131 if (settings == null)
134 if (cmd.HasBeenStopped)
137 Driver d = new Driver (new CompilerContext (settings, new ConsoleReportPrinter ()));
139 if (d.Compile () && d.Report.Errors == 0) {
140 if (d.Report.Warnings > 0) {
141 Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
143 Environment.Exit (0);
148 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
149 d.Report.Errors, d.Report.Warnings);
150 Environment.Exit (1);
154 public static string GetPackageFlags (string packages, Report report)
156 ProcessStartInfo pi = new ProcessStartInfo ();
157 pi.FileName = "pkg-config";
158 pi.RedirectStandardOutput = true;
159 pi.UseShellExecute = false;
160 pi.Arguments = "--libs " + packages;
163 p = Process.Start (pi);
164 } catch (Exception e) {
168 report.Error (-27, "Couldn't run pkg-config: " + e.Message);
172 if (p.StandardOutput == null) {
174 throw new ApplicationException ("Specified package did not return any information");
176 report.Warning (-27, 1, "Specified package did not return any information");
181 string pkgout = p.StandardOutput.ReadToEnd ();
183 if (p.ExitCode != 0) {
185 throw new ApplicationException (pkgout);
187 report.Error (-27, "Error running pkg-config. Check the above output.");
197 // Main compilation method
199 public bool Compile ()
201 var settings = ctx.Settings;
204 // If we are an exe, require a source file for the entry point or
205 // if there is nothing to put in the assembly, and we are not a library
207 if (settings.FirstSourceFile == null &&
208 ((settings.Target == Target.Exe || settings.Target == Target.WinExe || settings.Target == Target.Module) ||
209 settings.Resources == null)) {
210 Report.Error (2008, "No files to compile were specified");
214 if (settings.Platform == Platform.AnyCPU32Preferred && (settings.Target == Target.Library || settings.Target == Target.Module)) {
215 Report.Error (4023, "Platform option `anycpu32bitpreferred' is valid only for executables");
219 TimeReporter tr = new TimeReporter (settings.Timestamps);
220 ctx.TimeReporter = tr;
223 var module = new ModuleContainer (ctx);
224 RootContext.ToplevelTypes = module;
226 tr.Start (TimeReporter.TimerType.ParseTotal);
228 tr.Stop (TimeReporter.TimerType.ParseTotal);
230 if (Report.Errors > 0)
233 if (settings.TokenizeOnly || settings.ParseOnly) {
239 var output_file = settings.OutputFile;
240 string output_file_name;
241 if (output_file == null) {
242 var source_file = settings.FirstSourceFile;
244 if (source_file == null) {
245 Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
249 output_file_name = source_file.Name;
250 int pos = output_file_name.LastIndexOf ('.');
253 output_file_name = output_file_name.Substring (0, pos);
255 output_file_name += settings.TargetExt;
256 output_file = output_file_name;
258 output_file_name = Path.GetFileName (output_file);
260 if (string.IsNullOrEmpty (Path.GetFileNameWithoutExtension (output_file_name)) ||
261 output_file_name.IndexOfAny (Path.GetInvalidFileNameChars ()) >= 0) {
262 Report.Error (2021, "Output file name is not valid");
268 var importer = new StaticImporter (module);
269 var references_loader = new StaticLoader (importer, ctx);
271 tr.Start (TimeReporter.TimerType.AssemblyBuilderSetup);
272 var assembly = new AssemblyDefinitionStatic (module, references_loader, output_file_name, output_file);
273 assembly.Create (references_loader.Domain);
274 tr.Stop (TimeReporter.TimerType.AssemblyBuilderSetup);
276 // Create compiler types first even before any referenced
277 // assembly is loaded to allow forward referenced types from
278 // loaded assembly into compiled builder to be resolved
280 tr.Start (TimeReporter.TimerType.CreateTypeTotal);
281 module.CreateContainer ();
282 importer.AddCompiledAssembly (assembly);
283 tr.Stop (TimeReporter.TimerType.CreateTypeTotal);
285 references_loader.LoadReferences (module);
287 tr.Start (TimeReporter.TimerType.PredefinedTypesInit);
288 if (!ctx.BuiltinTypes.CheckDefinitions (module))
291 tr.Stop (TimeReporter.TimerType.PredefinedTypesInit);
293 references_loader.LoadModules (assembly, module.GlobalRootNamespace);
295 var assembly = new AssemblyDefinitionDynamic (module, output_file_name, output_file);
296 module.SetDeclaringAssembly (assembly);
298 var importer = new ReflectionImporter (module, ctx.BuiltinTypes);
299 assembly.Importer = importer;
301 var loader = new DynamicLoader (importer, ctx);
302 loader.LoadReferences (module);
304 if (!ctx.BuiltinTypes.CheckDefinitions (module))
307 if (!assembly.Create (AppDomain.CurrentDomain, AssemblyBuilderAccess.Save))
310 module.CreateContainer ();
312 loader.LoadModules (assembly, module.GlobalRootNamespace);
314 module.InitializePredefinedTypes ();
316 tr.Start (TimeReporter.TimerType.ModuleDefinitionTotal);
318 tr.Stop (TimeReporter.TimerType.ModuleDefinitionTotal);
320 if (Report.Errors > 0)
323 if (settings.DocumentationFile != null) {
324 var doc = new DocumentationBuilder (module);
325 doc.OutputDocComment (output_file, settings.DocumentationFile);
330 if (Report.Errors > 0)
334 tr.Start (TimeReporter.TimerType.EmitTotal);
336 tr.Stop (TimeReporter.TimerType.EmitTotal);
338 if (Report.Errors > 0){
342 tr.Start (TimeReporter.TimerType.CloseTypes);
343 module.CloseContainer ();
344 tr.Stop (TimeReporter.TimerType.CloseTypes);
346 tr.Start (TimeReporter.TimerType.Resouces);
347 assembly.EmbedResources ();
348 tr.Stop (TimeReporter.TimerType.Resouces);
350 if (Report.Errors > 0)
356 references_loader.Dispose ();
361 return Report.Errors == 0;
366 // This is the only public entry point
368 public class CompilerCallableEntryPoint : MarshalByRefObject {
369 public static bool InvokeCompiler (string [] args, TextWriter error)
372 CommandLineParser cmd = new CommandLineParser (error);
373 var setting = cmd.ParseArguments (args);
377 var d = new Driver (new CompilerContext (setting, new StreamReportPrinter (error)));
384 public static int[] AllWarningNumbers {
386 return Report.AllWarnings;
390 public static void Reset ()
395 public static void PartialReset ()
400 public static void Reset (bool full_flag)
407 Linq.QueryBlock.TransparentParameter.Reset ();