Search code examples
pythonpython-2.7shared-librariespypypython-cffi

PYPY, CFFI import error cffi library '_heap_i' has no function, constant, or global variable named 'initQueue'


So I am trying to use cffi to access a c library quickly in pypy.

I am using my macpro with command line tools 9.1

specifically I am comparing a pure python priority queue, with heapq, with a cffi, and ctypes for a project.

I have got code from roman10's website for a C implementation of a priority queue.

I am following the docs for cffi but I get an error when trying to call a function that is inside of the library.

I have 5 files: the .c/.h cheap.c cheap.hfor the priority queue, the interface python file with cffi heap_inter.py, a wrapper for the program to access the queue heap.py, and a test script test_heap.py

This is the error: I tried with export CC=gcc and export CC=clang and also my mpich

pypy test_heap.py

AttributeError: cffi library '_heap_i' has no function, constant, or global variable named 'initQueue'

however I do have a function in the c library that is being compiled called initQueue.

when i call pypy on heap_inter.py the commands executed are 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]

here are my sources,

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);

then 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)

then 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

and finally 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

Thanks anyone for looking and let me know if you have experienced this before.


Solution

  • You must tell ffi.set_source() about heap.c. The easiest way is

    with open('heap.c', 'r') as fid: ffi.set_source(fid.read())

    like in this example. The way it works is:

    • declarations of functions, structs, enums, typedefs that will be accessible from python appear in your ffi.cdef(...)
    • the source code that implements those functions is given as a string to ffi.set_source(...) ( you can also use various distutils keywords there)
    • ffi.compile() builds a shared object that exports the things defined in ffi.cdef() and arranges it so those things will be exposed to python