python编译pyd及发布exe

参考:
http://c.biancheng.net/view/2690.html

在编写完python程序之后,我们假如想让别人使用我们这个程序。一般来说,是直接把python文件提供给别人,让别人在他自己的python环境中执行。
但是假如别人的电脑没装python,而且又是离线,无法安装该程序(或者说是脚本?)所依赖的一堆东西呢?
有没有办法可以直接发布exe+dll就可以让别人开箱即用我们的程序呢?
有,用 PyInstaller就可以了。
详细的介绍可以看前面的链接。

假如想直接发布单独一个exe,不依赖dll的话,可以

#demo.py是我的程序,请替换成自己的文件
pyinstaller -F demo.py

但是更适合我的是这个

#demo.py是我的程序,请替换成自己的文件
pyinstaller -D demo.py

这个的话是exe+dll的,适合发布大型软件。
在这里插入图片描述

但是此时我们的源代码其实还是可以看到的,假如不想让别人看到我们的代码的话,还要配合用别的办法。

python常用的一些文件格式介绍:
http://forum.digitser.cn/thread-1758-1-1.html
https://www.cnblogs.com/anliven/p/9185549.html

假如仅仅是把源码编译成pyc格式的话,别人还是可以通过反编译看到你的源码的。
可以参考这个博文实现源码编译加密
https://www.cnblogs.com/ke10/p/py2so.html
主要是利用cython把源码编译成库文件,然后再通过python调用。
下面这个脚本是从原作者那里拷贝,经过了一些修改之后得到的。修改之后,在编译源文件文件夹生成pyd时,可以保留彼此的文件夹架构。
在这里插入图片描述

#-* -coding: UTF-8 -* -
__author__ = 'Arvin'
__modifier__ = 'zy'

"""
执行前提:
    系统安装python-devel 和 gcc
    Python安装cython
编译某个文件夹:
    python py2so.py BigoModel
生成结果:
    目录 build 下
生成完成后:
    启动文件还需要py/pyc担当,须将启动的py/pyc拷贝到编译目录并删除so文件
    
zy修改:
   原程序在编译之后,所有文件夹里面的py文件编译得到的库文件全都放在build里面,而丧失了原来的目录架构,导致互相之间的调用出问题。
   这里简单增加一些语句,实现编译后的库文件保留原来的py文件的目录架构
   但是这样子做的话,需要一个个地编译。而不能批量传入,会比较慢。暂时只想到这个办法 
     
"""

import sys, os, shutil, time
from distutils.core import setup
from Cython.Build import cythonize

from distutils.extension import Extension

starttime = time.time()
setupfile = os.path.join(os.path.abspath('.'), __file__)

def getpy(basepath=os.path.abspath('.'), parentpath='', name='', build_dir="build", 
          excepts=(), copyOther=False, delC=False):
    """
    获取py文件的路径
    :param basepath: 根路径
    :param parentpath: 父路径
    :param name: 文件/夹
    :param excepts: 排除文件
    :param copy: 是否copy其他文件
    :return: py文件的迭代器
    """
    # 文件夹的全路径
    fullpath = os.path.join(basepath, parentpath, name)

    # 遍历文件夹
    for fname in os.listdir(fullpath):
        ffile = os.path.join(fullpath, fname)
        # 假如是文件夹 而且 不是build文件夹 而且不是‘.’开头
        if os.path.isdir(ffile) and ffile != os.path.join(basepath, build_dir) and not fname.startswith('.'):
            # 递归调用
            for f in getpy(basepath, os.path.join(parentpath, name), fname, build_dir, excepts, copyOther, delC):
                yield f
        # 假如是文件
        elif os.path.isfile(ffile):
            # print("\t", basepath, parentpath, name, ffile)
            # 获取文件的后缀名
            ext = os.path.splitext(fname)[1]
            # 假如是c文件,而且是本次编译生成的(最后修改时间 > 本次编译的开始时间),且指定了要执行删除操作,就删除
            if ext == ".c":
                if delC and os.stat(ffile).st_mtime > starttime:
                    os.remove(ffile)
            # 假如 这个文件不是本文件,而且不是pyc、pyx文件
            elif ffile not in excepts and ext not in('.pyc', '.pyx'):
                # print("\t\t", basepath, parentpath, name, ffile)
                # 假如是py文件
                if ext in('.py', '.pyx') and not fname.startswith('__'):
                    yield os.path.join(parentpath, name, fname)
                # 假如需要复制
                elif copyOther:
                    print('copy---------')
                    # 目标文件夹为build_dir的目录源码目录
                    dstdir = os.path.join(basepath, build_dir, parentpath, name)
                    # 假如路径不存在,创建路径
                    if not os.path.isdir(dstdir):
                        os.makedirs(dstdir)
                    # 复制文件
                    shutil.copyfile(ffile, os.path.join(dstdir, fname))
                    print("------------", ffile, os.path.join(dstdir, fname))
        else:
            pass

if __name__ == "__main__":
    # 当前路径
    currdir = os.path.abspath('.')
    # 要编译的源代码文件夹
    parentpath = sys.argv[1] if len(sys.argv) > 1 else "."

    # currdir为源代码路径上一层, parentpath为源代码文件夹
    currdir, parentpath = os.path.split(currdir if parentpath == "." else os.path.abspath(parentpath))

    # 用来存放编译文件的build文件夹
    build_dir = os.path.join(parentpath, "build")
    build_tmp_dir = os.path.join(build_dir, "temp")
    print("start:", currdir, parentpath, build_dir)

    # cd到currdir, 也就是源代码文件夹的上一层
    os.chdir(currdir)

    try:
        #获取py列表
        module_list = list(getpy(basepath=currdir, parentpath=parentpath, build_dir=build_dir, excepts=(setupfile)))
        print("build these:", module_list)

        # 编译
        # setup(ext_modules=cythonize(module_list), script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir])
        for filePath in module_list:
            path, file = os.path.split(filePath)
            absPath = os.path.join(build_dir, path)
            # 假如路径不存在,创建路径
            if not os.path.isdir(absPath):
                os.makedirs(absPath)
            # 编译
            setup(ext_modules=cythonize(filePath), script_args=["build_ext", "-b", absPath, "-t", build_tmp_dir])

            # # 清理缓存文件夹
            # if os.path.exists(build_tmp_dir):
            #     shutil.rmtree(build_tmp_dir)


        # 将编译好的pyd文件拷贝指build文件路径中 这一句貌似没执行(因为原本就已经在build文件夹里面了)
        print("begin copy")
        module_list = list(getpy(basepath=currdir, parentpath=parentpath, build_dir=build_dir, excepts=(setupfile), copyOther=True))

    except Exception as ex:
        print("error! ", ex)
    finally:
        print("cleaning...")
        # 清理生成的中间C文件
        module_list = list(getpy(basepath=currdir, parentpath=parentpath, build_dir=build_dir, excepts=(setupfile), delC=True))

        # 清理缓存文件夹
        if os.path.exists(build_tmp_dir):
            shutil.rmtree(build_tmp_dir)


    print("complete! time:", time.time()-starttime, 's')
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python 中,有两种方法可以创建 C/C++ 扩展模块,一种是使用 ctypes 库将 C/C++ 代码封装为 Python 模块,另一种是使用 Python 的 C API 构建 Python 模块。 如果你想使用 Python 的 C API 构建 Python 模块,那么可以使用以下步骤编译 pyd 文件: 1. 编写 C/C++ 扩展模块的代码,并将代码保存为 .c 或 .cpp 文件。 2. 使用 Visual Studio 或者 GCC 等编译器将 C/C++ 代码编译成动态链接库(DLL)或共享对象(SO)文件。 3. 在编译时链接 Python 库文件和头文件。 4. 将生成的 DLL 或 SO 文件重命名为 pyd 文件。 下面是一个示例代码: ```c++ #include <Python.h> static PyObject* example(PyObject* self, PyObject* args) { // 实现扩展模块的逻辑 return Py_BuildValue("s", "Hello, World!"); } static PyMethodDef exampleMethods[] = { {"example", example, METH_VARARGS, "example function"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef exampleModule = { PyModuleDef_HEAD_INIT, "example", "example module", -1, exampleMethods }; PyMODINIT_FUNC PyInit_example(void) { return PyModule_Create(&exampleModule); } ``` 上面的代码实现了一个名为 example 的函数,并将其作为 Python 模块的一部分导出。如果你使用 Visual Studio 编译器,可以使用以下命令编译该代码: ``` cl /LD /I C:\Python38\include example.c /link /LIBPATH:C:\Python38\libs python38.lib ``` 这将在当前目录下生成 example.dll 文件。你可以将其重命名为 example.pyd 文件,然后将其导入到 Python 代码中使用。 注意:在编译时需要根据你的 Python 版本和安装路径设置头文件、库文件、链接库等相关参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值