PYPY、CFFI 导入报错 cffi library '_heap_i' has no function, constant, or global variable named 'initQueue'
PYPY, CFFI import error cffi library '_heap_i' has no function, constant, or global variable named 'initQueue'
所以我想在pypy中使用cffi快速访问一个c库。
我正在使用带有命令行工具 9.1 的 macpro
具体来说,我正在比较纯 python 优先级队列、heapq、cffi 和项目的 ctypes。
我从 roman10 的网站上获得了优先级队列的 C 实现代码。
我正在关注 cffi 的文档,但在尝试调用库中的函数时出现错误。
我有 5 个文件:优先级队列的 .c/.h cheap.c
cheap.h
,带有 cffi heap_inter.py
的接口 python 文件,一个包装器访问队列 heap.py
的程序和测试脚本 test_heap.py
这是错误:我尝试使用 export CC=gcc
和 export CC=clang
以及我的 mpich
pypy test_heap.py
AttributeError:cffi 库“_heap_i”没有名为 'initQueue'
的函数、常量或全局变量
但是我在正在编译的 c 库中有一个名为 initQueue 的函数。
当我在 heap_inter.py 上调用 pypy 时,执行的命令是
building '_heap_i' extension
clang -DNDEBUG -O2 -fPIC -I/opt/local/include -I/opt/local/lib/pypy/include -c _heap_i.c -o ./_heap_i.o
cc -pthread -shared -undefined dynamic_lookup ./_heap_i.o -L/opt/local/lib -o ./_heap_i.pypy-41.so
clang: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument]
这是我的消息来源,
cheap.h
#include <stdio.h>
#include <stdlib.h>
/* priority Queue implimentation via roman10.net */
struct heapData {
//everything from event
//tx string
char tx[64];
//txID int
int txID;
//rx string
char rx[64];
//rxID int
int rxID;
//name string
char name[64];
//data Object
//time float
float time;
};
struct heapNode {
int value;
struct heapData data; //dummy
};
struct PQ {
struct heapNode* heap;
int size;
};
void insert(struct heapNode aNode, struct heapNode* heap, int size);
void shiftdown(struct heapNode* heap, int size, int idx);
struct heapNode removeMin(struct heapNode* heap, int size);
void enqueue(struct heapNode node, struct PQ *q);
struct heapNode dequeue(struct PQ *q);
struct heapNode peak(struct PQ *q);
void initQueue(struct PQ *q, int n);
int nn = 1000000;
struct PQ q;
int main(int argc, char **argv);
然后heap.c
void insert(struct heapNode aNode, struct heapNode* heap, int size) {
int idx;
struct heapNode tmp;
idx = size + 1;
heap[idx] = aNode;
while (heap[idx].value < heap[idx/2].value && idx > 1) {
tmp = heap[idx];
heap[idx] = heap[idx/2];
heap[idx/2] = tmp;
idx /= 2;
}
}
void shiftdown(struct heapNode* heap, int size, int idx) {
int cidx; //index for child
struct heapNode tmp;
for (;;) {
cidx = idx*2;
if (cidx > size) {
break; //it has no child
}
if (cidx < size) {
if (heap[cidx].value > heap[cidx+1].value) {
++cidx;
}
}
//swap if necessary
if (heap[cidx].value < heap[idx].value) {
tmp = heap[cidx];
heap[cidx] = heap[idx];
heap[idx] = tmp;
idx = cidx;
} else {
break;
}
}
}
struct heapNode removeMin(struct heapNode* heap, int size) {
int cidx;
struct heapNode rv = heap[1];
//printf("%d:%d:%dn", size, heap[1].value, heap[size].value);
heap[1] = heap[size];
--size;
shiftdown(heap, size, 1);
return rv;
}
void enqueue(struct heapNode node, struct PQ *q) {
insert(node, q->heap, q->size);
++q->size;
}
struct heapNode dequeue(struct PQ *q) {
struct heapNode rv = removeMin(q->heap, q->size);
--q->size;
return rv;
}
struct heapNode peak(struct PQ *q) {
return q->heap[1];
}
void initQueue(struct PQ *q, int n) {
q->size = 0;
q->heap = (struct heapNode*)malloc(sizeof(struct heapNode)*(n+1));
}
int nn = 1000000;
struct PQ q;
int main(int argc, char **argv) {
int n;
int i;
struct PQ q;
struct heapNode hn;
n = atoi(argv[1]);
initQueue(&q, n);
srand(time(NULL));
for (i = 0; i < n; ++i) {
hn.value = rand()%10000;
printf("enqueue node with value: %dn", hn.value);
enqueue(hn, &q);
}
printf("ndequeue all values:n");
for (i = 0; i < n; ++i) {
hn = dequeue(&q);
printf("dequeued node with value: %d, queue size after removal: %dn", hn.value, q.size);
}
}
heap_inter.py
:
from cffi import FFI
ffibuilder = FFI()
ffibuilder.set_source("_heap_i",
r"""//passed to C compiler
#include <stdio.h>
#include <stdlib.h>
#include "cheap.h"
""",
libraries=[])
ffibuilder.cdef("""
struct heapData {
char tx[64];
int txID;
char rx[64];
int rxID;
char name[64];
float time;
} ;
struct heapNode {
int value;
struct heapData data; //dummy
} ;
struct PQ {
struct heapNode* heap;
int size;
} ;
""")
#
# Rank (Simian Engine) has a Bin heap
if __name__ == "__main__":
ffibuilder.compile(verbose=True)
然后 heap.py
from _heap_i import ffi, lib
infTime = 0
# /* create heap */
def init():
#global infTime
#infTime = int(engine.infTime) + 1
cheap = ffi.new("struct PQ *")
lib.initQueue(cheap,nn)
return cheap
def push(arr, element):
hn = ffi.new("struct heapNode")
value = element["time"]
hn.value = value
rx = ffi.new("char[]", element["rx"])
hn.data.rx = rx
tx = ffi.new("char[]", element["tx"])
hn.data.tx = tx
txID = ffi.new("int", element["txID"])
hn.data.txID = txID
rxID = ffi.new("int", element["rxID"])
hn.data.rxID = rxID
name = ffi.new("int", element["name"])
hn.data.name = name
hn.data.time = value
result = lib.enqueue(hn, arr)
def pop(arr):
hn = lib.dequeue(arr)
element = {"time": hn.value,
"rx" : hn.data.rx,
"tx" : hn.data.tx,
"rxID" : hn.data.rxID,
"txID" : hn.data.txID,
"name" : hn.data.name,
"data" : hn.data.data,
}
return element
def annihilate(arr, event):
pass
def peak(arr):
hn = lib.peak(arr)
element = {"time": hn.value,
"rx" : hn.data.rx,
"tx" : hn.data.tx,
"rxID" : hn.data.rxID,
"txID" : hn.data.txID,
"name" : hn.data.name,
"data" : hn.data.data,
}
return element
def isEvent(arr):
if arr.size:
return 1
else:
return None
def size(arr):
return arr.size
最后是 test_heap.py
import heap
pq = heap.init()
for x in range(1000) :
heap.push({"time" : x,
"rx" : "a",
"tx" : "b",
"txID" : 1,
"rxID" : 1,
"name" : "bob",
"data": "none",
},pq)
for x in range(100) :
heap.peak(pq)
for x in range(1000):
y = heap.dequeue(pq)
print y
感谢任何人的关注,如果您以前遇到过这种情况,请告诉我。
您的 ffi.cdef() 没有任何函数声明,因此生成的 _heap_i 库不会导出任何函数。尝试从 .h 文件中复制粘贴函数声明。
你必须告诉 ffi.set_source() 关于 heap.c
。最简单的方法是
with open('heap.c', 'r') as fid:
ffi.set_source(fid.read())
喜欢this example。它的工作方式是:
- 可从 python 访问的函数、结构、枚举、typedef 的声明出现在您的 ffi.cdef(...)
中
- 实现这些功能的源代码作为字符串提供给 ffi.set_source(...)(您也可以在那里使用各种
distutils
关键字)
- ffi.compile() 构建一个共享对象,导出 ffi.cdef() 中定义的内容并对其进行安排,以便将这些内容公开给 python
所以我想在pypy中使用cffi快速访问一个c库。
我正在使用带有命令行工具 9.1 的 macpro
具体来说,我正在比较纯 python 优先级队列、heapq、cffi 和项目的 ctypes。
我从 roman10 的网站上获得了优先级队列的 C 实现代码。
我正在关注 cffi 的文档,但在尝试调用库中的函数时出现错误。
我有 5 个文件:优先级队列的 .c/.h cheap.c
cheap.h
,带有 cffi heap_inter.py
的接口 python 文件,一个包装器访问队列 heap.py
的程序和测试脚本 test_heap.py
这是错误:我尝试使用 export CC=gcc
和 export CC=clang
以及我的 mpich
pypy test_heap.py
AttributeError:cffi 库“_heap_i”没有名为 'initQueue'
的函数、常量或全局变量但是我在正在编译的 c 库中有一个名为 initQueue 的函数。
当我在 heap_inter.py 上调用 pypy 时,执行的命令是
building '_heap_i' extension
clang -DNDEBUG -O2 -fPIC -I/opt/local/include -I/opt/local/lib/pypy/include -c _heap_i.c -o ./_heap_i.o
cc -pthread -shared -undefined dynamic_lookup ./_heap_i.o -L/opt/local/lib -o ./_heap_i.pypy-41.so
clang: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument]
这是我的消息来源,
cheap.h
#include <stdio.h>
#include <stdlib.h>
/* priority Queue implimentation via roman10.net */
struct heapData {
//everything from event
//tx string
char tx[64];
//txID int
int txID;
//rx string
char rx[64];
//rxID int
int rxID;
//name string
char name[64];
//data Object
//time float
float time;
};
struct heapNode {
int value;
struct heapData data; //dummy
};
struct PQ {
struct heapNode* heap;
int size;
};
void insert(struct heapNode aNode, struct heapNode* heap, int size);
void shiftdown(struct heapNode* heap, int size, int idx);
struct heapNode removeMin(struct heapNode* heap, int size);
void enqueue(struct heapNode node, struct PQ *q);
struct heapNode dequeue(struct PQ *q);
struct heapNode peak(struct PQ *q);
void initQueue(struct PQ *q, int n);
int nn = 1000000;
struct PQ q;
int main(int argc, char **argv);
然后heap.c
void insert(struct heapNode aNode, struct heapNode* heap, int size) {
int idx;
struct heapNode tmp;
idx = size + 1;
heap[idx] = aNode;
while (heap[idx].value < heap[idx/2].value && idx > 1) {
tmp = heap[idx];
heap[idx] = heap[idx/2];
heap[idx/2] = tmp;
idx /= 2;
}
}
void shiftdown(struct heapNode* heap, int size, int idx) {
int cidx; //index for child
struct heapNode tmp;
for (;;) {
cidx = idx*2;
if (cidx > size) {
break; //it has no child
}
if (cidx < size) {
if (heap[cidx].value > heap[cidx+1].value) {
++cidx;
}
}
//swap if necessary
if (heap[cidx].value < heap[idx].value) {
tmp = heap[cidx];
heap[cidx] = heap[idx];
heap[idx] = tmp;
idx = cidx;
} else {
break;
}
}
}
struct heapNode removeMin(struct heapNode* heap, int size) {
int cidx;
struct heapNode rv = heap[1];
//printf("%d:%d:%dn", size, heap[1].value, heap[size].value);
heap[1] = heap[size];
--size;
shiftdown(heap, size, 1);
return rv;
}
void enqueue(struct heapNode node, struct PQ *q) {
insert(node, q->heap, q->size);
++q->size;
}
struct heapNode dequeue(struct PQ *q) {
struct heapNode rv = removeMin(q->heap, q->size);
--q->size;
return rv;
}
struct heapNode peak(struct PQ *q) {
return q->heap[1];
}
void initQueue(struct PQ *q, int n) {
q->size = 0;
q->heap = (struct heapNode*)malloc(sizeof(struct heapNode)*(n+1));
}
int nn = 1000000;
struct PQ q;
int main(int argc, char **argv) {
int n;
int i;
struct PQ q;
struct heapNode hn;
n = atoi(argv[1]);
initQueue(&q, n);
srand(time(NULL));
for (i = 0; i < n; ++i) {
hn.value = rand()%10000;
printf("enqueue node with value: %dn", hn.value);
enqueue(hn, &q);
}
printf("ndequeue all values:n");
for (i = 0; i < n; ++i) {
hn = dequeue(&q);
printf("dequeued node with value: %d, queue size after removal: %dn", hn.value, q.size);
}
}
heap_inter.py
:
from cffi import FFI
ffibuilder = FFI()
ffibuilder.set_source("_heap_i",
r"""//passed to C compiler
#include <stdio.h>
#include <stdlib.h>
#include "cheap.h"
""",
libraries=[])
ffibuilder.cdef("""
struct heapData {
char tx[64];
int txID;
char rx[64];
int rxID;
char name[64];
float time;
} ;
struct heapNode {
int value;
struct heapData data; //dummy
} ;
struct PQ {
struct heapNode* heap;
int size;
} ;
""")
#
# Rank (Simian Engine) has a Bin heap
if __name__ == "__main__":
ffibuilder.compile(verbose=True)
然后 heap.py
from _heap_i import ffi, lib
infTime = 0
# /* create heap */
def init():
#global infTime
#infTime = int(engine.infTime) + 1
cheap = ffi.new("struct PQ *")
lib.initQueue(cheap,nn)
return cheap
def push(arr, element):
hn = ffi.new("struct heapNode")
value = element["time"]
hn.value = value
rx = ffi.new("char[]", element["rx"])
hn.data.rx = rx
tx = ffi.new("char[]", element["tx"])
hn.data.tx = tx
txID = ffi.new("int", element["txID"])
hn.data.txID = txID
rxID = ffi.new("int", element["rxID"])
hn.data.rxID = rxID
name = ffi.new("int", element["name"])
hn.data.name = name
hn.data.time = value
result = lib.enqueue(hn, arr)
def pop(arr):
hn = lib.dequeue(arr)
element = {"time": hn.value,
"rx" : hn.data.rx,
"tx" : hn.data.tx,
"rxID" : hn.data.rxID,
"txID" : hn.data.txID,
"name" : hn.data.name,
"data" : hn.data.data,
}
return element
def annihilate(arr, event):
pass
def peak(arr):
hn = lib.peak(arr)
element = {"time": hn.value,
"rx" : hn.data.rx,
"tx" : hn.data.tx,
"rxID" : hn.data.rxID,
"txID" : hn.data.txID,
"name" : hn.data.name,
"data" : hn.data.data,
}
return element
def isEvent(arr):
if arr.size:
return 1
else:
return None
def size(arr):
return arr.size
最后是 test_heap.py
import heap
pq = heap.init()
for x in range(1000) :
heap.push({"time" : x,
"rx" : "a",
"tx" : "b",
"txID" : 1,
"rxID" : 1,
"name" : "bob",
"data": "none",
},pq)
for x in range(100) :
heap.peak(pq)
for x in range(1000):
y = heap.dequeue(pq)
print y
感谢任何人的关注,如果您以前遇到过这种情况,请告诉我。
您的 ffi.cdef() 没有任何函数声明,因此生成的 _heap_i 库不会导出任何函数。尝试从 .h 文件中复制粘贴函数声明。
你必须告诉 ffi.set_source() 关于 heap.c
。最简单的方法是
with open('heap.c', 'r') as fid:
ffi.set_source(fid.read())
喜欢this example。它的工作方式是:
- 可从 python 访问的函数、结构、枚举、typedef 的声明出现在您的 ffi.cdef(...) 中
- 实现这些功能的源代码作为字符串提供给 ffi.set_source(...)(您也可以在那里使用各种
distutils
关键字) - ffi.compile() 构建一个共享对象,导出 ffi.cdef() 中定义的内容并对其进行安排,以便将这些内容公开给 python