In the previous part of the article I talked about ways to make program independent of operating system. I already briefly explained the basics of Just-in-time compilation and its drawbacks so today I would like to finish off this two-part article by talking about Ahead of time compilation and some of it’s concrete implementations.
Ahead of time compilation
Ahead of time compilation (AOT) is an approach that allows you to compile your code into machine code beforehand (or at least some of it).
As of today, there are multiple options for how to handle ahead of time compilation(AOT), most notably Ngen, Crossgen (2), Native AOT, Mono AOT, etc.
Implementation of an optimal AOT compiler is an ongoing process and each solution has its own set of drawbacks. The most notable one is the inability to compile your entire codebase into the machine code. Usually, your machine code is accompanied by an IL version of the code that serves as a fallback.
Ngen is one of the first AOT compilers, but some may argue it’s not an “Ahead of time compilator” in a true sense. Ngen is not run during the compilation of the source code but during installation on the client’s machine. Windows caches generated the native code so that it can be used (or reused) later instead of generating the native code each time the program is run.
Crossgen 2 is a part of the .NET 6 release and it’s the youngest member of the “gen” family tree:
Ngen is the oldest version of the AOT compiler used for the .NET framework and crossgen is its newer version targeting the .NET core. Crossgen generates a native image which contains native code that will be used during runtime. The downside is that the resulting size of the build is greatly increased as native code is shipped with the original IL code.
The feature can be enabled simply by adding this element to your .csproj file:
Another very anticipated tool is Native AOT. It will be released with the .NET 7 but you can already try it as a part of the .NET 7 preview. The main advantage of NativeAOT is that it generates only native code unlike the other AOT compilers. NativeAOT comes with certain limitations as some features require JIT to work e.g. no dynamic loading (Assembly.LoadFile) and no runtime generation (System.Reflection.Emit).
To install the compiler, you will need the package Microsoft.DotNet.ILCompiler.
For a more detailed installation guide, please visit: Compiling with Native AOT (GitHub)
A viable alternatives for .NET compilation
In this two-part article, I presented a couple of ways how we can shift a little bit from the standard .NET paradigm that it was built upon in terms of independency on language runtime (at cost of specifying target runtime) and usage of AOT compiler rather than JIT compiler. Presented features and tools should not be considered as a “future” toward which .NET is moving but rather an alternative path that might be useful for your case.
Want to learn more?
- .NET Runtime - Native AOT (GitHub)
- ReadyToRun Compilation (Microsoft Learn)
- Conversation about crossgen2 (Microsoft .NET Blog)
- Publish self-contained (Microsoft Learn)
- Limitations of Native AOT deployment (Microsoft Learn)
Thank you very much for reading the article.
Senior .NET developer