X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FMicrosoft.CSharp%2FCSharpCodeCompiler.cs;h=26039bdd79b3de87fccd138b2345b4f809967f16;hb=01ea58cbd474d4a9230acbba5571738896539d42;hp=f63770b96a19cbb3e7b32ab6a83eafebc2a615a1;hpb=1fabd87b02f8d2e359150ed7a9e92613e60383bc;p=mono.git diff --git a/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs b/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs index f63770b96a1..26039bdd79b 100644 --- a/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs +++ b/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs @@ -34,6 +34,7 @@ namespace Mono.CSharp using System; using System.CodeDom; using System.CodeDom.Compiler; + using System.ComponentModel; using System.IO; using System.Text; using System.Reflection; @@ -41,12 +42,17 @@ namespace Mono.CSharp using System.Collections.Specialized; using System.Diagnostics; using System.Text.RegularExpressions; - + using System.Threading; + using System.Collections.Generic; + internal class CSharpCodeCompiler : CSharpCodeGenerator, ICodeCompiler { static string windowsMcsPath; static string windowsMonoPath; + Mutex mcsOutMutex; + StringCollection mcsOutput; + static CSharpCodeCompiler () { if (Path.DirectorySeparatorChar == '\\') { @@ -71,25 +77,11 @@ namespace Mono.CSharp "mono\\mono\\mini\\mono.exe"); if (!File.Exists (windowsMonoPath)) throw new FileNotFoundException ("Windows mono path not found: " + windowsMonoPath); -#if NET_2_0 - windowsMcsPath = - Path.Combine (p, "2.0\\gmcs.exe"); -#else - windowsMcsPath = - Path.Combine (p, "1.0\\mcs.exe"); -#endif + + windowsMcsPath = Path.Combine (p, "4.5\\mcs.exe"); if (!File.Exists (windowsMcsPath)) -#if NET_2_0 - windowsMcsPath = - Path.Combine( - Path.GetDirectoryName (p), - "lib\\net_2_0\\gmcs.exe"); -#else - windowsMcsPath = - Path.Combine( - Path.GetDirectoryName (p), - "lib\\default\\mcs.exe"); -#endif + windowsMcsPath = Path.Combine(Path.GetDirectoryName (p), "lib\\build\\mcs.exe"); + if (!File.Exists (windowsMcsPath)) throw new FileNotFoundException ("Windows mcs path not found: " + windowsMcsPath); } @@ -102,6 +94,11 @@ namespace Mono.CSharp { } + public CSharpCodeCompiler (IDictionary providerOptions) : + base (providerOptions) + { + } + // // Methods // @@ -169,72 +166,145 @@ namespace Mono.CSharp CompilerResults results=new CompilerResults(options.TempFiles); Process mcs=new Process(); - string mcs_output; - string mcs_stdout; - string[] mcs_output_lines; // FIXME: these lines had better be platform independent. if (Path.DirectorySeparatorChar == '\\') { mcs.StartInfo.FileName = windowsMonoPath; - mcs.StartInfo.Arguments = "\"" + windowsMcsPath + "\" " + BuildArgs (options, fileNames); + mcs.StartInfo.Arguments = "\"" + windowsMcsPath + "\" " + + BuildArgs (options, fileNames, ProviderOptions); } else { -#if NET_2_0 - // FIXME: This is a temporary hack to make code genaration work in 2.0 - mcs.StartInfo.FileName="gmcs"; -#else mcs.StartInfo.FileName="mcs"; + mcs.StartInfo.Arguments=BuildArgs(options, fileNames, ProviderOptions); + } + + mcsOutput = new StringCollection (); + mcsOutMutex = new Mutex (); +#if !NET_4_0 + /* + * !:. KLUDGE WARNING .:! + * + * When running the 2.0 test suite some assemblies will invoke mcs via + * CodeDOM and the new mcs process will find the MONO_PATH variable in its + * environment pointing to the net_2_0 library which will cause the runtime + * to attempt to load the 2.0 corlib into 4.0 process and thus mcs will + * fail. At the same time, we must not touch MONO_PATH when running outside + * the test suite, thus the kludge. + * + * !:. KLUDGE WARNING .:! + */ + if (Environment.GetEnvironmentVariable ("MONO_TESTS_IN_PROGRESS") != null) { + string monoPath = Environment.GetEnvironmentVariable ("MONO_PATH"); + if (!String.IsNullOrEmpty (monoPath)) { + monoPath = monoPath.Replace ("/class/lib/net_2_0", "/class/lib/net_4_0"); + mcs.StartInfo.EnvironmentVariables ["MONO_PATH"] = monoPath; + } + } #endif - mcs.StartInfo.Arguments=BuildArgs(options,fileNames); +/* + string monoPath = Environment.GetEnvironmentVariable ("MONO_PATH"); + if (monoPath != null) + monoPath = String.Empty; + + string privateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath; + if (privateBinPath != null && privateBinPath.Length > 0) + monoPath = String.Format ("{0}:{1}", privateBinPath, monoPath); + + if (monoPath.Length > 0) { + StringDictionary dict = mcs.StartInfo.EnvironmentVariables; + if (dict.ContainsKey ("MONO_PATH")) + dict ["MONO_PATH"] = monoPath; + else + dict.Add ("MONO_PATH", monoPath); } +*/ + /* + * reset MONO_GC_PARAMS - we are invoking compiler possibly with another GC that + * may not handle some of the options causing compilation failure + */ + mcs.StartInfo.EnvironmentVariables ["MONO_GC_PARAMS"] = String.Empty; + mcs.StartInfo.CreateNoWindow=true; mcs.StartInfo.UseShellExecute=false; mcs.StartInfo.RedirectStandardOutput=true; mcs.StartInfo.RedirectStandardError=true; + mcs.ErrorDataReceived += new DataReceivedEventHandler (McsStderrDataReceived); + try { mcs.Start(); - // If there are a few kB in stdout, we might lock - mcs_output=mcs.StandardError.ReadToEnd(); - mcs_stdout=mcs.StandardOutput.ReadToEnd (); + } catch (Exception e) { + Win32Exception exc = e as Win32Exception; + if (exc != null) { + throw new SystemException (String.Format ("Error running {0}: {1}", mcs.StartInfo.FileName, + Win32Exception.W32ErrorMessage (exc.NativeErrorCode))); + } + throw; + } + + try { + mcs.BeginOutputReadLine (); + mcs.BeginErrorReadLine (); mcs.WaitForExit(); + results.NativeCompilerReturnValue = mcs.ExitCode; } finally { + mcs.CancelErrorRead (); + mcs.CancelOutputRead (); mcs.Close(); } - mcs_output_lines=mcs_output.Split( - System.Environment.NewLine.ToCharArray()); - bool loadIt=true; - foreach (string error_line in mcs_output_lines) - { - CompilerError error=CreateErrorFromString(error_line); - if (null!=error) - { - results.Errors.Add(error); - if (!error.IsWarning) loadIt=false; + + StringCollection sc = mcsOutput; + + bool loadIt=true; + foreach (string error_line in mcsOutput) { + CompilerError error = CreateErrorFromString (error_line); + if (error != null) { + results.Errors.Add (error); + if (!error.IsWarning) + loadIt = false; } } + + if (sc.Count > 0) { + 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+"', Stdout='"+mcs_stdout+"'"); + 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]; fs.Read(buffer, 0, buffer.Length); - results.CompiledAssembly = Assembly.Load(buffer, null, options.Evidence); + results.CompiledAssembly = Assembly.Load(buffer, null); fs.Close(); } } else { - results.CompiledAssembly = Assembly.LoadFrom(options.OutputAssembly); + // Avoid setting CompiledAssembly right now since the output might be a netmodule results.PathToAssembly = options.OutputAssembly; } } else { results.CompiledAssembly = null; } - + return results; } - private static string BuildArgs(CompilerParameters options,string[] fileNames) + void McsStderrDataReceived (object sender, DataReceivedEventArgs args) + { + if (args.Data != null) { + mcsOutMutex.WaitOne (); + mcsOutput.Add (args.Data); + mcsOutMutex.ReleaseMutex (); + } + } + + private static string BuildArgs(CompilerParameters options,string[] fileNames, IDictionary providerOptions) { StringBuilder args=new StringBuilder(); if (options.GenerateExecutable) @@ -242,6 +312,10 @@ namespace Mono.CSharp else args.Append("/target:library "); + string privateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath; + if (privateBinPath != null && privateBinPath.Length > 0) + args.AppendFormat ("/lib:\"{0}\" ", privateBinPath); + if (options.Win32Resource != null) args.AppendFormat("/win32res:\"{0}\" ", options.Win32Resource); @@ -257,8 +331,11 @@ namespace Mono.CSharp if (options.WarningLevel >= 0) args.AppendFormat ("/warn:{0} ", options.WarningLevel); - if (options.OutputAssembly==null) - options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, "dll", !options.GenerateInMemory); + if (options.OutputAssembly == null || options.OutputAssembly.Length == 0) { + string extension = (options.GenerateExecutable ? "exe" : "dll"); + options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, extension, + !options.GenerateInMemory); + } args.AppendFormat("/out:\"{0}\" ",options.OutputAssembly); foreach (string import in options.ReferencedAssemblies) { @@ -273,7 +350,6 @@ namespace Mono.CSharp args.Append (" "); } -#if NET_2_0 foreach (string embeddedResource in options.EmbeddedResources) { args.AppendFormat("/resource:\"{0}\" ", embeddedResource); } @@ -281,6 +357,37 @@ namespace Mono.CSharp foreach (string linkedResource in options.LinkedResources) { args.AppendFormat("/linkresource:\"{0}\" ", linkedResource); } + + if (providerOptions != null && providerOptions.Count > 0) { + string langver; + + if (!providerOptions.TryGetValue ("CompilerVersion", out langver)) +#if NET_4_0 + langver = "3.5"; +#else + langver = "2.0"; +#endif + + if (langver.Length >= 1 && langver [0] == 'v') + langver = langver.Substring (1); + + switch (langver) { + case "2.0": + args.Append ("/langversion:ISO-2 "); + break; + + case "3.5": + // current default, omit the switch + break; + } + } + +#if NET_4_5 + args.Append("/sdk:4.5"); +#elif NET_4_0 + args.Append("/sdk:4"); +#else + args.Append("/sdk:2"); #endif args.Append (" -- "); @@ -290,10 +397,9 @@ namespace Mono.CSharp } private static CompilerError CreateErrorFromString(string error_string) { -#if NET_2_0 if (error_string.StartsWith ("BETA")) return null; -#endif + if (error_string == null || error_string == "") return null; @@ -301,7 +407,13 @@ namespace Mono.CSharp Regex reg = new Regex (@"^(\s*(?.*)\((?\d*)(,(?\d*))?\)(:)?\s+)*(?\w+)\s*(?.*):\s(?.*)", RegexOptions.Compiled | RegexOptions.ExplicitCapture); Match match=reg.Match(error_string); - if (!match.Success) return null; + if (!match.Success) { + // We had some sort of runtime crash + error.ErrorText = error_string; + error.IsWarning = false; + error.ErrorNumber = ""; + return error; + } if (String.Empty != match.Result("${file}")) error.FileName=match.Result("${file}"); if (String.Empty != match.Result("${line}"))