public Compilation CreateCompilation(CompilationOptionsReader compilationOptionsReader, string fileName) { var pdbCompilationOptions = compilationOptionsReader.GetMetadataCompilationOptions(); if (pdbCompilationOptions.Length == 0) { throw new InvalidDataException("Did not find compilation options in pdb"); } var metadataReferenceInfos = compilationOptionsReader.GetMetadataReferences(); var encoding = compilationOptionsReader.GetEncoding(); var sourceFileInfos = compilationOptionsReader.GetSourceFileInfos(encoding); _logger.LogInformation("Locating metadata references"); var metadataReferences = _referenceResolver.ResolveReferences(metadataReferenceInfos); logResolvedMetadataReferences(); var sourceLinks = ResolveSourceLinks(compilationOptionsReader); var sources = ResolveSources(sourceFileInfos, sourceLinks, encoding); logResolvedSources(); if (pdbCompilationOptions.TryGetUniqueOption("language", out var language)) { var compilation = language switch { LanguageNames.CSharp => CreateCSharpCompilation(fileName, compilationOptionsReader, sources, metadataReferences), LanguageNames.VisualBasic => CreateVisualBasicCompilation(fileName, compilationOptionsReader, sources, metadataReferences), _ => throw new InvalidDataException($"{language} is not a known language") }; return(compilation); } throw new InvalidDataException("Did not find language in compilation options"); void logResolvedMetadataReferences() { using var _ = _logger.BeginScope("Metadata References"); for (var i = 0; i < metadataReferenceInfos.Length; i++) { _logger.LogInformation($@"""{metadataReferences[i].Display}"" - {metadataReferenceInfos[i].Mvid}"); } } void logResolvedSources() { using var _ = _logger.BeginScope("Source Names"); foreach (var resolvedSource in sources) { var sourceFileInfo = resolvedSource.SourceFileInfo; var hash = BitConverter.ToString(sourceFileInfo.Hash).Replace("-", ""); var embeddedCompressedHash = sourceFileInfo.EmbeddedCompressedHash is { } compressedHash ? ("[uncompressed]" + BitConverter.ToString(compressedHash).Replace("-", "")) : null; _logger.LogInformation($@"""{resolvedSource.DisplayPath}"" - {sourceFileInfo.HashAlgorithm} - {hash} - {embeddedCompressedHash}"); } } }
private static (CSharpCompilationOptions, CSharpParseOptions) CreateCSharpCompilationOptions(string assemblyFileName, CompilationOptionsReader optionsReader) { var pdbCompilationOptions = optionsReader.GetMetadataCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption(CompilationOptionNames.LanguageVersion); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Optimization, out var optimization); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Platform, out var platform); // TODO: Check portability policy if needed // pdbCompilationOptions.TryGetValue("portability-policy", out var portabilityPolicyString); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Define, out var define); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Checked, out var checkedString); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Nullable, out var nullable); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Unsafe, out var unsafeString); CS.LanguageVersionFacts.TryParse(langVersionString, out var langVersion); var preprocessorSymbols = define == null ? ImmutableArray <string> .Empty : define.Split(',').ToImmutableArray(); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols); var(optimizationLevel, plus) = GetOptimizationLevel(optimization); var nullableOptions = nullable is null ? NullableContextOptions.Disable : (NullableContextOptions)Enum.Parse(typeof(NullableContextOptions), nullable); var compilationOptions = new CSharpCompilationOptions( optionsReader.GetOutputKind(), reportSuppressedDiagnostics: false, moduleName: assemblyFileName, mainTypeName: optionsReader.GetMainTypeName(), scriptClassName: null, usings: null, optimizationLevel, !string.IsNullOrEmpty(checkedString) && bool.Parse(checkedString), !string.IsNullOrEmpty(unsafeString) && bool.Parse(unsafeString), cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: optionsReader.GetPublicKey()?.ToImmutableArray() ?? default, delaySign: null, GetPlatform(platform), // presence of diagnostics is expected to not affect emit. ReportDiagnostic.Suppress, warningLevel: 4, specificDiagnosticOptions: null, concurrentBuild: true, deterministic: true, xmlReferenceResolver: null, sourceReferenceResolver: null, metadataReferenceResolver: null, assemblyIdentityComparer: null, strongNameProvider: null, publicSign: false, metadataImportOptions: MetadataImportOptions.Public, nullableContextOptions: nullableOptions); compilationOptions.DebugPlusMode = plus; return(compilationOptions, parseOptions); }
private static VisualBasicCompilationOptions CreateVisualBasicCompilationOptions(string assemblyFileName, CompilationOptionsReader optionsReader) { var pdbCompilationOptions = optionsReader.GetMetadataCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption(CompilationOptionNames.LanguageVersion); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Optimization, out var optimization); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Platform, out var platform); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.GlobalNamespaces, out var globalNamespacesString); IEnumerable <GlobalImport>?globalImports = null; if (!string.IsNullOrEmpty(globalNamespacesString)) { globalImports = GlobalImport.Parse(globalNamespacesString.Split(';')); } VB.LanguageVersion langVersion = default; VB.LanguageVersionFacts.TryParse(langVersionString, ref langVersion); IReadOnlyDictionary <string, object>?preprocessorSymbols = null; if (OptionToString(CompilationOptionNames.Define) is string defineString) { preprocessorSymbols = VisualBasicCommandLineParser.ParseConditionalCompilationSymbols(defineString, out var diagnostics); var diagnostic = diagnostics?.FirstOrDefault(x => x.IsUnsuppressedError); if (diagnostic is object) { throw new Exception($"Cannot create compilation options: {diagnostic}"); } } var parseOptions = VisualBasicParseOptions .Default .WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols.ToImmutableArrayOrEmpty()); var(optimizationLevel, plus) = GetOptimizationLevel(optimization); var isChecked = OptionToBool(CompilationOptionNames.Checked) ?? true; var embedVBRuntime = OptionToBool(CompilationOptionNames.EmbedRuntime) ?? false; var rootNamespace = OptionToString(CompilationOptionNames.RootNamespace); var compilationOptions = new VisualBasicCompilationOptions( optionsReader.GetOutputKind(), moduleName: assemblyFileName, mainTypeName: optionsReader.GetMainTypeName(), scriptClassName: "Script", globalImports: globalImports, rootNamespace: rootNamespace, optionStrict: OptionToEnum <OptionStrict>(CompilationOptionNames.OptionStrict) ?? OptionStrict.Off, optionInfer: OptionToBool(CompilationOptionNames.OptionInfer) ?? false, optionExplicit: OptionToBool(CompilationOptionNames.OptionExplicit) ?? false, optionCompareText: OptionToBool(CompilationOptionNames.OptionCompareText) ?? false, parseOptions: parseOptions, embedVbCoreRuntime: embedVBRuntime, optimizationLevel: optimizationLevel, checkOverflow: isChecked, cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: optionsReader.GetPublicKey()?.ToImmutableArray() ?? default, delaySign: null, platform: GetPlatform(platform), generalDiagnosticOption: ReportDiagnostic.Default, specificDiagnosticOptions: null, concurrentBuild: true, deterministic: true, xmlReferenceResolver: null, sourceReferenceResolver: null, metadataReferenceResolver: null, assemblyIdentityComparer: null, strongNameProvider: null, publicSign: false, reportSuppressedDiagnostics: false, metadataImportOptions: MetadataImportOptions.Public); compilationOptions.DebugPlusMode = plus; return(compilationOptions); string?OptionToString(string option) => pdbCompilationOptions.TryGetUniqueOption(option, out var value) ? value : null; bool?OptionToBool(string option) => pdbCompilationOptions.TryGetUniqueOption(option, out var value) ? ToBool(value) : null; T?OptionToEnum <T>(string option) where T : struct => pdbCompilationOptions.TryGetUniqueOption(option, out var value) ? ToEnum <T>(value) : null;
private (CSharpCompilationOptions, CSharpParseOptions) CreateCSharpCompilationOptions(CompilationOptionsReader optionsReader, string assemblyName) { using var scope = _logger.BeginScope("Options"); var pdbCompilationOptions = optionsReader.GetMetadataCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption("language-version"); var optimization = pdbCompilationOptions.GetUniqueOption("optimization"); // TODO: Check portability policy if needed // pdbCompilationOptions.TryGetValue("portability-policy", out var portabilityPolicyString); pdbCompilationOptions.TryGetUniqueOption(_logger, "define", out var define); pdbCompilationOptions.TryGetUniqueOption(_logger, "checked", out var checkedString); pdbCompilationOptions.TryGetUniqueOption(_logger, "nullable", out var nullable); pdbCompilationOptions.TryGetUniqueOption(_logger, "unsafe", out var unsafeString); CS.LanguageVersionFacts.TryParse(langVersionString, out var langVersion); var preprocessorSymbols = define == null ? ImmutableArray <string> .Empty : define.Split(',').ToImmutableArray(); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols); var(optimizationLevel, plus) = GetOptimizationLevel(optimization); var nullableOptions = nullable is null ? NullableContextOptions.Disable : (NullableContextOptions)Enum.Parse(typeof(NullableContextOptions), nullable); var compilationOptions = new CSharpCompilationOptions( optionsReader.GetOutputKind(), reportSuppressedDiagnostics: false, // TODO: can't rely on the implicity moduleName here. In the case of .NET Core EXE the output name will // end with .dll but the inferred name will be .exe moduleName: assemblyName + ".dll", mainTypeName: optionsReader.GetMainTypeName(), scriptClassName: null, usings: null, optimizationLevel, !string.IsNullOrEmpty(checkedString) && bool.Parse(checkedString), !string.IsNullOrEmpty(unsafeString) && bool.Parse(unsafeString), cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: optionsReader.GetPublicKey()?.ToImmutableArray() ?? default, delaySign: null, Platform.AnyCpu, // presence of diagnostics is expected to not affect emit. ReportDiagnostic.Suppress, warningLevel: 4, specificDiagnosticOptions: null, concurrentBuild: true, deterministic: true, xmlReferenceResolver: null, sourceReferenceResolver: null, metadataReferenceResolver: null, assemblyIdentityComparer: null, strongNameProvider: null, publicSign: false, metadataImportOptions: MetadataImportOptions.Public, nullableContextOptions: nullableOptions); compilationOptions.DebugPlusMode = plus; return(compilationOptions, parseOptions); }