python distutils не включает сгенерированный модуль SWIG

Я использую distutils для создания rpm из моего проекта. У меня есть это дерево каталогов:

project/
        my_module/
                 data/file.dat
                 my_module1.py
                 my_module2.py
        src/
            header1.h
            header2.h
            ext_module1.cpp
            ext_module2.cpp
            swig_module.i
        setup.py
        MANIFEST.in
        MANIFEST

my setup.py:

from distutils.core import setup, Extension

module1 = Extension('my_module._module',
                sources=['src/ext_module1.cpp',
                         'src/ext_module2.cpp',
                         'src/swig_module.i'],
                swig_opts=['-c++', '-py3'],
                include_dirs=[...],
                runtime_library_dirs=[...],
                libraries=[...],
                extra_compile_args=['-Wno-write-strings'])

setup(  name            = 'my_module',
        version         = '0.6',
        author          = 'microo8',
        author_email    = '[email protected]',
        description     = '',
        license         = 'GPLv3',
        url             = '',
        platforms       = ['x86_64'],
        ext_modules     = [module1],
        packages        = ['my_module'],
        package_dir     = {'my_module': 'my_module'},
        package_data    = {'my_module': ['data/*.dat']} )

мой MANIFEST.in файл:

include src/header1.h
include src/header2.h

файл MANIFEST автоматически создается python3 setup.py sdist. И когда я запускаю python3 setup.py bdist_rpm, он компилирует и создает правильные пакеты rpm. Но проблема в том, что когда я запускаю SWIG в исходном коде C++, он создает файл module.py, который обертывает двоичный файл _module.cpython32-mu.so, он создается с файлом module_wrap.cpp и не копируется в каталог my_module.

Что я должен написать в файл setup.py, чтобы автоматически копировать сгенерированные SWIG модули python?

А также у меня есть еще один вопрос: когда я устанавливаю пакет rpm, я хочу, чтобы исполняемый файл был создан в /usr/bin или около того для запуска приложения (например, если my_module/my_module1.py является стартовым скриптом приложения, тогда я могу запустить в Баш: $ my_module1).


person microo8    schedule 19.09.2012    source источник
comment
Большое спасибо ... Мне нужно было установить флаги компилятора clang ... это был ключ, который разблокировал это.   -  person Tim Seed    schedule 22.04.2020


Ответы (3)


Проблема в том, что build_py (которое копирует исходники Python в каталог сборки) предшествует build_ext, который запускает SWIG.

Вы можете легко создать подкласс команды сборки и поменять местами порядок, поэтому build_ext создаст module1.py до того, как build_py попытается его скопировать.

from distutils.command.build import build

class CustomBuild(build):
    sub_commands = [
        ('build_ext', build.has_ext_modules), 
        ('build_py', build.has_pure_modules),
        ('build_clib', build.has_c_libraries), 
        ('build_scripts', build.has_scripts),
    ]

module1 = Extension('_module1', etc...)

setup(
    cmdclass={'build': CustomBuild},
    py_modules=['module1'],
    ext_modules=[module1]
)

Однако с этим есть одна проблема: если вы используете setuptools, а не просто distutils, запуск python setup.py install не запустит пользовательскую команду сборки. Это связано с тем, что команда установки setuptools на самом деле сначала не запускает команду сборки, а запускает egg_info, затем install_lib, которая запускает build_py, а затем напрямую build_ext.

Поэтому, возможно, лучшим решением будет создание подкласса для команды сборки и установки и обеспечения запуска build_ext в начале обеих команд.

from distutils.command.build import build
from setuptools.command.install import install

class CustomBuild(build):
    def run(self):
        self.run_command('build_ext')
        build.run(self)


class CustomInstall(install):
    def run(self):
        self.run_command('build_ext')
        self.do_egg_install()

setup(
    cmdclass={'build': CustomBuild, 'install': CustomInstall},
    py_modules=['module1'],
    ext_modules=[module1]
)

Не похоже, что вам нужно беспокоиться о том, что build_ext запустится дважды.

person Matt Swain    schedule 20.01.2014
comment
Почему не подкласс build_py? Бессовестная вилка: stackoverflow.com/a/48942866/2321145 - person hmaarrfk; 23.02.2018

Это не полный ответ, потому что у меня нет полного решения. Причина, по которой модуль не копируется в каталог установки, заключается в том, что он отсутствовал, когда процесс установки пытался его скопировать. Последовательность событий такова:

running install
running build
running build_py
file my_module.py (for module my_module) not found
file vcanmapper.py (for module vcanmapper) not found
running build_ext

Если вы запустите второй раз python setup.py install, он сделает то, что вы хотели в первую очередь. Официальная документация SWIG для Python предлагает сначала запустить swig для создания файла оболочки, а затем запустить setup.py install для фактической установки.

person Vlad Wing    schedule 08.04.2013

Похоже вам нужно добавить параметр py_modules, например :

setup(...,
  ext_modules=[Extension('_foo', ['foo.i'],
                         swig_opts=['-modern', '-I../include'])],
  py_modules=['foo'],
)

Используя rpm для установки системных скриптов в Linux, вам придется изменить файл спецификаций . Раздел %files сообщает rpm, куда поместить файлы, которые вы можете переместить или связать в %post, но такое может быть определено в setup.py используя:

options = {'bdist_rpm':{'post_install':'post_install', 'post_uninstall':'post_uninstall'}},

Запуск скриптов Python в Bash можно выполнить с обычной первой строкой #!/usr/bin/python и исполняемый бит файла с использованием chmod +x filename.

person Cees Timmerman    schedule 19.09.2012
comment
Все, что вы написали, я и так знаю. Но мой вопрос заключался в том, как автоматически скопировать сгенерированный SWIG файл module.py в каталог my_module. А еще я могу запускать свои скрипты из bash. Но проблема в том, что когда я устанавливаю файл rpm, все мои модули устанавливаются в /usr/lib/python3.2/, и я хочу автоматически сделать ссылку из выбранного модуля на /usr/bin/module. - person microo8; 19.09.2012
comment
Разве py_modules этого не делает? Вам придется изменить файл спецификации для пользовательских мест установки или использовать Python --post-install. - person Cees Timmerman; 19.09.2012
comment
это вообще не ответ на вопрос - person thias; 19.10.2012
comment
@thias, даже не включая мой комментарий? - person Cees Timmerman; 19.10.2012
comment
@CeesTimmerman: ответ скрыт в строке py_modules в вашем примере кода, но без каких-либо объяснений в тексте этого ответа. Вместо этого вы развиваете более общие моменты, которые здесь не нужны. Я предлагаю вам немного подчистить ответ, чтобы другие тоже нашли ответ. - person thias; 22.10.2012
comment
@thias, это была та же логическая линия, но я упростил свой ответ. - person Cees Timmerman; 22.10.2012