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
;
23 using System
.Threading
;
28 /// The compiler driver.
32 readonly CompilerContext ctx
;
34 public Driver (CompilerContext ctx
)
45 void tokenize_file (SourceFile sourceFile
, ModuleContainer module
, ParserSession session
)
50 input
= File
.OpenRead (sourceFile
.Name
);
52 Report
.Error (2001, "Source file `" + sourceFile
.Name
+ "' could not be found");
57 SeekableStreamReader reader
= new SeekableStreamReader (input
, ctx
.Settings
.Encoding
);
58 var file
= new CompilationSourceFile (module
, sourceFile
);
60 Tokenizer lexer
= new Tokenizer (reader
, file
, session
, ctx
.Report
);
61 int token
, tokens
= 0, errors
= 0;
63 while ((token
= lexer
.token ()) != Token
.EOF
){
65 if (token
== Token
.ERROR
)
68 Console
.WriteLine ("Tokenized: " + tokens
+ " found " + errors
+ " errors");
74 void Parse (ModuleContainer module
)
76 bool tokenize_only
= module
.Compiler
.Settings
.TokenizeOnly
;
77 var sources
= module
.Compiler
.SourceFiles
;
79 Location
.Initialize (sources
);
81 var session
= new ParserSession
{
82 UseJayGlobalArrays
= true,
83 LocatedTokens
= new LocatedToken
[15000]
86 for (int i
= 0; i
< sources
.Count
; ++i
) {
88 tokenize_file (sources
[i
], module
, session
);
90 Parse (sources
[i
], module
, session
, Report
);
96 void ParseParallel (ModuleContainer module
)
98 var sources
= module
.Compiler
.SourceFiles
;
100 Location
.Initialize (sources
);
102 var pcount
= Environment
.ProcessorCount
;
103 var threads
= new Thread
[System
.Math
.Max (2, pcount
- 1)];
105 for (int i
= 0; i
< threads
.Length
; ++i
) {
106 var t
= new Thread (l
=> {
107 var session
= new ParserSession () {
108 //UseJayGlobalArrays = true,
111 var report
= new Report (ctx
, Report
.Printer
); // TODO: Implement flush at once printer
113 for (int ii
= (int) l
; ii
< sources
.Count
; ii
+= threads
.Length
) {
114 Parse (sources
[ii
], module
, session
, report
);
117 // TODO: Merge warning regions
124 for (int t
= 0; t
< threads
.Length
; ++t
) {
130 public void Parse (SourceFile file
, ModuleContainer module
, ParserSession session
, Report report
)
135 input
= File
.OpenRead (file
.Name
);
137 report
.Error (2001, "Source file `{0}' could not be found", file
.Name
);
142 if (input
.ReadByte () == 77 && input
.ReadByte () == 90) {
144 report
.Error (2015, "Source file `{0}' is a binary file and not a text file", file
.Name
);
150 SeekableStreamReader reader
= new SeekableStreamReader (input
, ctx
.Settings
.Encoding
, session
.StreamReaderBuffer
);
152 Parse (reader
, file
, module
, session
, report
);
154 if (ctx
.Settings
.GenerateDebugInfo
&& report
.Errors
== 0 && !file
.HasChecksum
) {
156 var checksum
= session
.GetChecksumAlgorithm ();
157 file
.SetChecksum (checksum
.ComputeHash (input
));
164 public static void Parse (SeekableStreamReader reader
, SourceFile sourceFile
, ModuleContainer module
, ParserSession session
, Report report
)
166 var file
= new CompilationSourceFile (module
, sourceFile
);
167 module
.AddTypeContainer (file
);
169 CSharpParser parser
= new CSharpParser (reader
, file
, report
, session
);
173 public static int Main (string[] args
)
175 Location
.InEmacs
= Environment
.GetEnvironmentVariable ("EMACS") == "t";
177 CommandLineParser cmd
= new CommandLineParser (Console
.Out
);
178 var settings
= cmd
.ParseArguments (args
);
179 if (settings
== null)
182 if (cmd
.HasBeenStopped
)
185 Driver d
= new Driver (new CompilerContext (settings
, new ConsoleReportPrinter ()));
187 if (d
.Compile () && d
.Report
.Errors
== 0) {
188 if (d
.Report
.Warnings
> 0) {
189 Console
.WriteLine ("Compilation succeeded - {0} warning(s)", d
.Report
.Warnings
);
191 Environment
.Exit (0);
196 Console
.WriteLine("Compilation failed: {0} error(s), {1} warnings",
197 d
.Report
.Errors
, d
.Report
.Warnings
);
198 Environment
.Exit (1);
202 public static string GetPackageFlags (string packages
, Report report
)
204 #if MONO_FEATURE_PROCESS_START
205 ProcessStartInfo pi
= new ProcessStartInfo ();
206 pi
.FileName
= "pkg-config";
207 pi
.RedirectStandardOutput
= true;
208 pi
.UseShellExecute
= false;
209 pi
.Arguments
= "--libs " + packages
;
212 p
= Process
.Start (pi
);
213 } catch (Exception e
) {
217 report
.Error (-27, "Couldn't run pkg-config: " + e
.Message
);
221 if (p
.StandardOutput
== null) {
223 throw new ApplicationException ("Specified package did not return any information");
225 report
.Warning (-27, 1, "Specified package did not return any information");
230 string pkgout
= p
.StandardOutput
.ReadToEnd ();
232 if (p
.ExitCode
!= 0) {
234 throw new ApplicationException (pkgout
);
236 report
.Error (-27, "Error running pkg-config. Check the above output.");
244 throw new NotSupportedException ("Process.Start is not supported on this platform.");
245 #endif // MONO_FEATURE_PROCESS_START
249 // Main compilation method
251 public bool Compile ()
253 var settings
= ctx
.Settings
;
256 // If we are an exe, require a source file for the entry point or
257 // if there is nothing to put in the assembly, and we are not a library
259 if (settings
.FirstSourceFile
== null &&
260 ((settings
.Target
== Target
.Exe
|| settings
.Target
== Target
.WinExe
|| settings
.Target
== Target
.Module
) ||
261 settings
.Resources
== null)) {
262 Report
.Error (2008, "No files to compile were specified");
266 if (settings
.Platform
== Platform
.AnyCPU32Preferred
&& (settings
.Target
== Target
.Library
|| settings
.Target
== Target
.Module
)) {
267 Report
.Error (4023, "Platform option `anycpu32bitpreferred' is valid only for executables");
271 TimeReporter tr
= new TimeReporter (settings
.Timestamps
);
272 ctx
.TimeReporter
= tr
;
275 var module
= new ModuleContainer (ctx
);
276 RootContext
.ToplevelTypes
= module
;
278 tr
.Start (TimeReporter
.TimerType
.ParseTotal
);
280 tr
.Stop (TimeReporter
.TimerType
.ParseTotal
);
282 if (Report
.Errors
> 0)
285 if (settings
.TokenizeOnly
|| settings
.ParseOnly
) {
291 var output_file
= settings
.OutputFile
;
292 string output_file_name
;
293 if (output_file
== null) {
294 var source_file
= settings
.FirstSourceFile
;
296 if (source_file
== null) {
297 Report
.Error (1562, "If no source files are specified you must specify the output file with -out:");
301 output_file_name
= source_file
.Name
;
302 int pos
= output_file_name
.LastIndexOf ('.');
305 output_file_name
= output_file_name
.Substring (0, pos
);
307 output_file_name
+= settings
.TargetExt
;
308 output_file
= output_file_name
;
310 output_file_name
= Path
.GetFileName (output_file
);
312 if (string.IsNullOrEmpty (Path
.GetFileNameWithoutExtension (output_file_name
)) ||
313 output_file_name
.IndexOfAny (Path
.GetInvalidFileNameChars ()) >= 0) {
314 Report
.Error (2021, "Output file name is not valid");
320 var importer
= new StaticImporter (module
);
321 var references_loader
= new StaticLoader (importer
, ctx
);
323 tr
.Start (TimeReporter
.TimerType
.AssemblyBuilderSetup
);
324 var assembly
= new AssemblyDefinitionStatic (module
, references_loader
, output_file_name
, output_file
);
325 assembly
.Create (references_loader
.Domain
);
326 tr
.Stop (TimeReporter
.TimerType
.AssemblyBuilderSetup
);
328 // Create compiler types first even before any referenced
329 // assembly is loaded to allow forward referenced types from
330 // loaded assembly into compiled builder to be resolved
332 tr
.Start (TimeReporter
.TimerType
.CreateTypeTotal
);
333 module
.CreateContainer ();
334 importer
.AddCompiledAssembly (assembly
);
335 references_loader
.CompiledAssembly
= assembly
;
336 tr
.Stop (TimeReporter
.TimerType
.CreateTypeTotal
);
338 references_loader
.LoadReferences (module
);
340 tr
.Start (TimeReporter
.TimerType
.PredefinedTypesInit
);
341 if (!ctx
.BuiltinTypes
.CheckDefinitions (module
))
344 tr
.Stop (TimeReporter
.TimerType
.PredefinedTypesInit
);
346 references_loader
.LoadModules (assembly
, module
.GlobalRootNamespace
);
348 var assembly
= new AssemblyDefinitionDynamic (module
, output_file_name
, output_file
);
349 module
.SetDeclaringAssembly (assembly
);
351 var importer
= new ReflectionImporter (module
, ctx
.BuiltinTypes
);
352 assembly
.Importer
= importer
;
354 var loader
= new DynamicLoader (importer
, ctx
);
355 loader
.LoadReferences (module
);
357 if (!ctx
.BuiltinTypes
.CheckDefinitions (module
))
360 if (!assembly
.Create (AppDomain
.CurrentDomain
, AssemblyBuilderAccess
.Save
))
363 module
.CreateContainer ();
365 loader
.LoadModules (assembly
, module
.GlobalRootNamespace
);
367 module
.InitializePredefinedTypes ();
369 if (settings
.GetResourceStrings
!= null)
370 module
.LoadGetResourceStrings (settings
.GetResourceStrings
);
372 tr
.Start (TimeReporter
.TimerType
.ModuleDefinitionTotal
);
374 tr
.Stop (TimeReporter
.TimerType
.ModuleDefinitionTotal
);
376 if (Report
.Errors
> 0)
379 if (settings
.DocumentationFile
!= null) {
380 var doc
= new DocumentationBuilder (module
);
381 doc
.OutputDocComment (output_file
, settings
.DocumentationFile
);
386 if (Report
.Errors
> 0)
390 tr
.Start (TimeReporter
.TimerType
.EmitTotal
);
392 tr
.Stop (TimeReporter
.TimerType
.EmitTotal
);
394 if (Report
.Errors
> 0){
398 tr
.Start (TimeReporter
.TimerType
.CloseTypes
);
399 module
.CloseContainer ();
400 tr
.Stop (TimeReporter
.TimerType
.CloseTypes
);
402 tr
.Start (TimeReporter
.TimerType
.Resouces
);
403 if (!settings
.WriteMetadataOnly
)
404 assembly
.EmbedResources ();
405 tr
.Stop (TimeReporter
.TimerType
.Resouces
);
407 if (Report
.Errors
> 0)
413 references_loader
.Dispose ();
418 return Report
.Errors
== 0;
423 // This is the only public entry point
425 public class CompilerCallableEntryPoint
: MarshalByRefObject
{
426 public static bool InvokeCompiler (string [] args
, TextWriter error
)
429 CommandLineParser cmd
= new CommandLineParser (error
);
430 var setting
= cmd
.ParseArguments (args
);
434 var d
= new Driver (new CompilerContext (setting
, new StreamReportPrinter (error
)));
441 public static int[] AllWarningNumbers
{
443 return Report
.AllWarnings
;
447 public static void Reset ()
452 public static void PartialReset ()
457 public static void Reset (bool full_flag
)
464 Linq
.QueryBlock
.TransparentParameter
.Reset ();