【问题标题】:Mono on Mac: DllNotFoundException despite SQLite.Interop.dll being in dllmapMac 上的 Mono:尽管 SQLite.Interop.dll 在 dllmap 中,但仍出现 DllNotFoundException
【发布时间】:2015-09-18 02:05:08
【问题描述】:

我有一个使用 SQLite 并且在 Windows 上运行良好的 C# 应用程序。

相同的 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>

我也试过加&lt;dllmap dll="SQLite.Interop.dll" target="libsqlite3.0.dylib" os="osx"/&gt;,不是更好。

有什么问题?

【问题讨论】:

  • 两件事:OS X 不使用Windows 使用的$PATH 变量,动态库是dylibs,而不是dlls。为了使dll 与单声道和OS X 正常工作,需要使用Dllmap 进行映射。
  • @l'L'l: This software 在 Mac 上使用带有 Mono 的 SQLite 并且不包含任何 Dllmap... 仍在尝试找到它是如何管理它的。
  • 看起来它有几个 dllmaps,所以我想interop.dll 可能也需要它。
  • @l'L'l:上面的软件没有与SQLite相关的Dllmap。如果我要添加一个,您建议添加什么库?我在 SQLite 网站上找不到任何 OS X 库,只有独立的可执行文件。
  • dllmap配置部分尝试添加:&lt;dllmap dll="sqlite" target="libsqlite.0.dylib" os="osx"/&gt;&lt;dllmap dll="sqlite3" target="libsqlite3.0.dylib" os="osx"/&gt;

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


【解决方案1】:

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

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

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

  1. 使用互操作 dll。
  2. 使用 libsqlite.x.x.dylib。

这两个都是原生代码,需要在 Mac 上构建。

Interop 是 Windows com 语言,因此在 MacOS 环境中使用它有点令人不安。这个原生 dll 是用一些额外的原生代码编译而成的 sqlite 源代码,这些原生代码可以由 System.Data.SQLite P\Invoked。有一些benefits 使用interop dll 而不是sqlite dylib。

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。也可以使用System.Data.SQLite.dll.config 文件中的dllmap 条目将运行时定向到dll。在我的情况下,Mono 在我的应用程序包中,所以我有:

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

dllmap 目标参数被传递给dlopen(),所以@executable_path 都是可用的。

我更喜欢这种方法,因为它进入了 repo 并提供了一些关于发生错误时发生的情况的见解。

【讨论】:

  • 感谢您的回答!我已经完全按照您的描述完成了,但是当我启动我的应用程序时,我总是收到此错误: System.EntryPointNotFoundException: Unable to find an entry point named "sqlite3_rekey" in DLL "sqlite3" 你碰巧知道为什么吗?我试图在编译文件中添加 DSQLITE_HAS_CODEC 但它似乎没有帮助
  • 您是否尝试过开启 Mono dll 跟踪?我的用例仍然可以正常工作(但我还没有使用最新版本的 Mono)所以我建议你继续戳它直到点击。
【解决方案2】:

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

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

或作为一个衬里,因此您不必取消设置环境变量:

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 和本机 dylib 的目录中
  • MONO_LOG_LEVEL=debug 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

【讨论】:

  • 我没有使用“/p:UseInteropDll=true /p:UseSqliteStandard=false”进行编译。如果有在 Mono/Mac 上使用 SQLite 的标准简单方法,我完全愿意使用它:-)
  • “单声道文件”确实是/usr/bin/mono: Mach-O executable i386
  • "file /usr/lib/libsqlite3.0.dylib" 的输出也和你的一样。
  • 我从另一个问题中看到,您现在正在尝试使用 Mono 提供的 SQLite,但如果您正在尝试使用“System.Data.SQLite”。 System.Data.SQLite 的 nuget 版本不附带 xplat 本机共享库,但您可以编译库以使用 Linux 或 OS-X 上提供的本机库,方法是使用它们的构建指令:system.data.sqlite.org/index.html/doc/trunk/www/build.wiki#mono
  • 实际上我尝试删除 DYLD_LIBRARY_PATH 和地图文件,现在它不再编译了,所以我很绝望......所以我尝试了各种方法。真的我只想做一些读/写,我认为这很容易,但我找不到任何明确的说明。我现在再试一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-08
  • 2017-06-11
  • 2014-10-31
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
相关资源
最近更新 更多