Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r351:42090ef917db Date: 2012-06-14 20:44 +0200 http://bitbucket.org/cffi/cffi/changeset/42090ef917db/
Log: Start writing the Reference section. diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -184,7 +184,7 @@ self._cached_btypes[type] = BType return BType - def verify(self, preamble='', **kwargs): + def verify(self, source='', **kwargs): """Verify that the current ffi signatures compile on this machine, and return a dynamic library object. The dynamic library can be used to call functions and access global @@ -194,7 +194,7 @@ which requires binary compatibility in the signatures. """ from .verifier import Verifier - return Verifier(self).verify(preamble, **kwargs) + return Verifier(self).verify(source, **kwargs) def _make_ffi_library(ffi, libname): name = libname diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -36,6 +36,31 @@ .. _`ctypes`: http://docs.python.org/library/ctypes.html +Installation and Status +======================================================= + +This code has been tested on Linux only. It is known to contain +some cross-platform issues. Work on Windows will be coming soon. + +Requirements: + + * Python 2.6 or 2.7 + + * pycparser 2.06: http://code.google.com/p/pycparser/ + +Installation as usual: + + * ``python setup.py install`` + + * or you can directly import and use ``cffi``, but if you don't + compile the ``_ffi_backend`` extension module, it will fall back + to using internally ``ctypes`` (slower). + + +Examples +======================================================= + + Simple example (ABI level) -------------------------- @@ -70,7 +95,8 @@ #include <sys/types.h> #include <pwd.h> """) - assert str(C.getpwuid(0).pw_name) == 'root' + p = C.getpwuid(0) + assert str(p.pw_name) == 'root' Note that the above example works independently of the exact layout of ``struct passwd``, but so far require a C compiler at runtime. (We plan @@ -101,41 +127,180 @@ .. _array: http://docs.python.org/library/array.html -What has actually happened? ---------------------------- +What actually happened? +----------------------- -CFFI interface operates on the same level as C - you declare types and functions -pretty much the same way you would define them in C. In fact most of the examples -from manpages can be copied without changes. +The CFFI interface operates on the same level as C - you declare types +and functions using the same syntax as you would define them in C. This +means that most of the documentation or examples can be copied straight +from the man pages. -The declarations can contain types, functions and global variables. -The cdef in the above example is just that - -it declared "there is a function in the C level with a given signature". +The declarations can contain types, functions and global variables. The +cdef in the above examples are just that - they declared "there is a +function in the C level with this given signature", or "there is a +struct type with this shape". -The next line loads libraries. C has multiple namespaces - a global one and local -ones per library. In this example we load the global one (None as argument to dlopen) -which always contains the standard C library. +The ``dlopen()`` line loads libraries. C has multiple namespaces - a +global one and local ones per library. In this example we load the +global one (``None`` as argument to ``dlopen()``) which always contains +the standard C library. You get as a result a ``<FFILibrary>`` object +that has as attributes all symbols declared in the ``cdef()`` and coming +from this library. -Next line is allocating new char[] object and then calling the printf. Simple, isn't it? +The ``verify()`` line in the second example is an alternative: instead +of doing a ``dlopen``, it generates and compiles a piece of C code. +When using ``verify()`` you have the advantage that you can use ``...`` +at various places in the ``cdef()``, and the missing information will +be completed with the help of the C compiler. It also does checking, +to verify that your declarations are correct. If the C compiler gives +warnings or errors, they are reported here. + +Finally, the ``ffi.new()`` lines allocate C objects. They are filled +with zeroes initially, unless the optional second argument is used. +If specified, this argument gives an "initializer", like you can use +with C code to initialize global variables. + +The actual function calls should be obvious. + + + +Reference +======================================================= + +As a guideline: you have already seen in the above examples all the +major pieces except maybe ``ffi.cast()``. The rest of this +documentation gives a more complete reference. + Declaring types and functions ----------------------------- -There is not much to say here +``ffi.cdef(source)`` parses the given C source. This should be done +first. It registers all the functions, types, and global variables in +the C source. The types can be used immediately in 'ffi.new()' and +other functions. Before you can access the functions and global +variables, you need to give ``ffi`` another piece of information: where +they actually come from (which you do with either ``ffi.dlopen()`` or +``ffi.verify()``). + +The C source is parsed internally (using ``pycparser``). This code +cannot contain ``#include``. It should typically be a self-contained +piece of declarations extracted from a man page. The only things it +can assume to exist are the standard types: + + * char, short, int, long, long long (both signed and unsigned) + + * float, double + + * intN_t, uintN_t (for N=8,16,32,64), intptr_t, uintptr_t, ptrdiff_t, + size_t, ssize_t + +As we will see on `the verification step`_ below, the declarations +can also contain ``...`` at various places as placeholders that are +completed only by during a call to ``verify()``. + Loading libraries ----------------- +``ffi.dlopen(libpath)``: this function opens a shared library and +returns a module-like library object. You can use the library object to +call the functions previously declared by ``ffi.cdef()``, and to read or +write global variables. Note that you can use a single ``cdef()`` to +declare functions from multiple libraries, as long as you load each of +them with ``dlopen()`` and access the functions from the correct one. + +The ``libpath`` is the file name of the shared library, which can +contain a full path or not (in which case it is searched in standard +locations, as described in ``man dlopen``). Alternatively, if +``libpath`` is None, it returns the standard C library (which can be +used to access the functions of glibc, on Linux). + +This gives ABI-level access to the library: you need to have all types +declared manually exactly as they were while the library was made. No +checking is done. For this reason, we recommend to use ``ffi.verify()`` +instead when possible. + +Note that only functions and global variables are in library objects; +types exist in the ``ffi`` instance independently of library objects. +This is due to the C model: the types you declare in C are not tied to a +particular library, as long as you ``#include`` their headers; but you +cannot call functions from a library without linking it in your program. + + +The verification step +--------------------- + +``ffi.verify(source, ...)``: verifies that the current ffi signatures +compile on this machine, and return a dynamic library object. The +dynamic library can be used to call functions and access global +variables declared by a previous 'ffi.cdef()'. The library is compiled +by the C compiler: it gives you C-level API compatibility (including +calling macros, as long as you declared them as functions in +``ffi.cdef()``). This differs from ``ffi.dlopen()``, which requires +ABI-level compatibility and must be called several times to open several +shared libraries. + +On top of CPython, the new library is actually a CPython C extension +module. This solution constrains you to have a C compiler (future work +will cache the compiled C code and let you distribute it to other +systems which don't have a C compiler). + +The arguments to ``ffi.verify()`` are: + + * ``source``: C code that is pasted verbatim in the generated code (it + is *not* parsed internally). It should contain at least the + necessary ``#include``. It can also contain the complete + implementation of some functions declared in ``cdef()``; this is + useful if you really need to write a piece of C code, e.g. to access + some advanced macros. + + * ``include_dirs``, ``define_macros``, ``undef_macros``, ``libraries``, + ``library_dirs``, ``extra_objects``, ``extra_compile_args``, + ``extra_link_args`` (keyword arguments): these are used when + compiling the C code, and are passed directly to distutils_. + +.. _distutils: http://docs.python.org/distutils/setupscript.html#describing-extension-modules + +On the plus side, this solution gives more "C-like" flexibility: + + * functions taking or returning integer or float-point arguments can be + misdeclared: if e.g. a function is declared by ``cdef()`` as taking a + ``int``, but actually takes a ``long``, then the C compiler handles the + difference. + + * other arguments are checked: you get a compilation warning or error + if you pass a ``int *`` argument to a function expecting a ``long *``. + +Moreover, you can use ``...`` in the following places in the ``cdef()`` +for leaving details unspecified (filled in by the C compiler): + + * structure declarations: any ``struct`` that ends with ``...;`` is + partial. It will be completed by the compiler. (You can only access + fields that you declared; the compiler can only consider the missing + fields as padding.) Any ``struct`` declaration without ``...;`` is + assumed to be exact, but this is checked: you get a + ``VerificationError`` if it is not. + + * unknown types: the syntax ``typedef ... foo_t;`` declares the type + ``foo_t`` as opaque. + + * enums: in ``enum foo { A, B, C, ... };``, the enumerated values are + not necessarily in order; the C compiler will reorder them as needed + and skip any unmentioned value. Like with structs, an ``enum`` that + does not end in ``...`` is assumed to be exact, and this is checked. + + Working with pointers, structures and arrays -------------------------------------------- -The verification step ---------------------- + + + Indices and tables ================== * :ref:`genindex` -* :ref:`modindex` * :ref:`search` _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit