feat: Add Native AOT compilation support for LibreHardwareMonitorLib (#2280)

* feat: Add Native AOT compilation support for LibreHardwareMonitorLib

- Replace non-generic Marshal.GetDelegateForFunctionPointer with generic versions
  (NvApi.cs, NvidiaML.cs, OpCode.cs)
- Replace non-generic Marshal.PtrToStructure/SizeOf with generic versions
  (AtiAdlxx.cs, AmdGpu.cs, Ipmi.cs)
- Replace reflection-based Mono.Posix calls with direct Syscall for non-NETFRAMEWORK
  (OpCode.cs)
- Add DynamicallyAccessedMembers annotations for trim-safe generic marshaling
  (MsiCoreLiquidController.cs, WireViewPro2.cs)
- Add IsAotCompatible, IsTrimmable, and AOT/trim analyzers to csproj for net8.0+
- All changes maintain full backward compatibility with net472/netstandard2.0

Tested: dotnet publish with PublishAot=true on net10.0 win-x64 succeeds.
AOT binary correctly enumerates all hardware and sensors without errors.

* feat: Add conditional compilation for .NET 5.0 or greater in various classes

* feat: Add AOT test project and update workflows for AOT compilation

* Drop test project

* NET5_0_OR_GREATER > NET

---------

Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
This commit is contained in:
MadLongTom
2026-04-07 13:38:41 +02:00
committed by GitHub
co-authored by PhyxionNL
parent 9e831e07b2
commit aa7c8be02f
9 changed files with 64 additions and 27 deletions
+2 -2
View File
@@ -194,12 +194,12 @@ internal static class AtiAdlxx
public static ADLStatus ADL2_Adapter_AdapterInfo_Get(ref IntPtr context, ADLAdapterInfo[] info)
{
int elementSize = Marshal.SizeOf(typeof(ADLAdapterInfo));
int elementSize = Marshal.SizeOf<ADLAdapterInfo>();
int size = info.Length * elementSize;
IntPtr ptr = Marshal.AllocHGlobal(size);
ADLStatus result = ADL2_Adapter_AdapterInfo_Get(context, ptr, size);
for (int i = 0; i < info.Length; i++)
info[i] = (ADLAdapterInfo)Marshal.PtrToStructure((IntPtr)((long)ptr + (i * elementSize)), typeof(ADLAdapterInfo));
info[i] = Marshal.PtrToStructure<ADLAdapterInfo>((IntPtr)((long)ptr + (i * elementSize)));
Marshal.FreeHGlobal(ptr);
+1 -1
View File
@@ -251,7 +251,7 @@ internal static class NvApi
if (ptr != IntPtr.Zero)
{
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
return Marshal.GetDelegateForFunctionPointer<T>(ptr);
}
else
{
+9 -9
View File
@@ -201,56 +201,56 @@ internal static class NvidiaML
if (nvmlInit != IntPtr.Zero)
{
_windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate));
_windowsNvmlInit = Marshal.GetDelegateForFunctionPointer<WindowsNvmlDelegate>(nvmlInit);
}
else
{
nvmlInit = PInvoke.GetProcAddress(_windowsDll, "nvmlInit");
if (nvmlInit != IntPtr.Zero)
_windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate));
_windowsNvmlInit = Marshal.GetDelegateForFunctionPointer<WindowsNvmlDelegate>(nvmlInit);
else
return false;
}
IntPtr nvmlShutdown = PInvoke.GetProcAddress(_windowsDll, "nvmlShutdown");
if (nvmlShutdown != IntPtr.Zero)
_windowsNvmlShutdown = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlShutdown, typeof(WindowsNvmlDelegate));
_windowsNvmlShutdown = Marshal.GetDelegateForFunctionPointer<WindowsNvmlDelegate>(nvmlShutdown);
else
return false;
IntPtr nvmlGetHandle = PInvoke.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex_v2");
if (nvmlGetHandle != IntPtr.Zero)
_windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate));
_windowsNvmlDeviceGetHandleByIndex = Marshal.GetDelegateForFunctionPointer<WindowsNvmlGetHandleDelegate>(nvmlGetHandle);
else
{
nvmlGetHandle = PInvoke.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex");
if (nvmlGetHandle != IntPtr.Zero)
_windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate));
_windowsNvmlDeviceGetHandleByIndex = Marshal.GetDelegateForFunctionPointer<WindowsNvmlGetHandleDelegate>(nvmlGetHandle);
else
return false;
}
IntPtr nvmlGetPowerUsage = PInvoke.GetProcAddress(_windowsDll, "nvmlDeviceGetPowerUsage");
if (nvmlGetPowerUsage != IntPtr.Zero)
_windowsNvmlDeviceGetPowerUsage = (WindowsNvmlGetPowerUsageDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPowerUsage, typeof(WindowsNvmlGetPowerUsageDelegate));
_windowsNvmlDeviceGetPowerUsage = Marshal.GetDelegateForFunctionPointer<WindowsNvmlGetPowerUsageDelegate>(nvmlGetPowerUsage);
else
return false;
IntPtr nvmlGetPcieThroughput = PInvoke.GetProcAddress(_windowsDll, "nvmlDeviceGetPcieThroughput");
if (nvmlGetPcieThroughput != IntPtr.Zero)
_windowsNvmlDeviceGetPcieThroughputDelegate = (WindowsNvmlDeviceGetPcieThroughputDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPcieThroughput, typeof(WindowsNvmlDeviceGetPcieThroughputDelegate));
_windowsNvmlDeviceGetPcieThroughputDelegate = Marshal.GetDelegateForFunctionPointer<WindowsNvmlDeviceGetPcieThroughputDelegate>(nvmlGetPcieThroughput);
else
return false;
IntPtr nvmlGetHandlePciBus = PInvoke.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByPciBusId_v2");
if (nvmlGetHandlePciBus != IntPtr.Zero)
_windowsNvmlDeviceGetHandleByPciBusId = (WindowsNvmlGetHandleByPciBusIdDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandlePciBus, typeof(WindowsNvmlGetHandleByPciBusIdDelegate));
_windowsNvmlDeviceGetHandleByPciBusId = Marshal.GetDelegateForFunctionPointer<WindowsNvmlGetHandleByPciBusIdDelegate>(nvmlGetHandlePciBus);
else
return false;
IntPtr nvmlDeviceGetPciInfo = PInvoke.GetProcAddress(_windowsDll, "nvmlDeviceGetPciInfo_v2");
if (nvmlDeviceGetPciInfo != IntPtr.Zero)
_windowsNvmlDeviceGetPciInfo = (WindowsNvmlDeviceGetPciInfo)Marshal.GetDelegateForFunctionPointer(nvmlDeviceGetPciInfo, typeof(WindowsNvmlDeviceGetPciInfo));
_windowsNvmlDeviceGetPciInfo = Marshal.GetDelegateForFunctionPointer<WindowsNvmlDeviceGetPciInfo>(nvmlDeviceGetPciInfo);
else
return false;