包装C库

时间:2011-10-01 10:59:29

标签: python c cython

我有private.hpublic.hfile.c,我需要将其打包到Cython。 如何包装函数Person_ptr Person_create(const char* name);

private.h:

#ifndef __PERSON_PRIVATE_H__
#define __PERSON_PRIVATE_H__

#include "Person.h"

typedef struct Person_TAG {
    char* name;
    int age;
} Person;


void person_init(Person_ptr self, const char* name);

# endif /* __PERSON_PRIVATE_H__ */

public.h

#ifndef __PERSON_H__
#define __PERSON_H__

#include <assert.h>

typedef struct Person_TAG* Person_ptr;

#define PERSON(x) \
    ((Person_ptr) (x))

#define PERSON_CHECK_INSTANCE(x) \
    assert(PERSON(x) != PERSON(NULL))

/* public interface */
Person_ptr Person_create(const char* name);
void Person_destroy(Person_ptr self);

const char* Person_get_name(const Person_ptr self);
int Person_get_age(const Person_ptr self);
void Person_birthday(Person_ptr self);

# endif /* __PERSON_H__ */

这是file.c

#include "Person.h"
#include "Person_private.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

Person_ptr Person_create(const char* name)
{
    Person_ptr self = PERSON(malloc(sizeof(Person)));
    PERSON_CHECK_INSTANCE(self);
    person_init(self, name);
    return self;
}

void Person_destroy(Person_ptr self)
{
    PERSON_CHECK_INSTANCE(self);
    if (NULL != self->name) free(self->name);
}

 /* Do not free not change the returned string! */
const char* Person_get_name(const Person_ptr self)
{
    PERSON_CHECK_INSTANCE(self);
    return self->name;
}

int Person_get_age(const Person_ptr self)
{
    PERSON_CHECK_INSTANCE(self);
    return self->age;
}

void Person_birthday(Person_ptr self)
{
    PERSON_CHECK_INSTANCE(self);
    ++self->age;
}

/* private/protected methods */
void person_init(Person_ptr self, const char* name)
{
    self->name = malloc(sizeof(char) * (strlen(name) + 1));
    assert(NULL != self->name);
    strcpy(self->name, name);
    self->age = 0;
}

我试图做的是file.pyx:

from ctypes import *

cdef extern from "Person.h":
ctypedef struct Person_ptr:
        pass
Person_ptr Person_create "P_create" (char *name)

cdef class Person:
    cdef Person P_create(p_name):
    return Person_create(p_name)

这不对 - 它在Cython中编译但是它在GCC中给了我很多错误。 我该如何解决这个问题?

2 个答案:

答案 0 :(得分:7)

cperson.pxd:

cdef extern from "Person.h":
    cdef struct Person_TAG:
        pass
    ctypedef Person_TAG* Person_ptr

    Person_ptr Person_create(char* name)
    void Person_destroy(Person_ptr self)

    char* Person_get_name(Person_ptr self)

person.pyx

from cperson cimport Person_ptr, Person_create, Person_destroy, Person_get_name

cdef class Person:
    cdef Person_ptr thisptr

    def __cinit__(self, char* name):
        self.thisptr = Person_create(name)
        if self.thisptr is NULL:
            raise MemoryError

    def __dealloc__(self):
        if self.thisptr is not NULL:
            Person_destroy(self.thisptr)

    property name:
        def __get__(self):
            return Person_get_name(self.thisptr)

person.pyxbld:

import os
from distutils.extension import Extension

dirname = os.path.dirname(__file__)

def make_ext(modname, pyxfilename):
    return Extension(name=modname,
        sources=[pyxfilename, "Person.c"],
        include_dirs=[dirname],
        # or libraries=["person"], if you compile Person.c separately 
        )

test_person.py

import pyximport; pyximport.install()

from person import Person

p = Person('Garry')
print p.name

实施例

$ python test_person.py 
Garry

答案 1 :(得分:1)

一般来说,除非你有一些非常特殊的要求,否则手工做这种事是没有意义的。相反,使用SWIG为您生成包装器。你不需要努力使这些细节正确,并且当C代码改变时作为奖励,重新生成新的包装器以匹配它是微不足道的。