|
| 1 | +# Native AOT Developer Workflow |
| 2 | + |
| 3 | +The Native AOT toolchain can be currently built for Linux (x64/arm64), macOS (x64) and Windows (x64/arm64). |
| 4 | + |
| 5 | +## High Level Overview |
| 6 | + |
| 7 | +Native AOT is a stripped down version of the CoreCLR runtime specialized for ahead of time compilation, with an accompanying ahead of time compiler. |
| 8 | + |
| 9 | +The main components of the toolchain are: |
| 10 | + |
| 11 | +* The AOT compiler (ILC/ILCompiler) built on a shared codebase with crossgen2 (src/coreclr/tools/aot). Where crossgen2 generates ReadyToRun modules that contain code and data structures for the CoreCLR runtime, ILC generates code and self-describing datastructures for a stripped down version of CoreCLR into object files. The object files use platform specific file formats (COFF with CodeView on Windows, ELF with DWARF on Linux, and Mach-O with DWARF on macOS). |
| 12 | +* The stripped down CoreCLR runtime (NativeAOT specific files in src/coreclr/nativeaot/Runtime, the rest included from the src/coreclr). The stripped down runtime is built into a static library that is linked with object file generated by the AOT compiler using a platform-specific linker (link.exe on Windows, ld on Linux/macOS) to form a standalone executable. |
| 13 | +* The bootstrapper library (src/coreclr/nativeaot/Bootstrap). This is a small native library that contains the actual native `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. |
| 14 | +* The core libraries (src/coreclr/nativeaot): System.Private.CoreLib (corelib), System.Private.Reflection.* (the implementation of reflection), System.Private.TypeLoader (ability to load new types that were not generated statically). |
| 15 | +* The dotnet integration (src/coreclr/nativeaot/BuildIntegration). This is a set of .targets/.props files that hook into `dotnet publish` to run the AOT compiler and execute the platform linker. |
| 16 | + |
| 17 | +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. |
| 18 | + |
| 19 | +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. |
| 20 | + |
| 21 | +## Building |
| 22 | + |
| 23 | +- [Install pre-requisites](../../README.md#build-requirements) |
| 24 | +- Run `build[.cmd|.sh] clr+libs -rc [Debug|Release] -lc Release` from the repo root. This will restore nuget packages required for building and build the parts of the repo required for general CoreCLR development. Alternatively, instead of specifying `clr+libs`, you can specify `clr.jit+clr.tools+clr.nativeaotlibs+libs` which is more targeted and builds faster. Replace `clr.jit` with `clr.alljits` if you need to crosscompile. |
| 25 | +- [NOT PORTED OVER YET] The build will place the toolchain packages at `artifacts\packages\[Debug|Release]\Shipping`. To publish your project using these packages: |
| 26 | + - [NOT PORTED OVER YET] Add the package directory to your `nuget.config` file. For example, replace `dotnet-experimental` line in `samples\HelloWorld\nuget.config` with `<add key="local" value="C:\runtimelab\artifacts\packages\Debug\Shipping" />` |
| 27 | + - [NOT PORTED OVER YET] Run `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. |
| 28 | +- *Optional*. The ObjWriter component of the AOT compiler is not built by default. If you're working on ObjWriter or bringing up a new platform that doesn't have ObjWriter packages yet, as additional pre-requiresites you need to run `build[.cmd|.sh] clr.objwriter` from the repo root before building the product. |
| 29 | + |
| 30 | +## Visual Studio Solutions |
| 31 | + |
| 32 | +The repository has a number of Visual Studio Solutions files (`*.sln`) 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. |
| 33 | + |
| 34 | +- `src\coreclr\nativeaot\nativeaot.sln`. This solution is for the runtime libraries. |
| 35 | +- `src\coreclr\tools\aot\ilc.sln`. This solution is for the compiler. |
| 36 | + |
| 37 | +Typical workflow for working on the compiler: |
| 38 | +- Open `ilc.sln` in Visual Studio |
| 39 | +- Set "ILCompiler" project in solution explorer as your startup project |
| 40 | +- Set Working directory in the project Debug options to your test project directory, e.g. `C:\runtimelab\samples\HelloWorld` |
| 41 | +- Set Application arguments in the project Debug options to the response file that was generated by regular native aot publishing of your test project, e.g. `@obj\Release\net6.0\win-x64\native\HelloWorld.ilc.rsp` |
| 42 | +- Build & run using **F5** |
| 43 | + |
| 44 | +## Convenience Visual Studio "repro" project |
| 45 | + |
| 46 | +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. |
| 47 | + |
| 48 | +The workflow looks like this: |
| 49 | + |
| 50 | +- Build the repo using the Building instructions above |
| 51 | +- Open the ilc.sln solution described above. This solution contains the compiler, but also an unrelated project named "repro". This repro project is a small Hello World. You can place any piece of C# you would like to compile in it. Building the project will compile the source code into IL, but also generate a response file that is suitable to pass to the AOT compiler. |
| 52 | +- Make sure you set the solution configuration in VS to the configuration you just built (e.g. x64 Debug). |
| 53 | +- In the ILCompiler project properties, on the Debug tab, set the "Application arguments" to the generated response file. This will be a file such as "C:\runtime\artifacts\bin\repro\x64\Debug\compile-with-Release-libs.rsp". Prefix the path to the file with "@" to indicate this is a response file so that the "Application arguments" field looks like "@some\path\to\file.rsp". |
| 54 | +- Build & run ILCompiler using **F5**. This will compile the repro project into an `.obj` file. You can debug the compiler and set breakpoints in it at this point. |
| 55 | +- The last step is linking the object file into an executable so that we can launch the result of the AOT compilation. |
| 56 | +- Open the src\coreclr\tools\aot\ILCompiler\reproNative\reproNative.vcxproj project in Visual Studio. This project is configured to pick up the `.obj` file we just compiled and link it with the rest of the runtime. |
| 57 | +- Set the solution configuration to the tuple you've been using so far (e.g. x64 Debug) |
| 58 | +- Build & run using **F5**. This will run the platform linker to link the obj file with the runtime and launch it. At this point you can debug the runtime and the various System.Private libraries. |
| 59 | + |
| 60 | +## Running tests |
| 61 | + |
| 62 | +If you haven't built the tests yet, run `src\tests\build[.cmd|.sh] nativeaot [Debug|Release] tree nativeaot`. 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. |
| 63 | + |
| 64 | +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. |
| 65 | + |
| 66 | +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: |
| 67 | + |
| 68 | +* CORE_ROOT=$repo_root\artifacts\tests\coreclr\[Windows|Linux|OSX[.x64.[Debug|Release]\Tests\Core_Root |
| 69 | +* RunNativeAot=1 |
| 70 | +* __TestDotNetCmd=$repo_root\dotnet[.cmd|.sh] |
| 71 | + |
| 72 | +`$repo_root` is the root of your clone of the repo. |
| 73 | + |
| 74 | +By default the test suite will delete the build artifacts (Native AOT images and response files) if the test compiled successfully. If you want to keep these files instead of deleting them after test run, set the following environment variables and make sure you'll have enough disk space (tens of MB per test): |
| 75 | + |
| 76 | +* CLRTestNoCleanup=1 |
| 77 | + |
| 78 | +For more advanced scenarios, look for at [Building Test Subsets](../../testing/coreclr/windows-test-instructions.md#building-test-subsets) and [Generating Core_Root](../../testing/coreclr/windows-test-instructions.md#generating-core_root) |
| 79 | + |
| 80 | +## Design Documentation |
| 81 | + |
| 82 | +- [ILC Compiler Architecture](../../../design/coreclr/botr/ilc-architecture.md) |
| 83 | +- [Managed Type System](../../../design/coreclr/botr/managed-type-system.md) |
0 commit comments