[pypy-commit] cffi release-1.7: Doc tweaks
arigo
pypy.commits at gmail.com
Mon Jun 20 10:33:31 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: release-1.7
Changeset: r2719:52f417ae8d67
Date: 2016-06-20 16:17 +0200
http://bitbucket.org/cffi/cffi/changeset/52f417ae8d67/
Log: Doc tweaks
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -636,6 +636,15 @@
variables defined as dynamic macros (``#define myvar (*fetchme())``).
Before version 1.2, you need to write getter/setter functions.
+Note that if you declare a variable in ``cdef()`` without using
+``const``, CFFI assumes it is a read-write variable and generates two
+pieces of code, one to read it and one to write it. If the variable
+cannot in fact be written to in C code, for one reason or another, it
+will not compile. In this case, you can declare it as a constant: for
+example, instead of ``foo_t *myglob;`` you would use ``foo_t *const
+myglob;``. Note also that ``const foo_t *myglob;`` is a *variable;* it
+contains a variable pointer to a constant ``foo_t``.
+
Debugging dlopen'ed C libraries
-------------------------------
diff --git a/doc/source/overview.rst b/doc/source/overview.rst
--- a/doc/source/overview.rst
+++ b/doc/source/overview.rst
@@ -44,81 +44,14 @@
arguments. In the above example it would be ``b"world"`` and ``b"hi
there, %s!\n"``. In general it is ``somestring.encode(myencoding)``.
-*This example does not call any C compiler.*
+*This example does not call any C compiler. It works in the so-called
+ABI mode, which means that it will crash if you call some function or
+access some fields of a structure that was slightly misdeclared in the
+cdef().*
-
-.. _out-of-line-abi-level:
-
-Out-of-line example (ABI level, out-of-line)
---------------------------------------------
-
-In a real program, you would not include the ``ffi.cdef()`` in your
-main program's modules. Instead, you can rewrite it as follows. It
-massively reduces the import times, because it is slow to parse a
-large C header. It also allows you to do more detailed checkings
-during build-time without worrying about performance (e.g. calling
-``cdef()`` many times with small pieces of declarations, based
-on the version of libraries detected on the system).
-
-*This example does not call any C compiler.*
-
-.. code-block:: python
-
- # file "simple_example_build.py"
-
- # Note: we instantiate the same 'cffi.FFI' class as in the previous
- # example, but call the result 'ffibuilder' now instead of 'ffi';
- # this is to avoid confusion with the other 'ffi' object you get below
-
- from cffi import FFI
-
- ffibuilder = FFI()
- ffibuilder.set_source("_simple_example", None)
- ffibuilder.cdef("""
- int printf(const char *format, ...);
- """)
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
-Running it once produces ``_simple_example.py``. Your main program
-only imports this generated module, not ``simple_example_build.py``
-any more:
-
-.. code-block:: python
-
- from _simple_example import ffi
-
- lib = ffi.dlopen(None) # Unix: open the standard C library
- #import ctypes.util # or, try this on Windows:
- #lib = ffi.dlopen(ctypes.util.find_library("c"))
-
- lib.printf(b"hi there, number %d\n", ffi.cast("int", 2))
-
-Note that this ``ffi.dlopen()``, unlike the one from in-line mode,
-does not invoke any additional magic to locate the library: it must be
-a path name (with or without a directory), as required by the C
-``dlopen()`` or ``LoadLibrary()`` functions. This means that
-``ffi.dlopen("libfoo.so")`` is ok, but ``ffi.dlopen("foo")`` is not.
-In the latter case, you could replace it with
-``ffi.dlopen(ctypes.util.find_library("foo"))``. Also, None is only
-recognized on Unix to open the standard C library.
-
-For distribution purposes, remember that there is a new
-``_simple_example.py`` file generated. You can either include it
-statically within your project's source files, or, with Setuptools,
-you can say in the ``setup.py``:
-
-.. code-block:: python
-
- from setuptools import setup
-
- setup(
- ...
- setup_requires=["cffi>=1.0.0"],
- cffi_modules=["simple_example_build.py:ffibuilder"],
- install_requires=["cffi>=1.0.0"],
- )
+If using a C compiler to install your module is an option, it is highly
+recommended to use the API mode described in the next paragraph. (It is
+also a bit faster at runtime.)
.. _out-of-line-api-level:
@@ -131,6 +64,10 @@
# file "example_build.py"
+ # Note: we instantiate the same 'cffi.FFI' class as in the previous
+ # example, but call the result 'ffibuilder' now instead of 'ffi';
+ # this is to avoid confusion with the other 'ffi' object you get below
+
from cffi import FFI
ffibuilder = FFI()
@@ -230,11 +167,11 @@
*This example does not call any C compiler.*
This example also admits an out-of-line equivalent. It is similar to
-`Out-of-line example (ABI level, out-of-line)`_ above, but without any
-call to ``ffi.dlopen()``. In the main program, you write ``from
-_simple_example import ffi`` and then the same content as the in-line
-example above starting from the line ``image = ffi.new("pixel_t[]",
-800*600)``.
+`Real example (API level, out-of-line)`_ above, but passing ``None`` as
+the second argument to ``ffibuilder.set_source()``. Then in the main
+program you write ``from _simple_example import ffi`` and then the same
+content as the in-line example above starting from the line ``image =
+ffi.new("pixel_t[]", 800*600)``.
.. _performance:
@@ -288,6 +225,77 @@
distributed in precompiled form like any other extension module.*
+.. _out-of-line-abi-level:
+
+Out-of-line, ABI level
+----------------------
+
+The out-of-line ABI mode is a mixture of the regular (API) out-of-line
+mode and the in-line ABI mode. It lets you use the ABI mode, with its
+advantages (not requiring a C compiler) and problems (crashes more
+easily).
+
+This mixture mode lets you massively reduces the import times, because
+it is slow to parse a large C header. It also allows you to do more
+detailed checkings during build-time without worrying about performance
+(e.g. calling ``cdef()`` many times with small pieces of declarations,
+based on the version of libraries detected on the system).
+
+.. code-block:: python
+
+ # file "simple_example_build.py"
+
+ from cffi import FFI
+
+ ffibuilder = FFI()
+ ffibuilder.set_source("_simple_example", None)
+ ffibuilder.cdef("""
+ int printf(const char *format, ...);
+ """)
+
+ if __name__ == "__main__":
+ ffibuilder.compile(verbose=True)
+
+Running it once produces ``_simple_example.py``. Your main program
+only imports this generated module, not ``simple_example_build.py``
+any more:
+
+.. code-block:: python
+
+ from _simple_example import ffi
+
+ lib = ffi.dlopen(None) # Unix: open the standard C library
+ #import ctypes.util # or, try this on Windows:
+ #lib = ffi.dlopen(ctypes.util.find_library("c"))
+
+ lib.printf(b"hi there, number %d\n", ffi.cast("int", 2))
+
+Note that this ``ffi.dlopen()``, unlike the one from in-line mode,
+does not invoke any additional magic to locate the library: it must be
+a path name (with or without a directory), as required by the C
+``dlopen()`` or ``LoadLibrary()`` functions. This means that
+``ffi.dlopen("libfoo.so")`` is ok, but ``ffi.dlopen("foo")`` is not.
+In the latter case, you could replace it with
+``ffi.dlopen(ctypes.util.find_library("foo"))``. Also, None is only
+recognized on Unix to open the standard C library.
+
+For distribution purposes, remember that there is a new
+``_simple_example.py`` file generated. You can either include it
+statically within your project's source files, or, with Setuptools,
+you can say in the ``setup.py``:
+
+.. code-block:: python
+
+ from setuptools import setup
+
+ setup(
+ ...
+ setup_requires=["cffi>=1.0.0"],
+ cffi_modules=["simple_example_build.py:ffibuilder"],
+ install_requires=["cffi>=1.0.0"],
+ )
+
+
.. _embedding:
Embedding
@@ -418,18 +426,18 @@
functions.)
The generated piece of C code should be the same independently on the
-platform on which you run it (or the Python version),
-so in simple cases you can directly
-distribute the pre-generated C code and treat it as a regular C
-extension module. The special Setuptools lines in the `example
+platform on which you run it (or the Python version), so in simple cases
+you can directly distribute the pre-generated C code and treat it as a
+regular C extension module (which depends on the ``_cffi_backend``
+module, on CPython). The special Setuptools lines in the `example
above`__ are meant for the more complicated cases where we need to
regenerate the C sources as well---e.g. because the Python script that
-regenerates this file will itself look around the system to know what
-it should include or not.
+regenerates this file will itself look around the system to know what it
+should include or not.
.. __: real-example_
-Note that the "API level + in-line" mode combination is deprecated.
-It used to be done with ``lib = ffi.verify("C header")``. The
-out-of-line variant with ``set_source("modname", "C header")`` is
+Note that the "API level + in-line" mode combination exists but is long
+deprecated. It used to be done with ``lib = ffi.verify("C header")``.
+The out-of-line variant with ``set_source("modname", "C header")`` is
preferred.
diff --git a/doc/source/using.rst b/doc/source/using.rst
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -537,7 +537,7 @@
lib.event_cb_register(lib.my_event_callback, userdata)
def process_event(self, evt):
- ...
+ print "got event!"
@ffi.def_extern()
def my_event_callback(evt, userdata):
@@ -566,7 +566,7 @@
lib.event_cb_register(ll_widget, lib.my_event_callback)
def process_event(self, evt):
- ...
+ print "got event!"
@ffi.def_extern()
def my_event_callback(ll_widget, evt):
@@ -789,7 +789,7 @@
lib.register_stuff_with_callback_and_voidp_arg(my_global_callback, handle)
def some_method(self, x):
- ...
+ print "method called!"
(See also the section about `extern "Python"`_ above, where the same
general style is used.)
@@ -881,7 +881,7 @@
``__cdecl`` is supported but is always the default so it can be left
out. In the ``cdef()``, you can also use ``WINAPI`` as equivalent to
-``__stdcall``. As mentioned above, it is not needed (but doesn't
+``__stdcall``. As mentioned above, it is mostly not needed (but doesn't
hurt) to say ``WINAPI`` or ``__stdcall`` when declaring a plain
function in the ``cdef()``. (The difference can still be seen if you
take explicitly a pointer to this function with ``ffi.addressof()``,
More information about the pypy-commit
mailing list