[pypy-commit] cffi default: Show the recommended use case: API/out-of-line first, in its own section.

jdb pypy.commits at gmail.com
Tue Mar 20 06:10:34 EDT 2018


Author: Jean-Daniel Browne <jeandaniel.browne at gmail.com>
Branch: 
Changeset: r3116:9318184d748c
Date: 2018-03-20 09:09 +0100
http://bitbucket.org/cffi/cffi/changeset/9318184d748c/

Log:	Show the recommended use case: API/out-of-line first, in its own
	section.

diff --git a/doc/source/overview.rst b/doc/source/overview.rst
--- a/doc/source/overview.rst
+++ b/doc/source/overview.rst
@@ -3,6 +3,131 @@
 =======================================================
 
 .. contents::
+   
+
+This document starts, in the first section, with a simple working
+example of using CFFI to call a C function from Python. CFFI is
+flexible and covers several use cases presented in the second
+section. Then, the next section shows how to export Python functions
+to a Python interpreter embedded in a C or C++ application. The last
+two sections delve deeper in the CFFI library.
+
+Make sure you have `cffi installed`__.
+
+.. __: installation.html
+
+.. _out-of-line-api-level:
+.. _real-example:
+
+
+Example: calling a C function from Python
+-----------------------------------------
+
+This example is about the use case when the library sources are
+available, the next section shows how use a compiled, installed
+library.
+
+1. Make sure the sources of the library defining the useful C function
+   is available. For this example, create the file ``pi.c`` and ``pi.h``:
+
+   .. code-block:: C
+
+      /* filename: pi.c*/
+      # include <stdlib.h>
+      # include <math.h>
+       
+      /* Returns a very crude approximation of Pi
+         given a int: a number of iteration */
+      float pi_approx(int n){
+      
+        double i,x,y,sum=0;
+      
+        for(i=0;i<n;i++){
+      
+          x=rand();
+          y=rand();
+      
+          if (sqrt(x*x+y*y) < sqrt((double)RAND_MAX*RAND_MAX))
+            sum++; }
+      
+        return 4*(float)sum/(float)n; }
+
+   .. code-block:: C
+
+      /* filename: pi.h*/
+      float pi_approx(int n);
+      
+2. Create a script named ``pi_extension_build.py``, building
+   the C extension:
+   
+   .. code-block:: python
+
+      from cffi import FFI
+      ffibuilder = FFI()
+      
+      # cdef() expects a string listing the C types, functions and 
+      # globals needed from Python. The string is in the C syntax,
+      # which saves us from learning a Python descriptive dialect.
+      ffibuilder.cdef("float pi_approx(int n);")
+   
+      ffibuilder.set_source(       
+          "_pi",  # name of the output C extension
+      	   '# include "pi.h"',
+      	   sources=['pi.c'],
+      	   libraries=['m'])
+   
+      if __name__ == "__main__":
+          ffibuilder.compile(verbose=True)
+
+       
+3. Build the extension:
+   
+   .. code-block:: shell
+
+      python pi_extension_build.py
+
+   Observe, in the working directory, the generated output files:
+   ``_pi.c``, ``_pi.o`` and the C extension ``_pi.so``.
+
+
+4. Call the C function from Python:
+
+   .. code-block:: python
+   
+       from _pi.lib import pi_approx
+   
+       approx = pi_approx(10)
+       assert str(pi_approximation).startswith("3.")
+   
+       approx = pi_approx(10000)
+       assert str(approx).startswith("3.1")  
+
+For more information, see the ``cdef()`` and ``set_source()`` methods
+of the ``FFI`` class covered in `Preparing and Distributing modules`__.
+
+.. __: cdef.html
+
+
+A common alternative for the step 3. and running the build script is
+to write a ``setup.py`` Setuptools distribution:
+
+.. code-block:: python
+
+    from setuptools import setup
+
+    setup(
+        ...
+        setup_requires=["cffi>=1.0.0"],
+        cffi_modules=["pi_extension_build:ffibuilder"],
+        install_requires=["cffi>=1.0.0"],
+    )
+
+``cffi_modules`` is a list of ``<extension builder script>:<FFI
+instance>`` describing the modules to build.
+
+
+Other CFFI modes
+----------------
 
 CFFI can be used in one of four modes: "ABI" versus "API" level,
 each with "in-line" or "out-of-line" preparation (or compilation).
@@ -18,13 +143,9 @@
 step of preparation (and possibly C compilation) that produces a
 module which your main program can then import.
 
-(The examples below assume that you have `installed CFFI`__.)
-
-.. __: installation.html
-
 
 Simple example (ABI level, in-line)
------------------------------------
++++++++++++++++++++++++++++++++++++
 
 .. code-block:: python
 
@@ -59,96 +180,9 @@
 also faster.)
 
 
-.. _out-of-line-api-level:
-.. _real-example:
-
-Real example (API level, out-of-line)
--------------------------------------
-
-.. code-block:: python
-
-    # 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()
-
-    ffibuilder.set_source("_example",
-       r""" // passed to the real C compiler,
-            // contains implementation of things declared in cdef()
-            #include <sys/types.h>
-            #include <pwd.h>
-
-            struct passwd *get_pw_for_root(void) {
-                return getpwuid(0);
-            }
-        """,
-        libraries=[])   # or a list of libraries to link with
-        # (more arguments like setup.py's Extension class:
-        # include_dirs=[..], extra_objects=[..], and so on)
-
-    ffibuilder.cdef("""
-        // declarations that are shared between Python and C
-        struct passwd {
-            char *pw_name;
-            ...;     // literally dot-dot-dot
-        };
-        struct passwd *getpwuid(int uid);     // defined in <pwd.h>
-        struct passwd *get_pw_for_root(void); // defined in set_source()
-    """)
-
-    if __name__ == "__main__":
-        ffibuilder.compile(verbose=True)
-
-You need to run the ``example_build.py`` script once to generate
-"source code" into the file ``_example.c`` and compile this to a
-regular C extension module.  (CFFI selects either Python or C for the
-module to generate based on whether the second argument to
-``set_source()`` is ``None`` or not.)
-
-*You need a C compiler for this single step.  It produces a file called
-e.g. _example.so or _example.pyd.  If needed, it can be distributed in
-precompiled form like any other extension module.*
-
-Then, in your main program, you use:
-
-.. code-block:: python
-
-    from _example import ffi, lib
-
-    p = lib.getpwuid(0)
-    assert ffi.string(p.pw_name) == b'root'
-    p = lib.get_pw_for_root()
-    assert ffi.string(p.pw_name) == b'root'
-
-Note that this works independently of the exact C layout of ``struct
-passwd`` (it is "API level", as opposed to "ABI level").  It requires
-a C compiler in order to run ``example_build.py``, but it is much more
-portable than trying to get the details of the fields of ``struct
-passwd`` exactly right.  Similarly, in the ``cdef()`` we declared
-``getpwuid()`` as taking an ``int`` argument; on some platforms this
-might be slightly incorrect---but it does not matter.
-
-Note also that at runtime, the API mode is faster than the ABI mode.
-
-To integrate it inside a ``setup.py`` distribution with Setuptools:
-
-.. code-block:: python
-
-    from setuptools import setup
-
-    setup(
-        ...
-        setup_requires=["cffi>=1.0.0"],
-        cffi_modules=["example_build.py:ffibuilder"],
-        install_requires=["cffi>=1.0.0"],
-    )
 
 Struct/Array Example (minimal, in-line)
----------------------------------------
++++++++++++++++++++++++++++++++++++++++
 
 .. code-block:: python
 
@@ -183,17 +217,18 @@
 *This example does not call any C compiler.*
 
 This example also admits an out-of-line equivalent.  It is similar to
-`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 =
+the first example `Example: calling a C function from Python`_ 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:
 
 Purely for performance (API level, out-of-line)
------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++
 
 A variant of the `section above`__ where the goal is not to call an
 existing C library, but to compile and call some C function written
@@ -244,7 +279,7 @@
 .. _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


More information about the pypy-commit mailing list