使用 setuptools 创建调用外部 C 库的 cython 包

Posted

技术标签:

【中文标题】使用 setuptools 创建调用外部 C 库的 cython 包【英文标题】:Using setuptools to create a cython package calling an external C library 【发布时间】:2015-12-08 07:34:24 【问题描述】:

我正在尝试编译、安装和运行一个我们称之为myPackage 的包。它包含一个*.pyx 文件,该文件从库fftw 中调用函数fftw_set_timelimit()。目前,当我运行导入包的脚本clientScript.py 时,我收到以下错误消息:

Traceback (most recent call last):
  File "clientScript.py", line 5, in <module>
    import myPackage.myModule
ImportError: /usr/local/lib/python2.7/dist-packages/myPackage/myModule.so: undefined symbol: fftw_set_timelimit

据我了解(我对 python 和 cython 很陌生),与 C 库的链接尚未在我的包中执行。事实上,我的setup.py 文件看起来像这样:

from setuptools   import setup,find_packages
from Cython.Build import cythonize
import os

setup(
    name = "myPackage",
    version = "0.0.1",
    url = "none",
    author = "me",
    author_email = "me@me.me",
    packages=find_packages(),
    ext_modules = cythonize("pyClo/pyClo.pyx"),
)

如您所见,我的setup.py 文件使用setuptools。我决定这样做,因为它是由Python Packaging User Guide 推荐的。但是,Cython documentation 中的说明使用 distutils 代替。链接库是通过调用distutils.Extension('file',['file.pyx'],libraries='fftw') 完成的。如何使用setuptools 获得相同的结果?

【问题讨论】:

【参考方案1】:

原来setuptools 有一个模块setuptools.extension.Extension,它的使用方式与distutils.extension.Extension 模块相同。

最后,setup.py 文件看起来像:

from setuptools import setup, find_packages
from setuptools.extension import Extension
from Cython.Build import cythonize

extensions = [
    Extension(
        "myPackage.myModule",
        ["myPackage/myModule.pyx"],
        include_dirs=['/some/path/to/include/'], # not needed for fftw unless it is installed in an unusual place
        libraries=['fftw3', 'fftw3f', 'fftw3l', 'fftw3_threads', 'fftw3f_threads', 'fftw3l_threads'],
        library_dirs=['/some/path/to/include/'], # not needed for fftw unless it is installed in an unusual place
    ),
]

setup(
    name = "myPackage",
    packages = find_packages(),
    ext_modules = cythonize(extensions)
)

这是我的安装目录的概述:

.
├── MANIFEST.in
├── myPackage
│   └── myModule.pyx
├── README.rst
└── setup.py

其中myModule.pyx 是调用fftw_set_timelimit() 的文件。

MANIFEST.in 包含:

include myPackage/*.*

README.rst 只是一个纯文本文件。

【讨论】:

根据distutils documentation,distutils.core.Extension 将作为第一个参数:"扩展的全名,包括任何包——即不是文件名或路径名,而是 Python 点名" 因此,应该使用"myPackage.myModule",而不是"myPackage/myModule" @SylM 我已经有一段时间没有使用 python 了……所以我需要努力仔细检查将斜杠“/”替换为点“。”正如你所建议的那样确实有效。但是,如果您测试解决方案并告诉我没问题,那么我将相应地编辑我的答案。通过“测试解决方案”,我的意思是从头开始一个新项目并确保你可以让它工作。你愿意这样做吗? ;) @GLorieul 我刚刚使用了上面的模板,使用了点名语法,并且编译成功了。 @Gilly 谢谢!我相应地更新了我的答案:您能否再次检查我所做的编辑是否正确?

以上是关于使用 setuptools 创建调用外部 C 库的 cython 包的主要内容,如果未能解决你的问题,请参考以下文章

Setuptools 从 git 子模块安装代码

C# 实体框架向来自外部库的实体添加新列

Go笔记-标准库的介绍

ctypes库的使用整理

Java - 为来自外部库的类定义一个通用接口

Python 标准库的入口点是如何注册的?