CFFI — C Foreign Function Interface for Python
CFFI (C Foreign Function Interface) lets Python code call C libraries by declaring C-like function signatures and types that can often be copy-pasted directly from header files. It supports four modes: ABI/API level each with inline or out-of-line (pre-compiled) preparation. The current stable release is 2.0.0 (released September 2025), requiring Python >=3.9. It is the recommended way to interface with C on PyPy and is used as a foundation by cryptography, bcrypt, and many other major Python packages.
Common errors
-
No module named '_cffi_backend'
cause The `_cffi_backend` C extension module, which is a core part of `cffi`, is either not installed, corrupted, or cannot be found by the Python interpreter. This often happens due to issues with virtual environments, multiple Python installations, or build failures during installation.fixActivate your virtual environment (if any), then run `pip uninstall cffi && pip install cffi`. Ensure you have the necessary system build tools (e.g., C compiler, `python3-dev`, `libffi-dev` on Linux, Visual C++ build tools on Windows) installed before reinstalling. -
OSError: cannot load library 'your_library_name.dll': error 0x7e
cause The C shared library (e.g., DLL on Windows, .so on Linux, .dylib on macOS) that `ffi.dlopen()` is attempting to load cannot be found by the operating system, or the library itself has missing dependencies. On Windows, `error 0x7e` specifically indicates that the specified module could not be found, often implying a missing dependent DLL.fixEnsure the C library file (`your_library_name.dll`, `.so`, or `.dylib`) exists and is located in a directory included in your system's library search path (e.g., `PATH` on Windows, `LD_LIBRARY_PATH` on Linux, `DYLD_LIBRARY_PATH` on macOS). Alternatively, provide an absolute path to the library in `ffi.dlopen()`. Verify that all dynamic dependencies of `your_library_name` are also present and discoverable. -
ImportError: ... undefined symbol: some_function_name
cause The C function or global variable declared in `ffi.cdef()` is not exported by the loaded C shared library, or there is an ABI (Application Binary Interface) incompatibility between the C library and the Python environment (e.g., C++ name mangling, different compiler versions used for `cffi` and the target C library, or Python C API changes).fixCarefully compare the C function/symbol name and signature in `ffi.cdef()` with the actual C header and exported symbols (e.g., using `nm` on Linux). If the C library is written in C++, ensure the functions are declared `extern "C"` to prevent name mangling. Confirm that the C library was compiled with a compatible compiler and settings for your environment and Python version. -
Exception: Version mismatch: this is the 'cffi' package version X.Y.Z, located in '.../cffi/api.py'. When we import the top-level '_cffi_backend' extension module, we get version A.B.C.
cause There is a mismatch between the installed Python `cffi` package (the Python-level code) and its underlying compiled C extension module (`_cffi_backend`). This usually means different versions of these components are being loaded, often due to incomplete upgrades, multiple `cffi` installations, or mixing `pip` installations with system package manager installations (e.g., `apt`).fixTo resolve this, completely uninstall and then reinstall `cffi` to ensure all its components are synchronized: `pip uninstall cffi && pip install cffi`. If you manage Python packages via a system package manager, ensure that both `cffi` and its backend are from the same source, or prefer using a virtual environment and `pip` exclusively for `cffi` related packages.
Warnings
- breaking In 2.0.0, reading a C '_Bool'/'bool' field whose underlying byte is not exactly 0 or 1 now raises an exception instead of returning the raw integer. Previously undefined-behavior values were silently returned.
- breaking Python 2.7, 3.6, and 3.7 support was dropped. The minimum supported version is now Python 3.9 (as of 2.0.0 PyPI metadata).
- breaking ffi.string() no longer works on bool[] arrays. It previously returned raw bytes up to the first zero byte, which was rarely meaningful.
- gotcha char* in C corresponds to bytes in Python 3, not str. Passing a Python str to any char* argument raises TypeError or produces garbage. Always encode strings explicitly: s.encode('utf-8').
- gotcha ABI mode (ffi.dlopen) is error-prone: wrong type declarations cause silent data corruption or crashes rather than compile-time errors. API mode (ffi.set_source + ffi.compile) is verified by a real C compiler.
- gotcha On Python 3.12+ any code path that calls ffi.compile() or uses cffi_modules= in setup.py requires setuptools at runtime because distutils was removed. CFFI does not declare this dependency automatically.
- gotcha ffi.dlopen(None) does not work on Python 3 on Windows. It raises OSError or returns an unusable handle.
Install
-
pip install cffi
Imports
- FFI
import cffi; cffi.FFI()
from cffi import FFI
- FFI (out-of-line)
from _my_compiled_module import ffi, lib
Quickstart
from cffi import FFI
ffi = FFI()
# Declare the C function signature (copy-paste from man page / header)
ffi.cdef("""
size_t strlen(const char *s);
""")
# ABI mode: open the C standard library
C = ffi.dlopen(None) # None = current process / libc on POSIX
# On Windows use ffi.dlopen('msvcrt') instead
# char* arguments must be bytes, not str
result = C.strlen(b"hello, cffi")
print(result) # 11
# Allocate a C buffer
buf = ffi.new("char[]", b"world")
print(ffi.string(buf)) # b'world'