因为考虑安全性,需要将代码加密,搜了一下,编译成.so文件是比较合适的。而又因为是运行在树莓派的,所以考虑使用交叉编译,不然每次编译都要使用树莓派。
流程:
1.编写Dockefile文件
这里的镜像使用的arm32v7的,因为树莓派是armv7的,一般镜像不行。
FROM arm32v7/python:2.7 RUN echo "deb http://archive.debian.org/debian buster main" > /etc/apt/sources.list && \ echo "deb http://archive.debian.org/debian buster-updates main" >> /etc/apt/sources.list && \ apt-get update && apt-get install -y gcc python-dev && \ pip install "cython<0.30" WORKDIR /work CMD ["python", "setup.py", "build_ext", "--inplace"]2.编译脚本
setup.py这个脚本做了很多的优化
1.extra_link_args = ["-Wl,-s"] # strip 符号表,减小 .so 体积,增加反查难度
2.'binding': False, # 不生成 Python 绑定,减小体积
3. 'embedsignature': False, # 不嵌入函数签名(docstring), 进一步减小体积
4.'language_level': "2", # 强制 Python 2 语法
5.annotate=False, # 不生成 HTML 分析报告,纯编译加速
6.force=True, # 强制重新生成 .c,即使 .c 已存在也强制重新 Cythonize,确保源码
变更一定生效
7.-Wl,-s 在链接阶段 去除 ELF 符号表 :
实测.so的编译文件大小从几十兆缩小到只有几兆
# -*- coding: utf-8 -*- """ Cython 编译脚本(Python 2.7) 用法: python setup.py build_ext --inplace """ from distutils.core import setup from distutils.command.build_ext import build_ext from Cython.Build import cythonize import os import shutil import sys # 清理上次编译残留,强制重新编译 BUILD_DIR = "build" if os.path.isdir(BUILD_DIR): shutil.rmtree(BUILD_DIR) for f in ["test1.c", "test2.c"]: if os.path.isfile(f): os.remove(f) extra_link_args = ["-Wl,-s"] # strip 符号表,减小 .so 体积,增加反查难度 ext_modules = cythonize( [ "test1.py", "test2.py", ], compiler_directives={ 'language_level': "2", # 强制 Python 2 语法 'binding': False, # 不生成 Python 绑定,减小体积 'embedsignature': False, # 不嵌入函数签名 }, annotate=False, # 不需要 HTML 分析报告 force=True, # 强制重新生成 .c quiet=False, # 显示编译进度 ) # 给每个编译目标加上 strip 参数 for ext in ext_modules: ext.extra_link_args = extra_link_args setup( name="test_encrypted", ext_modules=ext_modules, )3.运行编译
--rm 容器退出后删除。
--platform linux/arm/v7 指定目标平台为32位的ARM,强制 Docker 用 QEMU 模拟 armv7l 环境运行容器,编译出的 .so 才能在树莓派 4B 32 位系统上加载
-v ${PWD}:/work 挂载卷 。把当前目录( d:\code\python_work\frp\new_feature\加密 )映射到容器内的 /work 。容器里生成的文件( .so 、 build/ )会直接出现在宿主机当前目录
py2-arm-builder 使用的镜像名。通过 docker buildx build -t py2-arm-builder . 构建的,里面预装了 Python 2.7 + gcc + Cython
docker run --rm --platform linux/arm/v7 -v ${PWD}:/work py2-arm-builder这里需要到程序的目录执行,或者是指定-v挂载的目录
运行后就等着就可以了,一般要十几分钟到半小时,根据文件大小判断。
总结,使用交叉编译大大简化了编译的步骤,后续代码更新后,只需要在程序目录运行docker容器执行编译就可以了。而且setup.py编译脚本也做了优化,压缩了.so文件大小而且加上strip去除符号表进一步增加反向分析的难度。