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

但是,当P / Invoke进入此dll时,我得到了DllNotFound异常。我通读了Mono Interop Wiki,看来Mono上的P / Invoke只会查看DYLD_ *环境变量所指向的位置,而当前目录不在搜索路径中。当我将Framework复制到/ Library / Frameworks时,我的P / Invoke调用工作正常,但我希望我的Framework文件位于应用程序旁边,而不是/ Library / Frameworks中。

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

无论如何,我可以将我的Framework文件保留在该应用程序旁边,并且仍然可以进行P / Invoke吗?

最佳答案

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

设置环境变量

您可以在应用程序LSEnvironmentInfo.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>


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

该文件由MonoDevelop自动创建,因此您要做的就是添加LSEnvironment部分。

之后,您可以在MonoDevelop中对其进行编辑:转到项目选项,“ Mac OS X应用程序”,“高级”。

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

您无需设置任何环境变量即可在MonoMac应用程序中捆绑本机框架,这是一种更轻松,更简洁的方法,这与Objective C中的工作方式类似。

我创建了一个小的test applications,它在本机Objective C应用程序和MonoMac应用程序中都捆绑了一个框架。

您需要做的第一件事是将框架与应用程序捆绑在一起。 MonoDevelop当前没有自动执行此操作的方法,因此您需要手动复制文件或使用某些生成后脚本(请参见示例中的copy-framework.sh)。

我建议将框架放入YourApp.app/Contents/Frameworks/YourFramework.framework,因为这是XCode处理它的方式。另请参见Apple's Documentation

要在您的应用程序捆绑包中引用一个库,您可以使用“ @executable_path”(请参见dyld man page)。

我建议使用<dllmap>创建一个app.config文件,这样您就无需在代码中放入任何路径名,从而更容易更改框架版本。例如:

    <configuration>
       <dllmap dll="TestFramework" target="@executable_path/../Frameworks/TestFramework.framework/TestFramework" />
     </configuration>


如果框架内的实际库以lib开头或以.so / .dylib结尾,则必须指定该名称(例如,上面的dllmap不会归档TestFramework.framework/libTestFramework.dylib)。这是我刚刚修复的Mono中的错误。

关于pinvoke - 在Mac版Mono上为DllImport设置 native 库的路径,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12834141/

10-10 15:02