如何在软件包安装中包括(脚本构建的)库? [英] How to include (script-built) libraries with package installation?

查看:139
本文介绍了如何在软件包安装中包括(脚本构建的)库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个具有C ++扩展模块和所需的其他共享库的Python程序包.我希望所有内容都可以通过pip安装.我当前的setup.py文件在使用pip install -e .时有效,但是在不使用开发模式(省略-e)时,导入模块时出现无法打开共享库文件" 在Python中.我相信原因是setuptools认为共享库不是我的软件包的一部分,因此在将文件复制到安装目录时,安装过程中与该库的相对链接已断开.

I am making a Python package that has a C++-extension module and someone else's shared library that it requires. I want everything installable via pip. My current setup.py file works when I use pip install -e . but when I don't use develop mode (e.i. omit the -e) I get "cannot open shared object file" when importing the module in Python. I believe the reason is that setuptools doesn't consider the shared library to be part of my package, so the relative link to the library is broken during installation when files are copied to the install directory.

这是我的setup.py文件的样子:

from setuptools import setup, Extension, Command
import setuptools.command.develop
import setuptools.command.build_ext
import setuptools.command.install
import distutils.command.build
import subprocess
import sys
import os

# This function downloads and builds the shared-library
def run_clib_install_script():
    build_clib_cmd = ['bash', 'clib_install.sh']
    if subprocess.call(build_clib_cmd) != 0:
        sys.exit("Failed to build C++ dependencies")

# I make a new command that will build the shared-library
class build_clib(Command):
    user_options = []
    def initialize_options(self):
        pass
    def finalize_options(self):
        pass
    def run(self):
        run_clib_install_script()

# I subclass install so that it will call my new command
class install(setuptools.command.install.install):
    def run(self):
        self.run_command('build_clib')
        setuptools.command.install.install.run(self)

# I do the same for build...
class build(distutils.command.build.build):
    sub_commands = [
        ('build_clib', lambda self: True),
        ] + distutils.command.build.build.sub_commands

# ...and the same for develop
class develop(setuptools.command.develop.develop):
    def run(self):
        self.run_command('build_clib')
        setuptools.command.develop.develop.run(self)

# These are my includes...
# note that /clib/include only exists after calling clib_install.sh
cwd = os.path.dirname(os.path.abspath(__file__))
include_dirs = [
    cwd,
    cwd + '/clib/include',
    cwd + '/common',
]

# These are my arguments for the compiler to my shared-library
lib_path = os.path.join(cwd, "clib", "lib")
library_dirs = [lib_path]
link_args = [os.path.join(lib_path, "libclib.so")]

# My extension module gets these arguments so it can link to clib
mygen_module = Extension('mygen',
                    language="c++14",
                    sources=["common/mygen.cpp"],
                    libraries=['clib'],
                    extra_compile_args=['-std=c++14'],
                    include_dirs=include_dirs,
                    library_dirs=library_dirs,
                    extra_link_args=link_args
                        + ['-Wl,-rpath,$ORIGIN/../clib/lib'])

# I use cmdclass to override the default setuptool commands
setup(name='mypack',
      cmdclass = {'install': install,
                  'build_clib': build_clib, 'build': build,
                  'develop': develop},
      packages=['mypack'],
      ext_package='mypack',
      ext_modules=[mygen_module],
      # package_dir={'mypack': '.'},
      # package_data={'mypack': ['docs/*md']},
      include_package_data=True)

我将某些setuptools命令子类化,以便在编译扩展之前先构建共享库. clib_install.sh是一个bash脚本,可以在本地下载并构建/clib中的共享库,从而创建标头(在/clib/include中)和.so文件(在/clib/lib中).为了解决链接到共享库依赖项的问题,我使用$ORIGIN/../clib/lib作为链接参数,因此不需要clib的绝对路径.

I subclass some of the setuptools commands in order to build the shared-library before it compiles the extension. clib_install.sh is a bash script that locally downloads and builds the shared library in /clib, creating the headers (in /clib/include) and .so file (in /clib/lib). To solve problems with linking to shared-library dependencies I used $ORIGIN/../clib/lib as a link argument so that the absolute path to clib isn't needed.

不幸的是,/clib目录未复制到安装位置.我尝试修改package_data,但是没有复制我的目录.实际上,调用脚本后,我什至不知道pip/setuptools对/clib有何作用,我猜它是在某个临时构建目录中创建的,并在之后删除.我不确定在制作后如何将/clib到达需要的位置.

Unfortunately, the /clib directory doesn't get copied to the install location. I tried tinkering with package_data but it didn't copy my directory over. In fact, I don't even know what pip/setuptools does with /clib after the script is called, I guess it is made in some temporary build directory and gets deleted after. I am not sure how to get /clib to where it needs to be after it is made.

推荐答案

package_data={
    'mypack': [
        'clib/include/*.h',
        'clib/lib/*.so',
        'docs/*md',
    ]
},

这篇关于如何在软件包安装中包括(脚本构建的)库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆