-//\r
-// Microsoft VisualBasic VBCodeCompiler Class implementation\r
-//\r
-// Authors:\r
-// Jochen Wezel (jwezel@compumaster.de)\r
-// Gonzalo Paniagua Javier (gonzalo@ximian.com)\r
-//\r
-// (c) 2003 Jochen Wezel (http://www.compumaster.de)\r
-// (c) 2003 Ximian, Inc. (http://www.ximian.com)\r
-//\r
-// Modifications:\r
-// 2003-11-28 JW: create reference to Microsoft.VisualBasic if not explicitly done\r
+//
+// Microsoft VisualBasic VBCodeCompiler Class implementation
+//
+// Authors:
+// Jochen Wezel (jwezel@compumaster.de)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// (c) 2003 Jochen Wezel (http://www.compumaster.de)
+// (c) 2003 Ximian, Inc. (http://www.ximian.com)
+//
+// Modifications:
+// 2003-11-28 JW: create reference to Microsoft.VisualBasic if not explicitly done
//
// Permission is hereby granted, free of charge, to any person obtaining
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-\r
-namespace Microsoft.VisualBasic\r
-{\r
- using System;\r
- using System.CodeDom;\r
- using System.CodeDom.Compiler;\r
- using System.IO;\r
- using System.Text;\r
- using System.Reflection;\r
- using System.Collections;\r
- using System.Collections.Specialized;\r
- using System.Diagnostics;\r
- using System.Text.RegularExpressions;\r
-\r
- internal class VBCodeCompiler: VBCodeGenerator, ICodeCompiler\r
- {\r
- static string windowsMonoPath;\r
- static string windowsMbasPath;\r
- static VBCodeCompiler ()\r
- {\r
- if (Path.DirectorySeparatorChar == '\\') {\r
- // FIXME: right now we use "fixed" version 1.0\r
- // mcs at any time.\r
- PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static|BindingFlags.NonPublic);\r
- MethodInfo get_gac = gac.GetGetMethod (true);\r
- string p = Path.GetDirectoryName (\r
- (string) get_gac.Invoke (null, null));\r
- windowsMonoPath = Path.Combine (\r
- Path.GetDirectoryName (\r
- Path.GetDirectoryName (p)),\r
- "bin\\mono.bat");\r
- if (!File.Exists (windowsMonoPath))\r
- windowsMonoPath = Path.Combine (\r
- Path.GetDirectoryName (\r
- Path.GetDirectoryName (p)),\r
- "bin\\mono.exe");\r
- windowsMbasPath =\r
- Path.Combine (p, "1.0\\mbas.exe");\r
- }\r
- }\r
-\r
- //\r
- // Constructors\r
- //\r
- public VBCodeCompiler()\r
- {\r
- }\r
-\r
- //\r
- // Methods\r
- //\r
- [MonoTODO]\r
- public CompilerResults CompileAssemblyFromDom (CompilerParameters options,CodeCompileUnit e)\r
- {\r
- return CompileAssemblyFromDomBatch (options, new CodeCompileUnit []{e});\r
- }\r
-\r
- public CompilerResults CompileAssemblyFromDomBatch (CompilerParameters options,\r
- CodeCompileUnit [] ea)\r
- {\r
- string [] fileNames = new string [ea.Length];\r
- int i = 0;\r
- if (options == null)\r
- options = new CompilerParameters ();\r
-\r
- StringCollection assemblies = options.ReferencedAssemblies;\r
-\r
- foreach (CodeCompileUnit e in ea) {\r
- fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, "vb");\r
- FileStream f = new FileStream (fileNames [i], FileMode.OpenOrCreate);\r
- StreamWriter s = new StreamWriter (f);\r
- if (e.ReferencedAssemblies != null) {\r
- foreach (string str in e.ReferencedAssemblies) {\r
- if (!assemblies.Contains (str))\r
- assemblies.Add (str);\r
- }\r
- }\r
-\r
- ((ICodeGenerator)this).GenerateCodeFromCompileUnit (e, s, new CodeGeneratorOptions());\r
- s.Close();\r
- f.Close();\r
- i++;\r
- }\r
- return CompileAssemblyFromFileBatch (options, fileNames);\r
- }\r
-\r
- public CompilerResults CompileAssemblyFromFile (CompilerParameters options,string fileName)\r
- {\r
- return CompileAssemblyFromFileBatch (options, new string []{fileName});\r
- }\r
-\r
- public CompilerResults CompileAssemblyFromFileBatch (CompilerParameters options,\r
- string [] fileNames)\r
- {\r
- if (null == options)\r
- throw new ArgumentNullException ("options");\r
-\r
- if (null == fileNames)\r
- throw new ArgumentNullException ("fileNames");\r
-\r
- CompilerResults results = new CompilerResults (options.TempFiles);\r
- Process mbas = new Process ();\r
-\r
- string mbas_output;\r
- string [] mbas_output_lines;\r
- // FIXME: these lines had better be platform independent.\r
- if (Path.DirectorySeparatorChar == '\\') {\r
- mbas.StartInfo.FileName = windowsMonoPath;\r
- mbas.StartInfo.Arguments = windowsMbasPath + ' ' + BuildArgs (options, fileNames);\r
- }\r
- else {\r
- mbas.StartInfo.FileName = "mbas";\r
- mbas.StartInfo.Arguments = BuildArgs (options,fileNames);\r
- }\r
- mbas.StartInfo.CreateNoWindow = true;\r
- mbas.StartInfo.UseShellExecute = false;\r
- mbas.StartInfo.RedirectStandardOutput = true;\r
- try {\r
- mbas.Start();\r
- mbas_output = mbas.StandardOutput.ReadToEnd ();\r
- mbas.WaitForExit();\r
- } finally {\r
- results.NativeCompilerReturnValue = mbas.ExitCode;\r
- mbas.Close ();\r
- }\r
-\r
- mbas_output_lines = mbas_output.Split(Environment.NewLine.ToCharArray());\r
- bool loadIt=true;\r
- foreach (string error_line in mbas_output_lines) {\r
- CompilerError error = CreateErrorFromString (error_line);\r
- if (null != error) {\r
- results.Errors.Add (error);\r
- if (!error.IsWarning)\r
- loadIt = false;\r
- }\r
- }\r
-\r
- if (loadIt)\r
- results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);\r
- else\r
- results.CompiledAssembly=null;\r
-\r
- return results;\r
- }\r
-\r
- public CompilerResults CompileAssemblyFromSource (CompilerParameters options,\r
- string source)\r
- {\r
- return CompileAssemblyFromSourceBatch (options, new string [] {source});\r
- }\r
-\r
- public CompilerResults CompileAssemblyFromSourceBatch (CompilerParameters options,\r
- string [] sources)\r
- {\r
- string [] fileNames = new string [sources.Length];\r
- int i = 0;\r
- foreach (string source in sources) {\r
- fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, "vb");\r
- FileStream f = new FileStream (fileNames [i], FileMode.OpenOrCreate);\r
- StreamWriter s = new StreamWriter (f);\r
- s.Write (source);\r
- s.Close ();\r
- f.Close ();\r
- i++;\r
- }\r
- return CompileAssemblyFromFileBatch(options,fileNames);\r
- }\r
-\r
- static string BuildArgs (CompilerParameters options, string [] fileNames)\r
- {\r
- StringBuilder args = new StringBuilder ();\r
- if (options.GenerateExecutable)\r
- args.AppendFormat("/target:exe ");\r
- else\r
- args.AppendFormat("/target:library ");\r
-\r
- /* Disabled. It causes problems now. -- Gonzalo\r
- if (options.IncludeDebugInformation)\r
- args.AppendFormat("/debug ");\r
- */\r
-\r
- if (options.TreatWarningsAsErrors)\r
- args.AppendFormat ("/warnaserror ");\r
-\r
- if (options.WarningLevel != -1)\r
- args.AppendFormat ("/wlevel:{0} ", options.WarningLevel);\r
-\r
- if (options.OutputAssembly == null) {\r
- string ext = (options.GenerateExecutable ? "exe" : "dll");\r
- options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, ext);\r
- }\r
-\r
- args.AppendFormat ("/out:\"{0}\" ", options.OutputAssembly);\r
-\r
- bool Reference2MSVBFound;\r
- Reference2MSVBFound = false;\r
- if (null != options.ReferencedAssemblies) \r
- {\r
- foreach (string import in options.ReferencedAssemblies)\r
- {\r
- if (string.Compare (import, "Microsoft.VisualBasic", true, System.Globalization.CultureInfo.InvariantCulture) == 0)\r
- Reference2MSVBFound = true;\r
- args.AppendFormat ("/r:\"{0}\" ", import);\r
- }\r
- }\r
- // add standard import to Microsoft.VisualBasic if missing\r
- if (Reference2MSVBFound == false)\r
- args.AppendFormat ("/r:\"{0}\" ", "Microsoft.VisualBasic");\r
-\r
- args.AppendFormat(" -- "); // makes mbas not try to process filenames as options\r
-\r
- foreach (string source in fileNames)\r
- args.AppendFormat("\"{0}\" ",source);\r
-\r
- return args.ToString();\r
- }\r
-\r
- static CompilerError CreateErrorFromString (string error_string)\r
- {\r
- // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.\r
- if (error_string.StartsWith ("WROTE SYMFILE") || error_string.StartsWith ("OffsetTable"))\r
- return null;\r
-\r
- CompilerError error = new CompilerError ();\r
- Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*" +\r
- @"(?<level>error|warning)\s*(?<number>.*):\s(?<message>.*)",\r
- RegexOptions.Compiled | RegexOptions.ExplicitCapture);\r
-\r
- Match match = reg.Match (error_string);\r
- if (!match.Success)\r
- return null;\r
-\r
- if (String.Empty != match.Result("${file}"))\r
- error.FileName = match.Result ("${file}");\r
-\r
- if (String.Empty != match.Result ("${line}"))\r
- error.Line = Int32.Parse (match.Result ("${line}"));\r
-\r
- if (String.Empty != match.Result( "${column}"))\r
- error.Column = Int32.Parse (match.Result ("${column}"));\r
-\r
- if (match.Result ("${level}") =="warning")\r
- error.IsWarning = true;\r
-\r
- error.ErrorNumber = match.Result ("${number}");\r
- error.ErrorText = match.Result ("${message}");\r
- return error;\r
- }\r
-\r
- static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension)\r
- {\r
- return temp_files.AddExtension (extension);\r
- }\r
- }\r
-}\r
-\r
+
+using System;
+using System.CodeDom;
+using System.CodeDom.Compiler;
+using System.IO;
+using System.Text;
+using System.Reflection;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+
+namespace Microsoft.VisualBasic
+{
+ internal class VBCodeCompiler : VBCodeGenerator, ICodeCompiler
+ {
+ static string windowsMonoPath;
+ static string windowsMbasPath;
+ static VBCodeCompiler ()
+ {
+ if (Path.DirectorySeparatorChar == '\\') {
+ PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
+ MethodInfo get_gac = gac.GetGetMethod (true);
+ string p = Path.GetDirectoryName (
+ (string) get_gac.Invoke (null, null));
+ windowsMonoPath = Path.Combine (
+ Path.GetDirectoryName (
+ Path.GetDirectoryName (p)),
+ "bin\\mono.bat");
+ if (!File.Exists (windowsMonoPath))
+ windowsMonoPath = Path.Combine (
+ Path.GetDirectoryName (
+ Path.GetDirectoryName (p)),
+ "bin\\mono.exe");
+#if NET_2_0
+ windowsMbasPath =
+ Path.Combine (p, "2.0\\mbas.exe");
+#else
+ windowsMbasPath =
+ Path.Combine (p, "1.0\\mbas.exe");
+#endif
+ }
+ }
+
+ public CompilerResults CompileAssemblyFromDom (CompilerParameters options, CodeCompileUnit e)
+ {
+ return CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { e });
+ }
+
+ public CompilerResults CompileAssemblyFromDomBatch (CompilerParameters options, CodeCompileUnit[] ea)
+ {
+ if (options == null) {
+ throw new ArgumentNullException ("options");
+ }
+
+ try {
+ return CompileFromDomBatch (options, ea);
+ } finally {
+ options.TempFiles.Delete ();
+ }
+ }
+
+ public CompilerResults CompileAssemblyFromFile (CompilerParameters options, 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 ();
+ }
+ }
+
+ static string BuildArgs (CompilerParameters options, string[] fileNames)
+ {
+ StringBuilder args = new StringBuilder ();
+ args.Append ("/quiet ");
+ if (options.GenerateExecutable)
+ args.Append ("/target:exe ");
+ else
+ args.Append ("/target:library ");
+
+ /* Disabled. It causes problems now. -- Gonzalo
+ if (options.IncludeDebugInformation)
+ args.AppendFormat("/debug ");
+ */
+
+ if (options.TreatWarningsAsErrors)
+ args.Append ("/warnaserror ");
+
+ if (options.WarningLevel != -1)
+ args.AppendFormat ("/wlevel:{0} ", options.WarningLevel);
+
+ if (options.OutputAssembly == null) {
+ string ext = (options.GenerateExecutable ? "exe" : "dll");
+ options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, ext, !options.GenerateInMemory);
+ }
+
+ args.AppendFormat ("/out:\"{0}\" ", options.OutputAssembly);
+
+ bool Reference2MSVBFound;
+ Reference2MSVBFound = false;
+ if (null != options.ReferencedAssemblies) {
+ foreach (string import in options.ReferencedAssemblies) {
+ if (string.Compare (import, "Microsoft.VisualBasic", true, System.Globalization.CultureInfo.InvariantCulture) == 0)
+ Reference2MSVBFound = true;
+ args.AppendFormat ("/r:\"{0}\" ", import);
+ }
+ }
+
+ // add standard import to Microsoft.VisualBasic if missing
+ if (!Reference2MSVBFound)
+ args.Append ("/r:\"Microsoft.VisualBasic\" ");
+
+ if (options.CompilerOptions != null) {
+ args.Append (options.CompilerOptions);
+ }
+
+ args.Append (" -- "); // makes mbas not try to process filenames as options
+
+ foreach (string source in fileNames)
+ args.AppendFormat ("\"{0}\" ", source);
+
+ return args.ToString ();
+ }
+
+ 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"))
+ return null;
+
+ CompilerError error = new CompilerError ();
+ Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*" +
+ @"(?<level>error|warning)\s*(?<number>.*):\s(?<message>.*)",
+ RegexOptions.Compiled | RegexOptions.ExplicitCapture);
+
+ Match match = reg.Match (error_string);
+ if (!match.Success)
+ return null;
+
+ if (String.Empty != match.Result ("${file}"))
+ error.FileName = match.Result ("${file}");
+
+ if (String.Empty != match.Result ("${line}"))
+ 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;
+
+ error.ErrorNumber = match.Result ("${number}");
+ error.ErrorText = match.Result ("${message}");
+ return error;
+ }
+
+ 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 CompileFromFileBatch (CompilerParameters options, string[] fileNames)
+ {
+ if (options == null) {
+ throw new ArgumentNullException ("options");
+ }
+
+ if (fileNames == null) {
+ throw new ArgumentNullException ("fileNames");
+ }
+
+ CompilerResults results = new CompilerResults (options.TempFiles);
+ Process mbas = new Process ();
+
+ string mbas_output = "";
+ string[] mbas_output_lines;
+ // FIXME: these lines had better be platform independent.
+ if (Path.DirectorySeparatorChar == '\\') {
+ mbas.StartInfo.FileName = windowsMonoPath;
+ mbas.StartInfo.Arguments = windowsMbasPath + ' ' + BuildArgs (options, fileNames);
+ } else {
+ mbas.StartInfo.FileName = "mbas";
+ mbas.StartInfo.Arguments = BuildArgs (options, fileNames);
+ }
+ mbas.StartInfo.CreateNoWindow = true;
+ mbas.StartInfo.UseShellExecute = false;
+ mbas.StartInfo.RedirectStandardOutput = true;
+ try {
+ mbas.Start ();
+ mbas_output = mbas.StandardOutput.ReadToEnd ();
+ mbas.WaitForExit ();
+ } finally {
+ results.NativeCompilerReturnValue = mbas.ExitCode;
+ mbas.Close ();
+ }
+
+ mbas_output_lines = mbas_output.Split (Environment.NewLine.ToCharArray ());
+ bool loadIt = true;
+ foreach (string error_line in mbas_output_lines) {
+ CompilerError error = CreateErrorFromString (error_line);
+ if (null != error) {
+ results.Errors.Add (error);
+ if (!error.IsWarning)
+ loadIt = false;
+ }
+ }
+
+ if (loadIt) {
+ 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;
+ }
+
+ 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 + ".vb");
+ FileStream f = new FileStream (fileNames[i], FileMode.OpenOrCreate);
+ StreamWriter s = new StreamWriter (f);
+ 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 + ".vb");
+ FileStream f = new FileStream (fileNames[i], FileMode.OpenOrCreate);
+ using (StreamWriter s = new StreamWriter (f)) {
+ s.Write (sources[i]);
+ s.Close ();
+ }
+ f.Close ();
+ }
+ return CompileFromFileBatch (options, fileNames);
+ }
+ }
+}
+