2012-10-11 118 views
6

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

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

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

无论如何,我可以保留我的框架文件旁边的应用程序,仍然是亚伯的P/Invoke?

+0

你是说'System.Environment.SetEnvironmentVariable'在Mono中不起作用吗? –

回答

7

让我们分成两个问题:如何设置环境变量以及如何将本机框架绑定到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应用原生框架,有一个更容易和更清洁的方式做到这一点,这是也类似于目标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中的一个错误,我刚刚解决了这个错误。

+0

当我在环境变量中给出应用程序的完整路径时,此方法起作用,但如果尝试从当前工作目录应该给出相对路径,则失败。当我在我的应用程序中进行了一些更多的调试时,我发现cwd被设置为/。无论如何,我可以给我的应用程序的路径,而不必硬编码吗? – user408410

+0

你可以用shell脚本替换启动文件'YourApp.app/Contents/MacOS/YourApp'或者修改由MonoDevelop创建的文件(https://github.com/mono/monodevelop/blob/master/main/建立/ MacOSX的/ monostub.m)。 但是,我想我只是发现了一个更好,更干净的方法,让我快速测试它,然后我会用它更新我的答案。 –

+0

好的,实际上有一个干净而简单的方法 - 只需要快速修复Mono中的一个错误,以便让它发挥作用。 –

相关问题