学习交流而已,有不足之处还请各位大佬多多指点!!!
# 准备
项目需要,是在windows7上操作。python3.7,针对python项目,而非单个的python程序。
思路:先将py代码转成c代码,然后编译成pyd(window上是pyd,linux上是so)文件
安装cython:pip install cython
# 编译
**直接上源码**
-
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='', excepts=()):
-
"""
-
获取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),
-
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()
# 运行
在要打包的目录的同级目录下,创建setup.py,将上述代码复制到setup.py, 直接运行setup.py即可。
执行成功后,会出现一个build文件夹,其中包含有和要打包的项目结构一样的项目,和原项目不同的是,其中的py文件(除__init__外)均被打包成pyd文件,如此源码就被保护起来了。
![ab6bdc404aa7fd25b8d3c5365af2e2ae.png](https://i-blog.csdnimg.cn/blog_migrate/44a2714318e01f34fd2c918ac9f3df09.png)
# 注意
windows上使用cython打包有很多坑
1. 出现“Unable to find vcvarsall.bat”错误
**方法:**
python3只能通过安装对应版本的vc++来解决
2. FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2)
**方法:**
在要打包的每个py文件中的第一行,添加如下语句,# cython: language_level=3
3. 编译后执行需要相同的python版本和编码
参考:
https://blog.csdn.net/qq_20154743/article/details/77891572
Python生成pyd文件 - 杨仕航的博客
可乐小埋酱:setup-cython(1):保护Python源码,提升执行性能