使用distutils分发预编译的Python扩展模块

19

今天很简单:我正在学习Python的distutils库,并且希望在我的包中包含一个python扩展模块(.pyd)。 当然,我知道建议的方法是让distutils在创建包时编译扩展,但这是一个相当复杂的扩展,涵盖多个源文件并引用多个外部库,因此需要花费一些时间来让一切运作正常。

与此同时,我有一个已知的扩展构建版本,可以在Visual Studio中使用它作为临时解决方案,使我可以专注于其他问题。 然而,我不能将其指定为模块,因为那些显然必须具有明确的.py扩展名。 我应该如何在我的setup.py中指示我想要包括预编译的扩展模块?

(如果有影响,则使用Python 3.1)

5个回答

9

截至目前为止,此网址可用于工作:https://docs.python.org/3.11/distutils/sourcedist.html#specifying-the-files-to-distribute - undefined

8
我通过重写Extension.build_extension方法解决了这个问题。
setup_args = { ... }
if platform.system() == 'Windows':
    class my_build_ext(build_ext):
        def build_extension(self, ext):
            ''' Copies the already-compiled pyd
            '''
            import shutil
            import os.path
            try:
                os.makedirs(os.path.dirname(self.get_ext_fullpath(ext.name)))
            except WindowsError, e:
                if e.winerror != 183: # already exists
                    raise


            shutil.copyfile(os.path.join(this_dir, r'..\..\bin\Python%d%d\my.pyd' % sys.version_info[0:2]), self.get_ext_fullpath(ext.name))

    setup_args['cmdclass'] = {'build_ext': my_build_ext }

setup(**setup_args)

非常好!答案还应该提到放入 setup(..) 的扩展入口:ext_modules=[Extension("_my_extension", sources=[])] - letmaik
谢谢 Kevin;非常有用。 - Paul Bormans

1

我遇到了同样的问题。以下是为我解决该问题的方法。 我已经更改了模块的名称,仅为简单的示例。

我的设置如下: 使用 Visual Studio 2017 构建扩展的项目,最终文件名为 myextension.pyd

然后,我使用 mypy 模块的 stubgen 在本地创建了这个模块的存根。

这是我的文件树

myextension/__init__.pyi
myextension/submodule.pyi
setup.py
myextension.pyd

这是 setup.py 的内容

from setuptools import setup, Distribution


class BinaryDistribution(Distribution):
    def has_ext_modules(foo):
        return True


setup(
    name='myextension',
    version='1.0.0',
    description='myextension Wrapper',
    packages=['', 'myextension'],
    package_data={
        'myextension': ['*.pyi'],
        '': ['myextension.pyd'],
    },
    distclass=BinaryDistribution
)

在运行pip wheel .之后,我得到了一个包含扩展和所需存根的非常好的wheel。


1
我在使用Python 3.7、CMake 3.15.3和Swig 4.0.1以及Visual Studio 2017构建扩展库时遇到了同样的问题。构建系统生成三个文件:mymodule.py、_mymodule.lib和_mymodule.pyd。经过多次尝试,我发现以下组合可以解决问题:
1.创建一个'setup.cfg'文件,指定您正在安装一个包;例如:
    [metadata]
    name = mymodule
    version = 1.0

    [options]
    include_package_data = True
    package_dir=
        =src
    packages=mymodule
    python_requires '>=3.7'

    [options.package_data]
    * = *.pyd
  1. 将CMake更改为创建以下分发目录结构:
    setup.py
    setup.cfg
    src/
        mymodule/
                 __init__.py
                 _mymodule.pyd

"setup.py" 文件就很简单了:
    setup()

这需要使用CMake将'mymodule.py'输出文件重命名为'init.py'。我使用CMake中的'install'命令来完成这个操作:

    install (TARGETS ${SWIG_MODULE_${PROJECT_NAME}_REAL_NAME} DESTINATION "${CMAKE_BINARY_DIR}/dist/src/${PROJECT_NAME}")
    install (FILES 
            setup.py
            setup.cfg
            DESTINATION "${CMAKE_BINARY_DIR}/dist"
    )

    install (FILES
            ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.py
            DESTINATION "${CMAKE_BINARY_DIR}/dist/src/${PROJECT_NAME}"
            RENAME "__init__.py"


我认为让这个工作正常运行的关键秘密是将构建输出重组为Python包,而不是尝试使用默认构建输出作为Python脚本来设置。

0

1
package_data不遵守预编译模块的目录结构。 - Dilawar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接