使用Py++生成的代码作为Python扩展
我需要把一个现有的C++库包装一下,以便在Python中使用。在看过关于如何选择合适的方法将C++包装成Python可用的答案后,我决定使用Py++。
我按照Py++的教程,使用了教程中的文件,得到了我预期的输出在generated.cpp
中,但我还没搞明白怎么才能把生成的代码用作可以在Python中导入的扩展。我知道现在得编译这些代码,但用什么工具呢?我是不是应该用bjam?
3 个回答
我写了一个简单的makefile,内容如下:
GNUmakefile:
PYTHON_INC=$(shell python-config --includes)
PYTHON_LIBS=$(shell python-config --libs)
BOOST_LIBS=-lboost_python
all:
g++ -W -Wall $(PYTHON_INC) $(PYTHON_LIBS) $(BOOST_LIBS) -fPIC -shared generated.cpp -o hw.so
然后我把生成的.so文件加载到ipython里,想试试它的效果:
In [1]: import hw
In [2]: a = hw.animal('zebra')
In [3]: a.name()
Out[3]: 'zebra'
以下的回答是由Roman Yakovenko在Python C++-sig邮件列表上提供的;我在这里稍作修改后发布,目的是为了帮助Stack Overflow社区的朋友们。
我还没有完全理解这个回答,但我觉得它给了我一个正确的方向。
在你生成代码之后,接下来需要编译它。为此,你可以使用你喜欢的构建系统。我个人只用bjam来编译boost。之后,我更喜欢在Windows和Linux上使用scons。
下面是一个sconstruct文件的例子,这个文件用于编译Py++的一个单元测试(这也是生成的代码哦 :-)):
import sys
env = Environment()
if 'linux' not in sys.platform:
env['MSVS'] = {'VERSION': ''}
env['MSVS_VERSION'] = ''
Tool('msvc')(env)
t = env.SharedLibrary(
target=r'abstract_classes',
source=[r'/home/roman/language-binding/sources/pyplusplus_dev/unittests/temp/abstract_classes.cpp'],
LIBS=[r"boost_python"],
LIBPATH=[r"", r"/home/roman/include/libs"],
CPPPATH=[
r"/home/roman/boost_svn",
r"/usr/include/python2.6",
r"/home/roman/language-binding/sources/pyplusplus_dev/unittests/temp",
r"/home/roman/language-binding/sources/pyplusplus_dev/unittests/data",
r"/home/roman/boost_svn"
],
CCFLAGS=[ ],
SHLIBPREFIX='',
SHLIBSUFFIX='.so'
)
因为你的代码生成器是用Python写的,所以你可以在Py++停止的地方继续,生成你喜欢的“make”文件。你甚至可以做得更进一步。Py++的测试会生成代码、编译、加载新的模块并测试功能。所有这些操作都是在一个独立的进程中完成的。
Py++ 是一个工具,它可以帮你生成一些代码,这些代码和 boost::python 一起使用,目的是在你的应用程序中创建 Python 的入口点。
假设你在使用 Py++ 的过程中一切顺利,你需要下载 Boost 框架,然后把 Boost 的包含目录和 boost::python 的库添加到你的项目中,接着用 Py++ 生成的 cpp 文件进行编译。
你可以选择任何你喜欢的构建系统来处理你的项目,但 Boost 是用 bjam 构建的。你需要决定是要静态库还是动态库的 boost python,然后按照 这里 的说明来构建 Boost。
如果你是在 Windows 上,你需要把生成的库的扩展名从 .dll 改成 .pyd。并且,这个项目必须是一个库项目,不能是可执行文件。
然后,把这个 pyd 文件放到你的机器上 Python 可以找到的地方,接着打开 Python,执行 import [你的库名],希望一切都能正常工作。
最后要注意的是,在这个宏中生成的 cpp 文件里的名字:
BOOST_PYTHON_MODULE( -name- )
必须和你的项目名字完全一致,否则 Python 会报错。
我在不到一个月前刚经历过这一切,所以我知道这其中的困惑。
为了让我的 Python 扩展在构建库和测试时更容易使用,我选择在我的构建环境中自己构建 boost::python 和 Python。这样,pyd 文件就能放在我想要的位置,用户不需要安装 Python 就可以使用我的扩展。不过,这可能对你来说有点过于复杂。
补充说明:如果你希望你的扩展在其他机器上容易安装和编译,可以看看 Python 的 setuptools。只需几行简单的代码,你就可以让 Python 为你编译和安装你的包。不过,有一个缺点,就是它和那些喜欢在 Visual Studio 中开发的人不太兼容。