20

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

4

3 回答 3

12

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

您可以轻松地将构建命令子类化并交换顺序,因此在尝试复制它之前build_ext生成。module1.pybuild_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,runningpython 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 会运行两次。

于 2014-01-20T14:08:09.497 回答
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以进行实际安装。

于 2013-04-08T15:25:24.453 回答
0

看起来您必须添加一个py_modules选项,例如:

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

在 Linux 中使用 rpm 安装系统脚本,您必须修改您的规范文件。该%files部分告诉rpm将文件放在哪里,您可以将其移动或链接到 in %post,但可以使用以下方法定义setup.py

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

在 Bash 中运行 Python 脚本可以使用通常的第一行 as#!/usr/bin/python和文件上的可执行位使用chmod +x filename.

于 2012-09-19T09:56:01.177 回答