C#跨平台P/Invoke时导入动态库的问题
众所周知C#的DllImport特性只允许将常量字符串赋值给DllName。
C/C++动态库在不同平台上可能具有不同的名称。
用nativedep这个库来举例:在windows上可能叫nativedep.dll、linux上叫libnativedep.so、macos上叫libnativedep.dylib。
幸运的是C#会处理常见的变体,如果使用nativedep作为DllName,以上变体都能正确匹配:
[DllImport("nativedep")] static extern int ExportedFunction();
在 Windows 上运行时,将按以下顺序搜索 DLL: nativedep nativedep.dll(如果库名称尚未以 .dll 或 .exe 结尾) 在 Linux 或 macOS 上运行时,运行时将尝试在 lib 前添加,并追加规范共享库扩展。 在这些 OS 上,按以下顺序尝试库名称变体: nativedep.so / nativedep.dylib libnativedep.so / libnativedep.dylib 1 nativedep libnativedep 1 在 Linux 上,如果库名称以 .so 结尾或包含 .so.(注意尾随 .),则搜索顺序会有所不同。 请考虑以下示例: C# [DllImport("nativedep.so.6")] static extern int ExportedFunction(); 在这种情况下,将按以下顺序尝试库名称变体: nativedep.so.6 libnativedep.so.6 1 nativedep.so.6.so libnativedep.so.6.so 1 仅当库名称不包含目录分隔符 (/) 时才检查路径。
但不幸的是有些库作者不按常理命名,导致默认的行为不管用,比如使用“libnativedep-0.dll”这种名称。这时可以考虑使用 NativeLibrary.SetDllImportResolver 来自定义解析规则。
如果你的库面向standard2.0、standard2.1,那么 NativeLibrary.SetDllImportResolver 是用不了的。一个可以考虑的做法是手动改掉c/c++动态库的名称使其匹配默认规则,前提是库内部不会依赖文件名称;
另一个做法是使用kernel32.LoadLibrary、libdl.dlopen封装一个中间层。可参考 https://github.com/mellinoe/nativelibraryloader。
相关资料:
本文作者:陈百川,欢迎留言讨论。转载请注明原文链接:https://www.cnblogs.com/buachuan/p/18736769
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通