有时候交付python项目,但是不希望对方看到自己的源码,所以在此记录一个用cython编译项目的脚本,这个脚本能够将python项目一键编译成c输出文件。
pip install Cython
from distutils.core import setup
from distutils.extension import Extension
from pathlib import Path
from Cython.Build import cythonize
import glob, shutil, os
root_dir = os.path.dirname(__file__)
# 编译过程会产生build目录
cache_dir = os.path.join(root_dir, 'build')
# 输出到dist目录
output_dir = os.path.join(root_dir, 'dist')
# 要混淆的代码目录
target_dirs = ['app']
# 忽略的文件名
exclude_files = []
# 删除已存在输出目录
shutil.rmtree(output_dir)
### 遍历目录 ###
for dir in target_dirs:
# 遍历目录下所有py文件
for file in list(Path(os.path.join(root_dir, dir)).glob('**/*.py')):
filename = Path(file).resolve().stem
if filename not in exclude_files:
relpath = os.path.relpath(os.path.dirname(file.absolute().as_posix()), root_dir)
package_name = relpath.replace('/', '.') + '.' + filename if relpath != '.' else filename
# 执行编译
setup(ext_modules=cythonize([Extension(package_name, [str(file)])], compiler_directives={
'c_string_type': 'str',
'c_string_encoding': 'utf8',
'language_level': 3}))
# 移动so文件到输出目录
for dir in target_dirs:
target_path = os.path.join(root_dir, dir)
for file in list(Path(os.path.join(root_dir, dir)).glob('**/*.so')):
filepath = file.absolute().as_posix()
new_path = os.path.join(output_dir, os.path.relpath(filepath, root_dir))
new_dir = os.path.dirname(new_path)
if not os.path.exists(new_dir):
os.makedirs(new_dir)
shutil.move(filepath, new_path)
# 删除指定后缀文件
def delete_files(file_type):
for dir in target_dirs:
cfiles = list(Path(os.path.join(root_dir, dir)).glob('**/*.' + file_type))
for cfile in cfiles:
cfile.unlink()
# 删除产生的多余文件
delete_files('c')
delete_files('pyc')
shutil.rmtree(cache_dir)
执行脚本后,会把所有so文件移动到dist目录
python compile.py build_ext --inplace
build_ext
打包为动态库so文件--inplace
产出文件存在原目录进入输出的dist目录,执行原命令
注意: cython对新版本python的部分语法编译会出错,修改后重新编译即可