预览
编译主机:Ubuntu20.04 Linux version 5.8.0-53-generic
python版本及源码地址: https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
交叉编译工具:arm-oe-linux-gnueabi-gcc(gcc version 4.9.2)
编译记录
# 表示注释
$ 表示指令
1. 创建python项目
创建本次编译项目文件夹python
# 创建python项目文件, src用于存放源码,build_1表示第一次编译项目
$ mkdir -p python/src
$ mkdir -p python/build_1
$ tree python -d
python
├── build_1
└── src
2. 下载源码
$ cd python/src
$ wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
# 解压到build_1
$ tar -Jxvf Python-3.7.3.tar.xz -C ../build_1
$ ls ../build_1
Python-3.7.3
3. 安装主机版本
3.1 主机python
先检查主机上有没有python
$ python3 --version
Python 3.8.10
交叉编译时会检查主机上有没有对应版本的python(只要前两个版本号相同就可以, 推荐主机的版本号不低于目标版本号),安装主机python有两种方式,一是下载源码,本地编译安装(不推荐);二是使用apt在线安装(推荐)
推荐使用这个方式安装
# 先添加第三方维护的PPA软件源,apt安装python时会从这个地址获取python
$ sudo add-apt-repository ppa:deadsnakes/ppa
$ sudo apt-get update
# 安装需要的python, 保证前两个版本号相同就可以
$ sudo apt-get install python3.7
# 安装完成之后, 主机上可能就有多个版本python3,使用update-alternatives可以很方便的管理应用版本, 格式如下
# update-alternatives --install link name path priority
# link 表示软连接
# name 表示注册的应用的名称
# path 表示应用的正式路径
# priority 表示优先级,自定义设置, 数字越大优先级越大
# 这里3700 > 380, 表示优先使用python3.8
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 3700
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 380
# 设置成功后,update-alternatives会在/etc/alternatives/下创建应用的软连接, 通过这个链接管理不同版本
# 这里python3的调用路径为: /usr/bin/python3 --> /etc/alternatives/python3 --> /usr/bin/python3.7
# 这样就从原来的python3.8切换到了python3.7, 编译完成后最好再切换回去
$ python3 --version
Python 3.7.13
先下载源码, 解压, 进入源码
#--enable-optimizations 启动优化,编译会需要很长的时间, 不是必选的
$ ./configure --prefix=/usr/local/python3.7 --enable-optimizations
# 编译,安装后将会安装到/usr/local/python3.7
# 安装时可能会提示权限不足, 最好使用sudo
$ make
$ sudo make install
# 安装成功后,设置主机python环境, 同样使用update-alternatives管理多个版本
$ sudo update-alternatives --install /usr/local/python3.7/bin/python3 python3 /usr/bin/python3.7 3700
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 380
3.2 问题总结
编译完成后可能会遇到这种情况, 有些模块没有安装成功,有些模块未找到
3.2.1 _ctypes编译失败
安装_ctypes需要依赖libffi,编译主机版本直接安装libffi-dev即可。但是编译目标版本的python时就需要下载libffi源码,这一点见下一节。
$ sudo apt install libffi-dev
安装libffi-dev后
3.2.2 模块未找到
这是因为主机上缺少相关的依赖库,相关依赖库如下:
_bz2 _dbm _gdbm
_hashlib _lzma _sqlite3
_ssl _tkinter _uuid
readline
这里只找到一下这几个有效的库, 使用apt-get安装即可
模块 | 依赖库 |
---|---|
_bz2 | libbz2-dev |
_gdbm | libgdbm-dev |
_sqlite3 | libsqlite3-dev |
_lzma | liblzma-dev |
安装之后如下:
注意:如果编译arm版本的python时,如果也需要安装这里个库, 最好使用源码安装,经过交叉编译后才能安装到arm版本的python中。
4. 编译目标版本
4.1 基本流程
# 先清除编译主机版本时生成的中间文件
$ make clean
# 创建安装目录install
$ mkdir install
# 配置编译环境
# 1. 交叉编译环境 export PATH=$PATH:编译工具gcc的目录的路径
$ export PATH=$PATH:编译工具gcc的目录的路径
# 2. 安装路径使用绝对路径
# 3. 这里使用了变量LDFLAGS,CPPFLAGS, 后面如果要添加其他依赖环境, 都可以拷贝到python的安装路径下
$ ./configure --host=arm-oe-linux-gnueabi \
--build=x86_64-linux-gnu \
--target=arm-oe-linux-gnueabi --disable-ipv6 \
--prefix=$PWD/install \
ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=yes \
LDFLAGS="-L$PWD/install/lib" \
CPPFLAGS="-I$PWD/install/include"
# 编译,安装
$ make
$ make install
4.2 问题总结
4.2.1 lsb_release指令调用失败
参考这篇文章:https://blog.csdn.net/tao_627/article/details/90901563
# 将lsb_release.py和CommandNotFound复制到主机python中
$ sudo cp /usr/share/pyshared/lsb_release.py /usr/local/python3.7/lib/python3.7/
$ sudo cp -fr /usr/lib/python3/dist-packages/CommandNotFound /usr/local/python3.7/lib/python3.7/
# 将__pycache__子目录中的文件名中带有38名字(有的是35)的文件更改为37
$ ls -l /usr/lib/python3/dist-packages/CommandNotFound/__pycache__
总用量 48
-rw-r--r-- 1 root root 13503 5月 10 10:26 CommandNotFound.cpython-37.pyc
-rw-r--r-- 1 root root 13503 5月 27 16:12 CommandNotFound.cpython-38.pyc-bak
-rw-r--r-- 1 root root 199 5月 10 10:26 __init__.cpython-37.pyc
-rw-r--r-- 1 root root 199 5月 27 16:13 __init__.cpython-38.pyc-bak
-rw-r--r-- 1 root root 1464 5月 10 10:26 util.cpython-37.pyc
-rw-r--r-- 1 root root 1464 5月 27 16:13 util.cpython-38.pyc-bak
4.2.2 _ctypes安装失败
和编译主机时一样,由于缺少依赖库所以导致_ctypes安装失败, 这里需要使用源码安装libffi。
libffi源码地址:ftp://sourceware.org/pub/libffi/libffi-3.3.tar.gz
- 先编译libffi
# 下载源码
$ wget ftp://sourceware.org/pub/libffi/libffi-3.3.tar.gz
$ tar -zxvf libffi-3.3.tar.gz
$ cd libffi-3.3
$ mkdir install
$ ./configure --host=arm-oe-linux-gnueabi --build=x86_64-linux-gnu --prefix=`pwd`/install
$ make
# 需要注意的是,在当前目录make install时总是提示: make: "install"已是最新
# 解决办法:make之后会在当前目录生成arm-oe-linux-gnueabi的文件夹, 先进入这个文件夹,再执行make install。 这个arm-oe-linux-gnueabi对应--host=指定的名称
$ cd arm-oe-linux-gnueabi
$ make install
# 编译安装之后, 拷贝一份到python的安装路径下,假设python安装路径/opt/python3.7.3/install/
$ cp -rfp install/* /opt/python3.7.3/install/
- 重新编译后,_ctype已经从编译失败的列表里面消失了
4.2.3 _hashlib安装失败
解决_ctype编译失败后, 仍然还有一个_hashlib编译失败, 于_ctype一样, 先找到_hashlib所依赖的库。查看之前的编译日志, 可以看到_hashlib依赖了ssl, 同时日志也显示了ssl编译失败,所以需要先解决ssl的问题。
这里我选择重新安装openssl
openssl源码:https://www.openssl.org/source/old/1.1.0/openssl-1.1.0l.tar.gz
# 下载并解压到本地
$ wget https://www.openssl.org/source/old/1.1.0/openssl-1.1.0l.tar.gz
$ tar -zxvf openssl-python-0.1.1.tar.gz
$ cd openssl-1.1.1i
# --prefix= 指定安装路径
# --cross-compile-prefix= 指定编译链
# 注意, 这里使用了sudo,否则可能会出现“This system (linux-x86_64) is not supported”的错误
$ sudo ./config no-asm shared no-async --prefix=`pwd`/install --cross-compile-prefix=/opt/sdk/bin/arm-oe-linux-gnueabi/arm-oe-linux-gnueabi-
# ./config 生成的Makefile, 如果arm是32位系统, 先删除Makefile中的 -m64 编译选项
$ make
$ make install
openssl编译完成后,重新编译python,查看“./configure --help”,–with-openssl=可以指定openssl路径
# 使用--with-openssl=指定openssl
$ ./configure --host=arm-oe-linux-gnueabi \
--build=x86_64-linux-gnu \
--target=arm-oe-linux-gnueabi \
--disable-ipv6 \
--enable-optimizations \
--with-openssl=`pwd`/../Modules/openssl-1.1.1i/install \
--prefix=`pwd`/install \
ac_cv_file__dev_ptmx=yes \
ac_cv_file__dev_ptc=yes \
LDFLAGS="-L$PWD/install/lib" \
CPPFLAGS="-I$PWD/install/include"
# 重新编译,安装
$ make
$ make install
重新编译python之后,ssl已经编译成功
5. 模块安装
5.1 创建python模块交叉编译环境
修改/etc/sudoers,添加:Defaults env_keep += “PYTHONPATH”
在python源码目录下创建脚本mk_lib_config.sh,用于保存python模块交叉编译环境。
$ cat mk_lib_config.sh
export CROSS_COMPILE=arm-oe-linux-gnueabi-
export CC export CC="${CROSS_COMPILE}gcc"
export LDSHARED="${CC} -shared"
export LDFLAGS="-L${PWD}/install/lib"
export CFLAGS="-I${PWD}/install/include/python3.7m"
export PYTHONPATH=$PYTHONPATH:${PWD}/install/lib/python3.7/site-packages
${PWD}/install 表示python的安装路径, 安装模块时会自动安装到这个python的环境下, 这里使用了PWD,所以一定使用的时候一定要先cd到python源码目录下,再执行
$ source mk_lib_config.sh
5.2 asn1crypto模块
# 下载到本地
$ wget https://files.pythonhosted.org/packages/fc/f1/8db7daa71f414ddabfa056c4ef792e1461ff655c2ae2928a2b675bfed6b4/asn1crypto-0.24.0.tar.gz
$ tar -zxvf asn1crypto-0.24.0.tar.gz
$ cd asn1crypto-0.24.0
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
模块安装成功的关键:
- 配置交叉编译环境, 一般都是使用 export
- 配置python模块交叉编译环境,参考上一节
- 安装时指定安装路径, --prefix=
pwd
/…/…/Python-3.7.3/install
5.3 certifi模块
$ wget https://files.pythonhosted.org/packages/06/a9/cd1fd8ee13f73a4d4f491ee219deeeae20afefa914dfb4c130cfc9dc397a/certifi-2020.12.5.tar.gz
$ tar -zxvf certifi-2020.12.5.tar.gz
$ cd certifi-2020.12.5
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
5.4 chardet模块
$ wget https://files.pythonhosted.org/packages/ee/2d/9cdc2b527e127b4c9db64b86647d567985940ac3698eeabc7ffaccb4ea61/chardet-4.0.0.tar.gz
$ tar -zxvf chardet-4.0.0.tar.gz
$ cd chardet-4.0.0
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
5.5 crcmod模块
$ wget https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c3bcd6c33d2473c1918e0b7f6826a043ca1245dd4e5b/crcmod-1.7.tar.gz
$ tar -zxvf crcmod-1.7.tar.gz
$ cd crcmod-1.7
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
5.6 keyring模块
$ wget https://files.pythonhosted.org/packages/b2/aa/71f2e7990a33a23dfcb3a96b87a9b3029664553f3dae4ec08a6f536183ea/keyring-17.1.1.tar.gz
$ tar -zxvf keyring-17.1.1.tar.gz
$ cd keyring-17.1.1
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
安装时并没有提示明显的错误,但是查看日志发现有一个依赖库SecretStorage没有安装,这里也手动安装一下。
$ wget https://files.pythonhosted.org/packages/cd/08/758aeb98db87547484728ea08b0292721f1b05ff9005f59b040d6203c009/SecretStorage-3.3.1.tar.gz
$ tar -zxvf SecretStorage-3.3.1.tar.gz
$ cd SecretStorage-3.3.1
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
SecretStorage依赖jeepney,同样也安装一下, 方法都一样。
jeepney安装完成后,再往后依次安装SecretStorage和keyring,最终还发现还依赖了cryptography,cryptography再上一节中还未解决,所以keyring先安装到这里
5.7 keyrings.alt 模块
$ wget https://files.pythonhosted.org/packages/62/a4/cfa759dc4a5113d653a1dfdbd61011e88fe7abb7a476c8ca10f37e2a789c/keyrings.alt-3.1.1.tar.gz
$ tar -zxvf keyrings.alt-3.1.1.tar.gz
$ cd keyrings.alt-3.1.1
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
keyrings.alt依赖了six, 安装six
$ wget https://files.pythonhosted.org/packages/94/3e/edcf6fef41d89187df7e38e868b2dd2182677922b600e880baad7749c865/six-1.13.0.tar.gz
$ tar -zxvf six-1.13.0.tar.gz
$ cd six-1.13.0
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
安装six之后,重新安装keyrings.alt
5.8 modbus-tk 模块
$ wget https://files.pythonhosted.org/packages/ce/e9/30d86eb912bf868b8c97698b5747f10cf72dc26c674fd030249bc3275484/modbus_tk-1.1.2.tar.gz
$ tar -zxvf modbus_tk-1.1.2.tar.gz
$ cd modbus_tk-1.1.2
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
同样, 安装pyserial, 再重新安装modbus_tk
$ wget https://files.pythonhosted.org/packages/1e/7d/ae3f0a63f41e4d2f6cb66a5b57197850f919f59e558159a4dd3a818f5082/pyserial-3.5.tar.gz
$ tar -zxvf pyserial-3.5.tar.gz
$ cd pyserial-3.5
$ python3 setup.py install --prefix=`pwd`/../../Python-3.7.3/install
5.9 pycrypto 模块
使用pycryptodome替换pycrypto,
- 如果之前安装了pycrypto, 先把pycrypto卸载掉, 否则会冲突。
- 安装pycryptodome, 下载地址https://files.pythonhosted.org/packages/88/7f/740b99ffb8173ba9d20eb890cc05187677df90219649645aca7e44eb8ff4/pycryptodome-3.10.1.tar.gz