静态编译Python3程序模块指南- How to make Python3 static modules built-in , instead dynamic loading

静态编译的Python3程序可以不依赖发行版库文件环境,几乎可以在任何发行版零依赖运行。

构建静态Python3的方法

前提条件

建议在 Alpine Linux 的 Docker 中编译


步骤说明

1. 确定静态编译模块

首先确定要静态编译进Python的模块,比如需要将 asyncio 模块静态编译到 python3,而 asyncio 会依赖其它的底层模块(_socketmathselectarray_posixsubprocess_contextvars 等),详细的官方库编译项可以在 Modules/Setup 中查找,需要一次次尝试查漏补缺。


2. 恢复源码目录初始状态

make distclean

3. 编写静态编译模块配置文件

将需要静态编译的模块信息写到文件 Modules/Setup.local 中:

vi Modules/Setup.local

内容如下:

*static*
_asyncio _asynciomodule.c
_socket socketmodule.c
math mathmodule.c _math.c -DPy_BUILD_CORE_MODULE
select selectmodule.c
array arraymodule.c
_posixsubprocess _posixsubprocess.c
_contextvars _contextvarsmodule.c
_struct _struct.c
binascii binascii.c

4. 执行 configure 配置

./configure LDFLAGS="-static" --disable-shared

检查环境中是否还缺少编译依赖。


5. 检查 Modules/Setup.local 文件

再次检查 Modules/Setup.local 文件,确保执行 configure 后没有被覆盖或者置空:

  • 如果被修改覆盖了,需要重新写入 Modules/Setup.local,再执行第四步 ./configure LDFLAGS="-static" --disable-shared
  • 如果还是被覆盖了,检查 configure 过程中的报错。
  • 还是不行的,删除当前源码,重新解压出原始源码,再次尝试。

6. 执行编译

根据实际情况进行多线程编译(-j 后面接线程数):

make -j10 LDFLAGS="-static" LINKFORSHARED=" "
  • LDFLAGS="-static" 代表是将静态编译的参数传进编译器
  • LINKFORSHARED=" " 是置空 LINKFORSHARED 变量,避免编译出共享库 so

7. 测试运行

当前目录直接测试运行是否正常,是否报缺失模块:

ldd ./python  # 查看执行文件是否静态
./python xxxx.py

8. 打包 Python3 程序

程序运行正常就可以打包 python3 程序了(bin 文件 + lib PY 类型的依赖库):

pwd
/root/0616/Python-3.9.23

将程序临时安装在目录下的 1 路径:

make install LDFLAGS="-static" LINKFORSHARED=" " DESTDIR=/root/0616/Python-3.9.23/1

/root/0616/Python-3.9.23/2 目录下的文件打包到目标环境上的机器即可运行:

ls /root/0616/Python-3.9.23/2/usr/local/lib/
libpython3.9.a  pkgconfig       python3.9

执行以下命令复制文件到目标环境:

rsync -avP /root/0616/Python-3.9.23/2/usr/local/ root@new:/usr/local/
ln -sv /usr/local/bin/python3 /usr/bin/python3-static

更简单的:只用复制静态 python 文件和 usr/local/lib/python3.9 到目标环境中即可。

官方文档(Building Python Statically): https://wiki.python.org/moin/BuildStatically

发表回复