dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.

Home Page:https://docs.microsoft.com/dotnet/core/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Generated executable can't load main assembly

Aaron-Junker opened this issue · comments

Description

Using .NET 9 new PersistedAssemblyBuilder I try to generate an executable following the documentation.

Upon running the generated executable I get the following error:

Unbehandelte Ausnahme: System.IO.FileNotFoundException: Die Datei oder Assembly "System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.

Reproduction Steps

Official sample

PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), typeof(object).Assembly);
TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
// ...
MethodBuilder entryPoint = tb.DefineMethod("Main", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static);
ILGenerator il2 = entryPoint.GetILGenerator();
// ...
il2.Emit(OpCodes.Ret);
tb.CreateType();

MetadataBuilder metadataBuilder = ab.GenerateMetadata(out BlobBuilder ilStream, out BlobBuilder fieldData);
PEHeaderBuilder peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage);

ManagedPEBuilder peBuilder = new ManagedPEBuilder(
                header: peHeaderBuilder,
                metadataRootBuilder: new MetadataRootBuilder(metadataBuilder),
                ilStream: ilStream,
                mappedFieldData: fieldData,
                entryPoint: MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken));

BlobBuilder peBlob = new BlobBuilder();
peBuilder.Serialize(peBlob);

// in case saving to a file:
using var fileStream = new FileStream("MyAssembly.exe", FileMode.Create, FileAccess.Write);
peBlob.WriteContentTo(fileStream);

Expected behavior

The generated executable can be run

Actual behavior

Although I have the .NET 9 runtime installed and during generation typeof(object).Assembly points to the right assembly it cannot find it when running.

Unbehandelte Ausnahme: System.IO.FileNotFoundException: Die Datei oder Assembly "System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.

Regression?

No response

Known Workarounds

No response

Configuration

  • 9.0.0-preview.3.24172.9
  • x64 Windows 10.0.26212.5000

Other information

No response

Tagging subscribers to this area: @dotnet/area-system-reflection-metadata
See info in area-owners.md if you want to be subscribed.

Tagging subscribers to this area: @dotnet/area-system-reflection-emit
See info in area-owners.md if you want to be subscribed.

.NET Core managed assemblies are not directly executable. .NET Core does not have the integration with the OS loader to enable that. You have to launch the managed assembly using a native binary. For example, dotnet MyAssembly.exe.

Also, if you plan to generate the assembly on one machine and run it on a different machine with potentially difference version of .NET Core, it would be best to generate it against the reference assemblies. Look for "If Reflection.Emit is used to generate an assembly that targets a specific TFM, open the reference assemblies for the given TFM" in https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder .

.NET Core managed assemblies are not directly executable. .NET Core does not have the integration with the OS loader to enable that. You have to launch the managed assembly using a native binary. For example, dotnet MyAssembly.exe.

Also, if you plan to generate the assembly on one machine and run it on a different machine with potentially difference version of .NET Core, it would be best to generate it against the reference assemblies. Look for "If Reflection.Emit is used to generate an assembly that targets a specific TFM, open the reference assemblies for the given TFM" in https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder .

@jkotas Thank you for the quick answer. For the example you provided I don't really get what refAssembliesPath should be. This isn't really specified.

And for the executable, then why can you generate executables if you cannot execute them? If you have to load the assemblies anyway why is generating exe's directly mentioned in the docs?

What would be the best alternative here? Generating an exe that checks if dotnet exists and then runs dotnet MyAssembly.exe?

And for the executable, then why can you generate executables if you cannot execute them?

.NET Core tooling works in two stages. The first stage are managed compilers (C#, VB, F#, IL, ...) that produce managed executable. The managed executable cannot be run directly. The second stage takes the managed executable, combines it with native launcher, and produces native executable that can be run directly. There are number of options: https://learn.microsoft.com/en-us/dotnet/core/deploying/ .

Reflection.Emit is for the first stage that produces managed executable. The second stage is implemented by the msbuild in the .NET SDK. If you are building a real ,NET compiler, you want to look into integrating it into the .NET SDK so that you get the second stage for free.

For the example you provided I don't really get what refAssembliesPath should be

If you are building a real compiler, it is best to let the existing .NET SDK logic figure the reference assemblies (.NET SDK looks at the <TargetFramework> property in your project file and maps it into nuget package with the reference assemblies, downloading it if necessary).