-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Referencing assemblies produced by PersistedAssemblyBuilder generates a System.Private.CoreLib compiler error #103357
Description
Description
When following a code example on github for the new PersistedAssemblyBuilder API, I'm able to successfully produce an exe+pdb and step through source locations, it only works when I load the emitted assembly through reflection. Trying to reference the output assembly from a csproj or fsproj however produces this error
The type 'Object' is required here and is unavailable. You must add a reference to assembly 'System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'
Another issue I'm experiencing is that the PE builder only seems to work with the ExecutableImage setting, though this may be an error on my part?
Reproduction Steps
module Program
open System
open System.Diagnostics.SymbolStore
open System.IO
open System.Reflection
open System.Reflection.Emit
open System.Reflection.Metadata
open System.Reflection.Metadata.Ecma335
open System.Reflection.PortableExecutable
let outputPath = Path.Join(__SOURCE_DIRECTORY__, "output.exe")
let pdbPath = Path.Join(__SOURCE_DIRECTORY__, "output.pdb")
// https://github.com/dotnet/runtime/pull/100706/files#diff-66f7a7c2f17e1298d4f8e23e86e8e4390e504058c900a13c0aa5232d3605bd42
let currentAssemblies = AppDomain.CurrentDomain.GetAssemblies()
let objectAsm = typeof<obj>.Assembly
let builder = PersistedAssemblyBuilder(AssemblyName("output"), typeof<obj>.Assembly)
let mb = builder.DefineDynamicModule("Module")
let tb = mb.DefineType("MyType", TypeAttributes.Public ||| TypeAttributes.Class ||| TypeAttributes.Abstract ||| TypeAttributes.Sealed)
let srcPath = __SOURCE_FILE__
let src = mb.DefineDocument(srcPath, SymLanguageType.Cobol)
let entryPoint = tb.DefineMethod("Add", MethodAttributes.Public ||| MethodAttributes.Static, typeof<int>, [| typeof<int>; typeof<int> |])
let il = entryPoint.GetILGenerator()
let local = il.DeclareLocal(typeof<int>)
local.SetLocalSymInfo("Int")
il.MarkSequencePoint(src, 1, 0, 2, 2)
il.Emit(OpCodes.Ldarg_0)
il.MarkSequencePoint(src, 2, 0, 3, 2)
il.Emit(OpCodes.Ldarg_1)
il.MarkSequencePoint(src, 3, 0, 4, 2)
il.Emit(OpCodes.Add)
il.MarkSequencePoint(src, 4, 0, 5, 2)
il.Emit(OpCodes.Stloc, local)
il.MarkSequencePoint(src, 7, 0, 8, 2)
il.Emit(OpCodes.Ldloc, local)
il.MarkSequencePoint(src, 8, 0, 10, 2)
il.Emit(OpCodes.Ret)
tb.CreateType() |> ignore
let mutable ilStream = null
let mutable bar = null
let mutable pdbMetadata = null
let metadata = builder.GenerateMetadata(&ilStream, &bar, &pdbMetadata)
let portableBlob = BlobBuilder()
let entryPointHandle = MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken)
let pdbBuilder = PortablePdbBuilder(pdbMetadata, metadata.GetRowCounts(), entryPointHandle)
let pdbContentId = pdbBuilder.Serialize(portableBlob)
let dirBuilder = DebugDirectoryBuilder()
dirBuilder.AddCodeViewEntry(pdbPath, pdbContentId, pdbBuilder.FormatVersion)
let peBuilder = ManagedPEBuilder(
PEHeaderBuilder(imageCharacteristics=Characteristics.ExecutableImage),
// Also doesn't work: PEHeaderBuilder(imageCharacteristics=Characteristics.Dll),
MetadataRootBuilder(metadata),
ilStream,
debugDirectoryBuilder=dirBuilder
// entryPoint=entryPointHandle
)
File.WriteAllBytes(pdbPath, portableBlob.ToArray())
let peBlob = BlobBuilder()
let _ = peBuilder.Serialize(peBlob)
let peBytes = peBlob.ToArray()
File.WriteAllBytes(outputPath, peBytes)
let loadedAsm = Assembly.LoadFile outputPath
let myType = loadedAsm.GetType("MyType")
let info = myType.GetMethod("Add")
let result = info.Invoke(null, [| 1; 2 |])
printfn $"result = {result}"
// The following doesn't work after referencing the exe
// MyType.Add(1, 2)Expected behavior
Projects should be able to reference the output exe
Actual behavior
A compilation error is produced
Regression?
No response
Known Workarounds
Loading through reflection at runtime works fine
Configuration
9.0.100-preview.5.24307.3
Windows 10 x64
Other information
No response