0

I have some cffi definitions spread over a few project sub-directories -- each cffi file defines types and functions, each compiles into a _<package>.py file to be loaded. In the final application I ffi.include() the top level ones (which recursively ffi.include() the lower level ones) and generate an compile an _<app>.py file to be loaded in the application. I use a single ffi instance for loading the *.so files. I cannot see however how this loads the spread _<package>.py files into the application. I get the following error (example):

two separate FFI definition files, root/get/ffi_getA.py and root/use/ffi_useA.py

which C functions are both part of the same library, say libA.so.

ffi_getA.py:

from cffi import FFI
ffi=FFI()
ffi.set_source("getA",None)
ffi.cdef('''
typedef ... A;       // type also used in another ffi definition.
const A* get_A();
''')

ffi_useA.py:

from cffi import FFI
ffi=FFI()
ffi.set_source("useA",None)
from root.get import ffi_getA
ffi.include(ffi_getA.ffi)         # makes available type A
ffi.cdef('''
const void* use_A(const A*);  // use type A
''')

In an application:

from root.get import getA  # compiled ffi
from root.use import useA  # compiled ffi

libAget = getA.ffi.dlopen("libA.so")
libAuse = useA.ffi.dlopen("libA.so")

a = libAget.getA()

libAuse.useA(a)  # !!! mixing !!!, a is indeed of type A ... 
                 # ... but from a different ffi instance.

This mixing is not going to work, so the question is:

How to access/load cdef functions spread over various compiled ffi objects through a common/single ffi object?

Jongware
  • 22,200
  • 8
  • 54
  • 100
stustd
  • 303
  • 1
  • 10
  • Looks like cffi is not doing what you expect it to. But you'll need to come up with a concrete example in order for us to help you (or fix cffi :-) – Armin Rigo Apr 29 '16 at 15:38
  • 1
    @stustd instead of editing your question to share the solution you found, please post it as separate answer and accept it. You should explain it a bit more though. – Byte Commander May 03 '16 at 13:16

1 Answers1

1

Solution

To build the cffi interface from a single ffi instance everything must start with a root python cdef builder script. From this script the ffi instance is imported and extended in the next builder script that depends on types defined in the previous builder script; and so on. Basically,

In foo.py:

ffi = cffi.FFI()
ffi.cdef("...")

In bar.py:

from foo import ffi
ffi.cdef("...")

In this way, there is only one FFI instance. (Likely, so called "diamond import dependencies" between cffi/cdef files must be avoided in order to avoid duplicate definitions).

Importing the ffi instances at the module level is crucial for the decorator functions to have access to the types defined. (Retrospectively this is trivial but at first I imported at the instance constructiong level and used a separate instance for the decorators - this worked until I needed custom defined types...).

Finally, in this procedure you won't need ffi.include(...) -- the "inclusion" is done through imports. Also, as the source is only generated in the final builder script ffi.set_source(..) statements in subscripts must move under "if __name__=="__main__", before ffi.compile(...). (Thus, subscripts will generate source when called locally, e.g. for testing purposes.)

stustd
  • 303
  • 1
  • 10