diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 6c2c8d97..fcf874e2 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -36,11 +36,13 @@ steps: Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" +# Using the latest SDK does not prevent us from targeting other platforms. +# It ensures that we've got the latest tooling, fixes, and performance enhancements. - task: UseDotNet@2 - displayName: 'Use .NET 9 SDK' + displayName: 'Use .NET 10 SDK' inputs: packageType: sdk - version: '9.0.x' + version: '10.0.x' # Read version from the version-info artifact produced by compute_version stage. - task: PowerShell@2 @@ -127,7 +129,7 @@ steps: targetType: inline script: | $base = "$(repoRoot)/sdk/cs/src/bin/Release" - # The SDK targets net9.0 (standard) or net9.0-windows10.0.26100.0 (WinML). + # The SDK targets netstandard2.0 and any compatible runtime. # Find whichever TFM directory was produced by the build. $tfmDir = Get-ChildItem $base -Directory | Select-Object -First 1 if (-not $tfmDir) { throw "No target framework directory found under $base" } diff --git a/sdk/cs/src/Detail/CoreInterop.cs b/sdk/cs/src/Detail/CoreInterop.cs index b88f5597..eccaab09 100644 --- a/sdk/cs/src/Detail/CoreInterop.cs +++ b/sdk/cs/src/Detail/CoreInterop.cs @@ -156,41 +156,81 @@ internal CoreInterop(ILogger logger) private unsafe delegate void ExecuteCommandDelegate(RequestBuffer* req, ResponseBuffer* resp); // Import the function from the AOT-compiled library +#if NET7_0_OR_GREATER [LibraryImport(LibraryName, EntryPoint = "execute_command")] [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] private static unsafe partial void CoreExecuteCommand(RequestBuffer* request, ResponseBuffer* response); +#else + [DllImport(LibraryName, EntryPoint = "execute_command", CallingConvention = CallingConvention.Cdecl)] + private static unsafe extern void CoreExecuteCommand(RequestBuffer* request, ResponseBuffer* response); +#endif +#if NET7_0_OR_GREATER [LibraryImport(LibraryName, EntryPoint = "execute_command_with_callback")] [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] private static unsafe partial void CoreExecuteCommandWithCallback(RequestBuffer* nativeRequest, ResponseBuffer* nativeResponse, nint callbackPtr, // NativeCallbackFn pointer nint userData); +#else + [DllImport(LibraryName, EntryPoint = "execute_command_with_callback", CallingConvention = CallingConvention.Cdecl)] + private static unsafe extern void CoreExecuteCommandWithCallback(RequestBuffer* nativeRequest, + ResponseBuffer* nativeResponse, + nint callbackPtr, + nint userData); +#endif +#if NET7_0_OR_GREATER [LibraryImport(LibraryName, EntryPoint = "execute_command_with_binary")] [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] private static unsafe partial void CoreExecuteCommandWithBinary(StreamingRequestBuffer* nativeRequest, ResponseBuffer* nativeResponse); +#else + [DllImport(LibraryName, EntryPoint = "execute_command_with_binary", CallingConvention = CallingConvention.Cdecl)] + private static unsafe extern void CoreExecuteCommandWithBinary(StreamingRequestBuffer* nativeRequest, + ResponseBuffer* nativeResponse); +#endif // --- Audio streaming P/Invoke imports (kept for future dedicated entry points) --- +#if NET7_0_OR_GREATER [LibraryImport(LibraryName, EntryPoint = "audio_stream_start")] [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] private static unsafe partial void CoreAudioStreamStart( RequestBuffer* request, ResponseBuffer* response); +#else + [DllImport(LibraryName, EntryPoint = "audio_stream_start", CallingConvention = CallingConvention.Cdecl)] + private static unsafe extern void CoreAudioStreamStart( + RequestBuffer* request, + ResponseBuffer* response); +#endif +#if NET7_0_OR_GREATER [LibraryImport(LibraryName, EntryPoint = "audio_stream_push")] [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] private static unsafe partial void CoreAudioStreamPush( StreamingRequestBuffer* request, ResponseBuffer* response); +#else + [DllImport(LibraryName, EntryPoint = "audio_stream_push", CallingConvention = CallingConvention.Cdecl)] + private static unsafe extern void CoreAudioStreamPush( + StreamingRequestBuffer* request, + ResponseBuffer* response); +#endif +#if NET7_0_OR_GREATER [LibraryImport(LibraryName, EntryPoint = "audio_stream_stop")] [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] private static unsafe partial void CoreAudioStreamStop( RequestBuffer* request, ResponseBuffer* response); +#else + [DllImport(LibraryName, EntryPoint = "audio_stream_stop", CallingConvention = CallingConvention.Cdecl)] + private static unsafe extern void CoreAudioStreamStop( + RequestBuffer* request, + ResponseBuffer* response); +#endif // helper to capture exceptions in callbacks internal class CallbackHelper diff --git a/sdk/cs/src/Detail/ICoreInterop.cs b/sdk/cs/src/Detail/ICoreInterop.cs index 74e2a8ad..2bfc1789 100644 --- a/sdk/cs/src/Detail/ICoreInterop.cs +++ b/sdk/cs/src/Detail/ICoreInterop.cs @@ -22,7 +22,7 @@ internal record Response public delegate void CallbackFn(string callbackData); [StructLayout(LayoutKind.Sequential)] - protected unsafe struct RequestBuffer + public unsafe struct RequestBuffer { public nint Command; public int CommandLength; @@ -31,7 +31,7 @@ protected unsafe struct RequestBuffer } [StructLayout(LayoutKind.Sequential)] - protected unsafe struct ResponseBuffer + public unsafe struct ResponseBuffer { public nint Data; public int DataLength; @@ -42,7 +42,7 @@ protected unsafe struct ResponseBuffer // native callback function signature // Return: 0 = continue, 1 = cancel [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - protected unsafe delegate int NativeCallbackFn(nint data, int length, nint userData); + public unsafe delegate int NativeCallbackFn(nint data, int length, nint userData); Response ExecuteCommand(string commandName, CoreInteropRequest? commandInput = null); Response ExecuteCommandWithCallback(string commandName, CoreInteropRequest? commandInput, CallbackFn callback); @@ -56,7 +56,7 @@ Task ExecuteCommandWithCallbackAsync(string commandName, CoreInteropRe // --- Audio streaming session support --- [StructLayout(LayoutKind.Sequential)] - protected unsafe struct StreamingRequestBuffer + public unsafe struct StreamingRequestBuffer { public nint Command; public int CommandLength; diff --git a/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj b/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj index df8fc2cf..d9150c86 100644 --- a/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj +++ b/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj @@ -13,16 +13,15 @@ https://github.com/microsoft/Foundry-Local git - net9.0 + netstandard2.0 win-x64;win-arm64;linux-x64;linux-arm64;osx-arm64 true False enable - True - True + True enable - + latest true snupkg @@ -88,7 +87,7 @@ Microsoft.AI.Foundry.Local.WinML Microsoft.AI.Foundry.Local.WinML $(DefineConstants);IS_WINML - net9.0-windows10.0.26100.0 + net8.0-windows10.0.26100.0 win-x64;win-arm64 10.0.17763.0 @@ -128,6 +127,8 @@ + + diff --git a/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj b/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj index fe0dfcd2..7e21ff97 100644 --- a/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj +++ b/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj @@ -1,7 +1,7 @@  - net9.0 + net462;net8.0; enable enable false @@ -19,7 +19,7 @@ - net9.0-windows10.0.26100.0 + net8.0-windows10.0.26100.0; 10.0.17763.0 None