在 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 文件夹 ANDsetenv 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的主要内容,如果未能解决你的问题,请参考以下文章

在c ++中嵌入python:分段错误[重复]

在嵌入式linux上使用python可以套接字,绑定行为不端

在 CSS 中嵌套子选择器

在 Gorilla Mux 中嵌套子路由器

mysql怎么在查询中嵌套子查询

elementui 表格中嵌套子表格