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
+19 -9
View File
@@ -5,8 +5,13 @@
// All Rights Reserved.
using System;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
#if !NETFRAMEWORK
using Mono.Unix.Native;
#else
using System.Reflection;
#endif
using Windows.Win32;
using Windows.Win32.System.Memory;
@@ -207,6 +212,9 @@ internal static class OpCode
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate ulong RdtscDelegate();
#if NET
[RequiresUnreferencedCode("Dynamic code generation for OpCode delegates")]
#endif
public static unsafe void Open()
{
byte[] rdTscCode;
@@ -228,9 +236,6 @@ internal static class OpCode
{
#if NETFRAMEWORK
Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756");
#else
Assembly assembly = Assembly.Load("Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral");
#endif
Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall");
MethodInfo mmap = sysCall.GetMethod("mmap");
@@ -248,6 +253,11 @@ internal static class OpCode
if (mmap != null)
_codeBuffer = (IntPtr)mmap.Invoke(null, [IntPtr.Zero, _size, mmapProtsParam, mmapFlagsParam, -1, 0]);
#else
_codeBuffer = Syscall.mmap(IntPtr.Zero, _size,
MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC,
MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_PRIVATE, -1, 0);
#endif
}
else
{
@@ -258,10 +268,10 @@ internal static class OpCode
}
Marshal.Copy(rdTscCode, 0, _codeBuffer, rdTscCode.Length);
Rdtsc = Marshal.GetDelegateForFunctionPointer(_codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
Rdtsc = Marshal.GetDelegateForFunctionPointer<RdtscDelegate>(_codeBuffer);
IntPtr cpuidAddress = (IntPtr)((long)_codeBuffer + rdTscCode.Length);
Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
CpuId = Marshal.GetDelegateForFunctionPointer(cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;
CpuId = Marshal.GetDelegateForFunctionPointer<CpuidDelegate>(cpuidAddress);
}
public static unsafe void Close()
@@ -273,13 +283,13 @@ internal static class OpCode
{
#if NETFRAMEWORK
Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756");
#else
Assembly assembly = Assembly.Load("Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral");
#endif
Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall");
MethodInfo method = sysCall.GetMethod("munmap");
method?.Invoke(null, [_codeBuffer, _size]);
#else
Syscall.munmap(_codeBuffer, _size);
#endif
}
else
{