python 模块静态编译

最近有个需求,需要在服务器上跑一个简单的web服务,由于服务器上环境差异较大,准备编译一个独立的静态python。这样以后服务扩容,迁移都比较轻松。通过几天的研究,虽然中间报了一些错误,python的静态版本,基本编译成功。 staticpython

这里记录一下编译过程。

配置编译选项

配置之前需要安装 glibc-static zlib-static 等静态库,否则configure可能会失败

./configure LDFLAGS="-Wl,-no-export-dynamic -Wl,--no-as-needed -static-libgcc -static-libg++ -static" CPPFLAGS="-static -fPIC" -disable-shared -prefix="/home/fluyy/python3"

编译过程中,可能会出现其他错误,根据具体错误,对编译选项进行调整,最终还是编译成功了。 虽然python能够跑起来,但是make test 进行验证的时候,py还是出现了crash。 后来继续研究,网上已经有前辈总结过,当程序中有使用到一些网络库的时候,glibc的静态编译并不是真实的完全静态编译,换句话说glibc当初设计出来,对静态链接就是不友好的, 在你十分清楚你为什么要静态链接glibc之前,还是不要静态连接glibc,这其中可能有些非常隐藏的bug,除非你能处理好。

另一种解决方案

那么问题来了,怎样编译一个具有最大兼容性的binary文件呢,使她可以运行在更多的系统上。我们知道glibc高版本的是能够向下兼容低版本的glibc接口,如此这样,我们只需要找到一个 低版本的的机器,然后编译程序,这样这个程序在高版本的glibc的机器上也是可以运行的。

编译我的python解释器

在经过了一端时间的折腾之后,我决定在一台装有低版本glibc的机器上编译我的python,当然,在python中像openssl这种库也不是每一台机器都有的,折中的方案是对于一些常用模块通过静态编译 直接编译到python解释器中,这样在其他机器上就不会遇上一些模块不能用的问题,这要比编译一个静态的,没有任何动态链接的程序要简单的多。

如可将python的模块静态编译,可以仔细查看器文档。

编辑Modules/Setup文件

 #*shared* 注释掉这一行
 *static*  添加这一行

对于想要编译成静态的模块,取消模块名前面的注释即可。适当调整编译选项,例如我的ssl模块。因为我需要这个模块静态编译,而不去动态加载libcrypto.so和libssl.so 我需要告诉编译器去链接libcrypto.a libssl.a两个静态库,然后注释掉 -L 以及 -l 这部分,告诉编译器不用去目录下寻找这些动态库动态库。

#这是调整前的代码
#SSL=/usr/local/ssl
#_ssl _ssl.c \
#       -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
#       -L$(SSL)/lib -lssl -lcrypto

#我修改成下面的样子
SSL=/usr/local/ssl
_ssl _ssl.c \
    -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
    $(SSL)/lib/libssl.a $(SSL)/lib/libcrypto.a #-lssl -lcrypto

然后编译,安装,如此便很简单的搞定了这个python。我在不同的机器上使用,效果都很好。 接下来,我需要编译一个自带sqlite版本的python,如此就更加完美了。