-
Notifications
You must be signed in to change notification settings - Fork 4.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generated executable can't load main assembly #102393
Comments
Tagging subscribers to this area: @dotnet/area-system-reflection-metadata |
Tagging subscribers to this area: @dotnet/area-system-reflection-emit |
.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, 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 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 |
.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.
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 |
Thanks @jkotas for the quick replies above. Closing issue. FWIW, a quick way to get the sample above to be called via EXE is to create a console app that references the generated assembly and calls internal class Program
{
static void Main(string[] args)
{
MyType.Main();
}
} Here's some quick edits on the sample above to use reference assemblies, as well as generate a call to // Change the path as needed:
string[] runtimeAssemblies = Directory.GetFiles(@"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.0-preview.4.24223.11\ref\net9.0", "*.dll");
MetadataAssemblyResolver resolver = new PathAssemblyResolver(runtimeAssemblies);
MetadataLoadContext mlc = new MetadataLoadContext(resolver, "System.Runtime");
PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), mlc.CoreAssembly!);
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();
Type stringType = mlc.CoreAssembly!.GetType("System.String")!;
MethodInfo consoleWriteLine = mlc.LoadFromAssemblyName("System.Console").
GetType("System.Console")!.
GetMethod("WriteLine", BindingFlags.Public | BindingFlags.Static, null, new Type[] { stringType }, null)!;
il2.Emit(OpCodes.Ldstr, "Hello World");
il2.Emit(OpCodes.Call, consoleWriteLine);
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.dll", FileMode.Create, FileAccess.Write);
peBlob.WriteContentTo(fileStream); |
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:
Reproduction Steps
Official sample
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.Regression?
No response
Known Workarounds
No response
Configuration
Other information
No response
The text was updated successfully, but these errors were encountered: