在MonoMac应用程序中包含自定义dll和dylib

时间:2013-01-26 12:15:18

标签: mono bundle dylib monomac

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

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

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

  1. 将dylib复制到MyApp.app/Contents/SharedSupport。 (相关问题:这是第三方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)
    
  3. 问题

    1. MyApp.app/Contents/MacOS/MyApp不直接引用dylib,因此我无法使用install_name_tool指向新的库位置。我相信该库是由System.Data.Sqlite.dll引用的。
    2. 我想在启动器脚本中覆盖DYLD_FALLBACK_LIBRARY_PATH但是 MonoMac现在使用二进制启动器(MyApp.app/Contents/MacOS/MyApp),而不是脚本,所以我运气不好
    3. MonoMac众神会帮助解决一个简单的解决方案吗?我花了几个,打开和关闭,试图让它工作。

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

3 个答案:

答案 0 :(得分: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>添加@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")]在您的代码中引用它。

  6. 当其他图书馆引用

    当另一个库,例如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>
    

答案 1 :(得分:2)

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

答案 2 :(得分: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的路径。