Fix NuGet DLL Loading on Linux and macOS - #27266
Conversation
Use AcesShared pool for arm64 macOS
probes runtimes/{RID}/native/ subfolders
copy dylib
There was a problem hiding this comment.
Pull request overview
This PR addresses cross-platform native library resolution for the C# ONNX Runtime NuGet packages by removing hardcoded .dll names and introducing custom resolution logic, alongside CI/packaging adjustments to ensure required macOS artifacts (notably the custom op library and dylib layout) are present during NuGet validation.
Changes:
- Updated C# P/Invoke library names to use extension-less names and added a
DllImportResolverto control native library loading behavior. - Adjusted macOS NuGet test pipeline and macOS packaging steps to ensure required test artifacts (e.g.,
libcustom_op_library.dylib) are available/located as expected. - Tweaked Linux packaging Docker image dependencies and related CI pipeline configuration.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2404_gpu | Adds additional TensorRT-related packages for the Ubuntu 24.04 GPU packaging image. |
| tools/ci_build/github/linux/copy_strip_binary.sh | Ensures libonnxruntime.dylib is a real file (not a symlink) for NuGet packaging robustness. |
| tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-steps.yml | Copies libcustom_op_library.dylib into packaging/testdata locations for macOS artifacts. |
| tools/ci_build/github/azure-pipelines/nuget/templates/test_macos.yml | Updates macOS NuGet test job pool selection and unpacks macOS artifacts into testdata/; initializes ONNX submodule for test data. |
| tools/ci_build/github/azure-pipelines/c-api-noopenmp-test-pipelines.yml | Switches macOS NuGet tests to a specific pool/demands and removes the Node.js macOS stage from this pipeline. |
| csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs | Skips a set of pretrained-model testcases on macOS. |
| csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs | Changes DllImport names to extension-less and adds a DllImportResolver to map/load native libraries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ard, fix brace style
|
Is part of the problem that the props file for the nuget package does not have logic to copy files for non-windows platforms to the build output directory? Typically the build process would copy from the relevant |
I added a section of |
but would the
FWIW we're having to manually add this copy step in the FL Local samples for Linux and we wouldn't need to do that if the props file included logic for linux. |
If we have props for Linux/MacOS, we can simplify runtime probing logic. We can address props issue in another pull request since it is a different issue. |
|
@tianleiwu If the library client already called SetDllImportResolver() for the same assembly, this change causes a fatal error and makes Onnx unusable. Therefore if the client already has a custom way of handling DLL loading issues through its own resolver, the onnx attempt at registering a resolver should not cause catastrophic failure. The minimal code fix would be something like this: An better approach would be to add a static bool somewhere to configure onnx to not try to register a custom handler. That way one could prevent race conditions of who tries to register first (which can give hard to debug and unexpected results). Anyway, as-is I cannot use the latest release because we definitely require our own handler for onnx dll loading (Windows). |
|
Summary
This PR addresses persistent native library loading issues in the ONNX Runtime NuGet package, specifically on macOS and Linux, by implementing a robust DllImportResolver. It also includes necessary pipeline and packaging adjustments to ensure required macOS artifacts are correctly located and validated during CI.
Problem
#27263 reports that
Unable to load shared library 'onnxruntime.dll' or one of its dependencies. It was caused by #26415 since the commit hard-coded onnxruntime.dll even for Linux and MacOS (The correct filename shall be libonnxruntime.so for Linux, and libonnxruntime.dylib for MacOS).The Nuget test pipeline has been broken for a while, so we also need fix the pipeline to test our change. It has the following issues:
macOS-15is x64.Changes
1. Robust C# DLL Resolution
The DllImportResolver has been enhanced to handle various deployment scenarios where standard .NET resolution might fail:
onnxruntime,ortextensions) to appropriate filenames (onnxruntime.dll,libonnxruntime.so,libonnxruntime.dylib) based on the OS.NativeLibrary.TryLoadwith the mapped name.runtimesProbing: If the above fails, it probes theruntimes/{rid}/native/subdirectories relative to the assembly location, covering common RIDs (win-x64,linux-arm64,osx-arm64, etc.).AppContext.BaseDirectory.2. macOS CI/Packaging Improvements
libcustom_op_library.dylibis placed in the expected location (testdata/testdata) for end-to-end tests.AcesShared).copy_strip_binary.shscript now ensureslibonnxruntime.dylibis a real file rather than a symlink, improving NuGet packaging reliability.3. Test Refinements
Verification
Pipelines
NuGet_Test_MacOS.NuGet_Test_Linux.Net Effect
The C# bindings are now significantly more resilient to different deployment environments. The CI process for macOS is also more robust, correctly handling the artifacts required for comprehensive NuGet validation.