Python 静态编译: pyinstaller + staticx
由于Python是一种解释型语言,只要设备上安装了Python解释器,无需编译即可源码运行。但如果想要把Python发布给别人使用,要求别人安装Python或者第三方库显然不合理。
因此产生了一些Python打包工具,常见的例如pyinstaller,能够将Python解释器与源码一同打包,实现单文件分发。
但这种方法也存在一些问题,尤其是在Linux系统下,pyinstaller不会将Python解释器的动态依赖库一并打包,常见的例如GLIBC。如果你的打包环境和运行环境的GLIBC版本不一致,那么就会报错无法使用。
staticx应运而生,它能够将动态链接库一并打包,避免不同设备上动态库版本不一致问题。
一、pyinstaller
安装
pip install pyinstaller
打包
pyinstaller --onefile test.py
打包完成后即可在dist目录下找到可执行文件test/test.exe。
pyinstaller能够将Python程序及其依赖的库、以及Python解释器打包成为一个可执行文件。对Windows系统而言,到这一步就可以了。但对于Linux系统,还需要将动态链接库进行打包。
二、staticx
安装
pip install staticx
打包
staticx test_bin test_static
staticx打包后,可执行文件即可分发部署到其他Linux系统上,而不再受诸如GLIBC等动态库的困扰。
三、可执行文件路径问题
有时我们希望给代码增加一些配置文件,用来保存一些随时可能被修改的参数,又或者是一些图片、音乐等资源文件,而修改这些文件时我们又不想重新编译打包代码。这时我们会尝试获取当前可执行文件的绝对路径,并以此来计算资源文件的路径,进行读取资源文件的操作。
在Python中可以使用如下代码获取当前.py文件的路径:
import os
execPath = os.path.realpath(__file__)
print(execPath)
~# python /home/test/test.py
/home/test/test.py
当你使用pyinstaller打包后,执行这个可执行文件可能会得到这样的结果:
~# /home/test/test_bin
/tmp/_MEIzDcG8B/test.py
这是因为应用程序在执行时,会将打包的Python程序、解释器等内容解压到/tmp下的临时文件夹下,此时获取到的路径就是临时文件夹的路径,而不是可执行文件实际路径。此时可以使用 sys.executable 来获取路径:
import os
import sys
execPath = sys.executable if getattr(sys, "frozen", False) else os.path.realpath(__file__)
print(execPath)
这时执行pyinstaller打包后的文件可以得到正确的路径
~# /home/test/test_bin
/home/test/test_bin
但是。。。使用staticx打包后,这个方法也会失效。
~# /home/test/test_static
/tmp/staticx-EMdpDD/test
对于这个问题,我百思不得其解,网上的方法都试了一个遍,仍然都无效,诸如
sys.argv[0] ×
sys.path[0] ×
sys._MEIPASS ×
直到我看到了staticx的官方主页介绍
这句话的意思大概就是:这个生成的可执行文件实际上是StaticX引导加载程序,附带一个包含用户可执行文件和库的归档文件。而pyinstaller打包后的可执行文件是被staticx bootloader在/tmp文件夹下引导加载的,怪不得python中通过各种方法获取的路径都是/tmp临时文件夹。
也就是说我们想要获取的其实是staticx bootloader可执行文件的绝对路径,这在python里面并没有提供获取方法,但官方已经给出了答案
staticx提供了两个环境变量,分别用来获取临时文件夹路径和可执行文件绝对路径,我们想要的就是第二个环境变量,将上述代码稍作修改:
import os
import sys
execPath = (os.environ.get("STATICX_PROG_PATH") if os.environ.get("STATICX_PROG_PATH") else sys.executable) if getattr(sys, "frozen", False) else os.path.realpath(__file__)
print(execPath)
大功告成
~# /home/test/test_static
/home/test/test_static
转载自:https://juejin.cn/post/7369535515291959330