11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33
4- using System ;
4+ using System ;
55using System . CodeDom ;
66using System . CodeDom . Compiler ;
77using System . Collections . Generic ;
1212using System . Security . Permissions ;
1313using System . Security . Principal ;
1414using System . Text ;
15+ using static Microsoft . CodeDom . Providers . DotNetCompilerPlatform . Constants . CustomCompilerParameters ;
1516
1617namespace Microsoft . CodeDom . Providers . DotNetCompilerPlatform {
1718 internal abstract class Compiler : ICodeCompiler {
1819 private readonly CodeDomProvider _codeDomProvider ;
1920 private readonly ICompilerSettings _compilerSettings ;
20- private string _compilerFullPath = null ;
2121 private const string CLR_PROFILING_SETTING = "COR_ENABLE_PROFILING" ;
2222 private const string DISABLE_PROFILING = "0" ;
2323
24+ // Needs to be initialized using InitializeCompilerFullPath where the CompilerParameters are available.
25+ private string _compilerFullPath = null ;
26+
2427 public Compiler ( CodeDomProvider codeDomProvider , ICompilerSettings compilerSettings ) {
25- this . _codeDomProvider = codeDomProvider ;
26- this . _compilerSettings = compilerSettings ;
28+ _codeDomProvider = codeDomProvider ;
29+ _compilerSettings = compilerSettings ;
2730 }
2831
2932 public CompilerResults CompileAssemblyFromDom ( CompilerParameters options , CodeCompileUnit compilationUnit ) {
@@ -47,6 +50,8 @@ public CompilerResults CompileAssemblyFromDomBatch(CompilerParameters options, C
4750 throw new ArgumentNullException ( "compilationUnits" ) ;
4851 }
4952
53+ InitializeCompilerFullPath ( options ) ;
54+
5055 try {
5156 var sources = compilationUnits . Select ( c => {
5257 var writer = new StringWriter ( ) ;
@@ -82,6 +87,8 @@ public CompilerResults CompileAssemblyFromFileBatch(CompilerParameters options,
8287 throw new ArgumentNullException ( "fileNames" ) ;
8388 }
8489
90+ InitializeCompilerFullPath ( options ) ;
91+
8592 try {
8693 // Try opening the files to make sure they exists. This will throw an exception
8794 // if it doesn't
@@ -117,6 +124,8 @@ public CompilerResults CompileAssemblyFromSourceBatch(CompilerParameters options
117124 throw new ArgumentNullException ( "sources" ) ;
118125 }
119126
127+ InitializeCompilerFullPath ( options ) ;
128+
120129 try {
121130 return FromSourceBatch ( options , sources ) ;
122131 }
@@ -129,17 +138,41 @@ protected abstract string FileExtension {
129138 get ;
130139 }
131140
132- protected virtual string CompilerName {
133- get {
134- if ( null == _compilerFullPath ) {
135- _compilerFullPath = _compilerSettings . CompilerFullPath ;
141+ protected void InitializeCompilerFullPath ( CompilerParameters options = null ) {
142+ if ( string . IsNullOrEmpty ( _compilerFullPath ) ) {
143+ if ( options != null ) {
144+ // Determining whether the custom compiler path parameter is provided.
145+ var customCompilerPathParameter = options . CompilerOptions . Split ( '/' ) . FirstOrDefault ( p => p . StartsWith ( CustomCompilerPath ) ) ;
146+ if ( ! string . IsNullOrEmpty ( customCompilerPathParameter ) ) {
147+ if ( ! customCompilerPathParameter . Contains ( ":" ) ) {
148+ throw new ArgumentException ( $ "There's no value defined for the \" { CustomCompilerPath } \" compiler parameter!") ;
149+ }
136150
137- // Try opening the file to make sure the compiler exist. This will throw an exception
138- // if it doesn't
139- using ( var str = File . OpenRead ( _compilerFullPath ) ) { }
151+ // Removing trailing space (when this is not the last parameter) and extracting value.
152+ var customCompilerPath = customCompilerPathParameter . TrimEnd ( ' ' ) . Split ( ':' ) [ 1 ] ;
153+
154+ if ( string . IsNullOrEmpty ( customCompilerPath ) ) {
155+ throw new ArgumentException ( $ "The value of the \" { CustomCompilerPath } \" compiler parameter can't be empty!") ;
156+ }
157+
158+ // Extracting the name of the compiler executable from the default path.
159+ var compilerExecutable = _compilerSettings . CompilerFullPath . Substring ( _compilerSettings . CompilerFullPath . LastIndexOf ( '\\ ' ) ) ;
160+
161+ // And finally, we're able to construct the complete custom path to the compiler executable.
162+ // If the custom path contains spaces, then it has to be surrounded by quotes, which we don't need now.
163+ _compilerFullPath = CompilationSettingsHelper . CompilerFullPath ( $ "{ customCompilerPath . Trim ( '"' ) } \\ { compilerExecutable } ") ;
164+
165+ // Removing the custom parameter, as the compiler can't process it.
166+ options . CompilerOptions = options . CompilerOptions . Replace ( $ "/{ CustomCompilerPath } :{ customCompilerPath } ", "" ) ;
167+ }
168+ // Falling back to the default behavior.
169+ else _compilerFullPath = _compilerSettings . CompilerFullPath ;
140170 }
171+ else _compilerFullPath = _compilerSettings . CompilerFullPath ;
141172
142- return _compilerFullPath ;
173+ // Try opening the file to make sure that the compiler exists.
174+ // This will throw an exception if it doesn't.
175+ using ( var str = File . OpenRead ( _compilerFullPath ) ) { }
143176 }
144177 }
145178
@@ -282,7 +315,7 @@ private CompilerResults FromFileBatch(CompilerParameters options, string[] fileN
282315 }
283316
284317 Compile ( options ,
285- CompilerName ,
318+ _compilerFullPath ,
286319 args ,
287320 ref outputFile ,
288321 ref retValue ) ;
@@ -300,7 +333,7 @@ private CompilerResults FromFileBatch(CompilerParameters options, string[] fileN
300333 replacedArgs = true ;
301334 var outputLine = string . Format ( "{0}>{1} {2}" ,
302335 Environment . CurrentDirectory ,
303- CompilerName ,
336+ _compilerFullPath ,
304337 trueArgs ) ;
305338 results . Output . Add ( outputLine ) ;
306339 }
0 commit comments