Mac上的Mono:DllNotFoundException,尽管SQLite.Interop.dll在dllmap中

时间:2015-07-01 04:15:48

标签: macos sqlite mono system.data.sqlite dllnotfoundexception

我有一个使用SQLite的C#应用​​程序,可以在Windows上正常运行。

相同的Visual Studio项目在Xamarin Studio中编译得很好,但在运行时我得到:

DllNotFoundException: SQLite.Interop.dll

尽管:

  • libsqlite3.0.dylib位于/usr/lib中,并且与可执行文件和其他DLL位于同一文件夹中
  • .$DYLD_LIBRARY_PATH
  • 的一部分
  • 可执行文件和所有使用SQLite的DLL都有一个匹配的<the_exe_or_dll_including_filename_extension>.config文件,其中包含:

<configuration> <dllmap dll="sqlite" target="libsqlite.0.dylib" os="osx"/> <dllmap dll="sqlite3" target="libsqlite3.0.dylib" os="osx"/> </configuration>

我也尝试添加<dllmap dll="SQLite.Interop.dll" target="libsqlite3.0.dylib" os="osx"/>,而不是更好。

有什么问题?

2 个答案:

答案 0 :(得分:5)

通过将MONO_LOG_LEVEL设置为debug并将MONO_LOG_MASK过滤设置为仅与DLL相关的消息,您可以轻松找到mono寻找该本机库的位置。

export MONO_LOG_LEVEL=debug
export MONO_LOG_MASK=dll
mono yourprogram.exe

或作为一个班轮,所以你不必取消设置env vars:

MONO_LOG_LEVEL=debug MONO_LOG_MASK=dll mono yourprogram.exe

Mono和OS-X动态链接编辑器(有关详细信息的“man dyld”)不需要将DYLD_LIBRARY_PATH设置为当前目录('。')。注意:如果您愿意,Linux确实需要LD_LIBRARY_PATH来包含当前目录。

  • 将这些dll地图文件移开,将其从等式中移除。
  • 取消设置DYLD_LIBRARY_PATH
  • cd在包含基于CIL的exe,dll和native dylib(s)
  • 的目录中
  • MONO_LOG_LEVEL =调试MONO_LOG_MASK = dll mono yourprogram.exe

使用本机dll /共享库跟踪输出,您可以跟踪找不到哪个库(或其中一个依赖项),或者它是否是单声道版本的错误ARCH。

如果您仍然遇到问题,我们需要知道您正在使用哪个SQLite库来编译它(或者如果通过Nuget获取它,则使用arch版本)。发布你的dll跟踪输出也可以快速解决问题。

注意:

我假设您正在使用System.Data.SQLite库并正在编译选项“/ p:UseInteropDll = true / p:UseSqliteStandard = false”。

Mono在其默认安装中包含一个SQLite,它在OS-X上是32位:

file /Library/Frameworks/Mono.framework/Versions/4.0.2/lib/libsqlite3.dylib
/Library/Frameworks/Mono.framework/Versions/4.0.2/lib/libsqlite3.dylib: Mach-O dynamically linked shared library i386

假设您正在使用Mono的OS-X软件包安装程序,因此获得了32位版本的Mono,因此需要32位版本的本机库。

>>file `which mono`
/usr/bin/mono: Mach-O executable i386

/usr/lib/libsqlite3.0.dylib是一个多ARCH胖二进制文件,因此库不是问题,但是你的调试输出可能会显示另一个问题,

>>file /usr/lib/libsqlite3.0.dylib
libsqlite3.0.dylib: Mach-O universal binary with 3 architectures
libsqlite3.0.dylib (for architecture x86_64):   Mach-O 64-bit dynamically linked shared library x86_64
libsqlite3.0.dylib (for architecture i386): Mach-O dynamically linked shared library i386
libsqlite3.0.dylib (for architecture x86_64h):  Mach-O 64-bit dynamically linked shared library x86_64

答案 1 :(得分:3)

您需要构建并提供SQLite.Interop.dll(或更准确地说libSQLite.Interop.dylib)。 Mono发行包不包含它,可能是因为它是本机代码,并且确实需要在目标平台上构建。

Windows上的System.Data.SQLite使用混合模式方法(一个程序集中的托管数据适配器+ sqlite本机代码)。但Mono并不真正支持混合模式组件。

因此,在MacOS上,在Windows上构建System.Data.SQLite时有两种选择:

  1. 使用interop dll。
  2. 使用libsqlite.x.x.dylib。
  3. 这两个都是本机代码,需要在Mac上构建。

    Interop是Windows com,所以看到它在MacOS上下文中使用有点令人不安。这个原生的dll是使用一些额外的本机代码编译的sqlite源代码,可以由System.Data.SQLite进行P \ Invoked。使用benefits而不是sqlite dylib有一些interop dll

    System.Data.SQLite附带了./SQLite.Interop/src.core中相关SQLite本机源代码的副本。您可以通过在Mac上运行compile-interop-assembly-release.sh来构建互操作库。这将构建libSQLite.Interop.dylib。放在System.Data.SQLite旁边,你应该好好去。

    如果打开Mono dll跟踪,您可以观察加载程序(请参阅mono 4.8.0 loader.c)在各个位置搜索dll并使用各种名称替换。最终它找到了我们的dylib。也可以在dllmap文件中使用System.Data.SQLite.dll.config条目将运行时定向到dll。在我的情况下Mono在我的应用程序包上,所以我有:

    <dllmap dll="SQLite.Interop.dll" target="@executable_path/../Mono/libSQLite.Interop.dylib" os="!windows"/>
    

    dllmap目标参数传递给dlopen(),因此@executable_path 都可以使用。

    我喜欢这种方法,因为它进入了回购,并提供了一些洞察当发生犯规时发生的事情。