在Mono for Mac上为DllImport设置本机库的路径

Shi*_*sad 6 pinvoke environment-variables monomac

我移植到Mono for Mac的代码调用了一个非托管的C++库.在Mac上,我已将非托管库移植到框架中(不幸的是,我们的构建过程只允许将其编译为框架而不是作为dylib).在Mono中,我在项目中设置了一个构建后步骤,以复制构建应用程序旁边的Framework文件.

但是当一个P/Invoke进入这个DLL时,我得到一个DllNotFound异常.我通读了Mono Interop Wiki,看起来Mono上的P/Invoke只会查看DYLD_*环境变量指向的位置,而当前目录不在搜索路径中.当我将Framework复制到/ Library/Frameworks时,我的P/Invoke调用工作正常,但我更喜欢我的Framework文件出现在App旁边而不是/ Library/Frameworks中.

在我执行任何P/Invoke调用之前,我尝试将当前工作目录添加到我的代码中的DYLD_FRAMEWORK_PATH环境变量,但System.Environment命名空间在Mono for Mac上具有有限的功能,并且不支持获取或设置环境变量.

无论如何,我可以将我的框架文件保留在应用程序旁边,仍然可以使用P/Invoke吗?

Mar*_*lig 7

让我们将其分为两个问题:如何设置环境变量以及如何在MonoMac应用程序中捆绑本机框架.

设置环境变量

您可以在LSEnvironment应用程序的部分设置环境变量Info.plist,如下所示:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
            <dict>
            <key>CFBundleIdentifier</key>
            <string>com.yourcompany.TableViewTest</string>
            <key>CFBundleName</key>
            <string>TableViewTest2</string>
            <key>CFBundleVersion</key>
            <string>1</string>
            <key>LSMinimumSystemVersion</key>
            <string>10.6</string>
            <key>NSMainNibFile</key>
            <string>MainMenu</string>
            <key>NSPrincipalClass</key>
            <string>NSApplication</string>
            <key>LSEnvironment</key>
            <dict>
                    <key>Foo</key>
                    <string>Bar</string>
            </dict>
    </dict>
    </plist>
Run Code Online (Sandbox Code Playgroud)

似乎必须手动编辑该文件一次并添加至少一个环境变量.

该文件由MonoDevelop自动创建,因此您只需添加该LSEnvironment部分即可.

之后,您可以在MonoDevelop中编辑它们:转到项目选项,"Mac OS X Application","Advanced".

在MonoMac应用程序中捆绑本机框架

您不需要设置任何环境变量来在MonoMac应用程序中捆绑本机框架,这样做更简单,更清晰,这也与Objective C中的工作方式类似.

我创建了一个小型测试应用程序,它将本地Objective C应用程序和MonoMac应用程序中的框架捆绑在一起.

您需要做的第一件事是将框架与应用程序捆绑在一起.目前无法在MonoDevelop中自动执行此操作,因此您需要手动复制文件或使用一些构建后的脚本(请参阅copy-framework.sh我的示例).

我建议将框架放入,YourApp.app/Contents/Frameworks/YourFramework.framework就像XCode处理它一样; 另见Apple的文档.

要引用应用程序包中的库,可以使用`@executable_path'(请参阅dyld手册页).

我建议使用创建app.config文件<dllmap>,因此您不需要将任何路径名放入代码中,从而可以更轻松地更改框架版本.例如:

    <configuration>
       <dllmap dll="TestFramework" target="@executable_path/../Frameworks/TestFramework.framework/TestFramework" />
     </configuration>
Run Code Online (Sandbox Code Playgroud)

如果框架内的实际库lib.so/ 开头或以/ 结尾.dylib,则必须指定该名称(例如,上面的dllmap不会文件TestFramework.framework/libTestFramework.dylib).这是Mono中的一个错误,我刚刚解决了这个问题.