美文网首页
通过Cython打包py文件,生成包含pyd的wheel(.wh

通过Cython打包py文件,生成包含pyd的wheel(.wh

作者: qizhen816 | 来源:发表于2020-03-05 10:11 被阅读0次

setup.py写法,参考这里
linux:

from setuptools import setup
from setuptools.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext

setup(
    name="MyModule"  # 模块名称 import MyModule,
    ext_modules=cythonize(
        [
           Extension("pkg1.*", ["root/pkg1/*.py"]),
           Extension("pkg2.*", ["root/pkg2/*.py"]),
           Extension("1.*", ["root/*.py"])
        ],
        build_dir="build",
        compiler_directives=dict(
        always_allow_keywords=True
        )),
    cmdclass=dict(
        build_ext=build_ext
    ),
    packages=["pkg1", "pkg2"]  # packages=[]时打包后的wheel文件中不含源码(.py)
)

windows:

from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
from pathlib import Path
import shutil


class MyBuildExt(build_ext):
    def run(self):
        build_ext.run(self)

        build_dir = Path(self.build_lib)
        root_dir = Path(__file__).parent
        target_dir = build_dir if not self.inplace else root_dir

        self.copy_file(Path('root/pkg1') / '__init__.py', root_dir, target_dir)
        self.copy_file(Path('root/pkg2') / '__init__.py', root_dir, target_dir)
        self.copy_file(Path('root') / '__init__.py', root_dir, target_dir)
    def copy_file(self, path, source_dir, destination_dir):
        if not (source_dir / path).exists():
            return
        shutil.copyfile(str(source_dir / path), str(destination_dir / path))

setup(
    name="MyModule",
    ext_modules=cythonize(
        [
           Extension("pkg1.*", ["root/pkg1/*.py"]),
           Extension("pkg2.*", ["root/pkg2/*.py"]),
           Extension("1.*", ["root/*.py"])
        ],
        build_dir="build",
        compiler_directives=dict(
        always_allow_keywords=True
        )),
    cmdclass=dict(
        build_ext=MyBuildExt
    ),
    packages=[],
)

在cython3上线之前,windows下编译init始终有个问题:

LINK : error LNK2001: unresolved external symbol PyInit___init__
build\temp.win-amd64-3.7\Release\build\doug/core\__init__.cp37-win_amd64.lib : fatal error LNK1120: 1 unresolved externals
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\link.exe' failed with exit status 1120

这个问题是当前cython对windows包支持不好导致的,可以使用如下方法修复:
打开cython安装目录:

pip show cython

打开安装目录\cython\Compiler\ModuleNode.py,替换如下内容:

替换
将原来的
        code.putln(header2)
        code.putln("#else") 
        code.putln("%s CYTHON_SMALL_CODE; /*proto*/" % header3)

替换为

        if self.scope.is_package:
            code.putln("#if !defined(CYTHON_NO_PYINIT_EXPORT) && (defined(WIN32) || defined(MS_WINDOWS))")
            code.putln("__Pyx_PyMODINIT_FUNC init__init__(void) { init%s(); };" % env.module_name)
            code.putln("#endif")
        code.putln(header2)
        code.putln("#else")
        code.putln("%s CYTHON_SMALL_CODE; /*proto*/" % header3)
        if self.scope.is_package:
            code.putln("#if !defined(CYTHON_NO_PYINIT_EXPORT) && (defined(WIN32) || defined(MS_WINDOWS))")
            code.putln("__Pyx_PyMODINIT_FUNC PyInit___init__(void) { return %s(); };" % (
                self.mod_init_func_cname('PyInit', env)))
            code.putln("#endif")

然后删除项目build下的文件夹,重新buid就行了
python setup.py bdist_wheel

相关文章

网友评论

      本文标题:通过Cython打包py文件,生成包含pyd的wheel(.wh

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