打包包含C共享库的Python库的最佳方式是什么?

18 投票
3 回答
5891 浏览
提问于 2025-04-18 08:44

我写了一个库,主要功能是用C语言实现的,因为速度非常重要。然后我在它周围加了一层薄薄的Python代码,主要是为了处理一些ctypes相关的问题。

现在我想把它打包,想知道该怎么做比较好。我的代码需要和一个共享库进行交互。我有一个Makefile,可以用来编译C代码并生成.so文件,但我不太清楚如何通过distutils来编译这个文件。我是不是应该用subprocess调用make,并重写install命令?如果是这样的话,install适合放这个吗,还是build更合适呢?

更新:我想说明一下,这不是一个Python扩展。也就是说,这个C库里面没有任何代码是用来和Python运行时交互的。Python只是调用了一个普通的C共享库里的函数。

3 个回答

0

如果你按照说明书上的步骤去做,学习了如何用C语言创建Python扩展,那么你只需要像文档中提到的那样列出扩展模块就可以了。
所以,你的库的 setup.py 脚本应该是这样的:

from distutils.core import setup, Extension
setup(
   name='your_python_library',
   version='1.0',
   ext_modules=[Extension('your_c_extension', ['your_c_extension.c'])],
)

而且 distutils 知道怎么把你的扩展编译成C语言的共享库,并且知道把它放在哪里。

当然,我对你的库没有更多的信息,所以你可能还想在 setup(...) 的调用中添加更多的参数。

1

我之前也遇到过类似的情况,发现这个回答很有帮助:Python setup.py 调用 makefile 不包含二进制文件

我在我的项目的 src 文件夹里有一个 ANSI C 库。在这个 src 文件夹里有一个 Makefile,它会生成一个叫 liblsd.so 的文件,这个文件会放在我的包目录(lsd)里。我在 setup.py 里调用这个 Makefile,然后告诉 setup 包含这个库文件,使用的是 package_data 参数。

import os.path
import subprocess

from setuptools import setup

with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as f:
    readme = f.read()

subprocess.call(['make', '-C', 'src'])

setup(name='LSD',
  version='0.0.1',
  description='Python bindings for the LSD line segment detector.',
  long_description=readme,
  author='Geoff Hing',
  author_email='geoffhing@gmail.com',
  url='https://github.com/ghing/python-lsd',
  packages=['lsd'],
  package_data={'lsd': ['liblsd.so']},
  include_package_data=True,
  classifiers=[
      'Development Status :: 1 - Planning',
      'Intended Audience :: Developers',
      'License :: OSI Approved :: MIT License',
      'Operating System :: OS Independent',
      'Programming Language :: Python',
      'Programming Language :: C',
      ],
 )
1

我建议把这个Python模块当作一个普通共享库构建的子项目来做。也就是说,可以使用automake、autoconf之类的工具来构建共享库,然后在项目里创建一个叫做python_bindings的文件夹,里面放上setup.py和你的Python模块。

撰写回答