В дистрибутивах 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
).
Ответы
Ответ 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
.