VBCodeCompiler.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //
  2. // Microsoft VisualBasic VBCodeCompiler Class implementation
  3. //
  4. // Authors:
  5. // Jochen Wezel ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (c) 2003 Jochen Wezel (http://www.compumaster.de)
  9. // (c) 2003 Ximian, Inc. (http://www.ximian.com)
  10. //
  11. // Modifications:
  12. // 2003-11-28 JW: create reference to Microsoft.VisualBasic if not explicitly done
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining
  15. // a copy of this software and associated documentation files (the
  16. // "Software"), to deal in the Software without restriction, including
  17. // without limitation the rights to use, copy, modify, merge, publish,
  18. // distribute, sublicense, and/or sell copies of the Software, and to
  19. // permit persons to whom the Software is furnished to do so, subject to
  20. // the following conditions:
  21. //
  22. // The above copyright notice and this permission notice shall be
  23. // included in all copies or substantial portions of the Software.
  24. //
  25. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  29. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  30. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  31. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. //
  33. namespace Microsoft.VisualBasic
  34. {
  35. using System;
  36. using System.CodeDom;
  37. using System.CodeDom.Compiler;
  38. using System.IO;
  39. using System.Text;
  40. using System.Reflection;
  41. using System.Collections;
  42. using System.Collections.Specialized;
  43. using System.Diagnostics;
  44. using System.Text.RegularExpressions;
  45. internal class VBCodeCompiler: VBCodeGenerator, ICodeCompiler
  46. {
  47. static string windowsMonoPath;
  48. static string windowsMbasPath;
  49. static VBCodeCompiler ()
  50. {
  51. if (Path.DirectorySeparatorChar == '\\') {
  52. // FIXME: right now we use "fixed" version 1.0
  53. // mcs at any time.
  54. PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static|BindingFlags.NonPublic);
  55. MethodInfo get_gac = gac.GetGetMethod (true);
  56. string p = Path.GetDirectoryName (
  57. (string) get_gac.Invoke (null, null));
  58. windowsMonoPath = Path.Combine (
  59. Path.GetDirectoryName (
  60. Path.GetDirectoryName (p)),
  61. "bin\\mono.bat");
  62. if (!File.Exists (windowsMonoPath))
  63. windowsMonoPath = Path.Combine (
  64. Path.GetDirectoryName (
  65. Path.GetDirectoryName (p)),
  66. "bin\\mono.exe");
  67. windowsMbasPath =
  68. Path.Combine (p, "1.0\\mbas.exe");
  69. }
  70. }
  71. //
  72. // Constructors
  73. //
  74. public VBCodeCompiler()
  75. {
  76. }
  77. //
  78. // Methods
  79. //
  80. [MonoTODO]
  81. public CompilerResults CompileAssemblyFromDom (CompilerParameters options,CodeCompileUnit e)
  82. {
  83. return CompileAssemblyFromDomBatch (options, new CodeCompileUnit []{e});
  84. }
  85. public CompilerResults CompileAssemblyFromDomBatch (CompilerParameters options,
  86. CodeCompileUnit [] ea)
  87. {
  88. string [] fileNames = new string [ea.Length];
  89. int i = 0;
  90. if (options == null)
  91. options = new CompilerParameters ();
  92. StringCollection assemblies = options.ReferencedAssemblies;
  93. foreach (CodeCompileUnit e in ea) {
  94. fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, "vb");
  95. FileStream f = new FileStream (fileNames [i], FileMode.OpenOrCreate);
  96. StreamWriter s = new StreamWriter (f);
  97. if (e.ReferencedAssemblies != null) {
  98. foreach (string str in e.ReferencedAssemblies) {
  99. if (!assemblies.Contains (str))
  100. assemblies.Add (str);
  101. }
  102. }
  103. ((ICodeGenerator)this).GenerateCodeFromCompileUnit (e, s, new CodeGeneratorOptions());
  104. s.Close();
  105. f.Close();
  106. i++;
  107. }
  108. return CompileAssemblyFromFileBatch (options, fileNames);
  109. }
  110. public CompilerResults CompileAssemblyFromFile (CompilerParameters options,string fileName)
  111. {
  112. return CompileAssemblyFromFileBatch (options, new string []{fileName});
  113. }
  114. public CompilerResults CompileAssemblyFromFileBatch (CompilerParameters options,
  115. string [] fileNames)
  116. {
  117. if (null == options)
  118. throw new ArgumentNullException ("options");
  119. if (null == fileNames)
  120. throw new ArgumentNullException ("fileNames");
  121. CompilerResults results = new CompilerResults (options.TempFiles);
  122. Process mbas = new Process ();
  123. string mbas_output;
  124. string [] mbas_output_lines;
  125. // FIXME: these lines had better be platform independent.
  126. if (Path.DirectorySeparatorChar == '\\') {
  127. mbas.StartInfo.FileName = windowsMonoPath;
  128. mbas.StartInfo.Arguments = windowsMbasPath + ' ' + BuildArgs (options, fileNames);
  129. }
  130. else {
  131. mbas.StartInfo.FileName = "mbas";
  132. mbas.StartInfo.Arguments = BuildArgs (options,fileNames);
  133. }
  134. mbas.StartInfo.CreateNoWindow = true;
  135. mbas.StartInfo.UseShellExecute = false;
  136. mbas.StartInfo.RedirectStandardOutput = true;
  137. try {
  138. mbas.Start();
  139. mbas_output = mbas.StandardOutput.ReadToEnd ();
  140. mbas.WaitForExit();
  141. } finally {
  142. results.NativeCompilerReturnValue = mbas.ExitCode;
  143. mbas.Close ();
  144. }
  145. mbas_output_lines = mbas_output.Split(Environment.NewLine.ToCharArray());
  146. bool loadIt=true;
  147. foreach (string error_line in mbas_output_lines) {
  148. CompilerError error = CreateErrorFromString (error_line);
  149. if (null != error) {
  150. results.Errors.Add (error);
  151. if (!error.IsWarning)
  152. loadIt = false;
  153. }
  154. }
  155. if (loadIt)
  156. results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);
  157. else
  158. results.CompiledAssembly=null;
  159. return results;
  160. }
  161. public CompilerResults CompileAssemblyFromSource (CompilerParameters options,
  162. string source)
  163. {
  164. return CompileAssemblyFromSourceBatch (options, new string [] {source});
  165. }
  166. public CompilerResults CompileAssemblyFromSourceBatch (CompilerParameters options,
  167. string [] sources)
  168. {
  169. string [] fileNames = new string [sources.Length];
  170. int i = 0;
  171. foreach (string source in sources) {
  172. fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, "vb");
  173. FileStream f = new FileStream (fileNames [i], FileMode.OpenOrCreate);
  174. StreamWriter s = new StreamWriter (f);
  175. s.Write (source);
  176. s.Close ();
  177. f.Close ();
  178. i++;
  179. }
  180. return CompileAssemblyFromFileBatch(options,fileNames);
  181. }
  182. static string BuildArgs (CompilerParameters options, string [] fileNames)
  183. {
  184. StringBuilder args = new StringBuilder ();
  185. if (options.GenerateExecutable)
  186. args.AppendFormat("/target:exe ");
  187. else
  188. args.AppendFormat("/target:library ");
  189. /* Disabled. It causes problems now. -- Gonzalo
  190. if (options.IncludeDebugInformation)
  191. args.AppendFormat("/debug ");
  192. */
  193. if (options.TreatWarningsAsErrors)
  194. args.AppendFormat ("/warnaserror ");
  195. if (options.WarningLevel != -1)
  196. args.AppendFormat ("/wlevel:{0} ", options.WarningLevel);
  197. if (options.OutputAssembly == null) {
  198. string ext = (options.GenerateExecutable ? "exe" : "dll");
  199. options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, ext);
  200. }
  201. args.AppendFormat ("/out:\"{0}\" ", options.OutputAssembly);
  202. bool Reference2MSVBFound;
  203. Reference2MSVBFound = false;
  204. if (null != options.ReferencedAssemblies)
  205. {
  206. foreach (string import in options.ReferencedAssemblies)
  207. {
  208. if (string.Compare (import, "Microsoft.VisualBasic", true, System.Globalization.CultureInfo.InvariantCulture) == 0)
  209. Reference2MSVBFound = true;
  210. args.AppendFormat ("/r:\"{0}\" ", import);
  211. }
  212. }
  213. // add standard import to Microsoft.VisualBasic if missing
  214. if (Reference2MSVBFound == false)
  215. args.AppendFormat ("/r:\"{0}\" ", "Microsoft.VisualBasic");
  216. args.AppendFormat(" -- "); // makes mbas not try to process filenames as options
  217. foreach (string source in fileNames)
  218. args.AppendFormat("\"{0}\" ",source);
  219. return args.ToString();
  220. }
  221. static CompilerError CreateErrorFromString (string error_string)
  222. {
  223. // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
  224. if (error_string.StartsWith ("WROTE SYMFILE") || error_string.StartsWith ("OffsetTable"))
  225. return null;
  226. CompilerError error = new CompilerError ();
  227. Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*" +
  228. @"(?<level>error|warning)\s*(?<number>.*):\s(?<message>.*)",
  229. RegexOptions.Compiled | RegexOptions.ExplicitCapture);
  230. Match match = reg.Match (error_string);
  231. if (!match.Success)
  232. return null;
  233. if (String.Empty != match.Result("${file}"))
  234. error.FileName = match.Result ("${file}");
  235. if (String.Empty != match.Result ("${line}"))
  236. error.Line = Int32.Parse (match.Result ("${line}"));
  237. if (String.Empty != match.Result( "${column}"))
  238. error.Column = Int32.Parse (match.Result ("${column}"));
  239. if (match.Result ("${level}") =="warning")
  240. error.IsWarning = true;
  241. error.ErrorNumber = match.Result ("${number}");
  242. error.ErrorText = match.Result ("${message}");
  243. return error;
  244. }
  245. static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension)
  246. {
  247. return temp_files.AddExtension (extension);
  248. }
  249. }
  250. }