Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

NativeSdk

NuGet NuGet Downloads

A MSBuild SDK package for building Native AOT applications and libraries with C#.

Requirements

  • .NET 8.0 or later

Installation

Use NativeSdk as your project SDK:

<Project Sdk="NativeSdk/0.5.2">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
    </PropertyGroup>
</Project>

This SDK automatically inherits from Microsoft.NET.Sdk, so you don't need to specify it separately.

Features

This SDK automatically configures your project with:

Common Settings (All Project Types)

Setting Default Value Description
OutputType Exe Builds as executable by default
PublishAot true Enables Native AOT compilation
IsAotCompatible true Marks the project as AOT compatible
AllowUnsafeBlocks true Enables unsafe code
TrimMode full Full trimming for size optimization
InvariantGlobalization true Invariant globalization mode
EnableTrimAnalyzer true Enables trim compatibility analyzer
EnableAotAnalyzer true Enables AOT compatibility analyzer
TreatWarningsAsErrors true Treats warnings as errors

Default Using Namespaces

The following namespaces are automatically included for Interop scenarios:

Namespace Description
System.Runtime.InteropServices Core interop types ([DllImport], [UnmanagedCallersOnly], Marshal)
System.Runtime.InteropServices.Marshalling Source-generated marshalling ([LibraryImport])
System.Runtime.CompilerServices Compiler services ([SkipLocalsInit], Unsafe)
System.Buffers Buffer operations (Span<T>, Memory<T>)

Library-Specific Settings

When OutputType is set to Library, the following additional settings are applied:

Setting Default Value Description
NativeLib Shared Builds as a shared/dynamic library (can be overridden to Static)
DnneGenerateExports true DNNE export generation enabled
DnneBuildExports false DNNE build exports disabled

Debug Configuration

  • Stack trace support enabled
  • Metadata preserved for debugging

Release Configuration

  • Stack trace support disabled
  • Metadata trimmed for smaller binaries

Usage Examples

Building a Native Executable (Default)

<Project Sdk="NativeSdk/0.5.2">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
    </PropertyGroup>
</Project>

Building a Shared Library (DLL/SO)

<Project Sdk="NativeSdk/0.5.2">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <OutputType>Library</OutputType>
    </PropertyGroup>
</Project>

Building a Static Library

<Project Sdk="NativeSdk/0.5.2">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <OutputType>Library</OutputType>
        <NativeLib>Static</NativeLib>
    </PropertyGroup>
</Project>

Pointer-based QuickSort

This example demonstrates using unsafe pointers with stackalloc for high-performance sorting:

unsafe
{
    const int ArraySize = 10;

    // Allocate memory on the stack using stackalloc
    int* arr = stackalloc int[ArraySize];

    // Initialize array with random values
    Random rand = new(42);
    Console.WriteLine("Before sorting:");
    for (int i = 0; i < ArraySize; i++)
    {
        arr[i] = rand.Next(1, 100);
        Console.Write($"{arr[i]} ");
    }
    Console.WriteLine();

    // Execute QuickSort
    QuickSort(arr, 0, ArraySize - 1);

    // Print sorted result
    Console.WriteLine("\nAfter sorting:");
    for (int i = 0; i < ArraySize; i++)
    {
        Console.Write($"{arr[i]} ");
    }
    Console.WriteLine();

    static void QuickSort(int* arr, int left, int right)
    {
        if (left >= right) return;

        int pivotIndex = Partition(arr, left, right);
        QuickSort(arr, left, pivotIndex - 1);
        QuickSort(arr, pivotIndex + 1, right);
    }

    static int Partition(int* arr, int left, int right)
    {
        int pivot = arr[right];
        int i = left - 1;

        for (int j = left; j < right; j++)
        {
            if (arr[j] <= pivot)
            {
                i++;
                (arr[i], arr[j]) = (arr[j], arr[i]);  // Tuple swap
            }
        }

        (arr[i + 1], arr[right]) = (arr[right], arr[i + 1]);
        return i + 1;
    }
}

DNNE Integration

This SDK includes DNNE for generating native exports when building as a library. Use the [UnmanagedCallersOnly] attribute to export functions:

public static class NativeExports
{
    [UnmanagedCallersOnly(EntryPoint = "add")]
    public static int Add(int a, int b) => a + b;
}

Note: DNNE is only included when OutputType is set to Library. The System.Runtime.InteropServices namespace is already included by default.

Customization

All settings can be overridden in your project file:

<PropertyGroup>
  <!-- Build as library instead of executable -->
  <OutputType>Library</OutputType>
  
  <!-- Change to static library -->
  <NativeLib>Static</NativeLib>
  
  <!-- Optimize for size instead of speed -->
  <IlcOptimizationPreference>Size</IlcOptimizationPreference>
  
  <!-- Disable unsafe code -->
  <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>

Building

dotnet publish -c Release -r win-x64
dotnet publish -c Release -r linux-x64
dotnet publish -c Release -r osx-arm64

License

MIT