The .NET ecosystem consists of runtimes: .NET Framework, .NET Core, and Mono for Xamarin. If you want to learn what these runtimes are and how they are different, you should read this article about the .NET ecosystem.
In this article, we are going to focus on the tools and languages that make the runtimes in the .NET ecosystem work. These are the toolchains that contain languages and runtime components that make the frameworks actually work, and compile and run your code.
.NET Framework Toolchain
First, I want to discuss the toolchain for the .NET Framework. This is different form the toolchains for .NET Core and Mono for Xamarin. The purpose of the toolchain is to turn your code into a running application. In the .NET Framework, MSBuild is the linkpin that makes life easy for developers. MSBuild is a build engine, provided by Microsoft. It knows what solution files and project files are, and it knows which processes and tools to call to get your code built. Usually, MSBuild is the tool that gets invoked when you build your code in Visual Studio. You can also call MSBuild from the command line to do build automation or other more advanced things.
MSBuild knows what to build, including the files in the solution and projects. It also knows who should build those files, or rather, who should compile them. If the code that it needs to build is C# or VB.NET code, it will invoke the .NET Compiler Platform, better known as Rosyln. This contains the compilers for C# and VB.NET and exposes a number of extra functionality. Rosyln is used in many places in Visual Studio, to provide runtime compilation and code traversing capabilities. For instance, It is used to show intellisense for interactive coding assistance, and to compile your code in the watch windows in Visual Studio. In any case, when it is used for compiling code, it uses either the C# or VB.NET compiler to do so.
If the code is F# code, than the F# compiler is used. The F# compiler is not part of Rosyln at this moment. Both compilation steps result in the same thing; a DLL or executable, that contains Intermediate Language, or IL. Intermediate language is code that can be interpreted by runtimes, like the Common Language Runtime, or CLR.
The CLR contains another compiler, called the Just-In-Time-, or JIT, Compiler which compiles the Intermediate Language into native code, which is somethings that the operating system understands. It does this compilation at runtime, on demand. This is the process that makes you wait when you start a Web Application for the very first time; its Intermediate Language is compiled to native code on the fly.
Besides providing a JIT compiler, the CLR also acts as a host for running the application. Native code lives in memory and is managed by the CLR. It has tools for that, like the garbage collector, which cleans up resources in the application when they aren’t referenced anymore, to free up memory.
This is the basic process of how your code is compiled and run. Some of these tools are part of the .NET Framework such as the CLR. Others are tools that come with Visual Studio ,or as a part of the .NET Framework SDK. You can do most of the steps manually if you want to, but most of the time, all of this stuff is managed by tools like Visual Studio, which kicks off MSBuild.
.NET Core Toolchain
Now on to the .NET Core toolchain. As you can imagine, this is a mostly similar process. MSBuild is also used in the .NET Core toolchain and it also calls Roslyn to compile C# and VB.NET code, and the F# compiler, in the case of F# code. Both of these result in executables and DLLs that contain intermediate language, which is then used by the CoreCLR.
The CoreCLR is slightly different from the .NET Framework CLR. The most important difference is that CoreCLR can run on multiple platforms, like macOS and Linux, whereas the .NET Framework CLR only runs on Windows. The CoreCLR also contains a Just-In-Time Compiler that compiles Intermediate Language into native code. In this case, it can produce native code for Windows, macOS and Linux operating systems. This is the case for some of the .NET Core application workloads.
But there is another path to compile Intermediate Language code into native code. For now, this is only available for Universal Windows Application (UWP) apps. When you create a UWP app and want to deploy it to the Windows Store, it will be compiled Ahead of Time, with an Ahead-Of-Time (AOT) compiler. The AOT compiler used for this scenario today, is called .NET Native.
The AOT compiler also compiles Intermediate Language code into native code, but it produces this code as a deployable package, instead of compiling the code on demand at runtime. This provides a performance benefit. Just like in the .NET Framework, native code is run by the CoreCLR, which provides capabilities like Garbage Collection.
One thing that is also different in the .NET Core toolchain is that the CoreCLR and the native code gets loaded and kicked off by the application host process. This process actually hosts the CoreCLR and makes it run native code. The application host process often comes in the form of dotnet.exe.
So the process for .NET Core is similar but slightly different.
Mono for Xamarin Toolchain
Let’s look at Mono for Xamarin. This toolchain is different from the previous ones. Again, MSBuild is the orchestrator of the build process, but it only supports projects and files that are written in C#.
When you have C# code for an Android application, this is compiled by the Xamarin compiler, which compiles it into an executable and can package the application for use on an Android device. In any case, this contains Intermediate Language code. The Mono runtime takes the next steps.
The Mono runtime is different from the .NET Framework CLR, mainly because, like CoreCLR, it can run on multiple platforms.
It also contains a JIT compiler, which takes the Intermediate Language code and compiles it into native code, specific for that Android device on demand at runtime. Additionally, the Mono Runtime also provides runtime services like garbage collection.
This process is different when you have C# code for an iOS app. Again, this is compiled by the Xamarin compiler, but based on the type of application, the Xamarin compiler returns a different result. For IOS apps, it precompiled all the code into native code, using a C# compiler and Ahead-of-Time compiler. This is a special process that produces a package specifically for iOS, containing its native code, ARM assembly language. iOS understands this and can run it.
Let’s summarize the toolchains of the different runtimes:
- .NET Framework and .NET Core can compile C#, VB.NET and F#.
- Each of the runtime toolchains can be managed by MSBuild.
- C# and VB.NET are compiled by Roslyn, and F# is compiled by the F# compiler.
- Mono for Xamarin can only compile C# using the Xamarin compiler.
- The .NET Framework compiles Intermediate Language code into native code using the CLR.
- .NET Core does the same using CoreCLR and Mono for Xamarin does it using the JIT compiler in the Mono runtime, which it only does for Android applications.
- .NET Core compiles IL to native code Ahead of time in the case of Universal Windows Platform Store apps
- Mono for Xamarin also compiles IL to native code Ahead of Time for IOS applications.
Let me know what you think in the comments.
- .NET Standard Explained: How To Share Code - January 23, 2018
- How to Build Cross-Platform .NET Core Apps - January 15, 2018
- The .NET Ecosystem: Dive Into Runtime Tools and Languages - January 9, 2018
- The .NET Ecosystem Demystified - January 8, 2018
- Getting Started with Azure Container Instances: Tutorial with Examples - November 21, 2017