美文网首页
Python源文件编译为动态链接库文件

Python源文件编译为动态链接库文件

作者: Bug2Coder | 来源:发表于2019-10-23 09:46 被阅读0次

    Windows:pyd文件
    Linux:so文件

    import subprocess, re
    import sys, os, shutil, time
    from distutils.core import setup
    from Cython.Build import cythonize
    import platform
    
    starttime = time.time()  
    currdir = os.path.abspath('.')  # 当前目录
    parentpath = sys.argv[1] if len(sys.argv) > 1 else ""
    setupfile = os.path.join(os.path.abspath('.'), __file__)
    build_dir = currdir + "/build"  # 构建目录
    build_tmp_dir = build_dir + "/temp" # 临时目录
    
    
    def getpy(basepath=os.path.abspath('.'), parentpath='', name='', 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)
            if os.path.isdir(ffile) and fname != build_dir and not fname.startswith('.'):
                for f in getpy(basepath, os.path.join(parentpath, name), fname, excepts, copyOther, delC):
                    yield f
            elif os.path.isfile(ffile):
                ext = os.path.splitext(fname)[1]
                if ext == ".c":
                    if delC and os.stat(ffile).st_mtime > starttime:
                        os.remove(ffile)
                elif os.path.realpath(ffile) != os.path.realpath(excepts) and os.path.splitext(fname)[1] not in (
                        '.pyc', '.pyx'):
                    if os.path.splitext(fname)[1] in ('.py', '.pyx') and not fname.startswith('__'):
                        yield os.path.join(parentpath, name, fname)
                    elif copyOther:
                        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))
            else:
                pass
    
    
    def getc(basepath=os.path.abspath('.'), parentpath='', name=''):
        """
        获取c文件的路径
        :param basepath: 根路径
        :param parentpath: 父路径
        :param name: 文件/夹
        :return: py文件的迭代器
        """
        fullpath = os.path.join(basepath, parentpath, name)  # 本级目录
        for fname in os.listdir(fullpath):  # fname 所有文件
            ffile = os.path.join(fullpath, fname)  # 所有文件及绝对路径
            if os.path.isdir(ffile):  # 获得不是build目录和.开头的目录
                for f in getc(basepath, os.path.join(parentpath, name), fname):
                    yield f
            elif os.path.isfile(ffile):  # 同级的文件
                yield os.path.join(basepath, parentpath, name, fname)
            else:
                pass
    
    
    def GetDefaultPath():
        """
        获取默认的python路径,目前只使用与windows
        """
        path = os.environ['path']
        lst = path.split(';')
        for dir in lst:
            try:
                files = os.listdir(dir)
                for file in files:
                    if file == "python.exe":
                        return dir
            except:
                pass
    
    
    def chkCython(path):
        '''
        检查是否安装了cython
        '''
        path += "\Scripts"
        files = os.listdir(path)
        for file in files:
            if file == "cython.exe":
                return True
        return False
    
    
    def getLibName(path):
        """
        得到python的库名(如 python36)
        """
        path += '\libs'
        for fp in os.listdir(path):
            rtn = re.match(r'python...lib', fp)
            if rtn is not None:
                return fp[:len(fp) - 4]
    
    
    def check_system():
        system_name = platform.system()
        return system_name
    
    
    def packPydFiles():
        """
        打包pyd文件
        """
        sys_name = check_system()
        module_list = list(getpy(basepath=currdir, parentpath=parentpath, excepts=(setupfile)))
        if sys_name == "Windows":
            pythonPath = GetDefaultPath()
            res = (cythonize(module_list, build_dir=build_dir))
            cfile_list = list(getc(basepath=build_dir))
            if chkCython(pythonPath):
                for i in cfile_list:
                    str_c = i
                    str_pyd = os.path.splitext(i)[0] + '.pyd'
                    libname = getLibName(pythonPath)
                    cmd = 'gcc {} -o {} -shared -DMS_WIN64 -I "{}\include" -L "{}\libs" -l {}'.format(str_c, str_pyd,
                                                                                                      pythonPath,
                                                                                                      pythonPath,
                                                                                                      libname)
                    rtn2 = subprocess.run(cmd, stdin=subprocess.PIPE,
                                          stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                    os.remove(str_c)
            else:
                print('请安装cython模块')
        elif sys_name == "Linux":
            try:
                setup(ext_modules=cythonize(module_list, build_dir=build_dir),
                      script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir])
            except Exception as ex:
                print("error:", ex)
    
            module_list = list(getpy(basepath=currdir, parentpath=parentpath, excepts=(setupfile), delC=True))
            if os.path.exists(build_tmp_dir):
                shutil.rmtree(build_tmp_dir)
    
    
    packPydFiles()
    

    相关文章

      网友评论

          本文标题:Python源文件编译为动态链接库文件

          本文链接:https://www.haomeiwen.com/subject/evyhvctx.html