使用Cython传递int和struct包装C代码的最小示例

时间:2014-07-08 00:13:33

标签: python c cython wrapping

我在下面显示的代码有效,但我不确定为什么

我正在使用:

  • Mac OSX 10.8.5
  • brewed Python 2.7.5
  • Cython 0.20.2

此代码主要来自this video tutorialgit page,但遗憾的是,“开箱即用”并不适用于我。

这种包装的目的是通过Python提供对一个简单的C函数的访问,该函数接受整数或整数结构并将它们加在一起。

这需要5个文件,如下所述:

  • adder.c:两个加法器函数的C代码: add (标量输入)和 pair_add (结构输入)
  • adder.h:adder.c的头文件
  • c_adder.pxd:一个cython头文件 - 基本上告诉cython要关注主头文件的哪些部分
  • cy_adder.pyx:用于在python命名空间中定义两个函数的cython代码
  • setup.py:执行cython代码编译的distutils文件

并且该过程生成两个文件

  • c_adder.c:一个中级cython c文件
  • c_adder.so:可以导入命名空间的python模块

输入文件如下:

adder.c

#include <stdlib.h>
#include "adder.h"

int
pair_add(PAIR * ppair) {
    return ppair->x + ppair->y;
}

int
add(int x, int y) {
    return x + y;
}

adder.h

typedef struct {
    int x;
    int y;
} PAIR;

int pair_add(PAIR * ppair);
int add(int, int);

c_adder.pxd

cdef extern from "adder.h":

    ctypedef struct PAIR:
        int x
        int y


    int add(int x, int y)
    int pair_add(PAIR * ppair)

cy_adder.pyx

cimport c_adder

def add(x, y):
    return c_adder.add(x, y)

def pair_add(x, y):
    cdef c_adder.PAIR pair
    pair.x = x
    pair.y = y
    return c_adder.pair_add(&pair)

setup.py

from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize


ext_modules = cythonize([Extension("cy_adder", ["cy_adder.pyx",'adder.c'])])


setup(
  name = 'Hello world app',
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules
)

我能够通过运行

成功创建.so文件
$ python setup.py build_ext --inplace

与上述文件位于同一目录中。然后可以将cy_adder加载到python解释器的命名空间中。


问题

在设置声明中,我已将adder.c作为辅助模块。

如果我不这样做我导入.so文件时出现以下错误:

ImportError: dlopen(./cy_adder.so, 2): Symbol not found: _add
  Referenced from: ./cy_adder.so
  Expected in: flat namespace
 in ./cy_adder.so

是否有一个我遗漏的步骤,这意味着我不需要显式传递adder.c和我的设置命令?通过这样做,我是否打开了自己的潜在不稳定性?

1 个答案:

答案 0 :(得分:2)

需要在某处引用adder.c文件,以便知道在哪里找到add的实现。如您所见,列出adder.c作为附加源文件可以正常工作。使用外部(共享)C库的一种更常见的方法是将其编译为libadder.so,并通过Extension声明中的libraries参数将其链接。

对于这么简单的事情你也可以写

cdef extern from "adder.c":   # note the .c
    int add(int x, int y)
    ...

或将整个实现放在.h文件中。