User guide

NumPy User Guide, Release 1.9.0
available to you). Items to remember are:
A shared library must be compiled in a special way ( e.g. using the -shared flag with gcc).
On some platforms (e.g. Windows) , a shared library requires a .def file that specifies the functions to be
exported. For example a mylib.def file might contain.
LIBRARY mylib.dll
EXPORTS
cool_function1
cool_function2
Alternatively, you may be able to use the storage-class specifier __declspec(dllexport) in the C-definition of the
function to avoid the need for this .def file.
There is no standard way in Python distutils to create a standard shared library (an extension module is a “special”
shared library Python understands) in a cross-platform manner. Thus, a big disadvantage of ctypes at the time of
writing this book is that it is difficult to distribute in a cross-platform manner a Python extension that uses c-types and
includes your own code which should be compiled as a shared library on the users system.
Loading the shared library
A simple, but robust way to load the shared library is to get the absolute path name and load it using the cdll object of
ctypes.:
lib = ctypes.cdll[<full_path_name>]
However, on Windows accessing an attribute of the cdll method will load the first DLL by that name found in the
current directory or on the PATH. Loading the absolute path name requires a little finesse for cross-platform work
since the extension of shared libraries varies. There is a ctypes.util.find_library utility available that can
simplify the process of finding the library to load but it is not foolproof. Complicating matters, different platforms
have different default extensions used by shared libraries (e.g. .dll – Windows, .so – Linux, .dylib – Mac OS X). This
must also be taken into account if you are using c-types to wrap code that needs to work on several platforms.
NumPy provides a convenience function called ctypeslib.load_library (name, path). This function takes
the name of the shared library (including any prefix like ‘lib’ but excluding the extension) and a path where the
shared library can be located. It returns a ctypes library object or raises an OSError if the library cannot be found
or raises an ImportError if the ctypes module is not available. (Windows users: the ctypes library object loaded
using load_library is always loaded assuming cdecl calling convention. See the ctypes documentation under
ctypes.windll and/or ctypes.oledll for ways to load libraries under other calling conventions).
The functions in the shared library are available as attributes of the ctypes library object (returned from
ctypeslib.load_library) or as items using lib[’func_name’] syntax. The latter method for retriev-
ing a function name is particularly useful if the function name contains characters that are not allowable in Python
variable names.
Converting arguments
Python ints/longs, strings, and unicode objects are automatically converted as needed to equivalent c-types arguments
The None object is also converted automatically to a NULL pointer. All other Python objects must be converted to
ctypes-specific types. There are two ways around this restriction that allow c-types to integrate with other objects.
1. Don’t set the argtypes attribute of the function object and define an _as_parameter_ method for the object
you want to pass in. The _as_parameter_ method must return a Python int which will be passed directly to
the function.
5.2. Using Python as glue 73