e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
671 lines
30 KiB
C#
671 lines
30 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="CompilationConfiguration.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Code related to the <assemblies> config section
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*/
|
|
namespace System.Web.Compilation {
|
|
|
|
using System;
|
|
using System.Web;
|
|
using System.Configuration;
|
|
using System.Web.UI;
|
|
using System.Web.Configuration;
|
|
using System.Web.Hosting;
|
|
using System.Web.Util;
|
|
using System.Globalization;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.CodeDom.Compiler;
|
|
using System.Linq;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Reflection;
|
|
using System.Runtime.ExceptionServices;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
internal static class CompilationUtil {
|
|
|
|
internal const string CodeDomProviderOptionPath = "system.codedom/compilers/compiler/ProviderOption/";
|
|
private const string CompilerDirectoryPath = "CompilerDirectoryPath";
|
|
private static int _maxConcurrentCompilations;
|
|
|
|
internal static bool IsDebuggingEnabled(HttpContext context) {
|
|
CompilationSection compConfig = MTConfigUtil.GetCompilationConfig(context);
|
|
return compConfig.Debug;
|
|
}
|
|
|
|
internal static bool IsBatchingEnabled(string configPath) {
|
|
CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath);
|
|
return config.Batch;
|
|
}
|
|
|
|
internal static int GetRecompilationsBeforeAppRestarts() {
|
|
CompilationSection config = MTConfigUtil.GetCompilationAppConfig();
|
|
return config.NumRecompilesBeforeAppRestart;
|
|
}
|
|
|
|
internal static CompilerType GetCodeDefaultLanguageCompilerInfo() {
|
|
return new CompilerType(typeof(Microsoft.VisualBasic.VBCodeProvider), null);
|
|
}
|
|
|
|
internal static CompilerType GetDefaultLanguageCompilerInfo(CompilationSection compConfig, VirtualPath configPath) {
|
|
if (compConfig == null) {
|
|
// Get the <compilation> config object
|
|
compConfig = MTConfigUtil.GetCompilationConfig(configPath);
|
|
}
|
|
|
|
// If no default language was specified in config, use VB
|
|
if (compConfig.DefaultLanguage == null) {
|
|
return GetCodeDefaultLanguageCompilerInfo();
|
|
}
|
|
else {
|
|
return compConfig.GetCompilerInfoFromLanguage(compConfig.DefaultLanguage);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return a CompilerType that a file name's extension maps to.
|
|
*/
|
|
internal static CompilerType GetCompilerInfoFromVirtualPath(VirtualPath virtualPath) {
|
|
|
|
// Get the extension of the source file to compile
|
|
string extension = virtualPath.Extension;
|
|
|
|
// Make sure there is an extension
|
|
if (extension.Length == 0) {
|
|
throw new HttpException(
|
|
SR.GetString(SR.Empty_extension, virtualPath));
|
|
}
|
|
|
|
return GetCompilerInfoFromExtension(virtualPath, extension);
|
|
}
|
|
|
|
/*
|
|
* Return a CompilerType that a extension maps to.
|
|
*/
|
|
private static CompilerType GetCompilerInfoFromExtension(VirtualPath configPath, string extension) {
|
|
// Get the <compilation> config object
|
|
CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath);
|
|
|
|
return config.GetCompilerInfoFromExtension(extension, true /*throwOnFail*/);
|
|
}
|
|
|
|
/*
|
|
* Return a CompilerType that a language maps to.
|
|
*/
|
|
internal static CompilerType GetCompilerInfoFromLanguage(VirtualPath configPath, string language) {
|
|
// Get the <compilation> config object
|
|
CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath);
|
|
|
|
return config.GetCompilerInfoFromLanguage(language);
|
|
}
|
|
|
|
internal static CompilerType GetCSharpCompilerInfo(
|
|
CompilationSection compConfig, VirtualPath configPath) {
|
|
|
|
if (compConfig == null) {
|
|
// Get the <compilation> config object
|
|
compConfig = MTConfigUtil.GetCompilationConfig(configPath);
|
|
}
|
|
|
|
if (compConfig.DefaultLanguage == null)
|
|
return new CompilerType(typeof(Microsoft.CSharp.CSharpCodeProvider), null);
|
|
|
|
return compConfig.GetCompilerInfoFromLanguage("c#");
|
|
}
|
|
|
|
internal static CodeSubDirectoriesCollection GetCodeSubDirectories() {
|
|
// Get the <compilation> config object
|
|
CompilationSection config = MTConfigUtil.GetCompilationAppConfig();
|
|
|
|
CodeSubDirectoriesCollection codeSubDirectories = config.CodeSubDirectories;
|
|
|
|
// Make sure the config data is valid
|
|
if (codeSubDirectories != null) {
|
|
codeSubDirectories.EnsureRuntimeValidation();
|
|
}
|
|
|
|
return codeSubDirectories;
|
|
}
|
|
|
|
internal static long GetRecompilationHash(CompilationSection ps) {
|
|
HashCodeCombiner recompilationHash = new HashCodeCombiner();
|
|
AssemblyCollection assemblies;
|
|
BuildProviderCollection builders;
|
|
FolderLevelBuildProviderCollection buildProviders;
|
|
CodeSubDirectoriesCollection codeSubDirs;
|
|
|
|
// Combine items from Compilation section
|
|
recompilationHash.AddObject(ps.Debug);
|
|
recompilationHash.AddObject(ps.TargetFramework);
|
|
recompilationHash.AddObject(ps.Strict);
|
|
recompilationHash.AddObject(ps.Explicit);
|
|
recompilationHash.AddObject(ps.Batch);
|
|
recompilationHash.AddObject(ps.OptimizeCompilations);
|
|
recompilationHash.AddObject(ps.BatchTimeout);
|
|
recompilationHash.AddObject(ps.MaxBatchGeneratedFileSize);
|
|
recompilationHash.AddObject(ps.MaxBatchSize);
|
|
recompilationHash.AddObject(ps.NumRecompilesBeforeAppRestart);
|
|
recompilationHash.AddObject(ps.DefaultLanguage);
|
|
recompilationHash.AddObject(ps.UrlLinePragmas);
|
|
recompilationHash.AddObject(ps.DisableObsoleteWarnings);
|
|
if (ps.AssemblyPostProcessorTypeInternal != null) {
|
|
recompilationHash.AddObject(ps.AssemblyPostProcessorTypeInternal.FullName);
|
|
}
|
|
if (!String.IsNullOrWhiteSpace(ps.ControlBuilderInterceptorType)) {
|
|
recompilationHash.AddObject(ps.ControlBuilderInterceptorType);
|
|
}
|
|
|
|
// Combine items from Compilers collection
|
|
foreach (Compiler compiler in ps.Compilers) {
|
|
recompilationHash.AddObject(compiler.Language);
|
|
recompilationHash.AddObject(compiler.Extension);
|
|
recompilationHash.AddObject(compiler.Type);
|
|
recompilationHash.AddObject(compiler.WarningLevel);
|
|
recompilationHash.AddObject(compiler.CompilerOptions);
|
|
}
|
|
|
|
// Combine items from <expressionBuilders> section
|
|
foreach (System.Web.Configuration.ExpressionBuilder eb in ps.ExpressionBuilders) {
|
|
recompilationHash.AddObject(eb.ExpressionPrefix);
|
|
recompilationHash.AddObject(eb.Type);
|
|
}
|
|
|
|
// Combine items from the Assembly collection
|
|
assemblies = ps.Assemblies;
|
|
|
|
if (assemblies.Count == 0) {
|
|
recompilationHash.AddObject("__clearassemblies");
|
|
}
|
|
else {
|
|
foreach (AssemblyInfo ai in assemblies) {
|
|
recompilationHash.AddObject(ai.Assembly);
|
|
}
|
|
}
|
|
|
|
// Combine items from the Builders Collection
|
|
builders = ps.BuildProviders;
|
|
|
|
if (builders.Count == 0) {
|
|
recompilationHash.AddObject("__clearbuildproviders");
|
|
}
|
|
else {
|
|
foreach (System.Web.Configuration.BuildProvider bp in builders) {
|
|
recompilationHash.AddObject(bp.Type);
|
|
recompilationHash.AddObject(bp.Extension);
|
|
}
|
|
}
|
|
|
|
// Combine items from the FolderLevelBuildProviderCollection
|
|
buildProviders = ps.FolderLevelBuildProviders;
|
|
|
|
if (buildProviders.Count == 0) {
|
|
recompilationHash.AddObject("__clearfolderlevelbuildproviders");
|
|
}
|
|
else {
|
|
foreach (System.Web.Configuration.FolderLevelBuildProvider bp in buildProviders) {
|
|
recompilationHash.AddObject(bp.Type);
|
|
recompilationHash.AddObject(bp.Name);
|
|
}
|
|
}
|
|
|
|
codeSubDirs = ps.CodeSubDirectories;
|
|
if (codeSubDirs.Count == 0) {
|
|
recompilationHash.AddObject("__clearcodesubdirs");
|
|
}
|
|
else {
|
|
foreach (CodeSubDirectory csd in codeSubDirs) {
|
|
recompilationHash.AddObject(csd.DirectoryName);
|
|
}
|
|
}
|
|
|
|
// Make sure the <system.CodeDom> section is hashed properly.
|
|
CompilerInfo[] compilerInfoArray = CodeDomProvider.GetAllCompilerInfo();
|
|
if (compilerInfoArray != null) {
|
|
CompilerInfo cppCodeProvider = CodeDomProvider.GetCompilerInfo("cpp");
|
|
foreach (CompilerInfo info in compilerInfoArray) {
|
|
// Skip cpp code provider (Dev11 193323).
|
|
if (info == cppCodeProvider) {
|
|
continue;
|
|
}
|
|
|
|
// Ignore it if the type is not valid.
|
|
if (!info.IsCodeDomProviderTypeValid) {
|
|
continue;
|
|
}
|
|
|
|
CompilerParameters parameters = info.CreateDefaultCompilerParameters();
|
|
string option = parameters.CompilerOptions;
|
|
if (!String.IsNullOrEmpty(option)) {
|
|
Type type = info.CodeDomProviderType;
|
|
if (type != null) {
|
|
recompilationHash.AddObject(type.FullName);
|
|
}
|
|
// compilerOptions need to be hashed.
|
|
recompilationHash.AddObject(option);
|
|
}
|
|
|
|
// DevDiv 62998
|
|
// The tag providerOption needs to be added to the hash,
|
|
// as the user could switch between v2 and v3.5.
|
|
if (info.CodeDomProviderType == null)
|
|
continue;
|
|
|
|
// Add a hash for each providerOption added, specific for each codeDomProvider, so that
|
|
// if some codedom setting has changed, we know we have to recompile.
|
|
IDictionary<string, string> providerOptions = GetProviderOptions(info);
|
|
if (providerOptions != null && providerOptions.Count > 0) {
|
|
string codeDomProviderType = info.CodeDomProviderType.FullName;
|
|
foreach (string key in providerOptions.Keys) {
|
|
string value = providerOptions[key];
|
|
recompilationHash.AddObject(codeDomProviderType + ":" + key + "=" + value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return recompilationHash.CombinedHash;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a file provider Type that an extension maps to.
|
|
*/
|
|
internal static Type GetBuildProviderTypeFromExtension(VirtualPath configPath, string extension,
|
|
BuildProviderAppliesTo neededFor, bool failIfUnknown) {
|
|
|
|
// Get the <compilation> config object
|
|
CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath);
|
|
|
|
return GetBuildProviderTypeFromExtension(config, extension, neededFor, failIfUnknown);
|
|
}
|
|
|
|
internal static Type GetBuildProviderTypeFromExtension(CompilationSection config, string extension,
|
|
BuildProviderAppliesTo neededFor, bool failIfUnknown) {
|
|
|
|
BuildProviderInfo providerInfo = BuildProvider.GetBuildProviderInfo(config, extension);
|
|
|
|
Type buildProviderType = null;
|
|
// Never return an IgnoreFileBuildProvider/ForceCopyBuildProvider, since it's just a marker
|
|
if (providerInfo != null &&
|
|
providerInfo.Type != typeof(IgnoreFileBuildProvider) &&
|
|
providerInfo.Type != typeof(ForceCopyBuildProvider)) {
|
|
buildProviderType = providerInfo.Type;
|
|
}
|
|
|
|
// In updatable precomp mode, only aspx/ascx/master web files need processing. Ignore the rest.
|
|
if (neededFor == BuildProviderAppliesTo.Web &&
|
|
BuildManager.PrecompilingForUpdatableDeployment &&
|
|
!typeof(BaseTemplateBuildProvider).IsAssignableFrom(buildProviderType)) {
|
|
buildProviderType = null;
|
|
}
|
|
|
|
if (buildProviderType != null) {
|
|
// Only return it if it applies to what it's needed for
|
|
if ((neededFor & providerInfo.AppliesTo) != 0)
|
|
return buildProviderType;
|
|
}
|
|
// If the extension is registered as a compiler extension, use
|
|
// a SourceFileBuildProvider to handle it (not supported in Resources directory)
|
|
else if (neededFor != BuildProviderAppliesTo.Resources &&
|
|
config.GetCompilerInfoFromExtension(extension, false /*throwOnFail*/) != null) {
|
|
return typeof(SourceFileBuildProvider);
|
|
}
|
|
|
|
if (failIfUnknown) {
|
|
throw new HttpException( SR.GetString(SR.Unknown_buildprovider_extension, extension, neededFor.ToString()));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// Returns the list of buildProvider types associated to the specified appliesTo
|
|
internal static List<Type> GetFolderLevelBuildProviderTypes(CompilationSection config,
|
|
FolderLevelBuildProviderAppliesTo appliesTo) {
|
|
FolderLevelBuildProviderCollection buildProviders = config.FolderLevelBuildProviders;
|
|
return buildProviders.GetBuildProviderTypes(appliesTo);
|
|
}
|
|
|
|
// In partial trust, do not allow the CompilerDirectoryPath provider option in codedom settings (Dev10 bug 462348)
|
|
internal static void CheckCompilerDirectoryPathAllowed(IDictionary<string, string> providerOptions) {
|
|
if (providerOptions == null) {
|
|
return;
|
|
}
|
|
if (!providerOptions.ContainsKey(CompilerDirectoryPath)) {
|
|
return;
|
|
}
|
|
|
|
if (!HttpRuntime.HasUnmanagedPermission()) {
|
|
string errorString = SR.GetString(SR.Insufficient_trust_for_attribute, CompilerDirectoryPath);
|
|
throw new HttpException(errorString);
|
|
}
|
|
}
|
|
|
|
internal static void CheckCompilerOptionsAllowed(string compilerOptions, bool config, string file, int line) {
|
|
|
|
// If it's empty, we never block it
|
|
if (String.IsNullOrEmpty(compilerOptions))
|
|
return;
|
|
|
|
// Only allow the use of compilerOptions when we have UnmanagedCode access (ASURT 73678)
|
|
if (!HttpRuntime.HasUnmanagedPermission()) {
|
|
string errorString = SR.GetString(SR.Insufficient_trust_for_attribute, "compilerOptions");
|
|
|
|
if (config)
|
|
throw new ConfigurationErrorsException(errorString, file, line);
|
|
else
|
|
throw new HttpException(errorString);
|
|
}
|
|
}
|
|
|
|
// This is used to determine what files need to be copied, and what stub files
|
|
// need to be created during deployment precompilation.
|
|
// Note: createStub only applies if the method returns false.
|
|
internal static bool NeedToCopyFile(VirtualPath virtualPath, bool updatable, out bool createStub) {
|
|
|
|
createStub = false;
|
|
|
|
// Get the <compilation> config object
|
|
CompilationSection config = MTConfigUtil.GetCompilationConfig(virtualPath);
|
|
|
|
string extension = virtualPath.Extension;
|
|
|
|
BuildProviderInfo providerInfo = BuildProvider.GetBuildProviderInfo(config, extension);
|
|
|
|
if (providerInfo != null) {
|
|
// We only care about 'web' providers. Everything else we treat as static
|
|
if ((BuildProviderAppliesTo.Web & providerInfo.AppliesTo) == 0)
|
|
return true;
|
|
|
|
// If the provider is a ForceCopyBuildProvider, treat as static
|
|
if (providerInfo.Type == typeof(ForceCopyBuildProvider))
|
|
return true;
|
|
|
|
// During updatable precomp, everything needs to be copied over. However,
|
|
// aspx files that use code beside will later be overwritten by modified
|
|
// versions (see TemplateParser.CreateModifiedMainDirectiveFileIfNeeded)
|
|
if (providerInfo.Type != typeof(IgnoreFileBuildProvider) &&
|
|
BuildManager.PrecompilingForUpdatableDeployment) {
|
|
return true;
|
|
}
|
|
|
|
// There is a real provider, so don't copy the file. We also need to determine whether
|
|
// a stub file needs to be created.
|
|
|
|
createStub = true;
|
|
|
|
// Skip the stub file for some non-requestable types
|
|
if (providerInfo.Type == typeof(UserControlBuildProvider) ||
|
|
providerInfo.Type == typeof(MasterPageBuildProvider) ||
|
|
providerInfo.Type == typeof(IgnoreFileBuildProvider)) {
|
|
createStub = false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// If the extension is registered as a compiler extension, don't copy
|
|
if (config.GetCompilerInfoFromExtension(extension, false /*throwOnFail*/) != null) {
|
|
return false;
|
|
}
|
|
|
|
// Skip the copying for asax and skin files, which are not static even though they
|
|
// don't have a registered BuildProvider (but don't skip .skin files during
|
|
// updatable precomp).
|
|
//
|
|
if (StringUtil.EqualsIgnoreCase(extension, ".asax"))
|
|
return false;
|
|
if (!updatable && StringUtil.EqualsIgnoreCase(extension, ThemeDirectoryCompiler.skinExtension))
|
|
return false;
|
|
|
|
//
|
|
// If there is no BuildProvider registered, it's a static file, and should be copied
|
|
//
|
|
|
|
return true;
|
|
}
|
|
|
|
internal static Type LoadTypeWithChecks(string typeName, Type requiredBaseType, Type requiredBaseType2, ConfigurationElement elem, string propertyName) {
|
|
Type t = ConfigUtil.GetType(typeName, propertyName, elem);
|
|
|
|
if (requiredBaseType2 == null) {
|
|
ConfigUtil.CheckAssignableType(requiredBaseType, t, elem, propertyName);
|
|
}
|
|
else {
|
|
ConfigUtil.CheckAssignableType(requiredBaseType, requiredBaseType2, t, elem, propertyName);
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
// Devdiv Bug 57600
|
|
// We need to use the constructor with ProviderOptions to get the v3.5/v4.0 compiler that was possibly set in config.
|
|
// We first check if there is any providerOptions and invoke the constructor if so.
|
|
// Otherwise, we fall back to the default constructor.
|
|
internal static CodeDomProvider CreateCodeDomProvider(Type codeDomProviderType) {
|
|
CodeDomProvider codeDomProvider = CreateCodeDomProviderWithPropertyOptions(codeDomProviderType);
|
|
if (codeDomProvider != null) {
|
|
return codeDomProvider;
|
|
}
|
|
return (CodeDomProvider)Activator.CreateInstance(codeDomProviderType);
|
|
}
|
|
|
|
internal static CodeDomProvider CreateCodeDomProviderNonPublic(Type codeDomProviderType) {
|
|
CodeDomProvider codeDomProvider = CreateCodeDomProviderWithPropertyOptions(codeDomProviderType);
|
|
if (codeDomProvider != null) {
|
|
return codeDomProvider;
|
|
}
|
|
return (CodeDomProvider)HttpRuntime.CreateNonPublicInstance(codeDomProviderType);
|
|
}
|
|
|
|
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
|
|
private static CodeDomProvider CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType) {
|
|
// The following resembles the code in System.CodeDom.CompilerInfo.CreateProvider
|
|
|
|
// Make a copy to avoid modifying the original.
|
|
var originalProviderOptions = GetProviderOptions(codeDomProviderType);
|
|
IDictionary<string, string> providerOptions = null;
|
|
if (originalProviderOptions != null) {
|
|
providerOptions = new Dictionary<string, string>(originalProviderOptions);
|
|
} else {
|
|
providerOptions = new Dictionary<string, string>();
|
|
}
|
|
|
|
// Block CompilerDirectoryPath if we are in partial trust
|
|
CheckCompilerDirectoryPathAllowed(providerOptions);
|
|
|
|
// Check whether the user supplied the compilerDirectoryPath or was it added by us
|
|
bool addedCompilerDirectoryPath = false;
|
|
|
|
if (MultiTargetingUtil.IsTargetFramework20) {
|
|
// If the target framework is v2.0, there won't be any codedom settings, so we need
|
|
// to explicitly set the compiler to be the v2.0 compiler using compilerVersion=v2.0.
|
|
providerOptions["CompilerVersion"] = "v2.0";
|
|
}
|
|
else if (MultiTargetingUtil.IsTargetFramework35) {
|
|
// We need to explicitly set to v3.5, as it is possible for the
|
|
// user to only have specified it for one compiler but not
|
|
// the other.
|
|
// Dev10 bug 809212
|
|
providerOptions["CompilerVersion"] = "v3.5";
|
|
}
|
|
else {
|
|
// If we are targeting 4.0 but the compiler version is less than 4.0, set it to 4.0.
|
|
// This can happen if a user tries to run a 2.0/3.5 web site in a 4.0 application pool without
|
|
// upgrading it, and the codedom section still has 3.5 as the compilerVersion,
|
|
// so we have to set the compilerVersion to 4.0 explicitly.
|
|
string version = GetCompilerVersion(codeDomProviderType);
|
|
Version v = GetVersionFromVString(version);
|
|
if (v != null && v < MultiTargetingUtil.Version40) {
|
|
providerOptions["CompilerVersion"] = "v4.0";
|
|
}
|
|
}
|
|
|
|
if (providerOptions != null && providerOptions.Count > 0) {
|
|
Debug.Assert(codeDomProviderType != null, "codeDomProviderType should not be null");
|
|
// Check whether the codedom provider supports a constructor that takes in providerOptions.
|
|
// Currently only VB and C# support providerOptions for sure, while others such as JScript might not.
|
|
ConstructorInfo ci = codeDomProviderType.GetConstructor(new Type[] { typeof(IDictionary<string, string>) });
|
|
CodeDomProvider provider = null;
|
|
if (ci != null) {
|
|
// First, obtain the language for the given codedom provider type.
|
|
CodeDomProvider defaultProvider = (CodeDomProvider)Activator.CreateInstance(codeDomProviderType);
|
|
string extension = defaultProvider.FileExtension;
|
|
var language = CodeDomProvider.GetLanguageFromExtension(extension);
|
|
// Then, use the new createProvider API to create an instance.
|
|
provider = CodeDomProvider.CreateProvider(language, providerOptions);
|
|
}
|
|
// Restore the provider options if we previously manually added the compilerDirectoryPath.
|
|
// Otherwise, we might incorrectly invalidate the compilerDirectoryPath in medium trust (Dev10 bug 550299).
|
|
if (addedCompilerDirectoryPath) {
|
|
providerOptions.Remove(CompilerDirectoryPath);
|
|
}
|
|
return provider;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
|
|
internal static IDictionary<string, string> GetProviderOptions(Type codeDomProviderType) {
|
|
// Using reflection to get the property for the time being.
|
|
// This could simply return CompilerInfo.PropertyOptions if it goes public in future.
|
|
CodeDomProvider provider = (CodeDomProvider)Activator.CreateInstance(codeDomProviderType);
|
|
string extension = provider.FileExtension;
|
|
if (CodeDomProvider.IsDefinedExtension(extension)) {
|
|
CompilerInfo ci = CodeDomProvider.GetCompilerInfo(CodeDomProvider.GetLanguageFromExtension(extension));
|
|
return GetProviderOptions(ci);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
|
|
private static IDictionary<string, string> GetProviderOptions(CompilerInfo ci) {
|
|
Debug.Assert(ci != null, "CompilerInfo ci should not be null");
|
|
PropertyInfo pi = ci.GetType().GetProperty("ProviderOptions",
|
|
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
|
|
if (pi != null)
|
|
return (IDictionary<string, string>)pi.GetValue(ci, null);
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the compilerVersion providerOption specified for the codedom provider type.
|
|
/// Returns null if the providerOption is not found.
|
|
/// </summary>
|
|
internal static string GetCompilerVersion(Type codeDomProviderType) {
|
|
return GetProviderOption(codeDomProviderType, "CompilerVersion");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the value of the providerOption specified for the codedom provider type.
|
|
/// Returns null if the providerOption is not found.
|
|
/// </summary>
|
|
internal static string GetProviderOption(Type codeDomProviderType, string providerOption) {
|
|
IDictionary<string, string> providerOptions = CompilationUtil.GetProviderOptions(codeDomProviderType);
|
|
if (providerOptions != null) {
|
|
string version;
|
|
if (providerOptions.TryGetValue(providerOption, out version)) {
|
|
return version;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the string matches "v3.5" exactly.
|
|
/// </summary>
|
|
internal static bool IsCompilerVersion35(string compilerVersion) {
|
|
if (compilerVersion == "v3.5") {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This returns true only if the codedom CompilverVersion provider option is exactly v3.5.
|
|
/// </summary>
|
|
internal static bool IsCompilerVersion35(Type codeDomProviderType) {
|
|
string compilerVersion = GetCompilerVersion(codeDomProviderType);
|
|
bool result = IsCompilerVersion35(compilerVersion);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the codedom CompilerVersion provider option is at least v3.5.
|
|
/// </summary>
|
|
/// <param name="codeDomProviderType"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsCompilerVersion35OrAbove(Type codeDomProviderType) {
|
|
string compilerVersion = GetCompilerVersion(codeDomProviderType);
|
|
if (IsCompilerVersion35(compilerVersion)) {
|
|
return true;
|
|
}
|
|
// The compilerVersion provider option is known to exist only for v3.5.
|
|
// If it does not exist, then we need to rely on the target framework version to
|
|
// determine whether we need to use the 2.0 or 4.0 compiler.
|
|
if (MultiTargetingUtil.IsTargetFramework20) {
|
|
return false;
|
|
}
|
|
|
|
// If it isn't 2.0 or 3.5, assume it is 4.0 and above.
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the codedom provider has warnAsError set to true
|
|
/// </summary>
|
|
internal static bool WarnAsError(Type codeDomProviderType) {
|
|
string value = GetProviderOption(codeDomProviderType, "WarnAsError");
|
|
bool result;
|
|
if (value != null && bool.TryParse(value, out result)) {
|
|
return result;
|
|
}
|
|
|
|
// Assume false if the value wasn't set
|
|
return false;
|
|
}
|
|
|
|
// Returns the version when given string of form "v4.0"
|
|
internal static Version GetVersionFromVString(string version) {
|
|
if (string.IsNullOrEmpty(version)) {
|
|
return null;
|
|
}
|
|
Debug.Assert(version.Length > 1, "Version has invalid length");
|
|
return new Version(version.Substring(1));
|
|
}
|
|
|
|
// Returns maximum number of concurrent compilations
|
|
internal static int MaxConcurrentCompilations {
|
|
get {
|
|
if (_maxConcurrentCompilations == 0) {
|
|
int maxConcurrentCompilations;
|
|
|
|
if (AppSettings.MaxConcurrentCompilations.HasValue && AppSettings.MaxConcurrentCompilations.Value >= 0) {
|
|
maxConcurrentCompilations = AppSettings.MaxConcurrentCompilations.Value;
|
|
}
|
|
else {
|
|
CompilationSection config = MTConfigUtil.GetCompilationAppConfig();
|
|
maxConcurrentCompilations = config.MaxConcurrentCompilations;
|
|
}
|
|
|
|
if (maxConcurrentCompilations <= 0) {
|
|
maxConcurrentCompilations = Environment.ProcessorCount;
|
|
}
|
|
|
|
Interlocked.CompareExchange(ref _maxConcurrentCompilations, maxConcurrentCompilations, 0);
|
|
}
|
|
|
|
return _maxConcurrentCompilations;
|
|
}
|
|
}
|
|
}
|
|
}
|