1.在嵌入式python移植时,空间资源有限,而python在编译时,会自动编译一些扩展库
2.这些扩展库中,有一些是我们用不到的,所以就需要裁剪掉一部分库
3.未裁剪之前的python库文件大概占用127M空间,其中包含so库和python文件
动态链接库 ,也就是 lib-dynload
这个文件夹大概占用8.9m,其余为python相关的库文件
1.在满足功能的情况下,让Python尽可能的小。
2.可选择功能进行裁剪。
3.用户体验好,不能让用户修改源码或者Makefile。
1.最好找到python编译模块的数据元素,这样就可以对数据元素中的模块进行修改,达到裁剪的效果。
2.如果找不到的话,能否对生成的文件进行筛选,也能达到裁剪的效果。
两种办法一个是从源头上解决问题,一个是从尽头上解决问题。
当然最好是从源头上解决问题更好一些,因为这样可以防止一些依赖文件被裁剪的现象发生。
对python安装包中安装相关的文件进行梳理
其中setup.py文件是用来生成外部扩展库动态链接库的,所有的so库都会在这里配置
'disabled_module_list’这个变量为不编译的模块列表,如果不想编译某个模块,将其名称的字符串放入列表中即可。
例:disabled_module_list = [“_json”****] # 不编译json模块
所有的模块如下表
_asyncio | _crypt | _gdbm | _posixsubprocess |
---|---|---|---|
_bisect | _csv | _heapq | _random |
_blake2 | _ctypes | _json | _sha1 |
_bz2 | _ctypes_test | _lsprof | _sha256 |
_codecs_cn | _curses | _lzma | _sha3 |
_codecs_hk | _curses_panel | _md5 | _sha512 |
_codecs_iso2022 | _datetime | _multibytecodec | _socket |
_codecs_jp | _dbm | _multiprocessing | _sqlite3 |
_codecs_kr | _decimal | _opcode | _ssl |
_codecs_tw | _elementtree | _pickle | |
_testbuffer | fcntl | resource | |
_testcapi | grp | select | |
_testimportmultiple | math | spwd | |
_testmultiphase | mmap | syslog | |
_tkinter | nis | termios | |
array | ossaudiodev | time | |
atexit | parser | unicodedata | |
audioop | pwd | xxlimited | |
binascii | pyexpat | zlib | |
cmath | readline | _struct |
前面已经找到配置不编译项的接口了,根据计划,先试一下从源头上解决问题。
1.建立一个文件,在文件中创建一个元组not_make_module,将不编译的模块放入其中
只编译sockert和math
2.在setu.py文件中import这个文件的变量
3.将not_make_module的内容赋给disabled_module_list
查看编译出的文件
umm…再看看动态库文件
库文件确实是根据我们的配置not_make_module来编译的,也就是只编译sockert和math,但是python文件却是一个都没少
这和我预想的结果有些偏差,我预想的结果是这样的
那么到底是什么导致的呢?
解释起来就是这样的
1.先建立一堆文件夹
2.把python路径下Lib/*.py 和文件夹,全部考到install/lib/python3.6
所以它根本就没有关心我们的disabled_module_list里添加了什么,而是全部拷贝!
从源头上解决问题不行,只能从尽头上解决问题了。
纵览库文件夹中,占用空间较大的都是文件夹
所以对文件夹进行裁剪将会是比较可行的办法,其中
1.test测试文件夹占用56M,可以不要
2.__pycache__缓存文件夹占用9.5M,可以不要
3.config-3.6m-arm-linux-gnueabihf文件夹占用14M,编译过程生成的文件夹,可以不要
4.encodings文件夹,是python运行的必备文件夹
menu "Libs Setting"
menu "Python Module"
menu "图形界面相关模块(默认不编译)"
config PYTHON_MODULE_CURSES
bool "120K curses 图形函数库"
default n
config PYTHON_MODULE_TURTLEDEMO
bool "448K turtledemo 乌龟画图"
default n
config PYTHON_MODULE_TKINTER
bool "2.5M tkinter 界面接口"
default n
config PYTHON_MODULE_IDLELIB
bool "4.5M idlelib python编辑器,不用的话可以不要,依赖tkinter"
default n
endmenu
menu "网络相关模块"
config PYTHON_MODULE_HTTP
bool "620K http http服务模块"
default y
config PYTHON_MODULE_XMLRPC
bool "300K xmlrpc 使用http协议做为传输协议的rpc机制"
default y
config PYTHON_MODULE_XML
bool "1.2M xml xml解析模块"
default y
config PYTHON_MODULE_HTML
bool "316K html html模块"
default y
config PYTHON_MODULE_JSON
bool "188K json json解析模块"
default y
config PYTHON_MODULE_URLLIB
bool "516K urllib URL处理模块"
default y
config PYTHON_MODULE_EMAIL
bool "1.4M email 邮件模块"
default n
config PYTHON_MODULE_WSGIREF
bool "244K wsgiref web服务器网关接口"
default y
endmenu
config PYTHON_MODULE_ENSUREPIP
bool "2.0M ensurepip 启动 pip 安装程序"
default n
config PYTHON_MODULE_VENV
bool "112K venv 虚拟环境"
default n
config PYTHON_MODULE_LIB2TO3
bool "3.0M lib2to3 py2转py3自动化工具"
default n
config PYTHON_MODULE_UNITTEST
bool "2.9M unittest 单元测试框架"
default n
config PYTHON_MODULE_SITE_PACKAGES
bool "8.0K site-packages 三方包管理模块"
default y
config PYTHON_MODULE_DBM
bool "112K dbm 持久字典"
default y
config PYTHON_MODULE_IMPORTLIB
bool "428K importlib 动态导入模块"
default y
config PYTHON_MODULE_SQLITE3
bool "636K sqlite3 sqlite3数据库接口模块"
default y
config PYTHON_MODULE_DISTUTILS
bool "3.5M distutils 发布工具,默认不选"
default n
config PYTHON_MODULE_CONCURRENT
bool "224K concurrent 并发模块"
default y
config PYTHON_MODULE_COLLECTIONS
bool "204K collections 容器数据类型"
default y
config PYTHON_MODULE_MULTIPROCESSING
bool "940K multiprocessing 基于进程的并行"
default y
config PYTHON_MODULE_ASYNCIO
bool "1.5M asyncio 异步io"
default y
config PYTHON_MODULE_LOGGING
bool "508K logging 日志分级打印"
default y
config PYTHON_MODULE_PYDOC_DATA
bool "1.8M pydoc_data Python文档生成工具"
default n
config PYTHON_MODULE_CTYPES
bool "1.6M ctypes Python 的外部函数库"
default y
endmenu
文件拷贝脚本的思想是:
1.尽量不改变原有的文件,包括Makefile等
2.可根据CONFIG变量进行拷贝
实现过程
#!/bin/bash
PYTHON_INSTALL_LIBS_DIR=`pwd`/install/lib/python3.6
#python临时文件夹
PYTHON_LIBS_TEMP_DIR=${PYTHON_INSTALL_LIBS_DIR}/python
#拷贝bin文件
cp `pwd`/install/bin/* ${LIBBINS_DIR} -rfd
#建立python文件夹
mkdir ${PYTHON_LIBS_TEMP_DIR}
#拷贝python库文件
cp ${PYTHON_INSTALL_LIBS_DIR}/*.py ${PYTHON_LIBS_TEMP_DIR}
#拷贝SO库文件
cp ${PYTHON_INSTALL_LIBS_DIR}/lib-dynload ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/lib-dynload ${PYTHON_LIBS_TEMP_DIR} -R
#瘦身SO库文件
${STRIP} ${PYTHON_LIBS_TEMP_DIR}/lib-dynload/*
echo ${STRIP} ${PYTHON_LIBS_TEMP_DIR}/lib-dynload/*
#拷贝文件夹
if [ ${CONFIG_PYTHON_MODULE_ENSUREPIP}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/ensurepip ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/ensurepip ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_VENV}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/venv ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/venv ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_LIB2TO3}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/lib2to3 ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/lib2to3 ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_CURSES}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/curses ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/curses ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_HTTP}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/http ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/http ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_XMLRPC}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/xmlrpc ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/xmlrpc ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_UNITTEST}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/unittest ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/unittest ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_SITE_PACKAGES}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/site-packages ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/site-packages ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_DBM}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/dbm ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/dbm ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_TURTLEDEMO}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/turtledemo ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/turtledemo ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_IMPORTLIB}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/importlib ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/importlib ${PYTHON_LIBS_TEMP_DIR} -R
fi
#if [ ${CONFIG_PYTHON_MODULE_ENCODINGS}x = yx ] ; then
#核心库,缺失python无法运行, 条件判断就大可不必了
cp ${PYTHON_INSTALL_LIBS_DIR}/encodings ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/encodings ${PYTHON_LIBS_TEMP_DIR} -R
#fi
if [ ${CONFIG_PYTHON_MODULE_SQLITE3}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/sqlite3 ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/sqlite3 ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_DISTUTILS}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/distutils ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/distutils ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_XML}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/xml ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/xml ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_CONCURRENT}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/concurrent ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/concurrent ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_HTML}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/html ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/html ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_JSON}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/json ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/json ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_IDLELIB}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/idlelib ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/idlelib ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_COLLECTIONS}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/collections ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/collections ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_URLLIB}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/urllib ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/urllib ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_MULTIPROCESSING}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/multiprocessing ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/multiprocessing ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_ASYNCIO}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/asyncio ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/asyncio ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_TKINTER}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/tkinter ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/tkinter ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_LOGGING}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/logging ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/logging ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_PYDOC_DATA}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/pydoc_data ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/pydoc_data ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_CTYPES}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/ctypes ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/ctypes ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_EMAIL}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/email ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/email ${PYTHON_LIBS_TEMP_DIR} -R
fi
if [ ${CONFIG_PYTHON_MODULE_WSGIREF}x = yx ] ; then
cp ${PYTHON_INSTALL_LIBS_DIR}/wsgiref ${PYTHON_LIBS_TEMP_DIR} -R
echo cp ${PYTHON_INSTALL_LIBS_DIR}/wsgiref ${PYTHON_LIBS_TEMP_DIR} -R
fi
#删除python缓存文件夹
#rm ${PYTHON_LIBS_TEMP_DIR}/__pycache__ -R
#拷贝lib文件
cp ${PYTHON_LIBS_TEMP_DIR} ${LIBLIBS_DIR}/ -rfd
#删除lib临时文件夹
rm ${PYTHON_LIBS_TEMP_DIR} -R
实现效果:
1.生成一个拷贝后的文件夹
2.将so库文件strip
3.将bin文件拷贝到libs/install/bin中(之后会自动拷贝到开发板的文件系统中)
4.将lib文件拷贝到libs/install/lib中(之后会自动拷贝到开发板的文件系统中)
这个位置是make执行的的最后位置,放在这里等于make完毕后执行此脚本
python在开发板中默认的库位置是python编译的位置。
例如我的python库生成位置在home/longguancheng/linuxGatewayPlatform/libs/python-3.6.5/install/lib/python3.6
而开发板中不存在这个位置,所以需要重新定向一下这个位置,通过修改PYTHONHOME
和PYTHONPATH``这两个环境变量
来帮助python找到自己的库。
修改源文件系统的环境变量文件rootfs/node/etc/profile
添加两行代码
可见从之前的110m变成了24m左右,效果显著.
我们再看看这个文件夹内部的情况
和我们设想的效果一致
将生成的文件系统烧录到开发板,测试一下库是否都可以import
整理成表格:
模块名称 | menuconfig是否选中 | import是否成功 |
---|---|---|
ensurepip | —Yes— | —Yes— |
venv | —Yes— | —Yes— |
lib2to3 | —Yes— | —Yes— |
curses | —Yes— | No (不一致) |
http | —Yes— | —Yes— |
xmlrpc | —Yes— | —Yes— |
unittest | No | No |
site | —Yes— | —Yes— |
dbm | —Yes— | —Yes— |
turtledemo | No | No |
importlib | —Yes— | —Yes— |
sqlite3 | No | No |
distutils | No | No |
xml | No | No |
concurrent | —Yes— | —Yes— |
html | —Yes— | —Yes— |
json | —Yes— | —Yes— |
idlelib | No | No |
collections | —Yes— | —Yes— |
urllib | —Yes— | —Yes— |
multiprocessing | —Yes— | —Yes— |
asyncio | —Yes— | —Yes— |
tkinter | No | No |
logging | —Yes— | —Yes— |
pydoc_data | No | No |
ctypes | —Yes— | —Yes— |
No | No | |
wsgiref | —Yes— | —Yes— |
可以发现有一个curses模块是没有对起来的
curses是一个在Linux/Unix下广泛应用的图形函数库,作用是可以在终端内绘制简单的图形用户界面。
cueses模块没有移植成功主要是因为在编译阶段就因为缺少库而被忽略了