在ubuntu中,基于Qt平台,调用python文件,交叉编译到嵌入式linux开发板上运行

一、 简要介绍

1.1 明确目标

因为要在嵌入式linux开发板上运行,所以要通过交叉编译将x86_64平台的文件交叉编译为arm架构的文件。这里主要就是交叉编译python源码及其依赖库,然后才能在ubuntu的QT平台上通过交叉编译构建出使用python语言、能够在嵌入式linux平台上运行的可执行文件。

1.2 python版本及其背景

  1. 交叉编译工具链:gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
  2. ubuntu平台:ubuntu18.04.1 64bit
  3. python版本:python3.6.9
  4. 嵌入式linux开发板内核:NXP CORTEX-A7 IMX6ULL

1.3 步骤

  1. 首先交叉编译python源码及其依赖库
  2. 移植到linux开发板
  3. 在ubuntu的Qt平台上编写demo验证

二、 交叉编译python源码及其依赖库

2.1 编译步骤

  1. 交叉编译openssl库,这是大部分其他库都有可能使用到的库
  2. 交叉编译zlib库,这是 python源码安装必须的依赖库
  3. 交叉编译libffi库
  4. 交叉编译python源码
    这里贴一个百度网盘链接,大家可以在官网下载相关的库,也可以直接从这里获取:
    链接:https://pan.baidu.com/s/1mui3Vw8FfxnMUFSjFZhItA
    提取码:pwev

2.2 交叉编译openssl

  1. 下载openssl,https://www.openssl.org/source/。这里我使用的版本是openssl1.1.1。
    (注:为了方便管理,所有下载的源码都放在/home/book/pyarm/zlibarm/中)
  2. 解压:tar -xzvf openssl-1.1.1.tar.gz
  3. cd openssl-1.1.1
  4. 配置编译环境:./Configure no-asm shared no-async linux-generic32 --prefix=/home/book/pyarm/opensslarm --cross-compile-prefix=arm-linux-gnueabihf-
    no-asm 在交叉编译过程中不使用汇编代码代码加速编译过程;
    shared 生成动态链接库。
    no-async 交叉编译工具链没有提供GNU C的ucontext库
    –prefix= 安装路径(make和make install后,openssl相关的include和lib等文件就在该目录下。可自行选择安装目录)
    –cross-compile-prefix= 交叉编译工具
    linux-generic32 表示是交叉编译到32位操作系统
  5. make
  6. make install

2.3 交叉编译zlib

  1. 下载zlib,http://zlib.net/。这里我使用的版本是1.2.11.
  2. 解压:tar -xzvf zlib-1.2.11.tar.gz
  3. cd zlib-1.2.11
  4. 设置编译器:export CC=arm-linux-gnueabihf-gcc(因为zlib的configure中没有配置编译器的选项,所以这里设置环境变量)
  5. 配置编译环境:./configure --prefix=/home/book/pyarm/zlibarm --enable-shared
  6. make
  7. make install

2.4 交叉编译libffi

  1. 下载libffi,https://sourceware.org/libffi/。这里我使用的版本是3.2.1
  2. 解压:tar xvzf libffi-3.2.1.tar.gz
  3. cd libffi-3.2.1
  4. 配置编译环境:./configure CC=arm-linux-gnueabihf-gcc --host=arm-linux-gnueabihf --build=x86_64-linux-gnu target=arm-linux-gnueabihf --enable-shared --prefix=/home/book/pyarm/libffiarm
  5. make
  6. make install

2.5 交叉编译python

  1. 下载python,https://www.python.org/downloads/source/。这里我使用的版本是3.6.9

  2. 解压:tar xvf Python-3.6.9.tgz

  3. cd Python-3.6.9

  4. mkdir /home/book/arm-python(因为python编译要依赖上面的库,所以这里添加一个目录,上面编译出来的include和lib都移到该目录中)

  5. 将上面编译的相关库的头文件和链接库复制到/home/book/arm-python中
    cp -rfp /home/book/pyarm/zlibarm/* /home/book/arm-python
    cp -rfp /home/book/pyarm/libffiarm/* /home/book/arm-python
    cp -rfp /home/book/pyarm/opensslarm/* /home/book/arm-python

  6. 设置CFLAGS:CFLAGS=“-I /home/book/arm-python -I /home/book/arm-python/include/python3.6m -L /home/book/arm-python/lib”

  7. 设置LDFLAGS:LDFLAGS=“-L /home/book/arm-python/lib”

  8. vi Modules/Setup.dist,修改里面相关库的头文件和库文件的目录
    在这里插入图片描述
    在这里插入图片描述

    注意:从上面的图片中可以看到,我们设置的库的路径是绝对路径,所以在后面我们打包编译好的文件到开发板时,也要放在开发板的/home/book/arm-python目录中(如果没有,可以自行创建)
    (原因是:Python虚拟环境会记录 Python编译器的绝对路径;因此在其他主机上运行Python虚拟环境时,虚拟环境仍然会去这个绝对路径下寻找Python编译器。所以要在开发板上创建相同的目录,否则会出现找不到文件、模块等错误)

  9. ./configure CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ AR=arm-linux-gnueabihf-ar RANLIB=arm-linux-gnueabihf-ranlib --host=arm-linux-gnueabihf --build=x86_64-linux-gnu --target=arm-linux-gnueabihf --disable-ipv6 ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=yes --prefix=/home/book/arm-python --enable-shared --without-ensurepip

  10. make

  11. make install

三、 移植到linux开发板

  1. 压缩arm-python目录:cd /home/book tar cvf arm-python.tar arm-python
  2. 通过FileZilla等工具将arm-python.tar传到开发板的 /home/book目录
  3. 解压:tar xvf arm-python.tar
    总结:经过以上步骤,python移植就已经完成,这里还可以cd /home/book/arm-python/bin,然后./python3进入python界面编程,使用exit()退出python界面,回到命令行。

四、 在ubuntu的Qt平台上编写demo验证

  1. 在Qt中新建一个项目-----这里我选择的模板是Application(Qt)-----名称:py_test,创建路径为/home/book/QT/my_qt/qt_python------后面几步都默认-----最后勾选上交叉编译工具链----完成。
  2. 新建一个文件—选择Python,Python File----名称:test_pyfile.py,路径不用修改----完成。(创建完成后,可以在项目的Other files看到test_pyfile.py文件)
  3. 在test_pyfile.py文件中添加以下代码:(主要功能就是通过参数a传入字符串,然后返回一个拼接的字符串b)
def testpyfile(a):
    b = a+'jiayou'
    return b
# 这里必须空两行:
# python编码规范:类与类,类与函数,函数与函数之间空两行)
print(testpyfile("111"))
  1. 在.pro文件中导入python相关的库文件和头文件
INCLUDEPATH += \
               -I /home/book/arm-python/include/python3.6m/ \
               -I /home/book/arm-python/include  \
               -I /home/book/arm-python/include/openssl

LIBS += \
        -L /home/book/arm-python/lib/ -lpython3.6m  \
        -L /home/book/arm-python/lib/ -lssl   \
        -L /home/book/arm-python/lib/ -lcrypto   \
        -L /home/book/arm-python/lib/ -lz   \
  1. 在main函数中添加以下代码:
#include "mainwindow.h"

#include <QApplication>

#include "Python.h"   //引入python头文件
#include <QDebug>

int main(int argc, char *argv[])
{
    
    
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    Py_Initialize();   // 初始化Python

    PyObject *pModule = nullptr;
    PyObject *pLoadFunc = nullptr;
    PyObject *pArgs = nullptr;
    PyObject *pReturn = nullptr;
    PyObject *str = nullptr;

    const char *bytes = nullptr;

    if(!Py_IsInitialized())
    {
    
    
        qDebug()<<"inititalize failed";
        return -1;
    }
    else
        qDebug()<<"inititalize success";

    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('/home/book/QT/my_qt/qt_python/py_test')");

    pModule = PyImport_ImportModule("test_pyfile");
    if(!pModule)
    {
    
    
        PyErr_Print();
        qDebug()<<"not loaded module";
        return -1;
    }
    else
        qDebug()<<"load module success";

    pLoadFunc = PyObject_GetAttrString(pModule, "testpyfile");
    if(!pLoadFunc)
    {
    
    
        PyErr_Print();
        qDebug()<<"not loaded pLoadFunc";
        return -1;
    }
    else
        qDebug()<<"load pLoadFunc success";

    pArgs = PyTuple_New(1);
    PyTuple_SetItem(pArgs, 0 , Py_BuildValue("s", "xuheqing"));
    pReturn = PyObject_CallObject(pLoadFunc, pArgs);
    if(!pReturn)
    {
    
    
        qDebug()<<"no return value";
        return -1;
    }

    str = PyObject_Str(pReturn);

    bytes = PyUnicode_AsUTF8(str);

    qDebug()<<bytes;

	Py_Finalize();// 关闭 Python 脚本解释器

    return a.exec();
}

注意:在PyRun_SimpleString(“sys.path.append(‘/home/book/QT/my_qt/qt_python/py_test’)”)中使用了绝对路径添加了我们自己编写.py文件,所以需要将该文件放在开发板的/home/book/QT/my_qt/qt_python/py_test目录中(如果没有,可以自行创建)。不然在开发板运行时,会出现找不到文件模块的错误!!!

  1. 在构建之前先sudo vi /home/book/arm-python/include/python3.6m/object.h,按照下图修改。(因为QT中定义了slots作为关键了,而python3中有使用slot作为变量,所以在编译时会有冲突。)
    在这里插入图片描述

  2. 选择交叉编译工具,然后右击py_test项目,点击构建,即可得到能在arm架构上运行的程序py_test。
    在这里插入图片描述
    在这里插入图片描述

  3. 通过FileZilla等工具将py_test文件传到开发板的/mnt目录,先chmod +x py_test,给py_test添加可执行操作,然后./py_test。这时候会发现出错:
    ./py_test: error while loading shared libraries: libpython3.6m.so.1.0: cannot open shared object file: Norectory
    解决方法
    ① 首先使用指令echo $PATH显示当前PATH环境变量,我的环境变量有/bin:/sbin:/usr/bin:usr/sbin,当我们执行程序时,shell自动根据PATH变量的值去这些路径搜索该程序。所以可以使用export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/arm-python/lib将python相关库的路径添加进去,就可以执行了。
    (注:这只是其中一种方法,且只是临时修改,重启开发板后,需重新设置该环境变量)
    ② vi /etc/profile。在文件末尾添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/arm-python/lib然后重启开发板。/etc/profile中的环境变量是对所有用户都有效,并在系统启动时被运行,这就是环境变量永久有效的一种方式。

  4. 运行结果
    在这里插入图片描述

五、 参考文档链接

  1. python及第三方库交叉编译
  2. ubuntu环境下QT+python混合编程
  3. 使用虚拟Python环境 C++调用Python脚本出现 Py_Initialize : unable to load the file system codec 错误

猜你喜欢

转载自blog.csdn.net/m0_43443861/article/details/127907530