python distutils不包括SWIG生成的模块

时间:2012-09-19 08:52:24

标签: c++ python swig rpm distutils

我正在使用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

我的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    = 'magyarvladimir@gmail.com',
        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包。但问题是,当我在C ++源代码上运行SWIG时,它会创建一个包装二进制module.py文件的_module.cpython32-mu.so文件,它是使用module_wrap.cpp文件创建的,并且不会被复制到my_module目录。

我必须写setup.py文件来自动复制SWIG生成的python模块?

我还有另外一个问题:当我安装rpm包时,我希望在/usr/bin左右创建一个可执行文件来运行应用程序(例如,如果my_module/my_module1.py是然后我可以在bash中运行应用程序的启动脚本:$ my_module1)。

3 个答案:

答案 0 :(得分:11)

问题是build_py(将python源复制到构建目录)出现在运行SWIG的build_ext之前。

您可以轻松地对构建命令进行子类化并按顺序进行交换,因此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命令实际上并不首先运行build命令,它运行egg_info,然后运行install_lib,它直接运行build_py和build_ext。

所以可能更好的解决方案是将build和install命令子类化,并确保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会运行两次。

答案 1 :(得分:1)

这不是一个完整的答案,因为我没有完整的解决方案。 模块未复制到安装目录的原因是因为在安装过程尝试复制模块时它不存在。事件的顺序是:

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,它将首先执行您想要的操作。 Python的官方SWIG文档建议您先运行swig来生成包装文件,然后运行setup.py install来进行实际安装。

答案 2 :(得分:0)

It looks like您必须添加py_modules选项,例如:

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

Using rpm to Install System Scripts in Linux,您必须修改您的spec文件。 %files部分告诉rpm将文件放在哪里,您可以在%post中移动或链接到这些文件,但在setup.py中定义的can be使用:< / p>

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

Running Python scripts in Bash可以使用#!/usr/bin/python作为chmod +x filename的常规第一行和使用{{1}}的文件上的可执行位。