如何在Python包中包含共享C库

时间:2017-07-15 18:15:01

标签: python makefile setuptools

我有一个项目取决于共享库。从头开始说明:共享库是纯C库而不是Python库。为简单起见,我创建了一个名为 pkgtest 的小型演示项目,我将参考该项目。

所以需要做的是:运行Makefile来编译库并将编译好的共享库(在此处称为libhello.so)文件放在某个地方,可以从依赖的Python包中访问它。

到目前为止,我最好的猜测是将makefile作为预安装例程运行,将libhello.so文件复制到packages目录中,并将其添加到安装脚本的package_data参数中。安装后,共享库将被放置在site-packages/pkgtest/目录中,并且可以从模块访问。

包目录的结构就像这样简单:

pkgtest/
  src/
     libhello.c
     libhello.h
     Makefile
  pkgtest/
    __init__.py
    hello.py
  setup.py

我的setup.py看起来像这样:

setup.py

import subprocess
from setuptools import setup
from distutils.command.install import install as _install


class install(_install):
    def run(self):
        subprocess.call(['make', 'clean', '-C', 'src'])
        subprocess.call(['make', '-C', 'src'])
        _install.run(self)


setup(
    name='pkgtest',
    version='0.0.1',
    author='stefan',
    packages=['pkgtest'],
    package_data={'pkgtest': ['libhello.so']},
    cmdclass={'install': install},
)

Makefile实际上构建了库并将其复制到我的python包的目录中。

的src /生成文件

all: libhello.so

libhello.o: libhello.c
        gcc  -fPIC -Wall -g -c libhello.c

libhello.so: libhello.o
        gcc -shared -fPIC -o libhello.so libhello.o
        cp libhello.so ../pkgtest/libhello.so

clean:
        rm -f *.o *.so

所以hello.py实际上正在做的是加载库并调用打印一些文本的hello函数。但为了完整起见,我将在此处显示代码:

pkgtest / hello.py

import os
import ctypes

basedir = os.path.abspath(os.path.dirname(__file__))
libpath = os.path.join(basedir, 'libhello.so')

dll = ctypes.CDLL(libpath)

def say_hello():
    dll.hello()

所以这实际上有效但我不喜欢这种方法的是共享库存在于Python包的目录中。我认为最好将它放在某种中央库目录中,例如 / usr / lib / 。但是对于这个,在安装时需要root权限。有人有这方面的经验,想分享一个解决方案或有用的想法。会很棒。

2 个答案:

答案 0 :(得分:3)

您可以创建一个包含共享库的Python包,并使用manylinux(几乎)在任何Linux发行版上工作。

  

manylinux项目的目标是提供一种方便的方法来将二进制Python扩展作为Linux上的轮子进行分发。这项工作产生了PEP 513,用于定义manylinux1_x86_64manylinux1_i686平台广告代码。

一般程序是:

  1. 在manylinux团队提供的其中一个docker容器中构建外部库和Python包 (见python-manylinux-demo
  2. 运行auditwheel repair将包所依赖的外部共享库复制到Python滚轮中,相应地设置RPATH。
  3. 请参阅python-manylinux-demo回购中的.travis.ymlbuild-wheels.sh作为示例。

答案 1 :(得分:0)

package_data用于数据。 setup可以编译成*.so

按照我在python setup.py build ctypes.CDLL: cannot open shared object file: No such file or directory中的解决方案,我认为您的setup可以雇用ext_modulespy_modules,类似

setup(name='pkgtest',
      py_modules=['pkgtest'],
      ext_modules=[Extension('src.libhello', ['src/libhello.c'])]
     )