Подтвердить что ты не робот

Распространять предварительно скомпилированный модуль расширения python с distutils

Быстрый сегодня: я изучаю библиотеку distutils из Pythons и из нее, и я хотел бы добавить модуль расширения python (.pyd) с моим пакетом. Я знаю, конечно, что рекомендуемый способ заключается в том, чтобы distutils скомпилировал расширение на момент создания пакета, но это довольно сложное расширение, охватывающее множество исходных файлов и ссылающееся на несколько внешних библиотек, поэтому он собирается провести значительную игру, чтобы получить все право на работу.

Тем временем у меня есть известная рабочая сборка расширения, выходящего из Visual Studio, и хотела бы использовать ее в установщике как временное решение, позволяющее мне сосредоточиться на других проблемах. Однако я не могу указать его как модуль, поскольку они, очевидно, должны иметь явное расширение .py. Как я могу указать в моей setup.py, что я хочу включить предварительно скомпилированный модуль расширения?

(Python 3.1, если это имеет значение)

4b9b3361

Ответ 2

Я решил это, переопределив 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)

Ответ 4

Я столкнулся с этой же проблемой при создании библиотеки расширений с использованием 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
  1. Файл 'setup.py' будет тривиальным:
    setup()

Для этого необходимо, чтобы CMake переименовал выходной файл mymodule.py в init.py. Я сделал это с помощью команды 'install' в CMake:


    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.