**Full Changelog**: https://github.com/sanko/At.pm/compare/1.0...1.1
Sanko Robinson
Human.
2026
**Full Changelog**: https://github.com/sanko/At.pm/commits/1.0
## [v1.0.6] - 2026-01-22
## [0.1.4] - 2026-01-17
I've put it off for months but now have unit tests that sorta kinda demonstrates it. [Edit: I have no roadmap or timeline but] I'll need to come back to this before I try to wrap the C++ based SFML with Affix.
C is often called "portable assembly," but sometimes you need the real thing.
If you are doing heavy scientific computing, you will eventually encounter Fortran (BLAS, LAPACK).
Perl is great for glue; Rust is great for logic.
In previous chapters, we compiled code directly or used Alien::Base to find system libraries. But sometimes you want a library that isn't installed on the system, isn't on CPAN, but is available in the wider C/C++ ecosystem.
**Full Changelog**: https://github.com/sanko/Alien-Xmake/compare/0.07...0.08
Allow users to define types in Affix::Wrap
Minor documentation tweaks
In the previous chapter, we built a script that compiles its own dependencies. To share this on CPAN, we want a standard module structure.
Based on infix v0.1.3
For our next trick, we'll tackle the most common headache in the C ecosystem: Dependency Hell. Usually, if you want to manipulate images, you need libpng, libjpeg, zlib, and headers for all of them installed on your system. If your user is on a different OS, your script fails. To avoid that, let's use Affix::Build to compile the famous stb single-header libraries.
**Full Changelog**: https://github.com/sanko/Alien-Xmake/compare/0.05...0.06
Standard Perl scalars are designed for flexibility, not raw math throughput. When you need to process millions of coordinates, pixels, or audio samples, you want SIMD (Single Instruction, Multiple Data).
In Chapter 30, we wrapped C++ classes using extern "C" helper functions in a shim. That is the 'Right Way.' But what if you are stuck with a pre-compiled C++ library and can't recompile it? What if you're just super bored? Let's say you have an object pointer, but no C functions to pass it to.
C++ libraries are notoriously difficult for FFI systems to bind. Unlike C, which uses standard symbol names, C++ "mangles" function names (for example, turning Warrior::attack() into _ZN7Warrior6attackEv) to support features like overloading. Furthermore, C++ methods require a hidden this pointer to know which object instance they are acting upon.
While runtime wrapping is convenient, it has a startup cost (parsing headers every time). For a distributable CPAN module, you want the parsing to happen once (on your machine), generating a pure Perl module that users can load instantly.
The fastest way to use Affix::Wrap is Runtime Wrapping. In this workflow, you parse the headers and bind the functions immediately when your script starts. This is ideal for rapid prototyping, internal scripts, or testing, as you don't need to generate a separate .pm file.
Writing affix signatures manually is great for control, but it becomes tedious when wrapping a library with hundreds of functions and structs. Instead of staring at a .h file and manually translating C types to Affix types, let Affix::Wrap automate it!
2025
Sometimes, the best tool for the job involves three different tools. You might have legacy math models in Fortran, performance-critical loops in Assembly, and a clean C API to orchestrate them.
Throughout this cookbook, you've seen me use Affix::Build to generate shared libraries on the fly from C. However, building shared libraries isn't a concept limited to just C so neither are the capabilities of Affix::Build.
"Is Affix faster than... everything else?"
"Is Affix faster than pure Perl?"
In C, OOP is often simulated using structs containing function pointers. This pattern is commonly known as a vtable and allows a library to call different implementations of a function depending on the object it's holding. With Affix, you can populate these fields with Perl subroutines, effectively creating a Perl class that C can call into.
Manual free() is error-prone. We can use Perl's DESTROY phase to automate it.
When things go wrong in Perl, you probably get an error message. When they go wrong in C, you get a segfault, a frozen terminal, or data corruption that only shows up three hours later. This chapter provides a survival kit for when things go very wrong and it's your job to figure it all out.
System calls fail. In C, you check the global errno variable (or GetLastError() on Windows). In Affix, we expose this via errno().
Bridging I/O between languages is historically one of the most fragile aspects of FFI. While handling file descriptors manually as opaque pointers may be effective on POSIX systems, that approach is a minefield on Windows. Affix solves this by introducing two smart types: File and PerlIO. These types handle the extraction, translation, and lifecycle management of file handles automatically.
Speed is the reason I wrote infix and Affix and I think I've achieved a good balance of features vs. speed. I've done a lot of work to reduce overhead on the hot path but what if we could go... faster?
C headers are full of enum definitions. To the C compiler, these are just integers. To the programmer, they have semantic meaning. When binding these functions to Perl, passing magic numbers (like 0, 1, 2) makes your code unreadable. Affix solves this by allowing you to define Enums that generate Perl constants and return dualvars.
In Chapter 12, we passed a simple callback. But real-world C libraries often take a callback and an opaque pointer (usually something like void * user_data) which allows you to store context data. However, if the library's author decided not to provide that, Affix allows you to bake the context into the callback itself using closures.
Sometimes you need to peek inside the oven. If a function expects a C style struct to be passed by value or if you want to read struct members without writing C helper functions, you can define the struct layout in Perl and Affix handles the rest.
C libraries often use callback functions to delegate logic back to the user. The standard library's qsort is the classic example: it knows how to sort, but it doesn't know how you'd like to compare your data. Affix allows you to pass a standard Perl subroutine (CodeRef) where C expects a function pointer.
Some C functions don't have a fixed number of arguments. The most famous example is printf, which takes a format string and... almost everything else. Affix supports variadic functions, but they require a little more care than standard functions because the C compiler isn't there to cast types for you.
In C, arrays passed to functions are often used as output buffers. The function reads data from the array, modifies it in place, and expects the caller to see the changes. In XS, these are defined as IN_OUT parameters. Affix supports this functionality automatically.
In C, arrays and pointers are cousins. In function arguments, they are twins. Declaring void func(int a[]) is exactly the same as void func(int *a). However, in Perl and thus in Affix, this isn't the case.
Perl scripts often live in the terminal or deep inside a server handing out webpages or whatnot, but they don't have to stay there. Earlier, in chapter 2, we demonstrated using system libraries on Windows to display a simple MessageBox. This time, we turn to Linux (and BSDs with a desktop environment).
Perl handles memory for you. C does not. When you start allocating raw memory buffers in Affix, you are stepping into the C world. This recipe demonstrates how to manually allocate, manipulate, and free memory using the standard C lifecycle.
Affix cannot directly instantiate a C++ class or read a C struct unless we define every single field with the correct type and in the proper order. Often, we don't care about the fields, we just want to hold onto the object and pass it back to the library later. In this case, we can treat the object as a black box, an opaque pointer (Pointer[Void]) and use helper functions to interact with it.
Every operating system comes with a "C standard library" or, simply, libc. It contains the fundamental building blocks of C programming: memory allocation, file I/O, string manipulation, system calls, and much more.
Dealing with C strings usually involves asking "Who owns this memory?"
C strings are simple: they start at a memory address and end at the first zero/null byte (\0). But what if your data contains nulls? If you use standard string types like String or Array[Char], C (and Affix) will assume the data ends at the first null byte. This is fatal for encryption, compression, and binary formats.
When interacting with the Windows API (Win32), you will inevitably face two facts: libraries are named things like user32.dll, and text is almost always expected to be UTF-16 (Wide Characters). In XS, bridging this gap involved tedious calls to MultiByteToWideChar and manual buffer management.
Sometimes, you don't have a pre-existing .dll or .so file. Sometimes, you just have an idea, a heavy mathematical loop, or a snippet of C code you found on Stack Overflow, and you want to run it right now inside your Perl script.
For decades, the barrier between Perl and the raw speed of C (or Rust, or C++, or Fortran) has been guarded by the complex, arcane rituals of XS. You had to learn a new macro language, configure a build system, handle the Perl stack manually, and compile everything before you could even run a "Hello World".
This release contains real-world usage fixes since I'm using it in Affix.pm and not just experime...
This is the first public release of SDL3.pm, a pure Perl wrapper for SDL3.
**Full Changelog**: https://github.com/sanko/Affix.pm/compare/v1.0.0...v1.0.1
Full Changelog: https://github.com/sanko/Affix.pm/compare/v0.12.0...v1.0.0
## [0.1.2] - 2025-11-26
We have nearly reached the end of the current roadmap. infix is fast, secure, and portable. But optimization is an addiction, and I am already looking at the next bottleneck. The new direct marshalling API wins the benchmark races because it removes the intermediate step of packing C values into a buffer. Double indirection is slower than pulling them straight from the source SV*s.
This is an explanation and expansion of discussion #26 now that I've started actually implemented and designed my idea.
Really sanding down the rough edges this time around. This release includes significant ergonomic...
I've had this idea for a while now and might put effort into it next. I understand that this would be a massive task but the first 30% of it is already accomplished by infix existing in its current state.
## [0.1.0] - 2025-10-27
Shower thought time... Internally, would it be faster to coerce args that would end up on the stack into a single block of malloc'd memory? Currently, our trampolines must perform a double-indirection to put data on the stack:
2023
Neat.