使 distutils 将编译后的扩展放在正确的文件夹中

Make distutils place compiled extensions in the right folder

我用 distutils 编写了一个 Python C 扩展。这是 setup.py:

from distutils.core import setup, Extension

utilsmodule = Extension('utils', sources = ['utilsmodule.c'])

setup (name = 'myPackage',
       version = '1.0',
       description = 'My package',
       ext_modules = [utilsmodule])

当我 运行 python setup.y build 时,扩展构建正确,但 .pyd 文件进入文件夹 build/lib.win-amd64-3.7,而不是模块的根 Python 查找要导入的模块。我需要在构建后将该文件移出 build 才能导入它。

我想在 setup() 之后添加一行来移动文件,但这似乎有点脏,我猜 distutils 应该可以完成这项工作。

编译扩展的正确方法是什么可以在构建后立即被其他 Python 文件导入?

distutils should do that work.

不应该。构建只是打包、安装和使用的中间阶段。

What is the right way to compile an extension in a way that it can be imported by other Python files immediately after build?

没有这种方法。您可以将 %PYTHONPATH% 设置为指向 build/lib.win-amd64-3.7 并直接从 build/.

导入模块

或者您可以尝试改变 distutils:

from distutils.core import setup
from distutils.command.build_ext import build_ext as _build_ext
import os

class build_ext(_build_ext):
    def run(self):
        _build_ext.run(self)
        os.rename("build/lib.win-amd64-3.7/%s" % mypydname, dest_dir)

setup(
    …
    cmdclass={'build_ext': build_ext},
    …
)

但是无论如何您都必须决定将编译后的模块移动到哪里。

2022年更新资料~

如果你想在你开发包的项目中测试你的模块,我认为更改扩展名然后使用 --inplace 标志就足够了。

例如,如果 this_package 是您的扩展名,并且您希望您的包结构如下:

project_dir
    |-- package
    |   |-- __init__.py
    |   |-- this_package.xxxx.so
    |   |-- other.py
    |-- setup.py

您可以像这样设置此扩展程序的名称:

Extension("package.this_package", source_files)

然后通过以下方式构建它:

python setup.py build_ext --inplace

如果你想分发和发布包,并且你希望安装包的结构也像上面那样。

  1. 如果您愿意共享您的源文件,您可以使用 python setup.py sdist 创建 .tar.gz 发行版。如果所有的源文件都集中在.tar.gz文件中(通过配置setup.py)。该软件包将在目标机器上正确构建,然后安装在具有这种结构的 site-packages 目录中。

  2. 如果没有,您可能需要使用 python setup.py bdist_wheel 或其他东西来构建用于发布的二进制轮。它会在本地构建库,并且(我认为)我们只能发布 .so 库。但是,.whl 依赖于 OS+Arch,因此您可能需要为不同的 OS+Arch.

    构建多个发行版

无论我们使用什么方式,通过为扩展名设置名称 package.this_package,您总是可以在适当的位置使用 .so