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).