Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 103 additions & 8 deletions csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using static Microsoft.ML.OnnxRuntime.NativeMethods;

Expand Down Expand Up @@ -474,6 +475,12 @@ internal static class NativeMethods

static NativeMethods()
{
#if !NETSTANDARD2_0 && !__ANDROID__ && !__IOS__
// Register a custom DllImportResolver to handle platform-specific library loading.
// Replaces default resolution specifically on Windows for case-sensitivity.
NativeLibrary.SetDllImportResolver(typeof(NativeMethods).Assembly, DllImportResolver);
#endif

#if NETSTANDARD2_0
IntPtr ortApiBasePtr = OrtGetApiBase();
OrtApiBase ortApiBase = (OrtApiBase)Marshal.PtrToStructure(ortApiBasePtr, typeof(OrtApiBase));
Expand Down Expand Up @@ -847,7 +854,7 @@ static NativeMethods()
api_.CreateSyncStreamForEpDevice,
typeof(DOrtCreateSyncStreamForEpDevice));

OrtSyncStream_GetHandle =
OrtSyncStream_GetHandle =
(DOrtSyncStream_GetHandle)Marshal.GetDelegateForFunctionPointer(
api_.SyncStream_GetHandle,
typeof(DOrtSyncStream_GetHandle));
Expand All @@ -872,11 +879,98 @@ internal class NativeLib
// Define the library name required for iOS
internal const string DllName = "__Internal";
#else
// Note: the file name in ONNX Runtime nuget package must be onnxruntime.dll instead of onnxruntime.DLL(Windows filesystem can be case sensitive)
internal const string DllName = "onnxruntime.dll";
// For desktop platforms (including .NET Standard 2.0), we use the simple name
// to allow .NET's automatic platform-specific resolution (lib*.so, lib*.dylib, *.dll).
// For .NET Core 3.0+, case-sensitivity on Windows is handled by DllImportResolver.
internal const string DllName = "onnxruntime";
#endif
}

#if !NETSTANDARD2_0 && !__ANDROID__ && !__IOS__
/// <summary>
/// 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.
/// </summary>
private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName == NativeLib.DllName || libraryName == OrtExtensionsNativeMethods.ExtensionsDllName)
{
string mappedName = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Explicitly load with .dll extension to avoid issues where the OS might try .DLL
mappedName = libraryName + ".dll";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// Explicitly load with .so extension and lib prefix
mappedName = "lib" + libraryName + ".so";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
// Explicitly load with .dylib extension and lib prefix
mappedName = "lib" + libraryName + ".dylib";
}

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;

// We no longer support osx-x64 after 1.24
string[] ridsToTry = { rid, "win-x64", "win-arm64", "linux-x64", "linux-arm64", "osx-arm64"};
foreach (var tryRid in ridsToTry)
{
string probePath = System.IO.Path.Combine(assemblyDir, "runtimes", tryRid, "native", mappedName);
if (System.IO.File.Exists(probePath))
{
if (NativeLibrary.TryLoad(probePath, assembly, searchPath, out handle))
{
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))
{
return handle;
}

string rid = RuntimeInformation.RuntimeIdentifier;
probePath = System.IO.Path.Combine(baseDir, "runtimes", rid, "native", mappedName);
if (NativeLibrary.TryLoad(probePath, assembly, searchPath, out handle))
{
return handle;
}
}

System.Console.WriteLine($"[DllImportResolver] Failed loading {mappedName} (RID: {RuntimeInformation.RuntimeIdentifier}, Assembly: {assemblyLocation})");
}
}

// Fall back to default resolution
return IntPtr.Zero;
}
#endif

[DllImport(NativeLib.DllName, CharSet = CharSet.Ansi)]
#if NETSTANDARD2_0
public static extern IntPtr OrtGetApiBase();
Expand Down Expand Up @@ -2644,7 +2738,7 @@ public delegate void DOrtAddKeyValuePair(IntPtr /* OrtKeyValuePairs* */ kvps,
byte[] /* const char* */ value);

/// <summary>
/// Get the value for the provided key.
/// Get the value for the provided key.
/// </summary>
/// <returns>Value. Returns IntPtr.Zero if key was not found.</returns>
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
Expand Down Expand Up @@ -2767,7 +2861,7 @@ out IntPtr /* OrtSyncStream** */ stream
// Auto Selection EP registration and selection customization

/// <summary>
/// Register an execution provider library.
/// Register an execution provider library.
/// The library must implement CreateEpFactories and ReleaseEpFactory.
/// </summary>
/// <param name="env">Environment to add the EP library to.</param>
Expand Down Expand Up @@ -2952,9 +3046,10 @@ internal static class OrtExtensionsNativeMethods
#elif __IOS__
internal const string ExtensionsDllName = "__Internal";
#else
// For desktop platforms, explicitly specify the DLL name with extension to avoid
// issues on case-sensitive filesystems. See NativeLib.DllName for detailed explanation.
internal const string ExtensionsDllName = "ortextensions.dll";
// For desktop platforms, use the simple name to allow .NET's
// automatic platform-specific resolution (lib*.so, lib*.dylib, *.dll).
// Case-sensitivity on Windows is handled by DllImportResolver.
internal const string ExtensionsDllName = "ortextensions";
#endif

[DllImport(ExtensionsDllName, CharSet = CharSet.Ansi,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,30 @@ public void TestPretrainedModelsWithOrtValue(string opsetDir, string modelName)
[MemberData(nameof(GetSkippedModelForTest), Skip = "Skipped due to Error, please fix the error and enable the test")]
private void TestPreTrainedModels(string opsetDir, string modelName, bool useOrtValueAPIs = false)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
var skipModels = new HashSet<string>
{
"test_castlike_FLOAT_to_STRING_expanded",
"test_castlike_FLOAT_to_BFLOAT16_expanded",
"test_castlike_BFLOAT16_to_FLOAT",
"test_cast_FLOAT_to_STRING",
"test_castlike_FLOAT_to_BFLOAT16",
"test_castlike_STRING_to_FLOAT_expanded",
"test_castlike_STRING_to_FLOAT",
"test_cast_STRING_to_FLOAT",
"test_castlike_BFLOAT16_to_FLOAT_expanded",
"test_cast_BFLOAT16_to_FLOAT",
"test_castlike_FLOAT_to_STRING"
};

if (skipModels.Contains(modelName))
{
output.WriteLine($"Skipping {modelName} on macOS");
return;
}
}

var opsetDirInfo = new DirectoryInfo(opsetDir);
var opset = opsetDirInfo.Name;
string onnxModelFileName = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ stages:

- template: nuget/templates/test_macos.yml
parameters:
AgentPool: macOS-14
AgentPool: 'AcesShared'
PoolDemands: 'ImageOverride -equals ACES_VM_SharedPool_Sequoia'
ArtifactSuffix: 'CPU'

- template: nodejs/templates/test_win.yml
Expand All @@ -117,10 +118,6 @@ stages:
AgentPool: 'onnxruntime-Ubuntu2204-AMD-CPU'
StageSuffix: 'Linux_CPU_x64'

- template: nodejs/templates/test_macos.yml
parameters:
StageSuffix: 'macOS_CPU_x64'

- template: nuget/templates/test_win.yml
parameters:
AgentPool: 'onnxruntime-Win2022-GPU-A10'
Expand Down Expand Up @@ -225,7 +222,7 @@ stages:
- checkout: self
clean: true
submodules: none

- download: build
artifact: 'Windows_Packaging_tensorrt_build_artifacts'
displayName: 'Download Windows GPU Packages Build'
Expand All @@ -246,7 +243,7 @@ stages:
versionSpec: "17"
jdkArchitectureOption: x64
jdkSourceOption: 'PreInstalled'

- task: PythonScript@0
displayName: 'Update CTest Path References'
inputs:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
parameters:
AgentPool : 'macOS-15'
IsMacOS : 'true'
ArtifactSuffix: ''
PoolDemands: ''

stages:
- stage: NuGet_Test_MacOS
dependsOn:
Expand All @@ -11,7 +14,12 @@ stages:
workspace:
clean: all
pool:
vmImage: 'macOS-15'
${{ if contains(parameters.AgentPool, '-') }}:
vmImage: ${{ parameters.AgentPool }}
${{ else }}:
name: ${{ parameters.AgentPool }}
${{ if ne(parameters.PoolDemands, '') }}:
demands: ${{ parameters.PoolDemands }}

variables:
- name: OnnxRuntimeBuildDirectory
Expand All @@ -27,18 +35,33 @@ stages:

- script: |
mv $(Pipeline.Workspace)/build/drop-signed-nuget-${{ parameters.ArtifactSuffix }} $(Build.BinariesDirectory)/nuget-artifact
mv $(Pipeline.Workspace)/build/onnxruntime-osx $(Build.BinariesDirectory)/testdata

# Artifact is a folder containing tgz. Extract it to testdata.
mkdir -p $(Build.BinariesDirectory)/testdata
tar -xzf $(Pipeline.Workspace)/build/onnxruntime-osx/*.tgz -C $(Build.BinariesDirectory)/testdata

# Ensure libcustom_op_library.dylib is where EndToEndTests expects it (testdata/testdata)
mkdir -p $(Build.BinariesDirectory)/testdata/testdata
find $(Build.BinariesDirectory)/testdata -name "libcustom_op_library.dylib" -exec cp {} $(Build.BinariesDirectory)/testdata/testdata/ \;


- template: get-nuget-package-version-as-variable.yml
parameters:
packageFolder: '$(Build.BinariesDirectory)/nuget-artifact'

- script: |
git submodule update --init cmake/external/onnx
cd cmake/external/onnx
git checkout v1.13.1
cd ../../..
displayName: 'Initialize ONNX submodule for test data (pinned to v1.13.1 since new data types like float8 is not supported in nuget)'

- script: |
$(Build.SourcesDirectory)/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh \
$(Build.BinariesDirectory)/nuget-artifact \
$(NuGetPackageVersionNumber) \
true

if [ $? -ne 0 ]; then
echo "Failed to run test"
exit 1
Expand All @@ -48,4 +71,4 @@ stages:
OnnxRuntimeBuildDirectory: $(Build.BinariesDirectory)
DisableContribOps: $(DisableContribOps)
DisableMlOps: $(DisableMlOps)
IsReleaseBuild: $(IsReleaseBuild)
IsReleaseBuild: $(IsReleaseBuild)
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ steps:
args: '-r $(Build.BinariesDirectory) -a onnxruntime-osx-${{ parameters.MacosArch }}-$(OnnxRuntimeVersion) -l libonnxruntime.$(OnnxRuntimeVersion).dylib -c Release -s $(Build.SourcesDirectory) -t $(Build.SourceVersion)'
workingDirectory: '$(Build.BinariesDirectory)/Release'

- bash: |
mkdir -p $(Build.BinariesDirectory)/onnxruntime-osx-${{ parameters.MacosArch }}-$(OnnxRuntimeVersion)/testdata
cp $(Build.BinariesDirectory)/Release/libcustom_op_library.dylib $(Build.BinariesDirectory)/onnxruntime-osx-${{ parameters.MacosArch }}-$(OnnxRuntimeVersion)/testdata/libcustom_op_library.dylib
# Copy to testdata/testdata so EndToEndTests can find it when running in Debug configuration
mkdir -p $(Build.BinariesDirectory)/testdata/testdata
cp $(Build.BinariesDirectory)/Release/libcustom_op_library.dylib $(Build.BinariesDirectory)/testdata/testdata/libcustom_op_library.dylib
displayName: 'Copy custom op library'
condition: succeeded()

- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(Build.BinariesDirectory)/onnxruntime-osx-${{ parameters.MacosArch }}-$(OnnxRuntimeVersion)'
Expand Down
10 changes: 10 additions & 0 deletions tools/ci_build/github/linux/copy_strip_binary.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
set -e -o -x

while getopts r:a:l:c:s:t: parameter_Option
do case "${parameter_Option}"

Check warning on line 5 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Invalid flags are not handled. Add a *) case. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:5:4: warning: Invalid flags are not handled. Add a *) case. (ShellCheck.SC2220)
in
r) BINARY_DIR=${OPTARG};;
a) ARTIFACT_NAME=${OPTARG};;
l) LIB_NAME=${OPTARG};;
c) BUILD_CONFIG=${OPTARG};;

Check warning on line 10 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 BUILD_CONFIG appears unused. Verify use (or export if used externally). Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:10:4: warning: BUILD_CONFIG appears unused. Verify use (or export if used externally). (ShellCheck.SC2034)
s) SOURCE_DIR=${OPTARG};;
t) COMMIT_ID=${OPTARG};;
esac
Expand All @@ -17,16 +17,26 @@

uname -a
cd "$BINARY_DIR"
mv installed/usr/local $ARTIFACT_NAME

Check warning on line 20 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:20:24: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)
mv $ARTIFACT_NAME/include/onnxruntime/* $ARTIFACT_NAME/include

Check warning on line 21 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:21:41: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)

Check warning on line 21 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:21:4: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)
rmdir $ARTIFACT_NAME/include/onnxruntime

Check warning on line 22 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:22:7: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)
# Do not ship onnx_test_runner
rm -rf $ARTIFACT_NAME/bin

Check warning on line 24 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:24:8: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)

Check warning on line 24 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Use "${var:?}" to ensure this never expands to /bin . Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:24:8: warning: Use "${var:?}" to ensure this never expands to /bin . (ShellCheck.SC2115)
echo "Copy debug symbols in a separate file and strip the original binary."
if [[ $LIB_NAME == *.dylib ]]
then
dsymutil $BINARY_DIR/$ARTIFACT_NAME/lib/$LIB_NAME -o $BINARY_DIR/$ARTIFACT_NAME/lib/$LIB_NAME.dSYM

Check warning on line 28 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:28:26: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)

Check warning on line 28 in tools/ci_build/github/linux/copy_strip_binary.sh

View workflow job for this annotation

GitHub Actions / Optional Lint

[shellcheck] reported by reviewdog 🐶 Double quote to prevent globbing and word splitting. Raw Output: ./tools/ci_build/github/linux/copy_strip_binary.sh:28:14: info: Double quote to prevent globbing and word splitting. (ShellCheck.SC2086)
strip -S $BINARY_DIR/$ARTIFACT_NAME/lib/$LIB_NAME

# ORT NuGet packaging expects the unversioned library (libonnxruntime.dylib) to contain the binary content,
# because the versioned library is excluded by the nuspec generation script.
# We explicitly overwrite the symlink with the real file to ensure 'nuget pack' (especially on Windows)
# doesn't pack an empty/broken symlink.
if [[ "$LIB_NAME" != "libonnxruntime.dylib" && -L "$BINARY_DIR/$ARTIFACT_NAME/lib/libonnxruntime.dylib" ]]; then
rm "$BINARY_DIR/$ARTIFACT_NAME/lib/libonnxruntime.dylib"
cp "$BINARY_DIR/$ARTIFACT_NAME/lib/$LIB_NAME" "$BINARY_DIR/$ARTIFACT_NAME/lib/libonnxruntime.dylib"
fi

# copy the CoreML EP header for macOS build (libs with .dylib ext)
cp $SOURCE_DIR/include/onnxruntime/core/providers/coreml/coreml_provider_factory.h $BINARY_DIR/$ARTIFACT_NAME/include
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ RUN apt-get update && \
libnvonnxparsers-dev=${TRT_VERSION} \
libnvonnxparsers10=${TRT_VERSION} \
tensorrt-dev=${TRT_VERSION} \
libnvinfer-bin=${TRT_VERSION} && \
libnvinfer-bin=${TRT_VERSION} \
libnvinfer-headers-python-plugin-dev=${TRT_VERSION} \
libnvinfer-win-builder-resource10=${TRT_VERSION} && \
rm -rf /var/lib/apt/lists/*

COPY scripts /tmp/scripts
Expand Down
Loading