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.
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.
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.
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#.
Android
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.
iOS
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:
I hope that learning about these toolchains provides you with more context around the different runtimes and what makes them work the way they do.
With APM, server health metrics, and error log integration, improve your application performance with Stackify Retrace. Try your free two week trial today
If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]