From 753296f35eb3fd5dd352026d9dbb4296e3d42dda Mon Sep 17 00:00:00 2001 From: Tianlei Wu Date: Thu, 12 Feb 2026 01:10:02 -0800 Subject: [PATCH 1/4] Add props for Linux and MacOS --- .../NativeMethods.shared.cs | 77 +---------- .../targets/netstandard/props.xml | 120 ++++++++++++++++++ 2 files changed, 123 insertions(+), 74 deletions(-) diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs index abe73b77f4071..c445453aa06c5 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs @@ -889,8 +889,8 @@ internal class NativeLib #if !NETSTANDARD2_0 && !__ANDROID__ && !__IOS__ /// /// Custom DllImportResolver to handle platform-specific library loading. - /// On Windows, it explicitly loads the library with a lowercase .dll extension to handle - /// case-sensitive filesystems. + /// It handles the addition of "lib" prefix and file extensions (.so/.dylib) for Linux/macOS, + /// and .dll extension for Windows (handling case-sensitivity). /// private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) { @@ -915,74 +915,10 @@ private static IntPtr DllImportResolver(string libraryName, Assembly assembly, D if (mappedName != null) { - // 1. Try default loading (name only) if (NativeLibrary.TryLoad(mappedName, assembly, searchPath, out IntPtr handle)) { return handle; } - - // 2. Try relative to assembly location (look into runtimes subfolders) - string assemblyLocation = null; - try { assemblyLocation = assembly.Location; } catch { } - if (!string.IsNullOrEmpty(assemblyLocation)) - { - string assemblyDir = System.IO.Path.GetDirectoryName(assemblyLocation); - string rid = RuntimeInformation.RuntimeIdentifier; - - // Probe the specific RID first, then common fallbacks for the current OS - string[] ridsToTry; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - ridsToTry = new[] { rid, "win-x64", "win-arm64" }; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - ridsToTry = new[] { rid, "linux-x64", "linux-arm64" }; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - // We no longer provide osx-x64 in official package since 1.24. - // However, we keep it in the list for build-from-source users. - ridsToTry = new[] { rid, "osx-arm64", "osx-x64" }; - } - else - { - ridsToTry = new[] { rid }; - } - - foreach (var tryRid in ridsToTry) - { - string probePath = System.IO.Path.Combine(assemblyDir, "runtimes", tryRid, "native", mappedName); - if (System.IO.File.Exists(probePath) && NativeLibrary.TryLoad(probePath, assembly, searchPath, out handle)) - { - LogLibLoad($"[DllImportResolver] Loaded {mappedName} from: {probePath}"); - return handle; - } - } - } - - // 3. Try AppContext.BaseDirectory as a fallback - string baseDir = AppContext.BaseDirectory; - if (!string.IsNullOrEmpty(baseDir)) - { - string probePath = System.IO.Path.Combine(baseDir, mappedName); - if (NativeLibrary.TryLoad(probePath, assembly, searchPath, out handle)) - { - LogLibLoad($"[DllImportResolver] Loaded {mappedName} from: {probePath}"); - return handle; - } - - string rid = RuntimeInformation.RuntimeIdentifier; - probePath = System.IO.Path.Combine(baseDir, "runtimes", rid, "native", mappedName); - if (NativeLibrary.TryLoad(probePath, assembly, searchPath, out handle)) - { - LogLibLoad($"[DllImportResolver] Loaded {mappedName} from: {probePath}"); - return handle; - } - } - - LogLibLoad($"[DllImportResolver] Failed loading {mappedName} (RID: {RuntimeInformation.RuntimeIdentifier}, Assembly: {assemblyLocation})"); - } } @@ -990,14 +926,7 @@ private static IntPtr DllImportResolver(string libraryName, Assembly assembly, D return IntPtr.Zero; } - private static void LogLibLoad(string message) - { - System.Diagnostics.Trace.WriteLine(message); - if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ORT_LOADER_VERBOSITY"))) - { - Console.WriteLine(message); - } - } + #endif [DllImport(NativeLib.DllName, CharSet = CharSet.Ansi)] diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml b/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml index c3cd38c9cd56b..8d8873fa430d1 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml +++ b/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml @@ -142,5 +142,125 @@ PreserveNewest false + + + + libonnxruntime.so + PreserveNewest + false + + + libonnxruntime_providers_shared.so + PreserveNewest + false + + + libonnxruntime_providers_cuda.so + PreserveNewest + false + + + libonnxruntime_providers_dnnl.so + PreserveNewest + false + + + libonnxruntime_providers_tensorrt.so + PreserveNewest + false + + + libonnxruntime_providers_openvino.so + PreserveNewest + false + + + + + libonnxruntime.so + PreserveNewest + false + + + libonnxruntime_providers_shared.so + PreserveNewest + false + + + libonnxruntime_providers_cuda.so + PreserveNewest + false + + + libonnxruntime_providers_dnnl.so + PreserveNewest + false + + + libonnxruntime_providers_tensorrt.so + PreserveNewest + false + + + libonnxruntime_providers_openvino.so + PreserveNewest + false + + + + + libonnxruntime.dylib + PreserveNewest + false + + + libonnxruntime_providers_shared.dylib + PreserveNewest + false + + + + + libonnxruntime.dylib + PreserveNewest + false + + + libonnxruntime_providers_shared.dylib + PreserveNewest + false + From 9d04620f0c33b7af97ec366f44b6eb3c9d75d42e Mon Sep 17 00:00:00 2001 From: Tianlei WU Date: Fri, 13 Feb 2026 16:18:24 -0800 Subject: [PATCH 2/4] update props and targets --- .../targets/native/props.xml | 37 +++ .../targets/native/targets.xml | 11 + .../targets/netstandard/props.xml | 271 ++---------------- .../targets/netstandard/targets.xml | 52 +++- .../nuget/generate_nuspec_for_native_nuget.py | 59 +++- 5 files changed, 155 insertions(+), 275 deletions(-) create mode 100644 csharp/src/Microsoft.ML.OnnxRuntime/targets/native/props.xml create mode 100644 csharp/src/Microsoft.ML.OnnxRuntime/targets/native/targets.xml diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/targets/native/props.xml b/csharp/src/Microsoft.ML.OnnxRuntime/targets/native/props.xml new file mode 100644 index 0000000000000..126f7e932200e --- /dev/null +++ b/csharp/src/Microsoft.ML.OnnxRuntime/targets/native/props.xml @@ -0,0 +1,37 @@ + + + + + + + + + + $(MSBuildThisFileDirectory)include; + %(AdditionalIncludeDirectories) + + + + + + + + + + + $(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\onnxruntime.lib; + %(AdditionalDependencies) + + + + + + + + $(MSBuildThisFileDirectory)..\..\runtimes\win-arm64\native\onnxruntime.lib; + %(AdditionalDependencies) + + + + + diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/targets/native/targets.xml b/csharp/src/Microsoft.ML.OnnxRuntime/targets/native/targets.xml new file mode 100644 index 0000000000000..33e38ece56a48 --- /dev/null +++ b/csharp/src/Microsoft.ML.OnnxRuntime/targets/native/targets.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml b/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml index 8d8873fa430d1..66ace998dac0f 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml +++ b/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/props.xml @@ -1,266 +1,37 @@ + + + - $(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) + + $(MSBuildThisFileDirectory)..\native\include; + %(AdditionalIncludeDirectories) + - - $(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) - - + + + + - $(MSBuildThisFileDirectory)../../runtimes/win-arm64/native/onnxruntime.lib;%(AdditionalDependencies) + + $(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\onnxruntime.lib; + %(AdditionalDependencies) + - + - $(MSBuildThisFileDirectory)../../runtimes/win-arm/native/onnxruntime.lib;%(AdditionalDependencies) + + $(MSBuildThisFileDirectory)..\..\runtimes\win-arm64\native\onnxruntime.lib; + %(AdditionalDependencies) + - - - $(MSBuildThisFileDirectory)../../runtimes/win-x64/native/onnxruntime.lib;%(AdditionalDependencies) - - - - - arm64 - arm - $(Platform) - - - - $(MSBuildThisFileDirectory)..\..\runtimes\win-$(EnginePlatform)\native\onnxruntime.dll - - - - - true - true - true - - - - - - onnxruntime.dll - PreserveNewest - false - - - onnxruntime_providers_shared.dll - PreserveNewest - false - - - onnxruntime_providers_cuda.dll - PreserveNewest - false - - - onnxruntime_providers_dnnl.dll - PreserveNewest - false - - - onnxruntime_providers_tensorrt.dll - PreserveNewest - false - - - onnxruntime_providers_openvino.dll - PreserveNewest - false - - - dnnl.dll - PreserveNewest - false - - - mklml.dll - PreserveNewest - false - - - libiomp5md.dll - PreserveNewest - false - - - - - onnxruntime.dll - PreserveNewest - false - - - onnxruntime_providers_shared.dll - PreserveNewest - false - - - - - onnxruntime.dll - PreserveNewest - false - - - onnxruntime_providers_shared.dll - PreserveNewest - false - - - - - libonnxruntime.so - PreserveNewest - false - - - libonnxruntime_providers_shared.so - PreserveNewest - false - - - libonnxruntime_providers_cuda.so - PreserveNewest - false - - - libonnxruntime_providers_dnnl.so - PreserveNewest - false - - - libonnxruntime_providers_tensorrt.so - PreserveNewest - false - - - libonnxruntime_providers_openvino.so - PreserveNewest - false - - - - - libonnxruntime.so - PreserveNewest - false - - - libonnxruntime_providers_shared.so - PreserveNewest - false - - - libonnxruntime_providers_cuda.so - PreserveNewest - false - - - libonnxruntime_providers_dnnl.so - PreserveNewest - false - - - libonnxruntime_providers_tensorrt.so - PreserveNewest - false - - - libonnxruntime_providers_openvino.so - PreserveNewest - false - - - - - libonnxruntime.dylib - PreserveNewest - false - - - libonnxruntime_providers_shared.dylib - PreserveNewest - false - - - - - libonnxruntime.dylib - PreserveNewest - false - - - libonnxruntime_providers_shared.dylib - PreserveNewest - false - - - + diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/targets.xml b/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/targets.xml index 637ea7af32d5b..63ea750593cb6 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/targets.xml +++ b/csharp/src/Microsoft.ML.OnnxRuntime/targets/netstandard/targets.xml @@ -1,16 +1,44 @@ - - - + + + + + + + + + + + + + + + + + <_OrtArch>x64 + <_OrtArch Condition="'$(PlatformTarget)' == 'ARM64' OR '$(Platform)' == 'ARM64'">arm64 + + + + <_OrtNativeFiles Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-$(_OrtArch)\native\*.dll" /> + + + + + + + diff --git a/tools/nuget/generate_nuspec_for_native_nuget.py b/tools/nuget/generate_nuspec_for_native_nuget.py index 1f882c847c707..a5b417563524c 100644 --- a/tools/nuget/generate_nuspec_for_native_nuget.py +++ b/tools/nuget/generate_nuspec_for_native_nuget.py @@ -983,7 +983,7 @@ def _files_list_append(key: str): ): # Process props file if is_qnn_package: - source_props = os.path.join( + source_props_native = os.path.join( args.sources_path, "csharp", "src", @@ -992,11 +992,25 @@ def _files_list_append(key: str): "netstandard", "props_qnn.xml", ) + source_props_netstandard = source_props_native else: - source_props = os.path.join( + source_props_native = os.path.join( + args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "native", "props.xml" + ) + source_props_netstandard = os.path.join( args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "netstandard", "props.xml" ) - target_props = os.path.join( + + target_props_native = os.path.join( + args.sources_path, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "native", + args.package_name + ".props", + ) + target_props_netstandard = os.path.join( args.sources_path, "csharp", "src", @@ -1005,17 +1019,33 @@ def _files_list_append(key: str): "netstandard", args.package_name + ".props", ) - copy_file(source_props, target_props) - files_list.append("') + + copy_file(source_props_native, target_props_native) + copy_file(source_props_netstandard, target_props_netstandard) + + files_list.append("') if not is_snpe_package and not is_qnn_package: - files_list.append("') - files_list.append("') + files_list.append("') + files_list.append("') # Process targets file - source_targets = os.path.join( + source_targets_native = os.path.join( + args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "native", "targets.xml" + ) + source_targets_netstandard = os.path.join( args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "netstandard", "targets.xml" ) - target_targets = os.path.join( + + target_targets_native = os.path.join( + args.sources_path, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "native", + args.package_name + ".targets", + ) + target_targets_netstandard = os.path.join( args.sources_path, "csharp", "src", @@ -1024,11 +1054,14 @@ def _files_list_append(key: str): "netstandard", args.package_name + ".targets", ) - copy_file(source_targets, target_targets) - files_list.append("') + + copy_file(source_targets_native, target_targets_native) + copy_file(source_targets_netstandard, target_targets_netstandard) + + files_list.append("') if not is_snpe_package and not is_qnn_package: - files_list.append("') - files_list.append("') + files_list.append("') + files_list.append("') # Process xamarin targets files if args.package_name == "Microsoft.ML.OnnxRuntime": From a2d2a37a51949c76d32c4613d6f92a0d383a341c Mon Sep 17 00:00:00 2001 From: Tianlei Wu Date: Fri, 13 Feb 2026 23:28:40 -0800 Subject: [PATCH 3/4] Test native dll can be copied automatically --- .../runtest.bat | 18 +++++++++++++++--- .../runtest.sh | 19 ++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.bat b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.bat index aa90744de2e17..84d591f3835f1 100755 --- a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.bat +++ b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.bat @@ -57,16 +57,28 @@ IF "%PACKAGENAME%"=="Microsoft.ML.OnnxRuntime.Gpu" set gpu_package=T IF "%PACKAGENAME%"=="Microsoft.ML.OnnxRuntime.Gpu.Windows" set gpu_package=T IF %%gpu_package%%=="T" ( set TESTONGPU=ON - %dn% test -p:DefineConstants=USE_TENSORRT test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --filter TensorRT + %dn% build test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore -p:DefineConstants=USE_TENSORRT + dir /s /b test\Microsoft.ML.OnnxRuntime.EndToEndTests\bin\onnxruntime.dll + IF %ERRORLEVEL% NEQ 0 ( + @echo "Error: onnxruntime.dll not found in the output directory after build" + EXIT 1 + ) + %dn% test -p:DefineConstants=USE_TENSORRT test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --no-build --filter TensorRT IF NOT errorlevel 0 ( @echo "Failed to build or execute the end-to-end test" EXIT 1 ) - %dn% test -p:DefineConstants=USE_CUDA test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore + %dn% test -p:DefineConstants=USE_CUDA test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --no-build ) ELSE ( - %dn% test test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore + %dn% build test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore + dir /s /b test\Microsoft.ML.OnnxRuntime.EndToEndTests\bin\onnxruntime.dll + IF %ERRORLEVEL% NEQ 0 ( + @echo "Error: onnxruntime.dll not found in the output directory after build" + EXIT 1 + ) + %dn% test test\Microsoft.ML.OnnxRuntime.EndToEndTests\Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --no-build ) IF NOT errorlevel 0 ( diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh index 91e05e6ba58a2..77047b7bb6572 100755 --- a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh +++ b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh @@ -33,18 +33,31 @@ if [ $RunTestCsharp = "true" ]; then if [ $PACKAGENAME = "Microsoft.ML.OnnxRuntime.Gpu" ] || [ $PACKAGENAME = "Microsoft.ML.OnnxRuntime.Gpu.Linux" ]; then export TESTONGPU=ON - dotnet test -p:DefineConstants=USE_CUDA $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --verbosity detailed + dotnet build -p:DefineConstants=USE_CUDA $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore + native_lib=$(find $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/bin -name "libonnxruntime.so*" -o -name "libonnxruntime.dylib" | head -1) + if [ -z "$native_lib" ]; then + echo "Error: libonnxruntime not found in output directory after build" + exit 1 + fi + echo "Found native library: $native_lib" + dotnet test -p:DefineConstants=USE_CUDA $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --no-build --verbosity detailed if [ $? -ne 0 ]; then echo "Failed to build or execute the end-to-end test" exit 1 fi dotnet test -p:DefineConstants=USE_TENSORRT $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --verbosity detailed else - dotnet test $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --verbosity detailed + dotnet build $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore + native_lib=$(find $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/bin -name "libonnxruntime.so*" -o -name "libonnxruntime.dylib" | head -1) + if [ -z "$native_lib" ]; then + echo "Error: libonnxruntime not found in output directory after build" + exit 1 + fi + echo "Found native library: $native_lib" + dotnet test $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --no-build --verbosity detailed fi if [ $? -ne 0 ]; then echo "Failed to build or execute the end-to-end test" exit 1 fi fi - From ff3d4534828c83918c3538fce371bd5a476dfb68 Mon Sep 17 00:00:00 2001 From: Tianlei Wu Date: Sat, 14 Feb 2026 09:39:17 -0800 Subject: [PATCH 4/4] lintrunner --- tools/nuget/generate_nuspec_for_native_nuget.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/nuget/generate_nuspec_for_native_nuget.py b/tools/nuget/generate_nuspec_for_native_nuget.py index a5b417563524c..42e087da79d6a 100644 --- a/tools/nuget/generate_nuspec_for_native_nuget.py +++ b/tools/nuget/generate_nuspec_for_native_nuget.py @@ -1025,8 +1025,12 @@ def _files_list_append(key: str): files_list.append("') if not is_snpe_package and not is_qnn_package: - files_list.append("') - files_list.append("') + files_list.append( + "' + ) + files_list.append( + "' + ) # Process targets file source_targets_native = os.path.join( @@ -1060,8 +1064,12 @@ def _files_list_append(key: str): files_list.append("') if not is_snpe_package and not is_qnn_package: - files_list.append("') - files_list.append("') + files_list.append( + "' + ) + files_list.append( + "' + ) # Process xamarin targets files if args.package_name == "Microsoft.ML.OnnxRuntime":