【问题标题】:Setting path of the Native Library for DllImport on Mono for Mac在 Mono for Mac 上为 DllImport 设置本机库的路径
【发布时间】:2012-10-11 07:14:29
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你是说System.Environment.SetEnvironmentVariable 在 Mono 中不起作用?

标签: pinvoke environment-variables monomac


【解决方案1】:

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

设置环境变量

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

    <?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)。

我建议使用&lt;dllmap&gt; 创建一个 app.config 文件,这样您就不需要在代码中添加任何路径名,从而更容易更改框架版本。例如:

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

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

【讨论】:

  • 当我在环境变量中提供我的应用程序的完整路径时,此方法有效,但如果我尝试提供来自当前工作目录的相对路径,则会失败。当我在我的应用程序中进行更多调试时,我发现 cwd 设置为 / 。无论如何我可以提供我的应用程序的路径而无需对其进行硬编码?
  • 您可以使用 shell 脚本替换启动文件 YourApp.app/Contents/MacOS/YourApp 或修改由 MonoDevelop (github.com/mono/monodevelop/blob/master/main/build/MacOSX/…) 创建的文件。但是,我想我刚刚找到了一种更好、更清洁的方法,让我快速测试一下,然后我会用它更新我的答案。
  • 好的,实际上有一种简洁明了的方法 - 只需快速修复 Mono 中的一个错误,您就可以让它工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-20
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
相关资源
最近更新 更多