# libffi: the lowest layer of a foreign function interface

> libffi gives an interpreter or runtime a portable way to call compiled functions whose argument types are only known at run time. It is a building block, not a complete binding generator, and the README is explicit about that boundary.

**libffi/libffi** — A portable foreign-function interface library.

- Repository: https://github.com/libffi/libffi
- Website: http://sourceware.org/libffi
- Stars: 4,385 · Forks: 833
- Language: C
- License: NOASSERTION
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/libffi-libffi

## The problem libffi solves: calling a function whose signature you learn at run time

Compilers assume a calling convention: where arguments are placed on entry to a function, and where the return value is found. That assumption is baked into generated code. A program that only learns the number and types of arguments at run time cannot produce that code, because the compiler never saw the signature. The README gives the interpreter as the example: an interpreter may be told at run time about the number and types of arguments used to call a given function, and libffi is the bridge from that interpreter to compiled code.

The audience is narrow and specific. You are writing a language runtime, an interpreter, a plugin host, or a binding layer that must reach native code through a description assembled at run time rather than through a header the compiler can read. libffi calls itself a portable, high level programming interface to various calling conventions, which lets a programmer call any function specified by a call interface description at run time. The word to notice is lowest: the README states that libffi provides only the lowest, machine dependent layer of a fully featured foreign function interface, and that a layer must exist above it to handle type conversions between the two languages. If you want a finished binding, libffi is not that product. It is the part that knows how this machine passes arguments.

## How the calling-convention bridge works

The mechanism is a run-time description of a call. Instead of compiling a call site, you build a description of the function's interface and hand it to libffi, which then performs the call according to the conventions of the target architecture. That is what makes the library portable: the same program-level description works across the architectures listed in the README, while the machine-dependent work stays inside libffi.

The repository layout reflects that split. There is a src/ directory for the implementation and an include/ directory for the public headers, with configure.ac, acinclude.m4, m4/ and configure.host handling the per-platform configuration that the port list implies. The testsuite/ directory holds the tests, and the README shows a tested-configuration matrix pairing architectures with operating systems and compilers, from AArch64 on iOS with Clang through X86-64 on Linux with GCC, plus entries such as WASM32 and WASM64 on Emscripten with EMCC, and PowerPC 32-bit on AIX with IBM XL C. That matrix is a statement about what the maintainers exercised at release time, not a guarantee for every combination.

The critical design point is where libffi stops. It does not know that a Python int should become a C int, or that a Rust string should become a char pointer. It moves the call. The mapping of values is the caller's job, which is why projects that embed libffi all carry their own type-conversion code above it.

## Installing libffi and making a first call

The README points at sourceware.org/libffi as the project home. It does not give a copy-and-paste install recipe in the excerpt available here, so the commands below are the standard autotools sequence implied by the repository's configure.ac, autogen.sh and Makefile.am files rather than a documented quickstart. If you clone the repository rather than unpacking a release tarball, the autogen.sh script is the entry point that regenerates the build system.

```bash
./autogen.sh
./configure
make
make check
```

On a distribution, the library is usually already present because other runtimes depend on it. The search data around this project is dominated by package names, which is a useful signal about how most people meet libffi: as a dependency they install rather than as a library they build. The README does not name a distribution package, so check your distribution's package index for the libffi development package before building from source.

After installing, a first real use is to declare a function you want to call, describe its arguments, and let libffi perform the call. The header is included as ffi.h, and the repository ships a libffi.pc.in file, which means pkg-config metadata is generated for the installed library. Querying that metadata is the quickest way to confirm the headers and linker flags are in place.

What you should see is the include path for ffi.h and the linker flag for the library. If pkg-config reports nothing, the development package is not installed and a program that includes ffi.h will not compile. From there, the shape of a program is: include ffi.h, build a description of the call, prepare storage for the arguments and the return value, and invoke the function through libffi. The repository's testsuite/ directory is the place to look for working examples of that sequence, since the README itself does not walk through one.

## Where libffi is the wrong tool

The README's own framing is the biggest limitation. libffi is the lowest layer, and a layer above it must handle type conversions. If your problem is converting a Python object graph into C structures, or mapping a Rust type into a C ABI, libffi solves none of that. Choosing it means committing to write and maintain the conversion layer yourself, and that layer is usually larger and more fragile than the call mechanism it sits on.

Portability is also narrower than the architecture list suggests. The README presents a table of basic configurations that have been tested at release time, pairing a specific architecture, operating system and compiler. A combination that is not in that table is not covered by that statement. If you are targeting something unusual, you are the one doing the verification.

There is a second failure mode that comes from the design itself. Because the call is assembled at run time from a description, a mistake in the description is not caught by a compiler. Passing an argument of the wrong width or class does not produce a type error; it produces a call that the machine executes with whatever convention you asked for. The README does not document a validation step for the description, so the correctness of the description is on the caller. That is the price of the flexibility, and it is worth being explicit about before you build on it.

## libffi versus generating a binding at build time

The real alternative is not another library of the same kind; it is a different approach to the same problem. Tools that generate bindings ahead of time read a header or an interface definition and emit code that calls the target functions directly. The compiler then sees the call sites, checks the types, and applies the calling convention itself. There is no run-time description and no libffi dependency in the output.

That approach is better when the interface is known when you build. It is worse when it is not. An interpreter that accepts a function signature from a script, a plugin host that loads a module and asks it what it exports, or a REPL that builds calls interactively cannot use generated bindings, because there is nothing to generate from at build time. That is the gap libffi fills, and it is why the README reaches for the interpreter as its motivating example.

The difference in practice is where the work lands. With generated bindings, the work is in the generator and the build. With libffi, the work is in the run-time conversion layer and in getting the call description right. Neither is free, and the choice depends on whether the interface is fixed before the program runs.

## Maintenance, releases and what the licence files tell you

The repository is not archived, and the last push was on 2026-09-21, which is two days before the date used for this review. Releases are frequent enough to matter for anyone pinning a version: v3.7.0 on 2026-07-08, v3.7.1 on 2026-07-10, and v3.8.0 on 2026-08-08, which the README's status section also names. Two releases two days apart suggests that a regression in 3.7.0 was fixed quickly in 3.7.1, which is worth remembering if you are choosing between adjacent versions.

The upgrade cost is mostly the cost of rebuilding. The repository uses autotools, with configure.ac, acinclude.m4, m4/ and a configure.host file, plus a separate msvc_build/ directory and msvcc.sh for the MSVC path on Windows, and an Xcode project directory for Apple platforms. A distribution that packages libffi will rebuild it when the version changes; an application that links it will need to be relinked or will pick up the shared object at run time. The search phrases around libffi so 6 and libffi devel point at the two artefacts people actually encounter: the shared object and the development package that carries the headers. Upgrading the runtime library without the matching headers, or the reverse, is the kind of mismatch that shows up as a link error rather than a clear message.

The licence is reported as NOASSERTION, which means no recognised SPDX identifier was detected for the repository. The repository does contain a LICENSE file and a separate LICENSE-BUILDTOOLS file, so the terms are stated in the tree rather than left absent. Read both before you redistribute, and note that the build-tools licence may differ from the library licence. This is a description of what the repository contains, not legal advice.

## Conclusion

Use libffi when you are writing a runtime, interpreter or language binding that must call native code whose signature is only known at run time, and you are prepared to build the type layer above it yourself. Do not use it as a general-purpose binding generator, and do not expect it to convert values between languages; the README states that a layer above libffi must handle type conversions. Before adopting it, verify that your target architecture and operating system appear in the tested configurations table in the README, and check the LICENSE and LICENSE-BUILDTOOLS files in the repository, since the licence is reported as NOASSERTION rather than a recognised SPDX identifier.

## FAQ

### What does libffi do?

It provides a portable, high level programming interface to various calling conventions, so a program can call any function specified by a call interface description at run time. The README describes it as the lowest, machine dependent layer of a foreign function interface.

### How do I install libffi on Ubuntu?

The README does not give a distribution-specific command. The repository's own build path is the autotools sequence: autogen.sh, configure, make, make check, and the development headers come from your distribution's libffi development package.

### What is libffi used for?

It is used by programs that do not know at compile time what arguments will be passed to a function, such as an interpreter that is told at run time about the number and types of arguments. It bridges that interpreter to compiled code.

### What is libffi dev?

It is the development package: the part that carries the headers and the pkg-config metadata needed to compile against libffi. The repository ships a libffi.pc.in file, so an installed copy can be queried with pkg-config.

### What is libffi so 6?

It is the shared object file that programs link against at run time, as opposed to the development package used at build time. The README does not document the version numbering of the shared object, so the number itself is not explained there.

## Sources

- [Issues](https://github.com/libffi/libffi/issues)
- [libffi/libffi on GitHub](https://github.com/libffi/libffi)
- [Project website](http://sourceware.org/libffi)
- [README](https://github.com/libffi/libffi/blob/master/README.md)
- [Releases](https://github.com/libffi/libffi/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/libffi-libffi
