包裹C库
我有一个 private.h
文件,一个 public.h
文件,还有一个 file.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 个回答
1
一般来说,手动做这种事情没有太大意义,除非你有一些特别的需求。相反,你可以使用SWIG来为你生成这些包装代码。你不需要费力去搞清楚这些细节,而且当C代码发生变化时,重新生成新的包装代码也非常简单。
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)
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
)
import pyximport; pyximport.install()
from person import Person
p = Person('Garry')
print p.name
示例
$ python test_person.py
Garry