Python Distutils未包含由SWIG生成的模块。

21

我正在使用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_wrap.cpp文件包装二进制文件_module.cpython32-mu.so,但它没有被复制到my_module目录。

我该如何修改setup.py文件来自动复制由SWIG生成的Python模块?

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


非常感谢...我需要设置clang编译器标志...这是解锁的关键。 - Tim Seed
3个回答

12

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

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


为什么不对build_py进行子类化?不要脸地插一下:https://dev59.com/Xonca4cB1Zd3GeqP-2xt#48942866 - hmaarrfk

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进行实际安装。

0

看起来你需要添加一个py_modules选项,例如:

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

在Linux中使用rpm安装系统脚本, 您需要修改您的spec文件。 %files 部分告诉 rpm 应该把文件放在哪里,您可以在 %post 中移动或链接这些文件,但是这样的 操作 也可以在 setup.py 中定义:

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

可以使用通常的第一行 #!/usr/bin/python 和使用 chmod +x filename 命令将文件设置为可执行文件,从而在 Bash 中运行 Python 脚本。详见在 Bash 中运行 Python 脚本

你所写的我都已经知道了。但我的问题是如何自动将SWIG生成的module.py文件复制到my_module目录中。而且,我可以从bash中运行我的脚本。但问题是当我安装rpm文件时,所有的模块都被安装到/usr/lib/python3.2/,我想自动将选定的模块链接到/usr/bin/module - microo8
py_modules 不是做这个的吗?您需要修改您的规范文件以进行自定义安装位置,或使用Python的--post-install - Cees Timmerman
这并没有回答问题。 - thias
@thias,甚至不包括我的评论? - Cees Timmerman
@CeesTimmerman:答案隐藏在您代码示例中的py_modules行中,但在此答案的文本中没有任何解释。相反,您详细阐述了更一般的观点,这在这里是不必要的。我建议您稍微整理一下答案,以便其他人也能找到答案。 - thias
@thias,逻辑线是一样的,但我已经简化了我的答案。 - Cees Timmerman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接