[重要提醒]
执行打包的动作,不要在源文件上进行,把代码复制到打包环境后再去打包分发,否则会因为清理代码的动作,造成代码丢失
代码清理会清理'.c', '.py', '.pyc', '.o'
文件,所以如果项目中本身就有引用这些文件的话,则需要进行过滤忽略
这里选用一个 django 项目:将 django 整个项目的代码全部转为 so 文件后,再发布
1. 新建 Django 项目
新建一个 django 项目:代码目录如下
.
├── account # 新建的一个app
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── jiami
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ └── settings.cpython-310.pyc
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
复制代码
现在把这个项目的所有 py 文件全部转成 so,然后启动执行。
先回忆下单个文件的做法:新建一个setup.py
在guaner.py
的同级目录下
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize(["guaner.py"]))
复制代码
示例:创建完成后目录结构如下
.
├── __init__.py
├── guaner.py
└── setup.py
0 directories, 3 files
复制代码
然后执行以下命令进行转 so
python setup.py build_ext
复制代码
生成的 so 文件如下
jiami
├── build
│ ├── lib.macosx-10.9-x86_64-3.10
│ │ └── guaner.cpython-310-darwin.so
│ └── temp.macosx-10.9-x86_64-3.10
│ └── guaner.o
├── guaner.c
├── guaner.py
└── setup.py
复制代码
2. 梳理要实现的效果
同理我们要实现整个项目的 py 文件的so
化后然后可以直接部署运行,需要做到以下几个要求:
不能改变文件的目录结构
原py
文件不能存在,否则不能起到加密的用途
不能产生非so
的文件存在,如新生成的.c
文件需要删除
特殊文件不能转so
,比如django
的manage.py
文件就不能转so
,否则python manage.py xx
命令无法执行
3. 实现
3.1 先实现转 so 的动作
setup(ext_modules=cythonize(["guaner.py"]))
中cythonize
需要提供所有的 py 文件,那么要做的第一步就是获取所有的 py 文件
3.1.1 获取项目中的所有 py 文件
def get_all_py_files(dir_root):
"""获取所有的py文件,要编译成so的文件
:params dir_root: 项目根目录地址
"""
res_py_file_list = []
for root, dirs, files in os.walk(dir_root):
for file in files:
if os.path.splitext(file)[1] != '.py':
continue
if 'manage.py' in file:
# manage.py文件需要排除在外,不能转so
continue
_path = f'{root}/{file}'
res_py_file_list.append(_path)
return res_py_file_list
复制代码
3.1.2 转 so
将生成的 so 文件全部生成在其 py 文件原来的目录下
def py_to_so():
project_dir = './' # 项目相对路径
res_py_file_list = get_all_py_files(project_dir)
build_dir = './'
build_tmp_dir = './'
# 为了让so文件直接在源目录结构下生成,所以指定buid和dist都是当前目录
setup(ext_modules=cythonize(res_py_file_list), script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir])
复制代码
执行转 so,看看情况**完整的文件内容如下:jiami.py
文件
import os
from distutils.core import setup
from Cython.Build import cythonize
def get_all_py_files(dir_root):
"""获取所有的py文件,要编译成so的文件
:params dir_root: 项目根目录地址
"""
res_py_file_list = []
for root, dirs, files in os.walk(dir_root):
for file in files:
if os.path.splitext(file)[1] != '.py':
continue
if 'manage.py' in file:
# manage.py文件需要排除在外,不能转so
continue
_path = f'{root}/{file}'
res_py_file_list.append(_path)
return res_py_file_list
def py_to_so():
project_dir = './'
res_py_file_list = get_all_py_files(project_dir)
build_dir = './'
build_tmp_dir = './'
setup(ext_modules=cythonize(res_py_file_list), script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir])
if __name__ == '__main__':
py_to_so()
复制代码
执行python jiami.py
开始转so
,执行结束后,结果如下:
.
├── account
│ ├── __init__.c
│ ├── __init__.cpython-310-darwin.so
│ ├── __init__.o
│ ├── __init__.py
│ ├── admin.c
│ ├── admin.cpython-310-darwin.so
│ ├── admin.o
│ ├── admin.py
│ ├── apps.c
│ ├── apps.cpython-310-darwin.so
│ ├── apps.o
│ ├── apps.py
│ ├── migrations
│ │ ├── __init__.c
│ │ ├── __init__.cpython-310-darwin.so
│ │ ├── __init__.o
│ │ └── __init__.py
│ ├── models.c
│ ├── models.cpython-310-darwin.so
│ ├── models.o
│ ├── models.py
│ ├── tests.c
│ ├── tests.cpython-310-darwin.so
│ ├── tests.o
│ ├── tests.py
│ ├── views.c
│ ├── views.cpython-310-darwin.so
│ ├── views.o
│ └── views.py
├── jiami
│ ├── __init__.c
│ ├── __init__.cpython-310-darwin.so
│ ├── __init__.o
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ └── settings.cpython-310.pyc
│ ├── asgi.c
│ ├── asgi.cpython-310-darwin.so
│ ├── asgi.o
│ ├── asgi.py
│ ├── settings.c
│ ├── settings.cpython-310-darwin.so
│ ├── settings.o
│ ├── settings.py
│ ├── urls.c
│ ├── urls.cpython-310-darwin.so
│ ├── urls.o
│ ├── urls.py
│ ├── wsgi.c
│ ├── wsgi.cpython-310-darwin.so
│ ├── wsgi.o
│ └── wsgi.py
├── jiami.c
├── jiami.cpython-310-darwin.so
├── jiami.o
├── jiami.py
└── manage.py
复制代码
可以看到Cython
生成了一些.c
、.o
文件,以及我们想要的.so
文件,当前我们满足了第一个要求**生成的so
文件目录结构没有变化,下一步我们需要清理中间的.c
、.o
、.py
文件。清理办法:遍历目录删除.c
、.o
、.py
文件,剩下的都是想要的,只留下了so
文件,以及可能存在的一些项目配置文件
3.1.3 清理文件目录
注意清理文件的时候需要注意,不能把没有转 so 的 py 文件也给清理了,否则可能会影响业务运行
def clean_c_file(dir_root):
for root, dirs, files in os.walk(dir_root):
for file in files:
# 这是执行的jiami.py文件,不需要转so,也不需要删除
if 'jiami.py' in file:
continue
# 这是执行的django的命令入口文件,不需要转so,也不需要删除,否则会影响业务使用
if 'manage.py' in file:
continue
if os.path.splitext(file)[1] in ['.c', '.py', '.pyc', '.o']:
_path = f'{root}/{file}'
os.remove(_path)
复制代码
然后我们再执行一次看看,先看完整的jiami.py
文件内容
这里有个危险的动作,清除掉多余的文件是直接删除了,所以执行前不要在源项目代码执行,而是在打包环境秩序,否则有可能会导致文件丢失
import os
from distutils.core import setup
from Cython.Build import cythonize
def get_all_py_files(dir_root):
"""获取所有的py文件,要编译成so的文件
:params dir_root: 项目根目录地址
"""
res_py_file_list = []
for root, dirs, files in os.walk(dir_root):
for file in files:
if os.path.splitext(file)[1] != '.py':
continue
if 'manage.py' in file:
# manage.py文件需要排除在外,不能转so
continue
_path = f'{root}/{file}'
res_py_file_list.append(_path)
return res_py_file_list
def clean_c_file(dir_root):
for root, dirs, files in os.walk(dir_root):
for file in files:
# 这是执行的jiami.py文件,不需要转so,也不需要删除
if 'jiami.py' in file:
continue
# 这是执行的django的命令入口文件,不需要转so,也不需要删除,否则会影响业务使用
if 'manage.py' in file:
continue
if os.path.splitext(file)[1] in ['.c', '.py', '.pyc', '.o']:
_path = f'{root}/{file}'
os.remove(_path)
def py_to_so():
project_dir = './'
res_py_file_list = get_all_py_files(project_dir)
build_dir = './'
build_tmp_dir = './'
setup(ext_modules=cythonize(res_py_file_list), script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir])
# 清除文件
clean_c_file(project_dir)
if __name__ == '__main__':
py_to_so()
复制代码
执行python jiami.py
开始转so
,执行结束后,结果如下:
.
├── account
│ ├── __init__.cpython-310-darwin.so
│ ├── admin.cpython-310-darwin.so
│ ├── apps.cpython-310-darwin.so
│ ├── migrations
│ │ └── __init__.cpython-310-darwin.so
│ ├── models.cpython-310-darwin.so
│ ├── tests.cpython-310-darwin.so
│ └── views.cpython-310-darwin.so
├── jiami
│ ├── __init__.cpython-310-darwin.so
│ ├── __pycache__
│ ├── asgi.cpython-310-darwin.so
│ ├── settings.cpython-310-darwin.so
│ ├── urls.cpython-310-darwin.so
│ └── wsgi.cpython-310-darwin.so
├── jiami.cpython-310-darwin.so
├── jiami.py
└── manage.py
复制代码
不错,不错,是我想要的,除了 so 文件和我要留的外,项目代码很干净了,启动下看看,OK
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
August 19, 2023 - 10:16:20
Django version 4.2.1, using settings 'jiami.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
复制代码
4. 重点提醒
[重要提醒]
执行打包的动作,不要在源文件上进行,把代码复制到打包环境后再去打包分发,否则会因为清理代码的动作,造成代码丢失
代码清理会清理'.c', '.py', '.pyc', '.o'
文件,所以如果项目中本身就有引用这些文件的话,则需要进行过滤忽略
评论