前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用Cython加密打包python项目

用Cython加密打包python项目

作者头像
Ewdager
发布2020-07-14 14:22:57
4.5K0
发布2020-07-14 14:22:57
举报
文章被收录于专栏:Gvoidy备份小站Gvoidy备份小站

使用

将下述代码保存为setup.py至需打包项目根目录,安装cython后执行python setup.py即可打包。

代码语言:javascript
复制
import sys, os, shutil, time
from distutils.core import setup
from Cython.Build import cythonize

start_time = time.time()
curr_dir = os.path.abspath('.')
parent_path = sys.argv[1] if len(sys.argv) > 1 else ""
setup_file = __file__.replace('/', '\\')
build_dir = "build"
build_tmp_dir = build_dir + "/temp"

s = "# cython: language_level=3"


def get_py(base_path=os.path.abspath('.'), parent_path='', name = '', excepts=(), copyOther=False, delC = False):
    """
    获取py文件的路径
    :param base_path: 根路径
    :param parent_path: 父路径
    :param excepts: 排除文件
    :return: py文件的迭代器
    """
    full_path = os.path.join(base_path, parent_path, name)
    for filename in os.listdir(full_path):
        full_filename = os.path.join(full_path, filename)
        if os.path.isdir(full_filename) and filename != build_dir and not filename.startswith('.'):
            for f in get_py(base_path, os.path.join(parent_path, name), filename, excepts, copyOther, delC):
                yield f
        elif os.path.isfile(full_filename):
            ext = os.path.splitext(filename)[1]
            if ext == ".c":
                if delC and os.stat(full_filename).st_mtime > start_time:
                    os.remove(full_filename)
            elif full_filename not in excepts and os.path.splitext(filename)[1] not in ('.pyc', '.pyx'):
                if os.path.splitext(filename)[1] in ('.py', '.pyx') and not filename.startswith('__'):
                    path = os.path.join(parent_path, name, filename)
                    yield path
        else:
            pass


def pack_pyd():
    # 获取py列表
    module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,)))
    try:
        setup(
            ext_modules=cythonize(module_list, compiler_directives={'language_level': "3"}),
            script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir],
        )
    except Exception as ex:
        print("error! ", str(ex))
    else:
        module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,), copyOther=True))

    module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,), delC=True))
    if os.path.exists(build_tmp_dir):
        shutil.rmtree(build_tmp_dir)

    print("complate! time:", time.time() - start_time, 's')


def delete_c(path='.', excepts=(setup_file,)):
    '''
    删除编译过程中生成的.c文件
    :param path:
    :param excepts:
    :return:
    '''
    dirs = os.listdir(path)
    for dir in dirs:
        new_dir = os.path.join(path, dir)
        if os.path.isfile(new_dir):
            ext = os.path.splitext(new_dir)[1]
            if ext == '.c':
                os.remove(new_dir)
        elif os.path.isdir(new_dir):
            delete_c(new_dir)


if __name__ == '__main__':
    try:
        pack_pyd()
    except Exception as e:
        print(str(e))
    finally:
        delete_c()

常见问题

  1. 出现Unable to find vcvarsall.bat错误 需安装对应版本VC++
  2. 其他文件都能打包,某一文件迷之无法打包 检查文件名是否包含非法字符(比如-
  3. Linux下打包失败或卡住不动 检查是否安装依赖yum install python-devel gcc,如果确定安装依赖,可以稍微等一等,Linux内存不足编译稍大型文件会要很长时间
  4. 打包后出现无法调用某模块 检查对应文件是否循环import(如A文件首行调用B,B首行调用A,默认解释器执行不会出错,编译后会出错)
  5. 打包后路径出现问题 在每个需要打包的文件夹中加入空的__init__.py文件用于判断路径,如果有非空的__init__.py文件,记得打包后复制进对应文件夹

尚未解决的问题

  1. __init__.py判断路径打包和import相对路径绝对路径复用,某些情况下打包后会出现无法定位某些模块的奇怪问题
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用
  • 常见问题
  • 尚未解决的问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档