Cython 二进制包编译问题

Cython binary package compile issues

我想使用 x64 Native Tools Command Prompt for VS 2019 将 python3 包编译成可分发的二进制形式(无源代码)python 3.6(64 位)。但是,我在指定包应包含的文件的正确路径时遇到问题。在 site-packages 目录中生成的文件夹结构都是错误的,而不是我对源文件夹结构和 setup.py 的期望。 在我看来,顶级包中的模块被区别对待,但我不知道为什么会这样。

我的目录结构如下:

.
├── hello
│   ├── hello1.py
│   ├── hello2.py
│   └── __init__.py
│   bye
│   ├── bye1.py
│   ├── bye2.py
│   └── __init__.py
├── setup.py
└── test
    └── test.py

hello 包中的 __init__.py 包含行 from . import hello1, hello2, byebye 包中的 __init__.py 包含行 from . import bye1, bye2 . hello1.pyhello2.py分别包含函数print_helloprint_hello2bye1.pybye2.py也分别包含函数print_bye作为 print_bye2.

为了完成编译,我设置了以下 setup.py:

from setuptools import Extension, setup, find_packages
from Cython.Build import cythonize

setup(name='hello',
      version='0.3',
      url='https://someurl',
      license='somelicense',
      author='Pepper Wutz',
      author_email='wutz@gmail.com',
      description='Prints "Hello World"',
      ext_modules=cythonize([Extension("hello", ["hello/*.py"]), Extension("hello.bye", ["hello/bye/*.py"]), language_level=3),
      zip_safe=False)

当我 运行 这个模块来自 top_level 文件夹时:

py -3.6 setup.py bdist_wheel

然后安装它(从测试子文件夹中):

py -3.6 -m pip install dist/hello-0.3-cp36-cp36m-win_amd64.whl

我获得以下输出文件:

Verzeichnis von C:\Users\User\AppData\Roaming\Python\Python36\site-packages

18.01.2021  17:32    <DIR>          hello
18.01.2021  17:32    <DIR>          hello-0.3.dist-info
18.01.2021  17:32            20.480 hello.cp36-win_amd64.pyd
               1 Datei(en),         20.480 Bytes
               2 Verzeichnis(se), 15.070.900.224 Bytes frei

Verzeichnis von C:\Users\User\AppData\Roaming\Python\Python36\site-packages\hello

18.01.2021  17:32    <DIR>          .
18.01.2021  17:32    <DIR>          ..
18.01.2021  17:32            20.480 bye.cp36-win_amd64.pyd
               1 Datei(en),         20.480 Bytes
               2 Verzeichnis(se), 15.070.142.464 Bytes frei

很明显,site-packages 中 hello 包的文件夹结构与我原来的文件夹结构大不相同。例如,hello.cp36-win_amd64.pyd 被放入顶级作用域,bye 包被放入 hello 子目录各自的子作用域。 hello1hello2模块没有放入hello包,只放入bye包。这完全搞乱了在 运行 从解释器中编译代码时有效的相对导入:

C:\Users\User\source\repos\cython_tests\test>py -3.6 -c "import hello; print(dir(hello))"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "hello\__init__.py", line 1, in init hello
ImportError: attempted relative import with no known parent package

令人怀疑的是,包含 hello 源的 hello 文件夹只有 __init__.c 文件,但没有 hello1.chello2.chello\bye 文件夹也是如此。

18.01.2021  17:27    <DIR>          .
18.01.2021  17:27    <DIR>          ..
18.01.2021  17:27    <DIR>          bye
18.01.2021  10:58               147 hello1.py
15.01.2021  20:11               150 hello2.py
18.01.2021  17:27           103.044 __init__.c
18.01.2021  17:20                35 __init__.py
               4 Datei(en),        103.376 Bytes
               3 Verzeichnis(se), 15.068.041.216 Bytes frei

我只是迷失了写适当的 setup.py,尤其是指定 ext_modules。我不明白我做错了什么。也许其他人看到了。 我想要获得的是一个二进制包,我可以使用 import hello 导入它,我可以从中调用 hello1 和 hello2 中的函数,如下所示:hello.hello1.print_hello()hello.hello2.print_hello2() 以及 hello.bye.bye1.print_bye(), hello.bye.bye2.print_bye2().

您可能想要做的是为每个 .py 文件.

创建一个包含 扩展模块的包

setup.py 将包含:

      ext_modules=cythonize([
           Extension("hello.hello1", ["hello/hello1.py"]),
           Extension("hello.hello2", ["hello/hello2.py"]),
           Extension("bye.bye1", ["bye/bye1.py"]),
           Extension("bye.bye2", ["bye/bye2.py"]), language_level=3),

我跳过了 __init__.py 文件,因为用 Cython 编译它们通常没有什么价值,而且你必须解决 Windows.

上的安装工具错误

结果是 Python 通过首先搜索模块名称来导入扩展模块,然后查看它是否具有要调用的 PyInit_<module_name> 函数。当 Cython 编译文件时(例如 hello1.py),它会因此创建一个 PyInit_hello1 函数。

因此,您假设的组合“hello”模块最终包含 PyInit_hello1PyInit_hello2,但没有 PyInit_hello,因此不会导入。

如果您真的想要将多个模块捆绑到一个 .so 文件中,那么您可以按照 . You'll note that it isn't a built-in feature and it involves a lot of fine details of the Python import mechanism. Alternatively you could use some third-party tools designed to automated this (e.g. https://github.com/smok-serwis/snakehouse 中的说明进行操作。我不推荐这个,因为它很复杂而且可能有点脆弱。