В дистрибутивах python нет встроенного модуля SWIG - программирование

В дистрибутивах python нет встроенного модуля 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']} )

my MANIFEST.in файл:

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

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

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

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

4b9b3361

Ответ 1

Проблема заключается в том, что 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 install фактически не запускает команду сборки, она запускает 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 запускается дважды.

Ответ 2

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

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 для фактической установки.

Ответ 3

Он выглядит как, вам нужно добавить опцию py_modules, например:

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

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

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

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