docs/workflow/building/coreclr/nativeaot.md
The Native AOT toolchain can be currently built for Linux (x64/arm32/arm64), macOS (x64/arm64) and Windows (x86/x64/arm64).
build[.cmd|.sh] clr.aot+libs -rc [Debug|Checked|Release] -lc Release from the repo root to build binaries for local development. This will build individual components, but not the NuGet packages and builds much faster. The -rc parameters specifies build configuration of the runtime, AOT compiler, and corelib, -lc specifies the configuration of the rest of BCL libraries. The repo and test infra generally assumes BCL libraries are compiled as Release and you're unlikely to need Debug.Once you build the repo, you can use the produced binaries in one of four ways specified below ("Using built binaries", "Building packages", "Convenience Visual Studio "repro" project", "Running tests").
In this workflow, you have a project file that you want to dotnet publish, but you want to use your own build of the compiler/runtime/framework. You need to be using a daily build of the .NET SDK downloaded from the dotnet/sdk repo. It's typically enough to just download the daily build ZIP file, unpack it, and make sure the unpacked directory is the first thing in your PATH. Don't forget to add a NuGet.config as specified by the dotnet/sdk repo- you'll hit restore issues otherwise.
The native AOT MSBuild targets allow overriding the paths to compiler/runtime/framework with the compiler/runtime/framework you just built. This requires that the SDK you're using is not too far from the runtime repo you just built. They sometimes get out of sync, if that happens you need to use the "Building packages" workflow below (you'll see issues such as missing members/types in assemblies, incorrect command line arguments passed to the compiler, and linking failures).
The paths to major components can be overridden using IlcToolsPath, IlcSdkPath, IlcFrameworkPath, IlcFrameworkNativePath and IlcMibcPath properties for dotnet publish. For example, /p:IlcToolsPath=<repo root>\artifacts\bin\coreclr\windows.x64.Debug\ilc can be used to override the compiler with a local debug build for troubleshooting or quick iterations.
Run build[.cmd|.sh] -c Release from the repo root to build the NativeAOT toolchain packages. The build will place the toolchain packages at artifacts\packages\Release\Shipping. To publish your project using these packages:
nuget.config file. For example, add <add key="local" value="C:\runtime\artifacts\packages\Release\Shipping" />dotnet add package Microsoft.DotNet.ILCompiler -v 11.0.0-dev to add the local package reference to your project.dotnet publish --packages pkg -r [win-x64|linux-x64|osx-64] -c [Debug|Release] to publish your project. --packages pkg option restores the package into a local directory that is easy to cleanup once you are done. It avoids polluting the global nuget cache with your locally built dev package.Native AOT is a stripped down version of the CoreCLR runtime specialized for ahead of time compilation, with an accompanying ahead of time compiler.
The main components of the toolchain are:
main() entrypoint and bootstraps the runtime and dispatches to managed code. Two flavors of the bootstrapper are built - one for executables, and another for dynamic libraries.dotnet publish to run the AOT compiler and execute the platform linker.The AOT compiler typically takes the app, core libraries, and framework libraries as input. It then compiles the whole program into a single object file. Then the object file is linked to form a runnable executable. The executable is standalone (doesn't require a runtime), modulo any managed DllImports.
The executable looks like a native executable, in the sense that it can be debugged with native debuggers and have full-fidelity access to locals, and stepping information.
The compiler also has a mode where each managed assembly can be compiled into a separate object file. The object files are later linked into a single executable using the platform linker. This mode is mostly used in testing (it's faster to compile this way because we don't need to recompiling the same code from e.g. CoreLib). It's not a shipping configuration and has many problems (requires exactly matching compilation settings, forfeits many optimizations, and has trouble around cross-module generic virtual method implementations).
The repository has a number of Visual Studio Solutions files (*.slnx) that are useful for editing parts of the repository. Build the repo from command line first before building using the solution files. Remember to select the appropriate configuration that you built. By default, build.cmd builds Debug x64 and so Debug and x64 must be selected in the solution build configuration drop downs.
Solutions related to this:
src\coreclr\nativeaot\nativeaot.slnx. This solution is for the runtime libraries.src\coreclr\tools\aot\ilc.slnx. This solution is for the compiler.Typical workflow for working on the compiler:
ilc.slnx in Visual StudioC:\test@obj\Release\net8.0\win-x64\native\HelloWorld.ilc.rspNOTE: this requires that you globally install the same .NET SDK version as the one that is used to build the repo. You can avoid this requirement by launching Visual Studio through the build.cmd script at the root of the repo. build.cmd -vs src\coreclr\tools\aot\ilc.slnx opens the ILC solution, build.cmd -vs nativeaot opens the native AOT solution.
Typical native AOT runtime developer scenario workflow is to native AOT compile a short piece of C# and run it. The repo contains helper projects that make debugging the AOT compiler and the runtime easier.
The workflow looks like this:
@$(ArtifactsBinDir)repro\$(TargetArchitecture)\$(Configuration)\compile-with-Release-libs.rsp. The @ at the front of the argument indicates that this is the path to the response file generated when "repro" was built. Adjust the "compile-with-Release-libs" part to "compile-with-Debug-libs" depending on how you built the libraries (the -lc argument to build.cmd). Visual Studio will expand the path to something like @C:\runtime\artifacts\bin\repro\x64\Debug\compile-with-Release-libs.rsp..obj file. You can debug the compiler and set breakpoints in it at this point..obj file we just compiled and link it with the rest of the runtime.If you haven't built the tests yet, run src\tests\build.cmd nativeaot [Debug|Release] tree nativeaot on Windows, or src/tests/build.sh -nativeaot [Debug|Release] -tree:nativeaot on Linux. This will build the smoke tests only - they usually suffice to ensure the runtime and compiler is in a workable shape. To build all Pri-0 tests, drop the tree nativeaot parameter. The Debug/Release parameter should match the build configuration you used to build the runtime.
To run all the tests that got built, run src\tests\run.cmd runnativeaottests [Debug|Release] on Windows, or src/tests/run.sh --runnativeaottests [Debug|Release] on Linux. The Debug/Release flag should match the flag that was passed to build.cmd in the previous step.
To build an individual test, follow the instructions for compiling a individual test project located in Building an Individual Test, but add /t:BuildNativeAot /p:TestBuildMode=nativeaot to the build command.
To run an individual test (after it was built), navigate to the artifacts\tests\coreclr\[windows|linux|osx[.x64.[Debug|Release]\$path_to_test directory. $path_to_test matches the subtree of src\tests. You should see a [.cmd|.sh] file there. This file is a script that will compile and launch the individual test for you. Before invoking the script, set the following environment variables:
$repo_root is the root of your clone of the repo.
Sometimes it's handy to be able to rebuild the managed test manually or run the compilation under a debugger. A response file that was used to invoke the ahead of time compiler can be found in $repo_root\artifacts\tests\coreclr\obj\[windows|linux|osx].x64.[Debug|Release]\Managed.
For more advanced scenarios, look for at Building the Tests and Building the Core_Root
Build library tests by passing the libs.tests subset together with the /p:TestNativeAot=true to build the libraries, i.e. clr.aot+libs+libs.tests /p:TestNativeAot=true together with the full arguments as specified above. Then, to run a specific library, go to the tests directory of the library and run the usual command to run tests for the library (see Running tests for a single library) but add the /p:TestNativeAot=true and the build configuration that was used, i.e. dotnet.cmd build /t:Test /p:TestNativeAot=true -c Release.
Using native sanitizers with NativeAOT requires additional care compared to using them with CoreCLR. In addition to passing the -fsanitize flag to the command that builds NativeAOT, you must also pass the EnableNativeSanitizers MSBuild property to any commands that build projects with a sanitized NativeAOT build to ensure that any sanitizer runtimes are correctly linked with the project.
If you want to know more about working with NativeAOT in general, you can check out their more in-depth docs in the src/coreclr/nativeaot subtree.