diff --git a/src/IL2C.Build/Program.cs b/src/IL2C.Build/Program.cs index eea28463..1084586a 100644 --- a/src/IL2C.Build/Program.cs +++ b/src/IL2C.Build/Program.cs @@ -115,7 +115,7 @@ public static async Task Main(string[] args) if ((drivingMode & DrivingModes.Translation) == DrivingModes.Translation) { var translationOptions = new TranslationOptions( - true, enableBundler, targetPlatform, debugInformationOptions); + true, refDirs, enableBundler, targetPlatform, debugInformationOptions); #if DEBUG var results = new List(); foreach (var assemblyPath in inputPaths) diff --git a/src/IL2C.Core/Drivers/SimpleTranslator.cs b/src/IL2C.Core/Drivers/SimpleTranslator.cs index 321f8ce0..c4190081 100644 --- a/src/IL2C.Core/Drivers/SimpleTranslator.cs +++ b/src/IL2C.Core/Drivers/SimpleTranslator.cs @@ -20,17 +20,20 @@ namespace IL2C.Drivers public sealed class TranslationOptions { public readonly bool ReadSymbols; + public readonly string[] ReferenceBasePaths; public readonly bool EnableBundler; public readonly TargetPlatforms TargetPlatform; public readonly DebugInformationOptions DebugInformationOption; public TranslationOptions( bool readSymbols, + string[] referenceBasePaths, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOption) { this.ReadSymbols = readSymbols; + this.ReferenceBasePaths = referenceBasePaths; this.EnableBundler = enableBundler; this.TargetPlatform = targetPlatform; this.DebugInformationOption = debugInformationOption; @@ -52,7 +55,7 @@ await IOAccessor.SafeCreateDirectoryAsync( ConfigureAwait(false); var translateContext = new TranslateContext( - assemblyPath, options.ReadSymbols, options.TargetPlatform); + assemblyPath, options.ReferenceBasePaths, options.ReadSymbols, options.TargetPlatform); var preparedFunctions = AssemblyPreparer.Prepare( translateContext); diff --git a/src/IL2C.Core/Metadata/BasePathAssemblyResolver.cs b/src/IL2C.Core/Metadata/BasePathAssemblyResolver.cs deleted file mode 100644 index 868a9b45..00000000 --- a/src/IL2C.Core/Metadata/BasePathAssemblyResolver.cs +++ /dev/null @@ -1,28 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// -// IL2C - A translator for ECMA-335 CIL/MSIL to C language. -// Copyright (c) Kouji Matsui (@kozy_kekyo, @kekyo@mastodon.cloud) -// -// Licensed under Apache-v2: https://opensource.org/licenses/Apache-2.0 -// -//////////////////////////////////////////////////////////////////////////// - -using Mono.Cecil; - -namespace IL2C.Metadata -{ - internal sealed class BasePathAssemblyResolver : DefaultAssemblyResolver - { - public BasePathAssemblyResolver(string basePath) - { - this.AddSearchDirectory(basePath); - } - - public override AssemblyDefinition Resolve(AssemblyNameReference name) - { - var definition = base.Resolve(name); - this.RegisterAssembly(definition); - return definition; - } - } -} diff --git a/src/IL2C.Core/Metadata/IL2CAssemblyResolver.cs b/src/IL2C.Core/Metadata/IL2CAssemblyResolver.cs new file mode 100644 index 00000000..8380277f --- /dev/null +++ b/src/IL2C.Core/Metadata/IL2CAssemblyResolver.cs @@ -0,0 +1,112 @@ +//////////////////////////////////////////////////////////////////////////// +// +// IL2C - A translator for ECMA-335 CIL/MSIL to C language. +// Copyright (c) Kouji Matsui (@kozy_kekyo, @kekyo@mastodon.cloud) +// +// Licensed under Apache-v2: https://opensource.org/licenses/Apache-2.0 +// +//////////////////////////////////////////////////////////////////////////// + +#nullable enable + +using System.IO; +using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Pdb; + +namespace IL2C.Metadata +{ + internal sealed class IL2CAssemblyResolver : DefaultAssemblyResolver + { + private sealed class IL2CSymbolReaderProvider : ISymbolReaderProvider + { + // HACK: cecil will lock symbol file when uses defaulted reading method. + // Makes safer around entire building process. + + private static readonly PdbReaderProvider parent = new(); + + public ISymbolReader? GetSymbolReader(ModuleDefinition module, string fileName) + { + if (module.HasDebugHeader) + { + var header = module.GetDebugHeader(); + if (header.Entries. + FirstOrDefault(e => e.Directory.Type == ImageDebugType.EmbeddedPortablePdb) is { } entry) + { + return new EmbeddedPortablePdbReaderProvider(). + GetSymbolReader(module, fileName); + } + + var fullPath = Path.GetFullPath(fileName); + var debuggingPath = Path.Combine( + fullPath, + Path.GetFileNameWithoutExtension(fullPath) + ".pdb"); + + if (File.Exists(debuggingPath)) + { + var ms = new MemoryStream(); + using (var pdbStream = new FileStream( + debuggingPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + pdbStream.CopyTo(ms); + } + ms.Position = 0; + + return parent.GetSymbolReader(module, ms); + } + } + + return null; + } + + public ISymbolReader? GetSymbolReader(ModuleDefinition module, Stream symbolStream) + { + var ms = new MemoryStream(); + symbolStream.CopyTo(ms); + ms.Position = 0; + + symbolStream.Dispose(); + + return parent.GetSymbolReader(module, ms); + } + } + + public IL2CAssemblyResolver( + string assemblyPath, string[] referenceBasePaths, bool readSymbols) + { + base.AddSearchDirectory(Path.GetDirectoryName(Path.GetFullPath(assemblyPath))); + + foreach (var referenceBasePath in referenceBasePaths) + { + base.AddSearchDirectory(Path.GetFullPath(referenceBasePath)); + } + } + + public override AssemblyDefinition Resolve(AssemblyNameReference name) + { + var parameters = new ReaderParameters() + { + ReadWrite = false, + InMemory = true, + AssemblyResolver = this, + SymbolReaderProvider = new IL2CSymbolReaderProvider(), + ReadSymbols = true, + }; + return base.Resolve(name, parameters); + } + + public AssemblyDefinition ReadFrom(string assemblyPath) + { + var parameters = new ReaderParameters() + { + ReadWrite = false, + InMemory = true, + AssemblyResolver = this, + SymbolReaderProvider = new IL2CSymbolReaderProvider(), + ReadSymbols = true, + }; + return AssemblyDefinition.ReadAssembly(assemblyPath, parameters); + } + } +} diff --git a/src/IL2C.Core/Metadata/MetadataContext.cs b/src/IL2C.Core/Metadata/MetadataContext.cs index 94c3c9de..526d577c 100644 --- a/src/IL2C.Core/Metadata/MetadataContext.cs +++ b/src/IL2C.Core/Metadata/MetadataContext.cs @@ -13,6 +13,7 @@ using System.Linq; using Mono.Cecil; +using Mono.Cecil.Pdb; using IL2C.Metadata.Specialized; @@ -81,18 +82,15 @@ internal sealed class MetadataContext new Dictionary(ModuleReferenceComparer.Instance); private readonly Dictionary members = new Dictionary(MemberReferenceComparer.Instance); - private readonly BasePathAssemblyResolver resolver; + private readonly IL2CAssemblyResolver resolver; - internal MetadataContext(string assemblyPath, bool readSymbols) + internal MetadataContext( + string assemblyPath, string[] referenceBasePaths, bool readSymbols) { - resolver = new BasePathAssemblyResolver(Path.GetDirectoryName(assemblyPath)); - var assemblyReaderParameter = new ReaderParameters - { - AssemblyResolver = resolver, - ReadSymbols = readSymbols - }; + resolver = new IL2CAssemblyResolver( + assemblyPath, referenceBasePaths, readSymbols); - var mainAssembly = AssemblyDefinition.ReadAssembly(assemblyPath, assemblyReaderParameter); + var mainAssembly = resolver.ReadFrom(assemblyPath); var mainAssemblyInformation = new AssemblyInformation(mainAssembly, this); resolvedCoreModule = mainAssembly.MainModule.TypeSystem.Object.Resolve().Module; diff --git a/src/IL2C.Core/TranslateContext.cs b/src/IL2C.Core/TranslateContext.cs index e369cc98..b9f90a6f 100644 --- a/src/IL2C.Core/TranslateContext.cs +++ b/src/IL2C.Core/TranslateContext.cs @@ -44,9 +44,12 @@ public sealed class TranslateContext private string currentExceptionNestedFrameIndexName; #endregion - public TranslateContext(string assemblyPath, bool readSymbols, TargetPlatforms targetPlatform) + public TranslateContext( + string assemblyPath, string[] referenceBasePath, bool readSymbols, + TargetPlatforms targetPlatform) { - var context = new MetadataContext(assemblyPath, readSymbols); + var context = new MetadataContext( + assemblyPath, referenceBasePath, readSymbols); this.MetadataContext = context; this.Assembly = context.MainAssembly; this.TargetPlatform = targetPlatform;