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, bye
,bye
包中的 __init__.py
包含行 from . import bye1, bye2
.
hello1.py
和hello2.py
分别包含函数print_hello
和print_hello2
,bye1.py
和bye2.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 子目录各自的子作用域。 hello1
和hello2
模块没有放入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.c
和 hello2.c
。 hello\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_hello1
、PyInit_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 中的说明进行操作。我不推荐这个,因为它很复杂而且可能有点脆弱。
我想使用 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, bye
,bye
包中的 __init__.py
包含行 from . import bye1, bye2
.
hello1.py
和hello2.py
分别包含函数print_hello
和print_hello2
,bye1.py
和bye2.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 子目录各自的子作用域。 hello1
和hello2
模块没有放入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.c
和 hello2.c
。 hello\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_hello1
、PyInit_hello2
,但没有 PyInit_hello
,因此不会导入。
如果您真的想要将多个模块捆绑到一个 .so 文件中,那么您可以按照