New test.
[mono.git] / mcs / class / System / Microsoft.CSharp / CSharpCodeCompiler.cs
index edc8da68872c2f07ed256887de71772f4d8162e6..f63770b96a19cbb3e7b32ab6a83eafebc2a615a1 100644 (file)
@@ -50,8 +50,6 @@ namespace Mono.CSharp
                static CSharpCodeCompiler ()
                {
                        if (Path.DirectorySeparatorChar == '\\') {
-                               // FIXME: right now we use "fixed" version 1.0
-                               // mcs at any time.
                                PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static|BindingFlags.NonPublic);
                                MethodInfo get_gac = gac.GetGetMethod (true);
                                string p = Path.GetDirectoryName (
@@ -65,8 +63,35 @@ namespace Mono.CSharp
                                                Path.GetDirectoryName (
                                                        Path.GetDirectoryName (p)),
                                                "bin\\mono.exe");
+                               if (!File.Exists (windowsMonoPath))
+                                       windowsMonoPath = Path.Combine (
+                                               Path.GetDirectoryName (
+                                                       Path.GetDirectoryName (
+                                                               Path.GetDirectoryName (p))),
+                                               "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
+                               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
+                               if (!File.Exists (windowsMcsPath))
+                                       throw new FileNotFoundException ("Windows mcs path not found: " + windowsMcsPath);
                        }
                }
 
@@ -80,48 +105,61 @@ namespace Mono.CSharp
                //
                // Methods
                //
-               [MonoTODO]
-               public CompilerResults CompileAssemblyFromDom (
-                       CompilerParameters options,CodeCompileUnit e)
+               public CompilerResults CompileAssemblyFromDom (CompilerParameters options, CodeCompileUnit e)
                {
-                       return CompileAssemblyFromDomBatch(options,new CodeCompileUnit[]{e});
+                       return CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { e });
                }
-               public CompilerResults CompileAssemblyFromDomBatch (
-                       CompilerParameters options,CodeCompileUnit[] ea)
-               {
-                       string[] fileNames=new string[ea.Length];
-                       int i=0;
-                       if (options == null)
-                               options = new CompilerParameters ();
-                       
-                       StringCollection assemblies = options.ReferencedAssemblies;
 
-                       foreach (CodeCompileUnit e in ea) {
-                               fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, i.ToString () + ".cs");
-                               FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
-                               StreamWriter s=new StreamWriter(f, Encoding.UTF8);
-                               if (e.ReferencedAssemblies != null) {
-                                       foreach (string str in e.ReferencedAssemblies) {
-                                               if (!assemblies.Contains (str))
-                                                       assemblies.Add (str);
-                                       }
-                               }
+               public CompilerResults CompileAssemblyFromDomBatch (CompilerParameters options, CodeCompileUnit[] ea)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
 
-                               ((ICodeGenerator)this).GenerateCodeFromCompileUnit (e, s, new CodeGeneratorOptions());
-                               s.Close();
-                               f.Close();
-                               i++;
+                       try {
+                               return CompileFromDomBatch (options, ea);
+                       } finally {
+                               options.TempFiles.Delete ();
                        }
-                       return CompileAssemblyFromFileBatch (options, fileNames);
                }
-               
-               public CompilerResults CompileAssemblyFromFile (
-                       CompilerParameters options,string fileName)
+
+               public CompilerResults CompileAssemblyFromFile (CompilerParameters options, string fileName)
                {
-                       return CompileAssemblyFromFileBatch (options, new string []{fileName});
+                       return CompileAssemblyFromFileBatch (options, new string[] { fileName });
                }
 
                public CompilerResults CompileAssemblyFromFileBatch (CompilerParameters options, string[] fileNames)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       try {
+                               return CompileFromFileBatch (options, fileNames);
+                       } finally {
+                               options.TempFiles.Delete ();
+                       }
+               }
+
+               public CompilerResults CompileAssemblyFromSource (CompilerParameters options, string source)
+               {
+                       return CompileAssemblyFromSourceBatch (options, new string[] { source });
+               }
+
+               public CompilerResults CompileAssemblyFromSourceBatch (CompilerParameters options, string[] sources)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       try {
+                               return CompileFromSourceBatch (options, sources);
+                       } finally {
+                               options.TempFiles.Delete ();
+                       }
+               }
+
+               private CompilerResults CompileFromFileBatch (CompilerParameters options, string[] fileNames)
                {
                        if (null == options)
                                throw new ArgumentNullException("options");
@@ -132,25 +170,33 @@ namespace Mono.CSharp
                        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);
-                       }
-                       else {
+                               mcs.StartInfo.Arguments = "\"" + windowsMcsPath + "\" " + BuildArgs (options, fileNames);
+                       } 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";
+#endif
                                mcs.StartInfo.Arguments=BuildArgs(options,fileNames);
                        }
                        mcs.StartInfo.CreateNoWindow=true;
                        mcs.StartInfo.UseShellExecute=false;
                        mcs.StartInfo.RedirectStandardOutput=true;
+                       mcs.StartInfo.RedirectStandardError=true;
                        try {
                                mcs.Start();
-                               mcs_output=mcs.StandardOutput.ReadToEnd();
+                               // If there are a few kB in stdout, we might lock
+                               mcs_output=mcs.StandardError.ReadToEnd();
+                               mcs_stdout=mcs.StandardOutput.ReadToEnd ();
                                mcs.WaitForExit();
-                       } finally {
                                results.NativeCompilerReturnValue = mcs.ExitCode;
+                       } finally {
                                mcs.Close();
                        }
                        mcs_output_lines=mcs_output.Split(
@@ -165,59 +211,78 @@ namespace Mono.CSharp
                                        if (!error.IsWarning) loadIt=false;
                                }
                        }
-                       if (loadIt)
-                               results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);
-                       else
-                               results.CompiledAssembly=null;
+                       if (loadIt) {
+                               if (!File.Exists (options.OutputAssembly)) {
+                                       throw new Exception ("Compiler failed to produce the assembly. Stderr='"
+                                               +mcs_output+"', Stdout='"+mcs_stdout+"'");
+                               }
+                               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);
+                                               fs.Close();
+                                       }
+                               } else {
+                                       results.CompiledAssembly = Assembly.LoadFrom(options.OutputAssembly);
+                                       results.PathToAssembly = options.OutputAssembly;
+                               }
+                       } else {
+                               results.CompiledAssembly = null;
+                       }
 
                        return results;
                }
-               public CompilerResults CompileAssemblyFromSource (
-                       CompilerParameters options,string source)
-               {
-                       return CompileAssemblyFromSourceBatch(options,new string[]{source});
-               }
-               public CompilerResults CompileAssemblyFromSourceBatch (
-                       CompilerParameters options,string[] sources)
-               {
-                       string[] fileNames=new string[sources.Length];
-                       int i=0;
-                       foreach (string source in sources) {
-                               fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, i.ToString () + ".cs");
-                               FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
-                               StreamWriter s=new StreamWriter(f);
-                               s.Write(source);
-                               s.Close();
-                               f.Close();
-                               i++;
-                       }
-                       return CompileAssemblyFromFileBatch (options, fileNames);
-               }
-               private static string BuildArgs(
-                       CompilerParameters options,string[] fileNames)
+
+               private static string BuildArgs(CompilerParameters options,string[] fileNames)
                {
                        StringBuilder args=new StringBuilder();
                        if (options.GenerateExecutable)
-                               args.AppendFormat("/target:exe ");
+                               args.Append("/target:exe ");
                        else
-                               args.AppendFormat("/target:library ");
+                               args.Append("/target:library ");
+
+                       if (options.Win32Resource != null)
+                               args.AppendFormat("/win32res:\"{0}\" ",
+                                       options.Win32Resource);
+
                        if (options.IncludeDebugInformation)
-                               args.AppendFormat("/debug ");
+                               args.Append("/debug+ /optimize- ");
+                       else
+                               args.Append("/debug- /optimize+ ");
+
                        if (options.TreatWarningsAsErrors)
-                               args.AppendFormat("/warnaserror ");
+                               args.Append("/warnaserror ");
 
-                       if (options.WarningLevel != -1)
+                       if (options.WarningLevel >= 0)
                                args.AppendFormat ("/warn:{0} ", options.WarningLevel);
 
                        if (options.OutputAssembly==null)
-                               options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, "dll");
+                               options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, "dll", !options.GenerateInMemory);
                        args.AppendFormat("/out:\"{0}\" ",options.OutputAssembly);
-                       if (null != options.ReferencedAssemblies)
-                       {
-                               foreach (string import in options.ReferencedAssemblies)
-                                       args.AppendFormat("/r:\"{0}\" ",import);
+
+                       foreach (string import in options.ReferencedAssemblies) {
+                               if (import == null || import.Length == 0)
+                                       continue;
+
+                               args.AppendFormat("/r:\"{0}\" ",import);
+                       }
+
+                       if (options.CompilerOptions != null) {
+                               args.Append (options.CompilerOptions);
+                               args.Append (" ");
+                       }
+
+#if NET_2_0
+                       foreach (string embeddedResource in options.EmbeddedResources) {
+                               args.AppendFormat("/resource:\"{0}\" ", embeddedResource);
+                       }
+
+                       foreach (string linkedResource in options.LinkedResources) {
+                               args.AppendFormat("/linkresource:\"{0}\" ", linkedResource);
                        }
-                       
+#endif
+
                        args.Append (" -- ");
                        foreach (string source in fileNames)
                                args.AppendFormat("\"{0}\" ",source);
@@ -225,12 +290,15 @@ namespace Mono.CSharp
                }
                private static CompilerError CreateErrorFromString(string error_string)
                {
-                       // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
-                       if (error_string.StartsWith ("WROTE SYMFILE") || error_string.StartsWith ("OffsetTable"))
+#if NET_2_0
+                       if (error_string.StartsWith ("BETA"))
+                               return null;
+#endif
+                       if (error_string == null || error_string == "")
                                return null;
 
                        CompilerError error=new CompilerError();
-                       Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
+                       Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)(:)?\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
                                RegexOptions.Compiled | RegexOptions.ExplicitCapture);
                        Match match=reg.Match(error_string);
                        if (!match.Success) return null;
@@ -240,16 +308,82 @@ namespace Mono.CSharp
                                error.Line=Int32.Parse(match.Result("${line}"));
                        if (String.Empty != match.Result("${column}"))
                                error.Column=Int32.Parse(match.Result("${column}"));
-                       if (match.Result("${level}")=="warning")
-                               error.IsWarning=true;
+
+                       string level = match.Result ("${level}");
+                       if (level == "warning")
+                               error.IsWarning = true;
+                       else if (level != "error")
+                               return null; // error CS8028 will confuse the regex.
+
                        error.ErrorNumber=match.Result("${number}");
                        error.ErrorText=match.Result("${message}");
                        return error;
                }
 
-               static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension)
+               private static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension, bool keepFile)
+               {
+                       return temp_files.AddExtension (extension, keepFile);
+               }
+
+               private static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension)
                {
                        return temp_files.AddExtension (extension);
                }
+
+               private CompilerResults CompileFromDomBatch (CompilerParameters options, CodeCompileUnit[] ea)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       if (ea == null) {
+                               throw new ArgumentNullException ("ea");
+                       }
+
+                       string[] fileNames = new string[ea.Length];
+                       StringCollection assemblies = options.ReferencedAssemblies;
+
+                       for (int i = 0; i < ea.Length; i++) {
+                               CodeCompileUnit compileUnit = ea[i];
+                               fileNames[i] = GetTempFileNameWithExtension (options.TempFiles, i + ".cs");
+                               FileStream f = new FileStream (fileNames[i], FileMode.OpenOrCreate);
+                               StreamWriter s = new StreamWriter (f, Encoding.UTF8);
+                               if (compileUnit.ReferencedAssemblies != null) {
+                                       foreach (string str in compileUnit.ReferencedAssemblies) {
+                                               if (!assemblies.Contains (str))
+                                                       assemblies.Add (str);
+                                       }
+                               }
+
+                               ((ICodeGenerator) this).GenerateCodeFromCompileUnit (compileUnit, s, new CodeGeneratorOptions ());
+                               s.Close ();
+                               f.Close ();
+                       }
+                       return CompileAssemblyFromFileBatch (options, fileNames);
+               }
+
+               private CompilerResults CompileFromSourceBatch (CompilerParameters options, string[] sources)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       if (sources == null) {
+                               throw new ArgumentNullException ("sources");
+                       }
+
+                       string[] fileNames = new string[sources.Length];
+
+                       for (int i = 0; i < sources.Length; i++) {
+                               fileNames[i] = GetTempFileNameWithExtension (options.TempFiles, i + ".cs");
+                               FileStream f = new FileStream (fileNames[i], FileMode.OpenOrCreate);
+                               using (StreamWriter s = new StreamWriter (f, Encoding.UTF8)) {
+                                       s.Write (sources[i]);
+                                       s.Close ();
+                               }
+                               f.Close ();
+                       }
+                       return CompileFromFileBatch (options, fileNames);
+               }
        }
 }