在 Linux 程序中嵌入 Python
Posted
技术标签:
【中文标题】在 Linux 程序中嵌入 Python【英文标题】:Embedding Python in Linux program 【发布时间】:2015-03-05 11:06:53 【问题描述】:我目前正在尝试将 Python 嵌入到我的 C++ 应用程序中,以便为用户提供高级脚本编写可能性。
到目前为止,我的程序在 Windows 上运行良好(它完全可以运行),现在我正在尝试在 GNU/Linux(目前是 Debian 7)上做同样的事情,但这给我带来的麻烦比我预期的要多得多。
首先,我下载 python.tar.gz 并使用 enable-shared 选项从源代码编译它以获得 fPIC 选项:
./configure --enable-shared --prefix=/opt/python
制作 && 制作 altinstall
然后,感谢 pip:python3.4 -m pip install numpy
,我安装了 numpy。简单的。
最后,我将安装复制到另一个位置(是的,它应该部署在任何地方),准确地说是在我的主目录中,并将其命名为 python_install。这个副本似乎让我很痛苦。
在代码方面,我调用了运行良好的 Py_Initialize。这是我到目前为止所做的:
#include "Python.h"
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "numpy/arrayobject.h"
#include <iostream>
int InitNumpy()
import_array();
int main()
std::string python_home = "/home/xxxx/dev/test-python/python_install";
setenv("PYTHONHOME", python_home.c_str(),1 );
Py_Initialize();
std::cout << "Importing Numpy... ";
int cr = InitNumpy();
std::cout << cr << std::endl;
return 0;
ImportError: numpy.core.multiarray 导入失败 我认为错误很明显,Python 找不到任何库,包括 numpy。但是我已经尝试了从设置 PYTHONPATH 到使用 -Wl,-rpath 来设置其他目录的所有方法......甚至 PySys_SetPath......在 Windows 上工作的东西在 Linux 上失败了。 欢迎任何想法!谢谢。
编辑:这是我使用的makefile(已更正):
CC=g++
CFLAGS= -Ipython_install/include/python3.4m -Ipython_install/lib/python3.4/site-packages/numpy/core/include -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall
#Wrong
#LDFLAGS= -Lpython_install/lib/python3.4/config-3.4m -lpython3.4m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-rpath,\$$ORIGIN/python_install/lib
#Right
LDFLAGS= -Lpython_install/lib/ -lpython3.4m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-rpath,\$$ORIGIN/python_install/lib
EXEC=test-python
all: $(EXEC)
test-python: test-python.o
$(CC) -o $@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) -o $@ -c $< $(CFLAGS)
.PHONY: clean mrproper
clean:
rm -rf *.o
mrproper: clean
rm -rf $(EXEC)
选项直接来自 python3.4m-config 可执行文件...
【问题讨论】:
我无法重现您的问题。按照您提供的所有步骤进行操作,并且有效。我能想到的只是 numpy 在你给出的 python 主页下实际上并不存在。您是否尝试过运行安装的交互式解释器并导入 numpy(确保PYTHONPATH
未设置)?
是的,我也是。长话短说:我第一次安装了 Python 并在我的小项目中复制安装。我不知道为什么,但 numpy 指的是第一次安装。 'strace' 给了我线索。我删除了第一次安装,现在它可以工作了...但是我希望将来能够与其他 Python 安装很好地集成,否则一些用户肯定会抱怨...
我发现 pip 被硬编码为使用原始安装路径来查找 python 可执行文件。也就是说,它不会尝试使用与其共享目录的 python 可执行文件。可能 pip 的安装路径也是硬编码的——这意味着您将无法移动 python 安装。
@Dunes :是的,你可能是对的。当我尝试在移动的文件夹上使用 pip 时,我得到一个 /usr/bin/ld: cannot find -lpython3.4m
。真正的问题是:我应该通过 apt-get 在 .deb 存档中部署我的应用程序和 python 包装器......所以我可能会强制在某个地方安装 python。我必须考虑一下。
@Dunes 我终于找到了我的问题所在。生成文件不正确。我在 libpython.a 上静态链接,但是像 numpy 这样的附加安装使用了 libpython3.4.so,它似乎引发了一些我不明白的奇怪冲突。好吧,现在我在两边都使用了动态链接(共享对象),它工作得很好。 5 天的麻烦,一个奇怪的选择......
【参考方案1】:
简短的回答是:不要在 Python 上进行静态链接。所有 Python 模块都动态地链接到 libpython3.4.so,因此 C++ 程序也必须这样做。 总结一下 Python 嵌入:
-
在 Python 上动态链接(参见更正的 Makefile)。使用 rpath 定位 python .so。
在 C++ 代码中,将
PYTHONHOME
环境变量设置为 Python 安装或使用 Py_SetPythonHome()
函数。
致电Py_Initialize();
如果要导入自定义模块,请将模块路径添加到 Python 路径。
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyUnicode_FromString(sys_path.toUtf8().data()));
【讨论】:
您介意添加一个示例,说明如何在 C++ 代码中设置PYTHONHOME
吗?
我认为使用Py_SetPythonHome
做同样的事情并且应该使用。 cfdocs.python.org/3.6/c-api/init.html【参考方案2】:
您说“python 找不到任何库”,您是否尝试过启动 python 并导入它们?如果直接在 python 中导入有问题,您将不得不重新检查 PYTHOPATH
是否正确,或者您安装的文件可能没有安装权限设置才能执行。 (我已经发生过两次了)。
另外,您是否查看了manual 中有关在类 unix 系统上编译的提示?
找到正确的标志传递给你的并不一定是微不足道的 编译器(和链接器),以便将 Python 解释器嵌入 您的应用程序,特别是因为 Python 需要加载库 实现为链接的 C 动态扩展(.so 文件)的模块 它。
要找出所需的编译器和链接器标志,您可以执行 生成的 pythonX.Y-config 脚本 安装过程(也可以使用python3-config脚本)
你如何编译你的代码?
编辑
我已尽力重现您的错误,但无法在我的机器上重现。我得到的最远的是我认为你对错误的分析是错误的。
我认为错误很明显,Python 找不到任何库 包括 numpy。
import_array()
背后的原因是检查是否有 numpy 以及您拥有的 numpy 版本是否与已安装的 python 版本匹配。在源代码中它被定义为一个宏(即对于 py2 的 np):
#if PY_VERSION_HEX >= 0x03000000
#define NUMPY_IMPORT_ARRAY_RETVAL NULL
#else
#define NUMPY_IMPORT_ARRAY_RETVAL
#endif
#define import_array() if (_import_array() < 0) PyErr_Print();
PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to
import"); return NUMPY_IMPORT_ARRAY_RETVAL;
由于这是您看到的错误,我有理由怀疑您的 pip
为您的 python 版本安装了“错误”的 numpy。但是再次基于您的makefile,您的python3.4文件夹中有一个numpy,如果没有,它会抛出错误No such file or directory
。此外,您说您甚至不得不使用LD_LIBRARY_PATH
(不推荐顺便说一句)用 numpy 启动 python,这只是意味着当前为您定义的任何路径都没有正确指向 numpy python,包括您在已编译的 python 中的site-packages
文件夹(默认情况下会搜索)。
我怀疑您默认安装了一个预先存在的 python,并且您的系统范围的环境路径设置为它。但考虑到你在 python3 文件夹 AND 你 setenv
PYTHONHOME
中明确链接 numpy,这是一个非常奇怪的声明。
很抱歉,我无法提供更多帮助,但如果不从头开始实际构建 python(目前也不在 debian 上),我无法重现该问题。祝你好运,让我知道吗?
【讨论】:
我编辑了我的第一篇文章以显示完整的代码。如果我启动 Python 可执行文件本身(使用 LD_LIBRARY_PATH 帮助他找到 .so),它工作得很好,numpy 正在正确导入。另一方面,当我从 C++ 代码中调用 import_array 时,总是会收到导入错误! 它终于在我的小例子中使用 rpath 和 strace 工作了。但我无法在我的大项目中转移它。必须找出原因。我会及时通知社区! @poukill 我尽力了,但无法让 python 表现得像你的那样,即使我取消设置路径链接似乎对我有用。 我又从头开始了,它也对我有用....即使我移动了我的程序。这是个好消息。 但是,如果我用完全相同的方法(但没有 numpy)在别处安装另一个 Python,主安装将不再起作用,并且我得到“ImportError: numpy.core.multiarray failed to import " 返回...如果我在最后一次安装 Python 时安装 numpy,那么这两个应用程序都可以工作。总结一下: 1- 使用 test-python.cpp 安装 Python 和 numpy。编译并启动。在职的! 2- 移动到另一个文件夹。还在工作。 3- 在旧文件夹上重新安装 Python。打破了新的。 看起来我至少在附近。希望我能帮上一点忙。不过,这对您来说是个坏消息,这意味着它不能按原样独立部署。不在全新安装或至少 virtualenv 之外。构建numpy inplace 是一种矫枉过正。此外,当我遇到 this 时,我正在搜索 boost 库安装以尝试找到解决方案的提示,您可能会发现它也很有用。以上是关于在 Linux 程序中嵌入 Python的主要内容,如果未能解决你的问题,请参考以下文章