Skip to content

Referencing assemblies produced by PersistedAssemblyBuilder generates a System.Private.CoreLib compiler error #103357

@weebs

Description

@weebs

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions