7

背景:我的 MonoMac 应用程序使用 sqlite3.0.8.6.dylib 的自定义构建。

我需要让 MyApp.app 使用这个 dylib 的确切步骤。

以下是我采取的一些步骤:

  1. 将 dylib 复制到 MyApp.app/Contents/SharedSupport。(相关问题:这是第 3 方 dylibs 的首选位置还是首选 MyApp.app/Contents/Frameworks?)

  2. 更改了库的安装名称,使其与新位置匹配。

    MyApp.app/Contents/SharedSupport> otool -L libsqlite3.0.8.6.dylib 
    libsqlite3.0.8.6.dylib:
        @executable_path/../SharedSupport/libsqlite3.0.8.6.dylib (compatibility version 9.0.0, current version 9.6.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
    

问题

  1. MyApp.app/Contents/MacOS/MyApp 没有直接引用 dylib,所以我不能使用 install_name_tool 指向新的库位置。我相信该库被 System.Data.Sqlite.dll 引用。
  2. 我想在启动器脚本中覆盖 DYLD_FALLBACK_LIBRARY_PATHMonoMac 现在使用二进制启动器(MyApp.app/Contents/MacOS/MyApp),而不是脚本,所以我在那里不走运。

请 MonoMac 大神帮忙解决一个简单的解决方案吗?我花了几个月的时间,断断续续地试图让它发挥作用。

请提供确切的步骤 - 这个问题是关于细节的。

4

3 回答 3

4

看看我对这个问题的回答: Setting path of the Native Library for DllImport on Mono for Mac

二进制启动器来自monodevelop/main/build/MacOSX/monostub.m

您可以使用任MyApp.app/Contents/Frameworks一路径或其他路径,重要的部分是不要在您的路径中使用任何路径名,[DllImport]而是将<dllmap>using添加@executable_path到您的路径中,app.config就像我在其他答案中解释的那样。

那里还有一个指向 github 上的测试应用程序的链接。

详细说明

  1. 选择一个路径MyApp.app来安装你的本地 dll,例如Contents/SharedSupport/sqlite3.0.8.6.dylib.

  2. 计算从托管程序集所在的目录到本机的相对路径,并将其添加到它的.dll前面@executable_path

    例如,如果您的托管程序集位于 Contents/MonoBundle/MyApp.exe且本机 dll 位于 中 Contents/SharedSupport/sqlite3.0.8.6.dylib,则它是 @executable_path/../SharedSupport/sqlite3.0.8.6.dylib.

  3. 使用 . 将库的安装名称更改为此相对路径install_name_tool

  4. 向您的项目添加一个新MyApp.exe.config文件,其中包含

    <configuration>
      <dllmap dll="sqlite" target="@executable_path/../SharedSupport/sqlite3.0.8.6.dylib" />
    </configuration>
    

    使用您在步骤 2. 中计算的路径作为target字段。在 MonoDevelop 中右键单击该文件,从上下文菜单中选择“快速属性”并启用“复制到输出目录”。这会将文件复制到Contents/MonoBundle目录中,因此它位于您的MyApp.exe.

  5. 用于[DllImport ("sqlite")]在您的代码中引用它。

当另一个库引用它时

例如,当另一个库Mono.Data.Sqlite.dll引用它时,它会变得有点复杂。

使用与上述相同的步骤,但您需要确定其他库在其中使用哪个名称[DllImport]来引用本机库并将其放入<dllimport dll="..." />. 您可以[DllImport]在源代码中查找语句,也可以monodis在程序集上运行并搜索pinvokeimpl,例如:

// method line 679
.method assembly static hidebysig pinvokeimpl ("sqlite3" as "sqlite3_create_function" cdecl )
       default int32 sqlite3_create_function (native int db, unsigned int8[] strName, int32 nArgs, int32 nType, native int pvUser, class Mono.Data.Sqlite.SQLiteCallback func, class Mono.Data.Sqlite.SQLiteCallback fstep, class Mono.Data.Sqlite.SQLiteFinalCallback ffinal)  cil managed preservesig 
{
    // Method begins at RVA 0x0
} // end of method UnsafeNativeMethods::sqlite3_create_function

Mono.Data.Sqlite.dll使用“sqlite3”来引用本机 dll 也是如此,因此您的文件MyApp.exe.config将如下所示:

    <configuration>
      <dllmap dll="sqlite3" target="@executable_path/../SharedSupport/sqlite3.0.8.6.dylib" />
    </configuration>
于 2013-02-01T08:30:05.783 回答
2

如果您使用单声道,请小心。@executable_path 将返回单声道二进制文件的路径,而不是实际的 .EXE 可执行文件。不过,这应该与 Xamarin 一起正常工作。

于 2013-10-25T05:04:19.460 回答
1

您可以尝试手动加载sqlite dylib.

[DllImport ("/usr/lib/libSystem.dylib")]
public static extern IntPtr dlopen (string path, int mode);
IntPtr p = dlopen("libsqlite3.0.8.6.dylib", 0);

当然正确地解决了你的dylib.

于 2013-01-28T21:14:27.467 回答