美文网首页工作记录
python文件编译为so及pyd格式

python文件编译为so及pyd格式

作者: 闭门造折 | 来源:发表于2020-05-26 20:44 被阅读0次

实验室有一个项目,涉及到外包搭建平台,算法源代码由python实现,外包方希望能把python文件编译成.so文件

首先从网上找到了一个转换用的setup文件(放置在路径中,会把同一路径下所有python文件转为.so文件,存储在build路径下),文件内容如下:

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

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

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 = "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)
        #print basepath, parentpath, name,file
        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 ffile not in 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

#获取py列表
module_list = list(getpy(basepath=currdir,parentpath=parentpath, excepts=(setupfile)))
try:
    setup(ext_modules = cythonize(module_list),script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir])
except Exception as ex:
    print("error! ", ex.message)
else:
    module_list = list(getpy(basepath=currdir, parentpath=parentpath, excepts=(setupfile), copyOther=True))

module_list = list(getpy(basepath=currdir, parentpath=parentpath, excepts=(setupfile), delC=True))
if os.path.exists(build_tmp_dir): shutil.rmtree(build_tmp_dir)

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

但是遇到了一些问题,我使用的本地环境是windows的,windows下cython编译转换成的文件为.pyd文件,我测试了一下,在windows环境下的算法中,可以正常的通过import调用使用。但是外包方反馈他们是Linux系统,没有办法调用pyd文件,还是希望我提供一下.so文件

于是在JupyterLab上,注册了一个账号,申请了一个Linux虚拟机,这次重新运行一下setup.py,可以生成.so文件了。(JupyterLab的.so文件不知道为什么是隐藏的,可以通过ls查看,但是直接通过文件目录是看不到的)

外包反应说,这个python版本是3.7,但是之前商议的版本是3.6。于是切换python版本。
JupyterLab中最简单的切换方法,即是直接这样子执行

[XXXXX] python3.6 xxxx.py 

类似于在本地多版本python环境一样,通过python指令名切换python版本。但是这样子会出现pip库内容不全的情况,所以最终还是用conda安了个虚环境

[XXXX] conda create -n my_python python=3.6.5
[XXXX] source activate my_python

然后pip安装一些必需包

[XXXX] pip install cython

然后执行setup.py即可在build目录下获得编译后.so文件,因为文件目录看不到.so文件,所以干脆把整个Build文件夹压缩,然后右键点击下载

[XXXX] tar czvf filename.tar build

到此终于获得了3.6版本下的.so文件了!

相关文章

网友评论

    本文标题:python文件编译为so及pyd格式

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