2 // Microsoft VisualBasic VBCodeCompiler Class implementation
5 // Jochen Wezel (jwezel@compumaster.de)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2003 Jochen Wezel (http://www.compumaster.de)
9 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
12 // 2003-11-28 JW: create reference to Microsoft.VisualBasic if not explicitly done
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 namespace Microsoft
.VisualBasic
39 using System
.CodeDom
.Compiler
;
42 using System
.Reflection
;
43 using System
.Collections
;
44 using System
.Collections
.Specialized
;
45 using System
.Diagnostics
;
46 using System
.Text
.RegularExpressions
;
48 internal class VBCodeCompiler
: VBCodeGenerator
, ICodeCompiler
50 static string windowsMonoPath
;
51 static string windowsMbasPath
;
52 static VBCodeCompiler ()
54 if (Path
.DirectorySeparatorChar
== '\\') {
55 // FIXME: right now we use "fixed" version 1.0
57 PropertyInfo gac
= typeof (Environment
).GetProperty ("GacPath", BindingFlags
.Static
|BindingFlags
.NonPublic
);
58 MethodInfo get_gac
= gac
.GetGetMethod (true);
59 string p
= Path
.GetDirectoryName (
60 (string) get_gac
.Invoke (null, null));
61 windowsMonoPath
= Path
.Combine (
62 Path
.GetDirectoryName (
63 Path
.GetDirectoryName (p
)),
65 if (!File
.Exists (windowsMonoPath
))
66 windowsMonoPath
= Path
.Combine (
67 Path
.GetDirectoryName (
68 Path
.GetDirectoryName (p
)),
71 Path
.Combine (p
, "1.0\\mbas.exe");
78 public VBCodeCompiler()
86 public CompilerResults
CompileAssemblyFromDom (CompilerParameters options
,CodeCompileUnit e
)
88 return CompileAssemblyFromDomBatch (options
, new CodeCompileUnit
[]{e}
);
91 public CompilerResults
CompileAssemblyFromDomBatch (CompilerParameters options
,
92 CodeCompileUnit
[] ea
)
94 string [] fileNames
= new string [ea
.Length
];
97 options
= new CompilerParameters ();
99 StringCollection assemblies
= options
.ReferencedAssemblies
;
101 foreach (CodeCompileUnit e
in ea
) {
102 fileNames
[i
] = GetTempFileNameWithExtension (options
.TempFiles
, "vb");
103 FileStream f
= new FileStream (fileNames
[i
], FileMode
.OpenOrCreate
);
104 StreamWriter s
= new StreamWriter (f
);
105 if (e
.ReferencedAssemblies
!= null) {
106 foreach (string str
in e
.ReferencedAssemblies
) {
107 if (!assemblies
.Contains (str
))
108 assemblies
.Add (str
);
112 ((ICodeGenerator
)this).GenerateCodeFromCompileUnit (e
, s
, new CodeGeneratorOptions());
117 return CompileAssemblyFromFileBatch (options
, fileNames
);
120 public CompilerResults
CompileAssemblyFromFile (CompilerParameters options
,string fileName
)
122 return CompileAssemblyFromFileBatch (options
, new string []{fileName}
);
125 public CompilerResults
CompileAssemblyFromFileBatch (CompilerParameters options
,
129 throw new ArgumentNullException ("options");
131 if (null == fileNames
)
132 throw new ArgumentNullException ("fileNames");
134 CompilerResults results
= new CompilerResults (options
.TempFiles
);
135 Process mbas
= new Process ();
138 string [] mbas_output_lines
;
139 // FIXME: these lines had better be platform independent.
140 if (Path
.DirectorySeparatorChar
== '\\') {
141 mbas
.StartInfo
.FileName
= windowsMonoPath
;
142 mbas
.StartInfo
.Arguments
= windowsMbasPath
+ ' ' + BuildArgs (options
, fileNames
);
145 mbas
.StartInfo
.FileName
= "mbas";
146 mbas
.StartInfo
.Arguments
= BuildArgs (options
,fileNames
);
148 mbas
.StartInfo
.CreateNoWindow
= true;
149 mbas
.StartInfo
.UseShellExecute
= false;
150 mbas
.StartInfo
.RedirectStandardOutput
= true;
153 mbas_output
= mbas
.StandardOutput
.ReadToEnd ();
156 results
.NativeCompilerReturnValue
= mbas
.ExitCode
;
160 mbas_output_lines
= mbas_output
.Split(Environment
.NewLine
.ToCharArray());
162 foreach (string error_line
in mbas_output_lines
) {
163 CompilerError error
= CreateErrorFromString (error_line
);
165 results
.Errors
.Add (error
);
166 if (!error
.IsWarning
)
172 results
.CompiledAssembly
=Assembly
.LoadFrom(options
.OutputAssembly
);
174 results
.CompiledAssembly
=null;
179 public CompilerResults
CompileAssemblyFromSource (CompilerParameters options
,
182 return CompileAssemblyFromSourceBatch (options
, new string [] {source}
);
185 public CompilerResults
CompileAssemblyFromSourceBatch (CompilerParameters options
,
188 string [] fileNames
= new string [sources
.Length
];
190 foreach (string source
in sources
) {
191 fileNames
[i
] = GetTempFileNameWithExtension (options
.TempFiles
, "vb");
192 FileStream f
= new FileStream (fileNames
[i
], FileMode
.OpenOrCreate
);
193 StreamWriter s
= new StreamWriter (f
);
199 return CompileAssemblyFromFileBatch(options
,fileNames
);
202 static string BuildArgs (CompilerParameters options
, string [] fileNames
)
204 StringBuilder args
= new StringBuilder ();
205 if (options
.GenerateExecutable
)
206 args
.AppendFormat("/target:exe ");
208 args
.AppendFormat("/target:library ");
210 /* Disabled. It causes problems now. -- Gonzalo
211 if (options.IncludeDebugInformation)
212 args.AppendFormat("/debug ");
215 if (options
.TreatWarningsAsErrors
)
216 args
.AppendFormat ("/warnaserror ");
218 if (options
.WarningLevel
!= -1)
219 args
.AppendFormat ("/wlevel:{0} ", options
.WarningLevel
);
221 if (options
.OutputAssembly
== null) {
222 string ext
= (options
.GenerateExecutable
? "exe" : "dll");
223 options
.OutputAssembly
= GetTempFileNameWithExtension (options
.TempFiles
, ext
);
226 args
.AppendFormat ("/out:\"{0}\" ", options
.OutputAssembly
);
228 bool Reference2MSVBFound
;
229 Reference2MSVBFound
= false;
230 if (null != options
.ReferencedAssemblies
)
232 foreach (string import
in options
.ReferencedAssemblies
)
234 if (string.Compare (import
, "Microsoft.VisualBasic", true, System
.Globalization
.CultureInfo
.InvariantCulture
) == 0)
235 Reference2MSVBFound
= true;
236 args
.AppendFormat ("/r:\"{0}\" ", import
);
239 // add standard import to Microsoft.VisualBasic if missing
240 if (Reference2MSVBFound
== false)
241 args
.AppendFormat ("/r:\"{0}\" ", "Microsoft.VisualBasic");
243 args
.AppendFormat(" -- "); // makes mbas not try to process filenames as options
245 foreach (string source
in fileNames
)
246 args
.AppendFormat("\"{0}\" ",source
);
248 return args
.ToString();
251 static CompilerError
CreateErrorFromString (string error_string
)
253 // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
254 if (error_string
.StartsWith ("WROTE SYMFILE") || error_string
.StartsWith ("OffsetTable"))
257 CompilerError error
= new CompilerError ();
258 Regex reg
= new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*" +
259 @"(?<level>error|warning)\s*(?<number>.*):\s(?<message>.*)",
260 RegexOptions
.Compiled
| RegexOptions
.ExplicitCapture
);
262 Match match
= reg
.Match (error_string
);
266 if (String
.Empty
!= match
.Result("${file}"))
267 error
.FileName
= match
.Result ("${file}");
269 if (String
.Empty
!= match
.Result ("${line}"))
270 error
.Line
= Int32
.Parse (match
.Result ("${line}"));
272 if (String
.Empty
!= match
.Result( "${column}"))
273 error
.Column
= Int32
.Parse (match
.Result ("${column}"));
275 if (match
.Result ("${level}") =="warning")
276 error
.IsWarning
= true;
278 error
.ErrorNumber
= match
.Result ("${number}");
279 error
.ErrorText
= match
.Result ("${message}");
283 static string GetTempFileNameWithExtension (TempFileCollection temp_files
, string extension
)
285 return temp_files
.AddExtension (extension
);