Extending Python
Francisco Fernandez Castano
upclose.me
francisco.fernandez.castano@gmail.com @fcofdezc
January 31, 2015
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 1 / 50
Overview
1 Motivations
2 Guidelines
3 Native extensions
4 CTypes
5 CFFI
6 Conclusions
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 2 / 50
Caution
Huge topic
Toy examples
Unix ĈPython centric
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 3 / 50
Motivation
Why write in C?
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 4 / 50
Motivation
Speed
Using legacy code
Integration
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 5 / 50
Motivation
Why is Python slow?
Interpretation overhead
Boxed arithmetic and automatic overflow handling
Dynamic dispatch of operations
Dynamic lookup of methods and attributes
Everything can change on runtime
Extreme introspective and reflective capabilities
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 6 / 50
Motivation
Speed
Using legacy code
Integration
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 7 / 50
Motivation
Speed
Using legacy code
Integration
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 8 / 50
Shared libraries
Single copy in memory
Runtime load
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 9 / 50
Native extensions
C API
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 10 / 50
Native extensions
Hello world, Newton method
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 11 / 50
Native extensions
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 12 / 50
Native extensions
#include "Python.h"
static PyObject *
newton(PyObject *self , PyObject *args)
{
float guess;
float x;
if (! PyArg_ParseTuple (args , "ff", &guess , &x))
return NULL;
while (fabs(powf(guess , 2) - x) > 0.01)
{
guess = ((x / guess) + guess) / 2;
}
return Py_BuildValue("f", guess );
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 13 / 50
Native extensions
static PyMethodDef
module_functions [] = {
{"newton", newton , METH_VARARGS , "Newton method."},
{NULL}
};
PyMODINIT_FUNC
initnewton(void)
{
Py_InitModule3 ("newton", module_functions , "Newton");
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 14 / 50
Native extensions
from distutils.core import setup , Extension
setup(name=’codemotion ’,
version =1.0,
ext_modules =[
Extension(’newton ’, [’newton.c’])])
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 15 / 50
Native extensions
Python 2.7.5 (default , Nov 3 2014, 14:26:24)
[GCC 4.8.3 20140911 (Red Hat 4.8.3 -7)] on linux2
>>> import newton
>>> newton.newton (1, 2)
1.4166667461395264
>>>
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 16 / 50
How?
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 17 / 50
Native extensions
NAME
dlopen --load and link a dynamic library or bundle
SYNOPSIS
#include <dlfcn.h>
void*
dlopen(const char* path , int mode );
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 18 / 50
Native extensions
$ nm -g newton.so
00000000002010 a0 B __bss_start
w __cxa_finalize@@GLIBC_2 .2.5
00000000002010 a0 D _edata
00000000002010 a8 B _end
0000000000000944 T _fini
w __gmon_start__
00000000000006 d0 T _init
0000000000000920 T initnewton
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
U PyArg_ParseTuple
U Py_BuildValue
U Py_InitModule4_64
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 19 / 50
Native extensions
cpython/Python/dynload shlib.c
handle = dlopen(pathname , dlopenflags );
if (handle == NULL) {
const char *error = dlerror ();
if (error == NULL)
error = "unknown dlopen () error";
PyErr_SetString (PyExc_ImportError , error );
return NULL;
}
if (fp != NULL && nhandles < 128)
handles[nhandles ++]. handle = handle;
p = (dl_funcptr) dlsym(handle , funcname );
return p;
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 20 / 50
Native extensions
Memory management
Manual memory management
Python GC - RC
Cycle detector
Py INCREF(x) Py DECREF(x)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 21 / 50
Native extensions
Error management
Return NULL as a convention
Register exceptions
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 22 / 50
Native extensions
Error management
if (err < 0) {
PyErr_SetString (PyExc_Exception , "Err");
return NULL;
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 23 / 50
Native extensions
Python 3 differences
static struct PyModuleDef examplemodule = {
PyModuleDef_HEAD_INIT ,
"newton",
"newton module doc string",
-1,
module_functions ,
NULL ,
NULL ,
NULL ,
NULL };
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 24 / 50
Native extensions
Python 3 differences
PyMODINIT_FUNC
PyInit_sum(void)
{
PyModule_Create (& examplemodule );
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 25 / 50
CTypes
Advanced FFI for Python
Allows call functions from Shared libs
Create, access, manipulate C data types
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 26 / 50
CTypes
Types correspondence
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 27 / 50
CTypes
Structs
from ctypes import *
class POINT(Structure ):
_fields_ = [("x", c_int), ("y", c_int )]
class RECT(Structure ):
_fields_ = [("upperleft", POINT),
("lowerright", POINT )]
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 28 / 50
CTypes
Example
Implemented fibonacci as c function
Map as Python code
Measure differences between Python and C
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 29 / 50
CTypes
int fib(int n){
if (n < 2)
return n;
else
return fib(n - 1) + fib(n - 2);
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 30 / 50
CTypes
import ctypes
lib_fib = ctypes.CDLL("libfib.so")
def ctypes_fib(n):
return lib_fib.fib(ctypes.c_int(n))
def py_fib(n):
if n < 2:
return n
else:
return py_fib(n-1) + py_fib(n-2)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 31 / 50
CTypes
In [3]: %timeit fib.ctypes_fib (20)
10000 loops , best of 3: 63.8 micro s per loop
In [4]: %timeit fib.py_fib (20)
100 loops , best of 3: 3.62 ms per loop
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 32 / 50
CTypes
Fortran example
Use of existing fortran code
Take random code at github
https://github.com/astrofrog/fortranlib
Wrap using ctypes
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 33 / 50
CTypes
Fortran example
real(dp) function mean_dp(x, mask)
implicit none
real(dp),intent(in) :: x(:)
logical ,intent(in),optional :: mask (:)
if(present(mask )) then
mean_dp = sum(x, mask=mask )/ size(x)
else
mean_dp = sum(x)/ size(x)
end if
end function mean_dp
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 34 / 50
CTypes
Fortran example
gfortran -fPIC -shared statistic.f90 -o lib_statistics .so
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 35 / 50
CTypes
Fortran example
bin git:( master) -> nm -g lib_statistics .so
001 eab T ___lib_statistics_MOD_clipped_mean_dp
000 afc T ___lib_statistics_MOD_clipped_mean_sp
00306c T ___lib_statistics_MOD_mean_dp
001 c55 T ___lib_statistics_MOD_mean_sp
002 db0 T ___lib_statistics_MOD_median_dp
0019 b0 T ___lib_statistics_MOD_median_sp
002544 T ___lib_statistics_MOD_quantile_dp
00115a T ___lib_statistics_MOD_quantile_sp
002299 T ___lib_statistics_MOD_variance_dp
000 ec3 T ___lib_statistics_MOD_variance_sp
U __gfortran_arandom_r4
U __gfortran_arandom_r8
U __gfortran_os_error
U __gfortran_pack
U __gfortran_pow_i4_i4
U __gfortran_runtime_error
U __gfortran_runtime_error_at
U __gfortran_st_write
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 36 / 50
CTypes
Fortran example
from ctypes import *
# Statistics fortran lib
st_lib = CDLL(’lib_statistics.so’)
mean = st_lib. __lib_statistics_MOD_mean_dp
mean.argtypes = [POINTER(c_float *2)]
mean.restype = c_float
vals = (c_float *2)(2.0 , 3.0)
print mean(vals)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 37 / 50
CTypes
CTypes source
cpython/Modules/ ctypes/callproc.c
static PyObject *py_dl_open(PyObject *self , PyObject *args)
{
char *name;
void * handle;
#ifdef RTLD_LOCAL
int mode = RTLD_NOW | RTLD_LOCAL;
#else
/* cygwin doesn ’t define RTLD_LOCAL */
int mode = RTLD_NOW;
#endif
if (! PyArg_ParseTuple (args , "z|i:dlopen", &name , &mode ))
return NULL;
mode |= RTLD_NOW;
handle = ctypes_dlopen(name , mode );
.
return PyLong_FromVoidPtr (handle );
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 38 / 50
CFFI
Advanced FFI for Python
Allows call functions from Shared libs
Create, access, manipulate C data types
Both API and ABI access
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 39 / 50
CFFI
Mostly the same as CTypes
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 40 / 50
CFFI
Recommended way to extend PyPy
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 41 / 50
CFFI
ABI
from cffi import FFI
ffi = FFI()
ffi.cdef(""" int printf(const char *format , ...); """)
C = ffi.dlopen(None)
arg = ffi.new("char []", "world")
C.printf("hi there , %s!n", arg)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 42 / 50
CFFI
ABI- Fibonacci
from cffi import FFI
ffi = FFI()
ffi.cdef(""" int fib(int n);""")
libfib = ffi.dlopen(’libfib.so’)
libfib.fib (10)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 43 / 50
CFFI
API Level
import cffi
ffi = cffi.FFI()
ffi.cdef(""" int fib(int n);""")
lib = ffi.verify(r’’’
int fib(int n){
if ( n < 2 )
return n;
else
return fib(n-1) + fib(n -2);
}’’’)
print lib.fib (10)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 44 / 50
CFFI
API Level
import cffi
ffi = cffi.FFI()
ffi.cdef(""" int fib(int n);""")
lib = ffi.verify(r’’’
int fib(int n){
if ( n < 2 )
return n;
else
return fib(n-1) + fib(n -2);
}’’’)
print lib.fib(’asd’)
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 45 / 50
CFFI
API Level
Traceback (most recent call last ):
File "fib.py", line 16, in <module >
print lib.fib("asd")
TypeError: an integer is required
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 46 / 50
CFFI
API Level
from cffi import FFI
ffi = FFI()
ffi.cdef(""" typedef struct { float x, y; } point;""")
point = ffi.new("point *")
point.x = 2.0
point.y = 3.0
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 47 / 50
CFFI
Internals
cffi/c/ cffi backend.c
static PyObject *
b_load_library (PyObject *self , PyObject *args)
{
void *handle;
DynLibObject *dlobj;
if (( flags & (RTLD_NOW | RTLD_LAZY )) == 0)
flags |= RTLD_NOW;
printable_filename = filename_or_null ? filename_or_null :
handle = dlopen(filename_or_null , flags );
dlobj = PyObject_New(DynLibObject , &dl_type );
dlobj ->dl_handle = handle;
dlobj ->dl_name = strdup( printable_filename );
return (PyObject *) dlobj;
}
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 48 / 50
Conclusions
Three different ways
Same principles
Less portable - More portable
Harder - Easier
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 49 / 50
Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 50 / 50

Extending Python - FOSDEM 2015

  • 1.
    Extending Python Francisco FernandezCastano upclose.me francisco.fernandez.castano@gmail.com @fcofdezc January 31, 2015 Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 1 / 50
  • 2.
    Overview 1 Motivations 2 Guidelines 3Native extensions 4 CTypes 5 CFFI 6 Conclusions Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 2 / 50
  • 3.
    Caution Huge topic Toy examples UnixĈPython centric Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 3 / 50
  • 4.
    Motivation Why write inC? Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 4 / 50
  • 5.
    Motivation Speed Using legacy code Integration FranciscoFernandez Castano (@fcofdezc) Extending Python January 31, 2015 5 / 50
  • 6.
    Motivation Why is Pythonslow? Interpretation overhead Boxed arithmetic and automatic overflow handling Dynamic dispatch of operations Dynamic lookup of methods and attributes Everything can change on runtime Extreme introspective and reflective capabilities Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 6 / 50
  • 7.
    Motivation Speed Using legacy code Integration FranciscoFernandez Castano (@fcofdezc) Extending Python January 31, 2015 7 / 50
  • 8.
    Motivation Speed Using legacy code Integration FranciscoFernandez Castano (@fcofdezc) Extending Python January 31, 2015 8 / 50
  • 9.
    Shared libraries Single copyin memory Runtime load Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 9 / 50
  • 10.
    Native extensions C API FranciscoFernandez Castano (@fcofdezc) Extending Python January 31, 2015 10 / 50
  • 11.
    Native extensions Hello world,Newton method Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 11 / 50
  • 12.
    Native extensions Francisco FernandezCastano (@fcofdezc) Extending Python January 31, 2015 12 / 50
  • 13.
    Native extensions #include "Python.h" staticPyObject * newton(PyObject *self , PyObject *args) { float guess; float x; if (! PyArg_ParseTuple (args , "ff", &guess , &x)) return NULL; while (fabs(powf(guess , 2) - x) > 0.01) { guess = ((x / guess) + guess) / 2; } return Py_BuildValue("f", guess ); } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 13 / 50
  • 14.
    Native extensions static PyMethodDef module_functions[] = { {"newton", newton , METH_VARARGS , "Newton method."}, {NULL} }; PyMODINIT_FUNC initnewton(void) { Py_InitModule3 ("newton", module_functions , "Newton"); } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 14 / 50
  • 15.
    Native extensions from distutils.coreimport setup , Extension setup(name=’codemotion ’, version =1.0, ext_modules =[ Extension(’newton ’, [’newton.c’])]) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 15 / 50
  • 16.
    Native extensions Python 2.7.5(default , Nov 3 2014, 14:26:24) [GCC 4.8.3 20140911 (Red Hat 4.8.3 -7)] on linux2 >>> import newton >>> newton.newton (1, 2) 1.4166667461395264 >>> Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 16 / 50
  • 17.
    How? Francisco Fernandez Castano(@fcofdezc) Extending Python January 31, 2015 17 / 50
  • 18.
    Native extensions NAME dlopen --loadand link a dynamic library or bundle SYNOPSIS #include <dlfcn.h> void* dlopen(const char* path , int mode ); Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 18 / 50
  • 19.
    Native extensions $ nm-g newton.so 00000000002010 a0 B __bss_start w __cxa_finalize@@GLIBC_2 .2.5 00000000002010 a0 D _edata 00000000002010 a8 B _end 0000000000000944 T _fini w __gmon_start__ 00000000000006 d0 T _init 0000000000000920 T initnewton w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable w _Jv_RegisterClasses U PyArg_ParseTuple U Py_BuildValue U Py_InitModule4_64 Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 19 / 50
  • 20.
    Native extensions cpython/Python/dynload shlib.c handle= dlopen(pathname , dlopenflags ); if (handle == NULL) { const char *error = dlerror (); if (error == NULL) error = "unknown dlopen () error"; PyErr_SetString (PyExc_ImportError , error ); return NULL; } if (fp != NULL && nhandles < 128) handles[nhandles ++]. handle = handle; p = (dl_funcptr) dlsym(handle , funcname ); return p; Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 20 / 50
  • 21.
    Native extensions Memory management Manualmemory management Python GC - RC Cycle detector Py INCREF(x) Py DECREF(x) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 21 / 50
  • 22.
    Native extensions Error management ReturnNULL as a convention Register exceptions Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 22 / 50
  • 23.
    Native extensions Error management if(err < 0) { PyErr_SetString (PyExc_Exception , "Err"); return NULL; } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 23 / 50
  • 24.
    Native extensions Python 3differences static struct PyModuleDef examplemodule = { PyModuleDef_HEAD_INIT , "newton", "newton module doc string", -1, module_functions , NULL , NULL , NULL , NULL }; Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 24 / 50
  • 25.
    Native extensions Python 3differences PyMODINIT_FUNC PyInit_sum(void) { PyModule_Create (& examplemodule ); } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 25 / 50
  • 26.
    CTypes Advanced FFI forPython Allows call functions from Shared libs Create, access, manipulate C data types Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 26 / 50
  • 27.
    CTypes Types correspondence Francisco FernandezCastano (@fcofdezc) Extending Python January 31, 2015 27 / 50
  • 28.
    CTypes Structs from ctypes import* class POINT(Structure ): _fields_ = [("x", c_int), ("y", c_int )] class RECT(Structure ): _fields_ = [("upperleft", POINT), ("lowerright", POINT )] Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 28 / 50
  • 29.
    CTypes Example Implemented fibonacci asc function Map as Python code Measure differences between Python and C Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 29 / 50
  • 30.
    CTypes int fib(int n){ if(n < 2) return n; else return fib(n - 1) + fib(n - 2); } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 30 / 50
  • 31.
    CTypes import ctypes lib_fib =ctypes.CDLL("libfib.so") def ctypes_fib(n): return lib_fib.fib(ctypes.c_int(n)) def py_fib(n): if n < 2: return n else: return py_fib(n-1) + py_fib(n-2) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 31 / 50
  • 32.
    CTypes In [3]: %timeitfib.ctypes_fib (20) 10000 loops , best of 3: 63.8 micro s per loop In [4]: %timeit fib.py_fib (20) 100 loops , best of 3: 3.62 ms per loop Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 32 / 50
  • 33.
    CTypes Fortran example Use ofexisting fortran code Take random code at github https://github.com/astrofrog/fortranlib Wrap using ctypes Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 33 / 50
  • 34.
    CTypes Fortran example real(dp) functionmean_dp(x, mask) implicit none real(dp),intent(in) :: x(:) logical ,intent(in),optional :: mask (:) if(present(mask )) then mean_dp = sum(x, mask=mask )/ size(x) else mean_dp = sum(x)/ size(x) end if end function mean_dp Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 34 / 50
  • 35.
    CTypes Fortran example gfortran -fPIC-shared statistic.f90 -o lib_statistics .so Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 35 / 50
  • 36.
    CTypes Fortran example bin git:(master) -> nm -g lib_statistics .so 001 eab T ___lib_statistics_MOD_clipped_mean_dp 000 afc T ___lib_statistics_MOD_clipped_mean_sp 00306c T ___lib_statistics_MOD_mean_dp 001 c55 T ___lib_statistics_MOD_mean_sp 002 db0 T ___lib_statistics_MOD_median_dp 0019 b0 T ___lib_statistics_MOD_median_sp 002544 T ___lib_statistics_MOD_quantile_dp 00115a T ___lib_statistics_MOD_quantile_sp 002299 T ___lib_statistics_MOD_variance_dp 000 ec3 T ___lib_statistics_MOD_variance_sp U __gfortran_arandom_r4 U __gfortran_arandom_r8 U __gfortran_os_error U __gfortran_pack U __gfortran_pow_i4_i4 U __gfortran_runtime_error U __gfortran_runtime_error_at U __gfortran_st_write Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 36 / 50
  • 37.
    CTypes Fortran example from ctypesimport * # Statistics fortran lib st_lib = CDLL(’lib_statistics.so’) mean = st_lib. __lib_statistics_MOD_mean_dp mean.argtypes = [POINTER(c_float *2)] mean.restype = c_float vals = (c_float *2)(2.0 , 3.0) print mean(vals) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 37 / 50
  • 38.
    CTypes CTypes source cpython/Modules/ ctypes/callproc.c staticPyObject *py_dl_open(PyObject *self , PyObject *args) { char *name; void * handle; #ifdef RTLD_LOCAL int mode = RTLD_NOW | RTLD_LOCAL; #else /* cygwin doesn ’t define RTLD_LOCAL */ int mode = RTLD_NOW; #endif if (! PyArg_ParseTuple (args , "z|i:dlopen", &name , &mode )) return NULL; mode |= RTLD_NOW; handle = ctypes_dlopen(name , mode ); . return PyLong_FromVoidPtr (handle ); } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 38 / 50
  • 39.
    CFFI Advanced FFI forPython Allows call functions from Shared libs Create, access, manipulate C data types Both API and ABI access Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 39 / 50
  • 40.
    CFFI Mostly the sameas CTypes Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 40 / 50
  • 41.
    CFFI Recommended way toextend PyPy Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 41 / 50
  • 42.
    CFFI ABI from cffi importFFI ffi = FFI() ffi.cdef(""" int printf(const char *format , ...); """) C = ffi.dlopen(None) arg = ffi.new("char []", "world") C.printf("hi there , %s!n", arg) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 42 / 50
  • 43.
    CFFI ABI- Fibonacci from cffiimport FFI ffi = FFI() ffi.cdef(""" int fib(int n);""") libfib = ffi.dlopen(’libfib.so’) libfib.fib (10) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 43 / 50
  • 44.
    CFFI API Level import cffi ffi= cffi.FFI() ffi.cdef(""" int fib(int n);""") lib = ffi.verify(r’’’ int fib(int n){ if ( n < 2 ) return n; else return fib(n-1) + fib(n -2); }’’’) print lib.fib (10) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 44 / 50
  • 45.
    CFFI API Level import cffi ffi= cffi.FFI() ffi.cdef(""" int fib(int n);""") lib = ffi.verify(r’’’ int fib(int n){ if ( n < 2 ) return n; else return fib(n-1) + fib(n -2); }’’’) print lib.fib(’asd’) Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 45 / 50
  • 46.
    CFFI API Level Traceback (mostrecent call last ): File "fib.py", line 16, in <module > print lib.fib("asd") TypeError: an integer is required Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 46 / 50
  • 47.
    CFFI API Level from cffiimport FFI ffi = FFI() ffi.cdef(""" typedef struct { float x, y; } point;""") point = ffi.new("point *") point.x = 2.0 point.y = 3.0 Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 47 / 50
  • 48.
    CFFI Internals cffi/c/ cffi backend.c staticPyObject * b_load_library (PyObject *self , PyObject *args) { void *handle; DynLibObject *dlobj; if (( flags & (RTLD_NOW | RTLD_LAZY )) == 0) flags |= RTLD_NOW; printable_filename = filename_or_null ? filename_or_null : handle = dlopen(filename_or_null , flags ); dlobj = PyObject_New(DynLibObject , &dl_type ); dlobj ->dl_handle = handle; dlobj ->dl_name = strdup( printable_filename ); return (PyObject *) dlobj; } Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 48 / 50
  • 49.
    Conclusions Three different ways Sameprinciples Less portable - More portable Harder - Easier Francisco Fernandez Castano (@fcofdezc) Extending Python January 31, 2015 49 / 50
  • 50.
    Francisco Fernandez Castano(@fcofdezc) Extending Python January 31, 2015 50 / 50