2008-02-27 Marek Habersack <mhabersack@novell.com>
authorMarek Habersack <grendel@twistedcode.net>
Wed, 27 Feb 2008 00:39:00 +0000 (00:39 -0000)
committerMarek Habersack <grendel@twistedcode.net>
Wed, 27 Feb 2008 00:39:00 +0000 (00:39 -0000)
* CSharpCodeCompiler.cs: use asynchronous method of capturing mcs
output in the 2.0+ profile.

svn path=/trunk/mcs/; revision=96714

mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs
mcs/class/System/Microsoft.CSharp/ChangeLog

index 006f710426868c26eb2577ae6b5aef3bd907d396..764416a5c6889a8578a2745048a67b3765fe1387 100644 (file)
@@ -41,8 +41,9 @@ namespace Mono.CSharp
        using System.Collections.Specialized;
        using System.Diagnostics;
        using System.Text.RegularExpressions;
-
+       
 #if NET_2_0
+       using System.Threading;
        using System.Collections.Generic;
 #endif
        
@@ -51,6 +52,11 @@ namespace Mono.CSharp
                static string windowsMcsPath;
                static string windowsMonoPath;
 
+#if NET_2_0
+               Mutex mcsOutMutex;
+               StringCollection mcsOutput;
+#endif
+               
                static CSharpCodeCompiler ()
                {
                        if (Path.DirectorySeparatorChar == '\\') {
@@ -180,9 +186,12 @@ namespace Mono.CSharp
                        CompilerResults results=new CompilerResults(options.TempFiles);
                        Process mcs=new Process();
 
+#if !NET_2_0
                        string mcs_output;
                        string mcs_stdout;
-                       string[] mcs_output_lines;
+                       string[] mcsOutput;
+#endif
+                       
                        // FIXME: these lines had better be platform independent.
                        if (Path.DirectorySeparatorChar == '\\') {
                                mcs.StartInfo.FileName = windowsMonoPath;
@@ -202,11 +211,20 @@ namespace Mono.CSharp
                                mcs.StartInfo.Arguments=BuildArgs(options, fileNames);
 #endif
                        }
+
+#if NET_2_0
+                       mcsOutput = new StringCollection ();
+                       mcsOutMutex = new Mutex ();
+#endif
+                       
                        mcs.StartInfo.CreateNoWindow=true;
                        mcs.StartInfo.UseShellExecute=false;
                        mcs.StartInfo.RedirectStandardOutput=true;
                        mcs.StartInfo.RedirectStandardError=true;
 #if NET_2_0
+                       mcs.OutputDataReceived += new DataReceivedEventHandler (McsStdoutDataReceived);
+                       mcs.ErrorDataReceived += new DataReceivedEventHandler (McsStderrDataReceived);
+
                        string mono_inside_mdb = null;
 #endif
                        
@@ -219,47 +237,67 @@ namespace Mono.CSharp
                                        Environment.SetEnvironmentVariable ("MONO_INSIDE_MDB", null);
                                }
 #endif
-                               
+
                                mcs.Start();
+
+#if NET_2_0
+                               mcs.BeginOutputReadLine ();
+                               mcs.BeginErrorReadLine ();
+#else
                                // If there are a few kB in stdout, we might lock
                                mcs_output=mcs.StandardError.ReadToEnd();
                                mcs_stdout=mcs.StandardOutput.ReadToEnd ();
+#endif
                                mcs.WaitForExit();
+                               
                                results.NativeCompilerReturnValue = mcs.ExitCode;
                        } finally {
-                               mcs.Close();
 #if NET_2_0
+                               mcs.CancelErrorRead ();
+                               mcs.CancelOutputRead ();
+                               
                                if (mono_inside_mdb != null)
                                        Environment.SetEnvironmentVariable ("MONO_INSIDE_MDB", mono_inside_mdb);
 #endif
+
+                               mcs.Close();
                        }
-                       mcs_output_lines=mcs_output.Split(
-                               System.Environment.NewLine.ToCharArray());
-                       bool loadIt=true;
+
+#if NET_2_0
+                       StringCollection sc = mcsOutput;
+#else
+                       mcsOutput = mcs_output.Split (System.Environment.NewLine.ToCharArray ());
                        StringCollection sc = new StringCollection ();
-                       foreach (string error_line in mcs_output_lines)
-                       {
+#endif
+                      
+                       bool loadIt=true;
+                       foreach (string error_line in mcsOutput) {
+#if !NET_2_0
+                               Console.WriteLine ("Adding error line");
                                sc.Add (error_line);
-                               
-                               CompilerError error=CreateErrorFromString(error_line);
-                               if (null!=error)
-                               {
-                                       results.Errors.Add(error);
-                                       if (!error.IsWarning) loadIt=false;
+#endif
+                               CompilerError error = CreateErrorFromString (error_line);
+                               if (error != null) {
+                                       results.Errors.Add (error);
+                                       if (!error.IsWarning)
+                                               loadIt = false;
                                }
                        }
-
-                       // (g)mcs outputs no useful information to stdout, we can ignore it here.
+                       
                        if (sc.Count > 0) {
-                               sc.Insert (0, Environment.NewLine);
-                               sc.Insert (0, mcs.StartInfo.FileName + " " + mcs.StartInfo.Arguments);
+                               sc.Insert (0, mcs.StartInfo.FileName + " " + mcs.StartInfo.Arguments + Environment.NewLine);
                                results.Output = sc;
                        }
-                       
+
                        if (loadIt) {
                                if (!File.Exists (options.OutputAssembly)) {
-                                       throw new Exception ("Compiler failed to produce the assembly. Stderr='" +mcs_output + "'");
+                                       StringBuilder sb = new StringBuilder ();
+                                       foreach (string s in sc)
+                                               sb.Append (s + Environment.NewLine);
+                                       
+                                       throw new Exception ("Compiler failed to produce the assembly. Output: '" + sb.ToString () + "'");
                                }
+                               
                                if (options.GenerateInMemory) {
                                        using (FileStream fs = File.OpenRead(options.OutputAssembly)) {
                                                byte[] buffer = new byte[fs.Length];
@@ -279,6 +317,20 @@ namespace Mono.CSharp
                }
 
 #if NET_2_0
+               void McsStdoutDataReceived (object sender, DataReceivedEventArgs args)
+               {
+                       mcsOutMutex.WaitOne ();
+                       mcsOutput.Add (args.Data);
+                       mcsOutMutex.ReleaseMutex ();
+               }
+
+               void McsStderrDataReceived (object sender, DataReceivedEventArgs args)
+               {
+                       mcsOutMutex.WaitOne ();
+                       mcsOutput.Add (args.Data);
+                       mcsOutMutex.ReleaseMutex ();
+               }               
+
                private static string BuildArgs(CompilerParameters options,string[] fileNames, Dictionary <string, string> providerOptions)
 #else
                private static string BuildArgs(CompilerParameters options,string[] fileNames)
index 109824377e95aaeb88a32082e1cd52fb98104039..f2bfbad8eeb5ec595d678885158f548816016612 100644 (file)
@@ -1,3 +1,8 @@
+2008-02-27  Marek Habersack  <mhabersack@novell.com>
+
+       * CSharpCodeCompiler.cs: use asynchronous method of capturing mcs
+       output in the 2.0+ profile.
+
 2008-02-26  Marek Habersack  <mhabersack@novell.com>
 
        * CSharpCodeCompiler.cs: CompilerResults.Output can now be set