实验室有一个项目,涉及到外包搭建平台,算法源代码由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文件了!
网友评论