.net-7.0.net-8.0ahead-of-time-compile

Is it possible to use .Net AOT (Ahead-Of-Time) compilation for only some of my application projects, but not all of them?


I'm a bit confused about the .Net AOT (Ahead-Of-Time) compilation capabilities in .Net 7.0 and .Net 8.0.

I understand that it's possible to publish and deploy a whole application as a Native AOT application, if it meets certain criteria (https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=net7%2Cwindows). The limitations described speak in terms of the whole application (i.e., "Native AOT apps have the following limitations: No C++\CLI...." etc.), while the property is defined in a project file.

My question is, is it possible to define only a single project in your solution to be compiled to machine code using AOT (Ahead-Of-Time) compilation, or only some of them, while leaving the rest of the application projects to use the JIT compiler?

I've tried setting the property as true for a single infrastructure project in my solution and then publish my application, but I think it had no effect on the resulting files.


Solution

  • You can publish a DLL project with AOT and have other non-AOT projects in the same solution, but there are some heavy restrictions. Mainly:

    1. All arguments to externally-accessible methods must be primitive or properly marshaled by the compiler or your AOT DLL code. If you can't reliably marshal it, then you can't pass that argument.
    2. All externally-accessible methods in the AOT DLL must be static. (I suspect this is because marshaling a first 'this' argument is not reliable, but maybe there's a way)
    3. All externally-accessible methods in your AOT code must be preceded with: [UnmanagedCallersOnly(EntryPoint = "MyMethodName")]
    4. The AOT project can't have any references to other projects, and no other project can have a project reference to the AOT project. You can, of course, simply share source files (have a project source file as a link)
    5. Some C# assemblies are not compatible with AOT or the trimming that goes along with it. (Although you can disable and control trimming with certain project vars: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0)

    Then, of course, put this in the AOT project file:

    <PropertyGroup>
      <PublishAot>true</PublishAot>
    </PropertyGroup>
    

    And enable AOT warnings:

    <PropertyGroup>
      <IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
    </PropertyGroup>
    

    ...and publish like this (run this in the project directory, or as a post build event of another project than the AOT project, since it would recurse forever if it were in the AOT project):

    dotnet publish -r win-x64
    

    Your C# projects must include the DLL in their output directory (for example, include the DLL file in the project but mark it as 'Content' that should be copied to the output folder) and then call those AOT methods just as they would call a C++ function in a C++ DLL, like this, for example:

    [DllImport("MyAotDll.dll")]
    public static extern int MyMethodName();
    ...
    MyMethodName();
    

    So, publishing a C# DLL as a AOT DLL is as if you converted it to C++ and then built the C++ DLL. In fact, one advantage of an AOT DLL is that any unmanaged language can call its functions.