CFFI — C Foreign Function Interface for Python

raw JSON →
2.0.0 verified Tue May 12 auth: no python install: verified quickstart: verified

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.

pip install cffi
error 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.
fix
Activate 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.
error 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.
fix
Ensure 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.
error 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).
fix
Carefully 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.
error 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`).
fix
To 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.
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.
fix If interfacing with a library that stores non-0/1 values in bool fields, replace 'bool' with 'uint8_t' in your ffi.cdef() declaration.
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).
fix Upgrade to Python 3.9+. If you must target older Pythons, pin cffi<2.
breaking ffi.string() no longer works on bool[] arrays. It previously returned raw bytes up to the first zero byte, which was rarely meaningful.
fix Iterate the bool[] directly or cast to uint8_t[] before calling ffi.string().
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').
fix Use b'...' literals or call str.encode() before passing strings to CFFI char* parameters. Decode return values with ffi.string(ptr).decode().
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.
fix Use out-of-line API mode (ffibuilder.set_source + ffibuilder.compile) for production bindings. Reserve ABI/inline mode for quick experiments only.
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.
fix Add 'setuptools' to your package's build-system requires and/or install_requires when using CFFI's build integration.
gotcha ffi.dlopen(None) does not work on Python 3 on Windows. It raises OSError or returns an unusable handle.
fix On Windows, use ffi.dlopen('msvcrt') or specify the full path to the target DLL instead of passing None.
python os / libc status wheel install import disk
3.10 alpine (musl) - - 0.01s 19.2M
3.10 slim (glibc) - - 0.00s 20M
3.11 alpine (musl) - - 0.01s 21.3M
3.11 slim (glibc) - - 0.01s 22M
3.12 alpine (musl) - - 0.01s 13.2M
3.12 slim (glibc) - - 0.01s 14M
3.13 alpine (musl) - - 0.01s 12.8M
3.13 slim (glibc) - - 0.01s 13M
3.9 alpine (musl) - - 0.01s 19.4M
3.9 slim (glibc) - - 0.00s 20M

Inline ABI mode: declare a C function signature and call it via dlopen. No C compiler needed, but prefer out-of-line API mode for production.

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'