Linux下c++调用python程序

按照上篇windows下调用的在linux下运行命令

其中linux下lib中为libpython3.6m.a,同时include中Python.h在python3.6m目录下,因此需要修改命令和main.cpp中#include "python3.6m/Python.h"

g++ -I "/root/Anaconda3/envs/tensorflow/include" -L "/root/Anaconda3/envs/tensorflow/lib" main.cpp -lpython3.6m
  1. 报错打不开libpython3.6m.so.1.0,参考:

加载共享库时出现 Linux 错误:无法打开共享对象文件:没有此类文件或目录 - 堆栈溢出 (stackoverflow.com)

您的库是一个动态库。您需要告诉操作系统它在运行时可以找到它的位置。

为此,我们需要执行以下简单步骤:

  1. 如果您不知道库的位置,请查找库的位置。
sudo find / -name the_name_of_the_file.so
  1. 检查动态库路径环境变量是否存在(LD_LIBRARY_PATH)
$ echo $LD_LIBRARY_PATH

如果没有任何要显示的内容,请添加默认路径值(或者,如果您愿意,则不添加)

$ LD_LIBRARY_PATH=/usr/local/lib
  1. 我们添加所需的路径,将其导出并试用该应用程序。

请注意,路径应为 所在的目录。所以如果是在它应该是:path.so.somethingpath.so.something/my_library/path.so.something

$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/my_library/
$ export LD_LIBRARY_PATH
$ ./my_app

2. 报错Python.error Py_initialize: Unable to get the locale encoding,解决思路:

2.1.参考:

(95条消息) python:Could not find platform independent libraries <prefix>解决方法_码农研究僧的博客-CSDN博客

Linux 系統中 Fatal Python error: Py_Initialize: Unable to get the locale encoding - IT閱讀 ​​​​​​(itread01.com)

Xlx@lx-PC:~$ python
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Fatal Python error: Py_Initialize: Unable to get the locale encoding
ModuleNotFoundError: No module named 'encodings'

類似問題:command not found:conda

暫時性的解決方法是:

export PATH="/home/[your_name]/anaconda/bin:$PATH"
但是下一次重啟之後,還是會出現這個問題,所以我們要acivate ~/.bash_profile

. ~/.bash_profile
#或者
source ~/.bash_profile

但该方法不适用与anaconda虚拟环境调用,遂放弃

2.2参考:

python - 我对"找不到独立于平台的库<prefix>"的原因的诊断是否正确,我该如何修复它?- 堆栈溢出 (stackoverflow.com)

 答案中提出:首先,为我指出解决这个问题(诚然非常非常狡猾)的方法而受到赞扬,这要归功于@John_Bollinger。其次,我发布这个答案只是为了作为那些无法以正确方式解决问题的人的解决方案(请参阅@John_Bollinger答案)。

我的机器上有多个版本的python,都安装在我的个人资料本地。当我定义"PYTHONHOME"时,我在我的".bash_profile"中这样做了。我正在使用IDE开发带有嵌入式python代码的C应用程序。当我运行应用程序时,我会得到上面得到的错误。第一个问题是用于启动python解释器的函数"Py_Initialize()"使用存储在PYTHONHOME中的路径来查找解释器的位置。由于我只通过我的.bash_profile在本地定义了PYTHONHOME,因此发生的事情是"Py_Initialize()"没有正确初始化。

第二个问题与解释器查找模块有关。纠正上述问题后,解释器无法找到运行所需的基本核心模块。我仍然不知道为什么(我怀疑它与第一个问题有关)。我的解决方案是手动指定要使用的模块的路径。若要获取这些内容,请运行 python 解释器并记录以下代码的输出:

import sys
print(sys.path)

将此处输出的每个路径作为 C 代码中路径的一部分。完整的工作解决方案是

#include <..../anaconda3/include/python3.7m/Python.h>    

int main(int argc, char **argv, char **envp)
{
    char[] env = "PYTHONHOME=<path to python interpreter>";// location of interpreter.  In my case ..../anaconda3/bin/python3.7m
   putenv(env);  
   Py_SetPath(L"<paths to python modules>");  // output from print(sys.path) above in normal path format; i.e. path1:path2:...
   Py_Initialize();
   // do your stuff
   Py_FinalizeEx();  // close the interpreter and free the memory its using
}

原因是Python解释器的问题,因为采用Anaconda3虚拟环境中的解释器,所以需要手动指定,根据答案思路修改代码如下:

    #include <stdlib.h>
    char env[] = "PYTHONHOME=/root/anaconda3/envs/nudt/bin/python3.6m";
    putenv(env);  
    
    // location of interpreter.  In my case ..../anaconda3/bin/python3.7m
    Py_SetPath(L"/root/anaconda3/envs/nudt/lib/python36.zip:"
                "/root/anaconda3/envs/nudt/lib/python3.6:"
                "/root/anaconda3/envs/nudt/lib/python3.6/lib-dynload:"
                "/root/anaconda3/envs/nudt/lib/python3.6/site-packages"); 
    //Py_SetPythonHome(L"/root/anaconda3/envs/nudt")
    //Py_SetProgramName(L"/root/anaconda3/envs/nudt/bin/python3.6m")
    Py_Initialize();
    PyErr_Print();
    //设置py脚本路径,否则报错3Segmentation Fault
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(r'/home/zhouzj/cproject')");
    PyObject *pModule = NULL;
    PyObject *pFunc = NULL;
    pModule = PyImport_ImportModule("hello");    //这里是要调用的文件名
    
    pFunc = PyObject_GetAttrString(pModule, "printHello"); //这里是要调用的函数名
    PyEval_CallObject(pFunc, NULL);      //调用函数
    Py_Finalize();

2.3采用Py_SetPythonHome来设置解释器路径,而不是Py_SetPath,后在sys.path中追加py脚本所在路径(否则报错3Segmentation falut)

    wchar_t env[] = L"/root/anaconda3/envs/nudt/";
    wchar_t program[] = L"/root/anaconda3/envs/nudt/bin/python3.6";
    Py_SetPythonHome(env);
    Py_SetProgramName(program);

    Py_Initialize();
    PyRun_SimpleString("print('hello world!')");
    //printf("python home: %s\n", Py_GetPythonHome());
    //printf("program name: %s\n", Py_GetProgramName());
    //printf("get path: %s\n", Py_GetPath());
    //printf("get prefix: %s\n", Py_GetPrefix());
    //printf("get exec prefix: %s\n", Py_GetExecPrefix());
    //printf("get prog full path: %s\n", Py_GetProgramFullPath());

    PyRun_SimpleString("import sys");
    printf("path: ");
    PyRun_SimpleString("print(sys.path)");
    PyRun_SimpleString("sys.path.append(r'/home/zhouzj/cproject')");
    //设置.py文件所在位置
    PyObject *pModule = NULL;
    PyObject *pFunc = NULL;
    pModule = PyImport_ImportModule("hello");    //这里是要调用的文件名
    if (pModule == NULL){
	cout << "don't find the python file!" << endl;
    }
    pFunc = PyObject_GetAttrString(pModule, "printHello"); //这里是要调用的函数名
    PyEval_CallObject(pFunc, NULL);      //调用函数
    Py_Finalize();

该方法第一次运行时报错3Segmentation fault,但后续可正常运行。

3. 报错Segmentation fault(core dumped) 首先参考:

Python 调用动态库时 Segmentation fault (core dumped) 问题 | 隔叶黄莺 Yanbin Blog - 软件编程实践

虽然提示说 core dumped,  但当前目录中没有发现 dumped 的 core 文件。原因是 ulimit 设置,默认时 ulimit -a 看到的

$ ulimit -a
core file size (blocks, -c) 0
......

core file size 为 0, 所以上面的 core dumped 是在撒谎,并没有生成 core 文件,我们可以用 ulimit -c unlimited(或设置一个具体数值) 打开 dump core 的选项

$ ulimit -c unlimited
$ ulimit -a
core file size (blocks, -c) unlimited

ulimit 是会话参数,所以重新连接终端后需要时又得重新执行 ulimit -c unlimited

这时再次执行./a.out, 在当前目录中就会产生一个 core.46951 文件

$ ./a.out
Segmentation fault (core dumped)
$ ls -l core.46951
-rw------- 1 vagrant vagrant 3235840 Aug 24 02:29 core

接下来要做的就是用 gdb 定位出问题的地方,没有 gdb 的用 yum 或 apt 自行安装

$ gdb ./a.out core.46951           # gdb 执行程序(python) core文件

这时进到 gdb 的控制台,输入 bt, 就能看到哪里出问题了

4. 报错/liblzma.so.5: version `XZ_5.1.2alpha' not found (required by /lib64/librpmio.so.3)

参考:

centos7安装anaconda之后报错:rpm: /home/wyl/anaconda3/lib/liblzma.so.5: version `XZ_5.1.2alpha' not found (required by /lib64/librpmio.so.3) - 吱吱了了 - 博客园 (cnblogs.com)

cd /data/anaconda3/lib/
unlink liblzma.so.5
cd /lib64/
cp liblzma.so.5.2.2 /data/anaconda3/lib/
ln -s -f liblzma.so.5.2.2 liblzma.so.5

最终采用2.2和2.3方法修改代码完成了运行!!!

posted @ 2022-01-09 10:43  Mr.zzz  阅读(972)  评论(0编辑  收藏  举报