Mac 上的单声道:DllNotFoundException 尽管 SQLite.Interop.dll 在 dllmap 中
Mono on Mac: DllNotFoundException despite SQLite.Interop.dll being in dllmap
我有一个使用 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>
我也试过加<dllmap dll="SQLite.Interop.dll" target="libsqlite3.0.dylib" os="osx"/>
,不是更好。
有什么问题?
通过将 MONO_LOG_LEVEL 设置为调试并 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 动态 link 编辑器('man dyld' 了解详情)不需要将 DYLD_LIBRARY_PATH 设置为当前目录 ('.' ).注意:Linux 确实需要 LD_LIBRARY_PATH 包含当前目录,如果这是您的意图。
- 将那些 dll 映射文件移开以将它们从等式中删除。
- 取消设置DYLD_LIBRARY_PATH
- cd 在包含基于 CIL 的 exe、dll 和本机 dylib 的目录中
- MONO_LOG_LEVEL=调试 MONO_LOG_MASK=dll 单声道 yourprogram.exe
使用本机 dll/shared 库跟踪输出,您可以跟踪未找到哪个库(或其依赖项之一)或者它是否是您的单声道版本的错误 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 fat 二进制文件,因此该库不是问题,但您的调试输出可能会显示另一个有问题的库,
>>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
您需要构建并提供 SQLite.Interop.dll
(或更准确地说 libSQLite.Interop.dylib
)。 Mono 分发包不包含它,可能是因为它是本机代码,确实需要在目标平台上构建。
System.Data.SQLite on Windows 使用混合模式方法(托管数据适配器 + 一个程序集中的 sqlite 本机代码)。然而,Mono 并不真正支持混合模式程序集。
因此 MacOS 在 Windows 上构建 System.Data.SQLite 时有两种选择:
- 使用互操作 dll。
- 使用libsqlite.x.x.dylib.
这两个都是本机代码,需要在 Mac.
上构建
Interop 是 Windows com 的说法,因此看到它在 MacOS 上下文中使用有点令人不安。这个本机 dll 是用一些额外的本机代码编译的 sqlite 源代码,这些本机代码可以是 P\Invoked by System.Data.SQLite。有一些 benefits to using the interop dll 与 sqlite dylib 相对。
System.Data.SQLite 在 ./SQLite.Interop/src.core
中附带了一份相关 SQLite 本机源代码的副本。您可以通过 运行 compile-interop-assembly-release.sh
在 Mac 上构建互操作库。这将构建 libSQLite.Interop.dylib
。把它放在 System.Data.SQLite 旁边,你应该可以开始了。
如果您打开 Mono dll 跟踪,您可以看到加载程序(参见 mono 4.8.0 loader.c)在不同位置搜索 dll 并使用不同的名称替换。最终它找到了我们的动态库。也可以在 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
等 都是可用的。
我更喜欢这种方法,因为它进入回购协议并提供一些关于发生错误时发生的情况的见解。
我有一个使用 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>
我也试过加<dllmap dll="SQLite.Interop.dll" target="libsqlite3.0.dylib" os="osx"/>
,不是更好。
有什么问题?
通过将 MONO_LOG_LEVEL 设置为调试并 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 动态 link 编辑器('man dyld' 了解详情)不需要将 DYLD_LIBRARY_PATH 设置为当前目录 ('.' ).注意:Linux 确实需要 LD_LIBRARY_PATH 包含当前目录,如果这是您的意图。
- 将那些 dll 映射文件移开以将它们从等式中删除。
- 取消设置DYLD_LIBRARY_PATH
- cd 在包含基于 CIL 的 exe、dll 和本机 dylib 的目录中
- MONO_LOG_LEVEL=调试 MONO_LOG_MASK=dll 单声道 yourprogram.exe
使用本机 dll/shared 库跟踪输出,您可以跟踪未找到哪个库(或其依赖项之一)或者它是否是您的单声道版本的错误 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 fat 二进制文件,因此该库不是问题,但您的调试输出可能会显示另一个有问题的库,
>>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
您需要构建并提供 SQLite.Interop.dll
(或更准确地说 libSQLite.Interop.dylib
)。 Mono 分发包不包含它,可能是因为它是本机代码,确实需要在目标平台上构建。
System.Data.SQLite on Windows 使用混合模式方法(托管数据适配器 + 一个程序集中的 sqlite 本机代码)。然而,Mono 并不真正支持混合模式程序集。
因此 MacOS 在 Windows 上构建 System.Data.SQLite 时有两种选择:
- 使用互操作 dll。
- 使用libsqlite.x.x.dylib.
这两个都是本机代码,需要在 Mac.
上构建Interop 是 Windows com 的说法,因此看到它在 MacOS 上下文中使用有点令人不安。这个本机 dll 是用一些额外的本机代码编译的 sqlite 源代码,这些本机代码可以是 P\Invoked by System.Data.SQLite。有一些 benefits to using the interop dll 与 sqlite dylib 相对。
System.Data.SQLite 在 ./SQLite.Interop/src.core
中附带了一份相关 SQLite 本机源代码的副本。您可以通过 运行 compile-interop-assembly-release.sh
在 Mac 上构建互操作库。这将构建 libSQLite.Interop.dylib
。把它放在 System.Data.SQLite 旁边,你应该可以开始了。
如果您打开 Mono dll 跟踪,您可以看到加载程序(参见 mono 4.8.0 loader.c)在不同位置搜索 dll 并使用不同的名称替换。最终它找到了我们的动态库。也可以在 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
等 都是可用的。
我更喜欢这种方法,因为它进入回购协议并提供一些关于发生错误时发生的情况的见解。