Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do .NET Core and .NET 5 generate an executable?

I have a question that I'm very confused about. The way I understand .NET is like this:

  • C# Application (source code) ->
  • csc.exe (compiler) ->
  • .NET application (which is in MSIL)

If so, why is the output from building a .NET app a Windows executable? I thought the whole idea was that your source code compiles down to MSIL, which targets the locally installed CLR. However, both .NET Core and .NET 5 generate a windows executable, which run atop of the operating system, not in a virtual machine.

This is unlike Java, which compiles to a .class bytecode file (not an .exe), and those files do run atop a virtual machine (or, later, you can package all the class files into a .jar).

What I'm trying to ask is: Why doesn't the C# compiler generate a specific application file type that runs atop .NET? E.g., a .net file that is associated with the common language runtime?

My best guess is that the Windows .exe generated is not, in fact, a Windows executable, but instead some kind of .NET executable. But, in that case, why can't it run on any platform with .NET Core? Linux doesn't know what an .exe file is.

like image 662
Lauren 835 Avatar asked Jun 05 '20 22:06

Lauren 835


2 Answers

It's a regular executable but the only native code it contains is a small stub that will call into the .NET runtime. The runtime will then inspect the MSIL embedded in that file and do the rest.

like image 79
Theodoros Chatzigiannakis Avatar answered Nov 02 '22 22:11

Theodoros Chatzigiannakis


As other answers already answered, the default on Windows is currently that a small host executable is generated that boots up the .NET runtime and loads the appropriate MSIL assembly.

An interesting factoid is that the MSIL assembly is packaged in the same runtime format ("PE" - portable executable) as all windows .exe or .dll files..

Earlier version of "the new .NET" (.NET Core, now .NET 5+) only produced the .dll file that could run on all platforms and required users to use dotnet theapp.dll to run the application.

While this works, .NET Core 3.0 and later moved to generating an "app host" assembly as an alternative entry point as well. The code generated by dotnet publish is still cross-platform, but additionally generating the executable has a few advantages:

  • Moving classic .NET Framework projects to .NET Core requires less changes in larger projects with CI/CD pipelines or tooling that expect .exe files.
  • Users have an easier time finding the right program in task explorer / ps - like finding the right java.exe process, having hundreds of dotnet.exe processes around is a bit hard for ops tasks.
  • The path to dotnet.exe or dotnet (linux / macOS) may be cumbersome to find or set up. By using an executable, it can look for the runtime in various places and is less dependent on a correctly set PATH environment variable.
  • On windows, people may want to change OS-specific definitions for the .exe, e.g.:
    • subsystem flag (GUI vs console app): a flag in the .exe file controls if windows will open a console window or not. java has java.exe and javaw.exe for console vs GUI programs. the required setting for .NET Core 3.0+ apps can be customized by the build process or project SDK (e.g. WinForms, WPF).
    • Embedded icon: Windows .exe files can contain icons. If you want your app (esp. GUI app) to show up in Explorer or in the Taskbar with an icon, you need an .exe file you can actually modify with the icon.
    • Embed a Win32 manifest: Manifest files can control lots of things, like elevated access requirements (these .exe files that will prompt you to allow admin access). Again something you can't do with dotnet.exe theapp.dll.

Do note that currently, this executable file generation is disabled on macOS due to Apple's notarization requirements. (Basically you would need to sign the app and apple would need to "notarize" it in order to run without warnings).

like image 38
Martin Ullrich Avatar answered Nov 02 '22 22:11

Martin Ullrich