【问题标题】:How to embed python in an Objective-C OS X application for plugins?如何将python嵌入到Objective-C OS X应用程序的插件中?
【发布时间】:2014-12-26 22:11:12
【问题描述】:

我正在尝试在新的 OS X 应用程序中使用 python 来编写插件脚本。我希望将一些程序逻辑卸载到 python 中,以便进行简单的即时修改。我从查看Big Nerd Ranch tutorial 开始。这似乎可行,但它提出了一种链接 Python 的旧方法。似乎从 Xcode 5 开始,我们应该使用this Mac Developer Library Tech Note 安装 python。然而,这个过程似乎创建了一个链接的 python 实例,而不是一个嵌入式实例。我已尝试遵循 answer to this question 中的指导方针,但它似乎坏了。

所以我的问题是:构建 python 以用作 Objective C Mac OS X 应用程序中的插件运行时的当前最佳实践是什么?如何确保它与应用程序捆绑在一起,并且可以在构建最终的 Objective C 应用程序之前安装任何可能需要的其他库?

【问题讨论】:

  • 链接到 OS X 附带的 Python 框架有什么问题?
  • OS X 附带的 Python 框架运行 python2.7。我更喜欢使用python3。另外,我如何将非标准模块合并到插件中?不想为了安装原生 Cocoa 应用程序而安装系统范围的 python 模块。

标签: python objective-c xcode macos cocoa


【解决方案1】:

我想出了一个似乎效果很好的方法。

首先,从official website下载你要使用的python版本的源码。在某处提取档案。我正在使用 Python 3.4.2。针对您使用的特定版本调整系统上的命令。

创建一个您将用于此开发 python 版本的构建目录。整个目录中不应包含空格,以确保 bash 正确解释 she-bang (#!) 行。我用/Users/myaccount/development/python/devbuild/python3.4.2

进入解压后的 Python 目录并运行以下命令:

./configure --prefix="/Users/myaccount/development/python/devbuild/python3.4.2"
make
make install

这将在该开发构建目录中安装 python。设置 Python 路径以使用正确的目录:

export PYTHONPATH="/Users/myaccount/development/python/devbuild/python3.4.2/lib/python3.4/site-packages/"

进入 python bin 目录 (/Users/myaccount/development/python/devbuild/python3.4.2/bin) 并使用pip3 安装您需要的任何模块。 $PYTHONPATH 设置将确保模块安装到正确的 site-packages 目录中。

为 PyObjC 存储库找到一个方便的家并将其克隆到那里。然后检查最新版本标签并安装它,确保您的$PYTHONPATH 仍然正确:

hg clone https://bitbucket.org/ronaldoussoren/pyobjc
cd pyobjc
hg tags
hg checkout [the id of the latest version from the tag list]
/Users/myaccount/development/python/devbuild/python3.4.2/bin/python3 ./install.py

当您需要更新 python 模块时,只需确保使用正确的 python bin 和$PYTHONPATH

现在将 python 添加到 Xcode 项目中。

/Users/myaccount/development/python/devbuild/python3.4.2目录拖到Xcode项目中,根据需要设置为不复制项目,并创建文件夹引用。

/Users/myaccount/development/python/devbuild/python3.4.2/include/python3.4m 添加到Xcode 项目的Build Settings 中的Header Search Paths 设置。不确定是否有办法将其作为一个通用步骤来搜索我们刚刚添加的文件夹引用目录。

将 `/Users/myaccount/development/python/devbuild/python3.4.2/lib/libpython3.4m.a 库拖到 Xcode 项目中,将其设置为作为参考添加而不复制。

Big Nerd Ranch scripting tutorial repository 中的代码现在可以通过一些修改来使用。

插件管理器代码需要一个 NSString 扩展来处理 Python API 似乎非常喜欢的 wchar_t 字符串:

@interface NSString (WcharEncodedString)

- (wchar_t*) getWideString;

@end

@implementation NSString (WcharEncodedString)

- (wchar_t*) getWideString {
    const char* tmp = [self cStringUsingEncoding:NSUTF8StringEncoding];
    unsigned long buflen = strlen(tmp) + 1;
    wchar_t* buffer = malloc(buflen * sizeof(wchar_t));
    mbstowcs(buffer, tmp, buflen);
    return buffer;
}

@end

Python 标头应包含如下:

#include "Python.h"

需要在调用 Py_Initialize() 之前运行以下代码,以便按照 Zorg 在其他问题上的建议设置正确的 python 可执行文件、PYTHONPATH 和 PYTHONHOME。

NSString* executablePath = [[NSBundle mainBundle] pathForResource:@"python3.4" ofType:nil inDirectory:@"python3.4.2/bin"];
Py_SetProgramName([executablePath getWideString]);

NSString* pythonDirectory = [[NSBundle mainBundle] pathForResource:@"python3.4" ofType:nil inDirectory:@"python3.4.2/lib"];
Py_SetPath([pythonDirectory getWideString]);
Py_SetPythonHome([pythonDirectory getWideString]);

最后,需要在PluginExecutor.py文件中扩展python路径以包含高级lib路径的各个子目录。将以下代码添加到 Plugin Executor 文件的顶部:

import sys
from os import walk
path = sys.path.copy()
for p in path:
    for root,dirs,files in walk(p):
        if p is not root:
            sys.path.append(root)

如果事情开始出现问题,我会发布更新,但这似乎是目前可行的解决方案。

【讨论】:

  • 感谢您的详尽解释。 +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 2010-09-08
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多