2 // Mono.CSharp CSharpCodeCompiler Class implementation
5 // Sean Kasun (seank@users.sf.net)
12 using System.CodeDom.Compiler;
15 using System.Reflection;
16 using System.Collections;
17 using System.Collections.Specialized;
18 using System.Diagnostics;
19 using System.Text.RegularExpressions;
21 internal class CSharpCodeCompiler : CSharpCodeGenerator, ICodeCompiler
26 public CSharpCodeCompiler()
34 public CompilerResults CompileAssemblyFromDom (
35 CompilerParameters options,CodeCompileUnit e)
37 return CompileAssemblyFromDomBatch(options,new CodeCompileUnit[]{e});
39 public CompilerResults CompileAssemblyFromDomBatch (
40 CompilerParameters options,CodeCompileUnit[] ea)
42 string[] fileNames=new string[ea.Length];
45 options = new CompilerParameters ();
47 StringCollection assemblies = options.ReferencedAssemblies;
49 foreach (CodeCompileUnit e in ea) {
50 fileNames [i] = GetTempFileNameWithExtension ("cs");
51 FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
52 StreamWriter s=new StreamWriter(f);
53 if (e.ReferencedAssemblies != null) {
54 foreach (string str in e.ReferencedAssemblies) {
55 if (!assemblies.Contains (str))
60 ((ICodeGenerator)this).GenerateCodeFromCompileUnit (e, s, new CodeGeneratorOptions());
65 return CompileAssemblyFromFileBatch (options, fileNames, true);
68 public CompilerResults CompileAssemblyFromFile (
69 CompilerParameters options,string fileName)
71 return CompileAssemblyFromFileBatch (options, new string []{fileName}, false);
74 public CompilerResults CompileAssemblyFromFileBatch (CompilerParameters options, string[] fileNames)
76 return CompileAssemblyFromFileBatch (options, fileNames, false);
79 CompilerResults CompileAssemblyFromFileBatch (CompilerParameters options, string [] fileNames,
83 throw new ArgumentNullException("options");
84 if (null == fileNames)
85 throw new ArgumentNullException("fileNames");
87 CompilerResults results=new CompilerResults(options.TempFiles);
88 Process mcs=new Process();
91 string[] mcs_output_lines;
92 mcs.StartInfo.FileName="mcs";
93 mcs.StartInfo.Arguments=BuildArgs(options,fileNames);
94 mcs.StartInfo.CreateNoWindow=true;
95 mcs.StartInfo.UseShellExecute=false;
96 mcs.StartInfo.RedirectStandardOutput=true;
99 mcs_output=mcs.StandardOutput.ReadToEnd();
102 results.NativeCompilerReturnValue = mcs.ExitCode;
105 mcs_output_lines=mcs_output.Split(
106 System.Environment.NewLine.ToCharArray());
108 foreach (string error_line in mcs_output_lines)
110 CompilerError error=CreateErrorFromString(error_line);
113 results.Errors.Add(error);
114 if (!error.IsWarning) loadIt=false;
118 results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);
120 results.CompiledAssembly=null;
123 foreach (string fi in fileNames) {
124 FileInfo info = new FileInfo (fi);
131 public CompilerResults CompileAssemblyFromSource (
132 CompilerParameters options,string source)
134 return CompileAssemblyFromSourceBatch(options,new string[]{source});
136 public CompilerResults CompileAssemblyFromSourceBatch (
137 CompilerParameters options,string[] sources)
139 string[] fileNames=new string[sources.Length];
141 foreach (string source in sources) {
142 fileNames [i] = GetTempFileNameWithExtension ("cs");
143 FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
144 StreamWriter s=new StreamWriter(f);
150 return CompileAssemblyFromFileBatch (options, fileNames, true);
152 private static string BuildArgs(
153 CompilerParameters options,string[] fileNames)
155 StringBuilder args=new StringBuilder();
156 if (options.GenerateExecutable)
157 args.AppendFormat("/target:exe ");
159 args.AppendFormat("/target:library ");
160 if (options.IncludeDebugInformation)
161 args.AppendFormat("/debug ");
162 if (options.TreatWarningsAsErrors)
163 args.AppendFormat("/warnaserror ");
165 if (options.WarningLevel != -1)
166 args.AppendFormat ("/warn:{0} ", options.WarningLevel);
168 if (options.OutputAssembly==null)
169 options.OutputAssembly = GetTempFileNameWithExtension ("dll");
170 args.AppendFormat("/out:\"{0}\" ",options.OutputAssembly);
171 if (null != options.ReferencedAssemblies)
173 foreach (string import in options.ReferencedAssemblies)
174 args.AppendFormat("/r:\"{0}\" ",import);
176 foreach (string source in fileNames)
177 args.AppendFormat("\"{0}\" ",source);
178 return args.ToString();
180 private static CompilerError CreateErrorFromString(string error_string)
182 // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
183 if (error_string.StartsWith ("WROTE SYMFILE") || error_string.StartsWith ("OffsetTable"))
186 CompilerError error=new CompilerError();
187 Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
188 RegexOptions.Compiled | RegexOptions.ExplicitCapture);
189 Match match=reg.Match(error_string);
190 if (!match.Success) return null;
191 if (String.Empty != match.Result("${file}"))
192 error.FileName=match.Result("${file}");
193 if (String.Empty != match.Result("${line}"))
194 error.Line=Int32.Parse(match.Result("${line}"));
195 if (String.Empty != match.Result("${column}"))
196 error.Column=Int32.Parse(match.Result("${column}"));
197 if (match.Result("${level}")=="warning")
198 error.IsWarning=true;
199 error.ErrorNumber=match.Result("${number}");
200 error.ErrorText=match.Result("${message}");
204 static string GetTempFileNameWithExtension (string extension)
210 string tmpFile = Path.GetTempFileName ();
211 FileInfo fileInfo = new FileInfo (tmpFile);
212 extFile = Path.ChangeExtension (tmpFile, extension);
214 fileInfo.MoveTo (extFile);
216 } catch (Exception e) {
219 } while (exc != null);