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.

This is where Affix::Build shines. It turns your Perl script into a build system, a linker, and a loader, all in about five lines of code.

Let's look at a classic "Hello World" of pointer manipulation: the Integer Swap.

The Recipe

use v5.40;
use Affix;
use Affix::Build;

# 1. Spin up the compiler
my $c = Affix::Build->new();

# 2. Add some C code directly into the script
$c->add( \<<~'', lang => 'c' );
    void swap(int *a, int *b) {
        int tmp = *b;
        *b = *a;
        *a = tmp;
    }

# 3. Compile, Link, and Bind
affix $c->link, swap => [ Pointer [Int], Pointer [Int] ] => Void;

# 4. Profit
my $a = 1;
my $b = 2;
say "Before: [a,b] = [$a, $b]";

# Pass references so C can write back to Perl
swap( \$a, \$b );
say "After:  [a,b] = [$a, $b]";

How It Works

This creates a seamless bridge between the two languages. Here is what is happening under the hood:

  1. The Builder

Affix::Build->new() creates a temporary workspace. It detects your operating system (Windows, Linux, macOS, BSD) and hunts for a viable compiler chain (GCC, Clang, MSVC). You don't need to configure Makefiles or worry about linker flags; the class handles the heavy lifting.

  1. The Source

We pass the source code as a reference to a string (\<<~''>). This tells the compiler, "I'm not giving you a filename; I'm giving you the raw code." We specify lang => 'c', but Affix::Build is a polyglot—it could just as easily have been cpp, rust, or fortran.

  1. The Link

Calling $c->link triggers the build process. It writes your source to a temp file, compiles it into an object file, and links it into a dynamic library. It returns the absolute path to that library (e.g., /tmp/affix_lib.so).

We pass that path immediately to affix( ... ), binding the symbol swap.

  1. The Types

This is the most critical part of this recipe:

[ Pointer [Int], Pointer [Int] ]

If we had defined this as [ Int, Int ], Affix would have passed the values 1 and 2 to C. The C code would have swapped those values in its own local stack and returned, leaving our Perl variables untouched.

By specifying that these are Pointers, we tell Affix we expect a memory address.

  1. The Execution

Because we defined the types as Pointers, we must pass B to our Perl scalars:

swap( \$a, \$b );

Affix takes the memory address of the value held in the scalar $a, passes it to C, and allows the C code to overwrite the memory directly. When swap returns, $a sees the data that was previously in $b and vice versa. Their values are swapped!

Kitchen Reminders

The chef would like to remind you of things you should have noted or learned from this recipe.

While Affix works on any machine, Affix::Build obviously requires a C compiler (like gcc, clang, or Visual Studio) to be in your system's PATH.

By default, Affix::Build creates a temporary directory for the build artifacts. When your script ends, that directory is wiped clean. If you want to inspect the generated C files or the .so library for debugging, pass clean => 0 to the constructor:

my $c = Affix::Build->new( clean => 0, debug => 1 );

C is unforgiving. If you tell Affix the argument is a Pointer[Int], but you pass a string like "Hello", Affix will try to make it work, but the C code effectively interprets the bytes of that string as an integer. Always match your Perl data types to your Affix definitions.