CSharpCodeCompiler.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. //
  2. // Mono.CSharp CSharpCodeCompiler Class implementation
  3. //
  4. // Author:
  5. // Sean Kasun ([email protected])
  6. //
  7. namespace Mono.CSharp
  8. {
  9. using System;
  10. using System.CodeDom;
  11. using System.CodeDom.Compiler;
  12. using System.IO;
  13. using System.Text;
  14. using System.Reflection;
  15. using System.Collections;
  16. using System.Collections.Specialized;
  17. using System.Diagnostics;
  18. using System.Text.RegularExpressions;
  19. internal class CSharpCodeCompiler : CSharpCodeGenerator, ICodeCompiler
  20. {
  21. //
  22. // Constructors
  23. //
  24. public CSharpCodeCompiler()
  25. {
  26. }
  27. //
  28. // Methods
  29. //
  30. [MonoTODO]
  31. public CompilerResults CompileAssemblyFromDom (
  32. CompilerParameters options,CodeCompileUnit e)
  33. {
  34. return CompileAssemblyFromDomBatch(options,new CodeCompileUnit[]{e});
  35. }
  36. public CompilerResults CompileAssemblyFromDomBatch (
  37. CompilerParameters options,CodeCompileUnit[] ea)
  38. {
  39. string[] fileNames=new string[ea.Length];
  40. int i=0;
  41. if (options == null)
  42. options = new CompilerParameters ();
  43. StringCollection assemblies = options.ReferencedAssemblies;
  44. foreach (CodeCompileUnit e in ea)
  45. {
  46. fileNames[i]=Path.ChangeExtension(Path.GetTempFileName(),"cs");
  47. FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
  48. StreamWriter s=new StreamWriter(f);
  49. if (e.ReferencedAssemblies != null) {
  50. foreach (string str in e.ReferencedAssemblies) {
  51. if (!assemblies.Contains (str))
  52. assemblies.Add (str);
  53. }
  54. }
  55. GenerateCodeFromCompileUnit(e,s,new CodeGeneratorOptions());
  56. s.Close();
  57. f.Close();
  58. i++;
  59. }
  60. return CompileAssemblyFromFileBatch(options,fileNames);
  61. }
  62. public CompilerResults CompileAssemblyFromFile (
  63. CompilerParameters options,string fileName)
  64. {
  65. return CompileAssemblyFromFileBatch(options,new string[]{fileName});
  66. }
  67. public CompilerResults CompileAssemblyFromFileBatch (
  68. CompilerParameters options,string[] fileNames)
  69. {
  70. if (null == options)
  71. throw new ArgumentNullException("options");
  72. if (null == fileNames)
  73. throw new ArgumentNullException("fileNames");
  74. CompilerResults results=new CompilerResults(options.TempFiles);
  75. Process mcs=new Process();
  76. string mcs_output;
  77. string[] mcs_output_lines;
  78. mcs.StartInfo.FileName="mcs";
  79. mcs.StartInfo.Arguments=BuildArgs(options,fileNames);
  80. mcs.StartInfo.CreateNoWindow=true;
  81. mcs.StartInfo.UseShellExecute=false;
  82. mcs.StartInfo.RedirectStandardOutput=true;
  83. try {
  84. mcs.Start();
  85. mcs_output=mcs.StandardOutput.ReadToEnd();
  86. mcs.WaitForExit();
  87. } finally {
  88. results.NativeCompilerReturnValue = mcs.ExitCode;
  89. mcs.Close();
  90. }
  91. mcs_output_lines=mcs_output.Split(
  92. System.Environment.NewLine.ToCharArray());
  93. bool loadIt=true;
  94. foreach (string error_line in mcs_output_lines)
  95. {
  96. CompilerError error=CreateErrorFromString(error_line);
  97. if (null!=error)
  98. {
  99. results.Errors.Add(error);
  100. if (!error.IsWarning) loadIt=false;
  101. }
  102. }
  103. if (loadIt)
  104. results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);
  105. else
  106. results.CompiledAssembly=null;
  107. return results;
  108. }
  109. public CompilerResults CompileAssemblyFromSource (
  110. CompilerParameters options,string source)
  111. {
  112. return CompileAssemblyFromSourceBatch(options,new string[]{source});
  113. }
  114. public CompilerResults CompileAssemblyFromSourceBatch (
  115. CompilerParameters options,string[] sources)
  116. {
  117. string[] fileNames=new string[sources.Length];
  118. int i=0;
  119. foreach (string source in sources)
  120. {
  121. fileNames[i]=Path.ChangeExtension(Path.GetTempFileName(),"cs");
  122. FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
  123. StreamWriter s=new StreamWriter(f);
  124. s.Write(source);
  125. s.Close();
  126. f.Close();
  127. i++;
  128. }
  129. return CompileAssemblyFromFileBatch(options,fileNames);
  130. }
  131. private static string BuildArgs(
  132. CompilerParameters options,string[] fileNames)
  133. {
  134. StringBuilder args=new StringBuilder();
  135. if (options.GenerateExecutables)
  136. args.AppendFormat("/target:exe ");
  137. else
  138. args.AppendFormat("/target:library ");
  139. if (options.IncludeDebugInformation)
  140. args.AppendFormat("/debug ");
  141. if (options.TreatWarningsAsErrors)
  142. args.AppendFormat("/warnaserror ");
  143. args.AppendFormat("/warn:{0} ",options.WarningLevel);
  144. if (options.OutputAssembly==null)
  145. options.OutputAssembly=Path.ChangeExtension(Path.GetTempFileName(),"dll");
  146. args.AppendFormat("/out:'{0}' ",options.OutputAssembly);
  147. if (null != options.ReferencedAssemblies)
  148. {
  149. foreach (string import in options.ReferencedAssemblies)
  150. args.AppendFormat("/r:'{0}' ",import);
  151. }
  152. foreach (string source in fileNames)
  153. args.AppendFormat("'{0}' ",source);
  154. return args.ToString();
  155. }
  156. private static CompilerError CreateErrorFromString(string error_string)
  157. {
  158. CompilerError error=new CompilerError();
  159. Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
  160. RegexOptions.Compiled | RegexOptions.ExplicitCapture);
  161. Match match=reg.Match(error_string);
  162. if (!match.Success) return null;
  163. if (String.Empty != match.Result("${file}"))
  164. error.FileName=match.Result("${file}");
  165. if (String.Empty != match.Result("${line}"))
  166. error.Line=Int32.Parse(match.Result("${line}"));
  167. if (String.Empty != match.Result("${column}"))
  168. error.Column=Int32.Parse(match.Result("${column}"));
  169. if (match.Result("${level}")=="warning")
  170. error.IsWarning=true;
  171. error.ErrorNumber=match.Result("${number}");
  172. error.ErrorText=match.Result("${message}");
  173. return error;
  174. }
  175. }
  176. }