1.目的

在x86-64平台上生成arm平台上可执行的代码,在x86-64平台上编译python和python依赖库与第三方库,使之能运行在arm平台上。

2. 交叉编译背景

  1. 交叉编译链:CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ AR=arm-linux-gnueabihf-ar RANLIB=arm-linux-gnueabihf-ranlib
  2. 目标板子:arm(暂未定)
  3. python版本:3.12.4
  4. numpy==1.26.3

3.第三方库

分类:

  • 数据分析和科学计算:pandas、numpy、matplotlib
  • 机器学习:tensorflow、pytorch
  • 图像处理:opencv
  • 数据库接口:pymysql

一般使用:

  • 查找库:在Python Package Index上查看找库
  • 安装库:pip install <pkg>
  • 导入库:import

4.整体思路

  1. 在x86主机上交叉编译zlib库
  2. 在x86主机上交叉编译openssl库
  3. 在x86主机上安装x86主机版本的python,称之为x86_python
  4. 在x86主机上交叉编译arm机版本的python,称之为arm_python
  5. 在x86主机上通过crossenv搭建arm_arm的运行虚拟环境
  6. 在crossenv虚拟环境中通过pip打包交叉编译第三方库——.whl形式

-----------------------------------------------------交叉编译工具已在一、里准备好----------------------------------

5.编译x86_zlib

  1. 下载zlib源码,我下载的是zlib1.3.1版本
  2. 解压缩包,我是依赖库的源码包放在~/Downloads/python_libs/rely/目录下(我看其他博主会解压两份源码用作x86_zlib编译和arm_zlib编译,我就用一个,大家根据各自需求来。)
  3. cd zlib-1.3.1
  4. 设置编译环境:  ./configure,默认安装如下
  5. 执行编译安装 make&&make install ,此时安装成功(注:make install时可能会报错权限不够,此时执行sudo make install避免错误。

6.编译arm_zlib

1.此时在~/Downloads/python_libs/rely/zlib-1.3.1目录下

2.设置交叉编译器:

       #(其实只设置第一个就够了)

        export CC=arm-linux-gnueabihf-gcc

        export CXX=arm-linux-gnueabihf-g++

        export  AR=arm-linux-gnueabihf-ar

        export  RANLIB=arm-linux-gnueabihf-ranlib,

3.设置编译环境:./configure --prefix=~/Downloads/arm_python_libs/rely/arm_zlib  --enable-shared

4.执行编译安装:make&&make install

7.编译x86_openssl

  1. 下载openssl-3.1.2版本源码
  2. 解压缩包,还是把源码包放在~/Downloads/python_libs/rely/目录下
  3. cd openssl-3.1.2
  4. 设置编译环境 :./config --prefix=/home/zoe/Downloads/python_lib/openssl
  5. 执行编译安装:make&&make install
  6. 此时检查一下主机自带的opensll版本 openssl version,我的是其它版本,所以还得先去掉主机自带的版本。要不然后面make的是时候报错找不到"xxxx"模块

  7. 备份主机旧版本:sudo mv /usr/bin/openssl /usr/bin/openssl.old 
  8. 建立新的软连接:sudo ln -s /home/zoe/Downloads/python_lib/openssl/bin/openssl /usr/bin/openssl
  9. 编辑链接文件:sudo nano /etc/ld.so.conf.d/libc.conf
  10. 在libc.conf文件中添加:/home/zoe/Downloads/python_lib/openssl/lib64 
  11. 重新加载配置:ldconfig
  12. 测试:openssl version,已经成功

8.编译arm_openssl

  1. 此时在~/Downloads/python_libs/rely/openssl-3.1.2目录下
  2. 设置编译环境 ./config no-asm --shared --cross-compile-prefix=arm-linux-gnueabihf- --prefix=~/Downloads/arm_python_libs/rely/arm_openssl

        no-asm:表示不使用汇编代码加速编译

        --cross-compile-prefix:指定交叉编译的前缀,执行此指令后会在Makefile中指定好交叉编译的工具,如下图是执行后的Makefile

        3.在编译后生成的Makefile中有两处是 -m64 的标记要删除,因为交叉编译后是在32位的板子上运行,参考在linux下为arm开发板交叉编译openssl报错arm-linux-gcc.br_real: error: unrecognized command line option '-m64'_arm-linux-gnueabihf-gcc: error: unrecognized comma-CSDN博客

        4.执行编译安装:make&&make install

9.编译x86_ctypes

使用这条指令:sudo apt-get install libffi-dev  

10.编译arm_ctypes

  1. 下载源码包 libffi-3.4.2
  2. 解压放在~/Downloads/python_libs/rely/目录下
  3. cd  libffi-3.4.2
  4. 设置编译环境:./configure CC=arm-linux-gnueabihf-gcc --host=arm-unknown-linux-gnueabihf --build=x86_64-linux-gnu   --target=arm-linux-gnueabihf --enable-shared --prefix=~/Downloads/arm_python_libs/rely/arm_ctypes
  5. 执行编译安装:make&&make install

11.编译x86_python

可参考:Linux系统安装python3.8与卸载教程 - 知乎 (zhihu.com)

1.安装依赖包

sudo apt-get install zlib1g-dev libbz2-dev libssl-dev libncurses5-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libpcap-dev xz-utils libexpat1-dev liblzma-dev libffi-dev libc6-dev

2.下载python源码3.12.4版本包

3.解压放到~/Downloads/python-3.12.4

4.mkdir x86_python   #当前与Python-3.12.4在同一目录

5.cd python-3.12.4

6.修改Modules/Setup文件:sudo nano Modules/Setup

  1.  修改zlib部分(去掉zlib前面的注释#)

zlib zlibmodule.c -I /usr/local/include -L  /usr/local/lib -lz

  1. 修改openssl部分

SSL=/home/zoe/Downloads/python_lib/openssl

_ssl _ssl.c \

        DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \

        -L$(SSL)/lib -lssl -lcrypto

5.编译并下载pyhton:先export CC=  ,这里将编译器设置回来,默认去找gcc,再执行以下信息

./configure --prefix=/home/zoe/Downloads/x86_python
make     #或者bear -- make ,可以生成编译信息.json文件,但是需要安装bear
make install

想要在这个过程中不安装pip时,使用 --without-ensurepip

3.进入x86_python目录,测试一个py示例,此时在x86本机上也可以import zlib来使用了

注:这里测试时需要进去x86_python/bin目录下,输入命令./python3.12,我是先进行了处理,把python3.12放到全局变量里。可以看以下操作。

zoe@zoe:~/Desktop$ python3.12
Python 3.12.4 (main, Jul 15 2024, 21:29:18) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import zlib
>>> import _ssl
>>> import ctypes
>>> print(1000)
1000
>>> 

注:这里采用自动安装pip的方法,本版本python的pip版本不低就没有采取自动安装,如果自动版本太低,参考这篇:python及第三方库交叉编译 - Se7eN_HOU - 博客园 (cnblogs.com)

12.编译arm_python

  1. 目前的目录为~/Downloads/python-3.12.4
  2. 创建一个新文件夹:mkdir ~/Downloads/arm_rely_libs
  3. 将之前交叉编译好的arm_zlib、arm_openssl、arm_libffi的头文件和链接库复制到~/Downloads/arm_rely_libs

#将各个依赖库的内容都放入新建的文件夹中,按bin、include、lib、share等分类存

cp -rfp ~/Downloads/arm_python_libs/rely/arm_zlib/*  ~/Downloads/arm_rely_libs/

cp -rfp ~/Downloads/arm_python_libs/rely/arm_openssl/*  ~/Downloads/arm_rely_libs/

cp -rfp ~/Downloads/arm_python_libs/rely/arm_ctypes/*  ~/Downloads/arm_rely_libs/

        4.设置CFLAGS:

CFLAGS="-I/home/zoe/Downloads/arm_rely_libs/include -L/home/zoeDownloads/arm_rely_libs/lib" 

        5.设置LDFLAGS:

LDFLAGS="-L /home/zoe/Downloads/arm_rely_libs/lib"

        6.编辑Modules/Setup文件启动依赖库

  • 修改zlib

zlib zlibmodule.c -I/home/zoe/Downloads/arm_rely_libs/include -  L/home/zoe/Downloads/arm_rely_libs/lib -lz

  • 修改openssl

SSL=/home/zoe/Downloads/arm_rely_libs

_ssl _ssl.c \

                -DUSE_SSL -I$(SSL)/inlude -I$(SSL)/include/openssl

                -L$(SSL)/lib -lssl -lcrypto

             7.执行命令进行编译环境设置

#创建安装目录
mkdir arm_py_build
./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=i686-linux-gnu  --target=arm-linux-gnueabihf --enable-shared --disable-ipv6 --with-system-ffi ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=no --enable-optimizations --prefix=/home/zoe/Downloads/arm_py_build

#理解以上编译信息

1)CC:C编译器

2)CXX:C++编译器

3)AR:归档器

4)RANLIB;随机库索引生成器,加快链接过程

5)--host=arm-unknown-linux-gnueabihf :目标机类型是arm-linux-gnueabihf,通常用于32位ARM架构     

6)--target=arm-linux-gnueabihf :指定了目标系统基于ARM架构

7)--enable-shared:

8) --disable-ipv6 :禁用对IPv6的支持。

9)ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=no:arm板子/dev目录下有ptmx,没有ptc

10) --enable-optimizations :启用编译优化,可能会启用一些提高性能的编译选项。

11) --prefix:指定安装路径

12)--with-build-python:指定用于构建过程中的Python解释器路径

13)disable-test-modules:禁用构建测试模块,这可以减少构建过程的时间和资源消耗。

14)--with-ensurepip=install:构建过程会包括 ensurepip 模块,并且会在安装Python解释器时,同时安装 pip 工具。

          8.编译命令: 

make HOSTPYTHON=/home/zoe/Downloads/x86_python/bin/python3 HOSTPGEN=/home/zoe/Downloads/Python-3.12.4/Parser/pgen

这里需要指定一个x86平台的python解释器,和python字节码生成器的路径,在python-3.12.4源码中。

        9.执行:

make install HOSTPYTHON=/home/zoe/Downloads/x86_python/bin/python3

    10.问题处理

  • 交叉编译时需要在本机上有同版本的python,即前面已经编译生成的x86_python,因为交叉编译时需要同版本x86平台的解释器,但我的主机上自带了一个3.9version的python。

直接将x86_python/bin/python3.12放到全局环境中

参考链接:

ubuntu系统: ubuntu22.04安装python,并设置系统环境变量_ubuntu22.04 python-CSDN博客

注:不要像我一样傻傻的sudo apt-get remove python删除了自带的python,这样会导致下次开启虚拟机进入tty模式,没有桌面了。

13.通过crossenv交叉编译第三方库,例如:numpy

原理:

在x86主机上使用x86_python搭建arm_python的虚拟环境,然后在虚拟环境中打包arm_python的带三方库(交叉编译+wheel打包),这里以numpy为例。

步骤:

  1. 进入x86_python目录下:cd /home/zoe/Downloads/x86_python/bin
  2. 安装crossenv:./pip3 install crossenv
  3. 使用crossenv代表arm_python的虚拟环境:
./python3 -m crossenv  /home/zoe/Downloads/arm_python/bin/python3 myvenv

1)./python3:当下目录的python

2)-m crossenv:-m 参数让 Python 作为模块运行,这里 crossenv 是一个用于创建交叉编译环境的模块。

3)/home/zoe/Downloads/arm_python/bin/python3:目标平台上的python解释器路径

4)myvenv:创建的交叉编译的虚拟环境名称

5)如果你的想在虚拟环境中安装新版本pip,加上选项:--without-pip

         note:这步我报错:unable to symlink....,我选择忽视了......

        4.进入虚拟环境目录:cd myvenv/cross/bin

        5.激活环境:source activate

        6.(可选) 安装pip指定版本

#下载pip包
curl https://bootstrap.pypa.io/pip/3.x/get-pip.py -o get-pip.py -k
#安装pip
./python3 get-pip.py 

          7.在myvenv这个虚拟环境中的安装Cython:./pip3 install Cython

          8.创建文件夹来放编译后的第三方库:mkdir /home/zoe/Downloads/arm_3rdparty

          9.在 /home/zoe/Downloads/arm_3rdparty目录下创建requirements.txt(我把文件放在第三方目录里,便于管理)

          10.sudo nano requirements.txt里面写上numpy和版本

       numpy==1.26.3

           11.交叉编译第三方库称为.whl格式的安装包:wheel是pip3的子命令(碰见问题,后续有解决方法)

#使用pip3工具根据requiremwnts.txt文件列出的依赖项创建轮子包
./pip3 wheel --wheel dir /home/zoe/Downloads/arm_3rdparty -r /home/zoe/Downloads/arm_3rdparty/requirement.txt

问题:

描述

最后第11步时,报错

Installing build dependencies ... done
Getting requirements to build wheel ... done
Installing backend dependencies ... error
error: subprocess-exited-with-error

× pip subprocess to install backend dependencies did not run successfully.
│ exit code: 1
╰─> [73 lines of output]
Collecting patchelf>=0.11.0
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<pip._vendor.urllib3.connection.HTTPSConnection object at 0x7ec814d20080>: Failed to establish a new connection: [Errno 101] Network is unreachable')': /packages/83/ec/ac383eb82792e092d8037649b382cf78a7b79c2ce4e5b861f61519b9b14e/patchelf-0.17.2.1.tar.gz

解决

1.更新pip(报出提示信息包含升级版本,但这不是根本原因)

#查看pip版本

pip --version

#升级pip

sudo python3 -m pip install --upgrade pip

2.网络问题-->使用国内镜像源

#交叉编译指令时加上 -i http....

#常见地址

国内镜像地址: 阿里云 http://mirrors.aliyun.com/pypi/simple/

中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/(我用的这个,https更安全)

豆瓣(douban) http://pypi.douban.com/simple/

清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/

中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/

3.报错不安全,应使用https

#交叉编译指令时加上 -i https....
./pip3 wheel --wheel dir /home/zoe/Downloads/arm_3rdparty -r /home/zoe/Downloads/arm_3rdparty/requirement.txt -i  https://pypi.mirrors.ustc.edu.cn/simple/

14.移植到arm板子

原理:

移植arm_python文件夹、numpy-1.26.3-cp312-cp312-linux_arm.whl到目标板子上

步骤:

1.压缩文件夹:tar cvf arm_python.tar arm_python

2.转移压缩包和.whl文件

3.解压并放在/home/zoe/Downloads目录下

4.cd /home/zoe/Downloads/arm_python/bin

5.运行python:./python3

6.验证第三方库

        1.验证pip        

       $ pip list

        2.给.whl文件改名:假设arm板子型号是armv7l,则 mv /home/numpy-1.26.3-cp312-cp312-linux_arm.whl  /home/numpy-1.26.3-cp312-cp312-linux_armv7l.whl 

        3.通过pip安装numpy,验证

./python3

>>import numpy

>>numpy.__version__

1.26.3

>>

其他参考博客

Python3交叉编译步骤(二)-三方库的交叉编译 - 秀才哥哥 - 博客园 (cnblogs.com)

二、python3移植到嵌入式系统并瘦身(交叉编译python3并瘦身)_减小python交叉编译大小-CSDN博客

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐