infix
A JIT-Powered FFI Library for C
|
infix
is a modern, security-conscious, and dependency-free Foreign Function Interface (FFI) library for C. It simplifies the process of calling native C functions from other environments and creating C-callable function pointers from your own handlers. All with a simple, human-readable string like ({int, *double}, *char) -> int
.
At its core, infix
is a Just-in-Time (JIT) compiler that generates tiny, highly-optimized machine code "trampolines" at runtime. These trampolines correctly handle the low-level Application Binary Interface (ABI) for the target platform, ensuring seamless and performant interoperability.
infix
is designed for developers who need to bridge the gap between different codebases or language runtimes. You'll find it especially useful if you are:
infix
is the ideal engine for allowing a high-level language like Python, Ruby, Perl, or Lua to call C libraries. The introspectable type system simplifies the complex task of data marshalling.infix
can provide the boundary layer, allowing you to load and call functions from shared libraries without tight coupling.user32.dll
, libc.so.6
, etc.) without needing to link against them at compile time, or create complex stateful callbacks for C APIs.infix
provides a powerful, fuzz-tested toolkit for analyzing and interacting with native code.infix
uses a unity build, making integration into any C/C++ project trivial by simply compiling src/infix.c
._Complex
numbers, and SIMD vectors.@Name
) across all your signatures for unparalleled readability and maintainability.user_data
parameter.infix
is hardened against vulnerabilities and validated through extensive fuzz testing:.so
, .dll
, .dylib
), look up symbols, and read/write global variables using the same powerful signature system.cmake
, xmake
, make
, etc.While you can use the provided build scripts, the simplest way to build infix
is to compile its single translation unit directly.
Include the Header:
c #include <infix/infix.h>
Link the Library: When compiling your application, link against the libinfix.a
(or infix.lib
) library.
bash gcc my_app.c -I/path/to/infix/include -L/path/to/build/dir -linfix -o my_app
Here is a complete, runnable example that calls the standard C library function puts
.
The signature language is the most powerful and convenient way to use infix
.
Name | infix Syntax | Example Signature | C/C++ Equivalent |
---|---|---|---|
Primitives | C type names | "int" , "double" , "uint64" | int , double , uint64_t |
Pointers | *<type> | "*int" , "*void" | int* , void* |
Structs | {<members>} | "{int, double, *char}" | struct { ... } |
Unions | <<members>> | "<int, float>" | union { ... } |
Arrays | [<size>:<type>] | "[10:double]" | double[10] |
Function Pointers | (<args>)-><ret> | "(int, int)->int" | int (*)(int, int) |
**_Complex** | c[<base_type>] | "c[double]" | _Complex double |
SIMD Vectors | v[<size>:<type>] | "v[4:float]" | __m128 , float32x4_t |
Enums | e:<int_type> | "e:int" | enum { ... } |
Packed Structs | !{...} or !<N>:{...} | "!{char, longlong}" | __attribute__((packed)) |
Variadic Functions | (<fixed>;<variadic>) | "(*char; int)->int" | printf(const char*, ...) |
Named Types | @Name or @NS::Name | "@Point" , "@UI::User" | typedef struct Point {...} |
Named Arguments | <name>:<type> | "(count:int, data:*void)" | (For reflection only) |
See the complete signature specification.
A wide range of recipes may be found in infix's cookbook.
infix
can read and write to global variables exported from a dynamic library.
**Library Code (libglobals.c
):**
Compile this into libglobals.so
or libglobals.dll
.
Main Application Code:
For dynamic use cases, you can build infix_type
objects programmatically. All types are allocated from an infix_arena_t
.
Beyond just calling functions, infix
provides a powerful introspection API that allows you to parse a signature string and examine the complete memory layout of a C type at runtime. This is the key feature that makes infix
an ideal engine for building language bindings, serializers, or any tool that needs to dynamically interact with C data structures.
Example: Inspecting a C Struct at Runtime
Output on a typical 64-bit system:
This runtime layout information allows you to, for example, take a Perl hash and correctly pack its key/value pairs into a C UserProfile
struct in memory, byte by byte.
Nearly all infix
API functions return an infix_status
enum. If an operation fails, you can get detailed, thread-safe error information.
A brief overview of the complete public API, grouped by functionality.
infix_registry_create()
: Creates a new, empty type registry.infix_registry_destroy()
: Frees a registry and all types defined within it.infix_register_types()
: Parses a string of definitions to populate a registry.infix_forward_create()
: Creates a bound forward trampoline from a signature.infix_forward_create_unbound()
: Creates an unbound forward trampoline from a signature.infix_reverse_create()
: Creates a reverse trampoline (callback) from a signature.infix_signature_parse()
: Parses a full function signature into its infix_type
components.infix_type_from_signature()
: Parses a string representing a single data type.infix_library_open()
: Opens a dynamic library (.so
, .dll
).infix_library_close()
: Closes a dynamic library handle.infix_library_get_symbol()
: Retrieves a function or variable address from a library.infix_read_global()
: Reads a global variable from a library using a signature.infix_write_global()
: Writes to a global variable in a library using a signature.infix_forward_create_manual()
: Creates a bound forward trampoline from infix_type
objects.infix_forward_create_unbound_manual()
: Creates an unbound forward trampoline from infix_type
objects.infix_reverse_create_manual()
: Creates a reverse trampoline from infix_type
objects.infix_forward_destroy()
: Frees a forward trampoline.infix_reverse_destroy()
: Frees a reverse trampoline.infix_type_create_primitive()
: Gets a static descriptor for a primitive C type.infix_type_create_pointer()
: Gets a static descriptor for void*
.infix_type_create_pointer_to()
: Creates a pointer type with a specific pointee type.infix_type_create_void()
: Gets the static descriptor for the void
type.infix_type_create_struct()
: Creates a struct type from an array of members.infix_type_create_packed_struct()
: Creates a struct with non-standard packing.infix_type_create_union()
: Creates a union type from an array of members.infix_type_create_array()
: Creates a fixed-size array type.infix_type_create_enum()
: Creates an enum type with an underlying integer type.infix_type_create_complex()
: Creates a _Complex
number type.infix_type_create_vector()
: Creates a SIMD vector type.infix_type_create_named_reference()
: (Internal) Creates a placeholder for a named type.infix_type_create_member()
: A factory function for infix_struct_member
.infix_arena_create()
: Creates a new memory arena.infix_arena_destroy()
: Frees an arena and all memory allocated from it.infix_arena_alloc()
: Allocates aligned memory from an arena.infix_arena_calloc()
: Allocates zero-initialized memory from an arena.infix_forward_get_code()
, infix_forward_get_unbound_code()
infix_reverse_get_code()
, infix_reverse_get_user_data()
infix_forward_get_num_args()
, infix_reverse_get_num_args()
infix_forward_get_return_type()
, infix_reverse_get_return_type()
infix_forward_get_arg_type()
, infix_reverse_get_arg_type()
infix_type_get_category()
, infix_type_get_size()
, infix_type_get_alignment()
infix_type_get_member_count()
, infix_type_get_member()
infix_type_get_arg_name()
, infix_type_get_arg_type()
infix_type_print()
: Serializes an infix_type
graph to a string.infix_function_print()
: Serializes a full function signature to a string.infix_get_last_error()
: Retrieves detailed information about the last error on the current thread.Full build instructions for xmake
, cmake
, GNU make
, and other systems are available in INSTALL.md.
Because infix
uses a unity build, integration into an existing project is simple: add src/infix.c
to your list of source files and add the include/
directory to your include paths.
infix
is rigorously tested on a wide array of operating systems, compilers, and architectures with every commit.
OS | Version | Architecture | Compiler | Status |
---|---|---|---|---|
DragonflyBSD | 6.4.0 | x86-64 | GCC | |
FreeBSD | 14.3 | x86-64 | GCC | |
14.3 | AArch64 | GCC | ||
14.3 | x86-64 | Clang | ||
14.3 | AArch64 | Clang | ||
macOS | 15 | AArch64 | Clang | |
15 | AArch64 | GCC | ||
NetBSD | 10.1 | AArch64 | GCC | |
10.1 | x86-64 | GCC | ||
OmniOS | r151052 | x86-64 | GCC | |
OpenBSD | 7.7 | AArch64 | Clang | |
7.7 | AArch64 | GCC | ||
7.7 | x86-64 | Clang | ||
7.7 | x86-64 | Clang | ||
Solaris | 11.4 | x86-64 | GCC | |
Ubuntu | 24.04 | AArch64 | Clang | |
24.04 | AArch64 | GCC | ||
24.04 | x86-64 | Clang | ||
24.04 | x86-64 | GCC | ||
Windows | Server 2025 | AArch64 | Clang | |
Server 2025 | AArch64 | GCC | ||
Server 2025 | AArch64 | MSVC | ||
Server 2025 | x86-64 | Clang | ||
Server 2025 | x86-64 | GCC | ||
Server 2025 | x86-64 | MSVC |
In addition to the CI platforms tested here on Github, I can verify infix builds and passes unit tests on Android/Termux.
Contributions are welcome! Please feel free to submit a pull request or open an issue for any bugs, feature requests, or documentation improvements.
infix
is provided under multiple licenses to maximize its usability for all.
Source code, including header files (.h
) and implementation files (.c
), is dual-licensed under the Artistic License 2.0 or the MIT License. You may choose to use the code under the terms of either license.
See the [LICENSE-A2](LICENSE-A2) and/or [LICENSE-MIT](LICENSE-MIT) for the full text of both licenses.
At your discretion, all standalone documentation (.md
), explanatory text, Doxygen-style documentation blocks, comments, and code examples contained within this repository may be used, modified, and distributed under the terms of the Creative Commons Attribution 4.0 International License (CC BY 4.0). We encourage you to share and adapt the documentation for any purpose (generating an API reference website, creating tutorials, etc.), as long as you give appropriate credit.
See the [LICENSE-CC](LICENSE-CC) for details.