We've spent the previous 50 chapters binding to existing C libraries or writing our own static extensions. For the grand finale, we'll look at the ultimate power of Affix::Build: Runtime Code Generation.

Imagine a program where the user provides a mathematical formula, a data transformation rule, or a filter predicate as a string at runtime. You could evaluate this using Perl's eval, but for millions of data points, eval is slow. Instead, you can compile the user's logic into a native DLL, bind it with Affix, and run it at full CPU speed.

The Recipe

We will build a "High-Speed Formula Evaluator" that compiles arbitrary C math expressions into callable Perl functions.

use v5.40;
use Affix qw[:all];
use Affix::Build;
$|++;

# A helper to compile and bind a custom math function
sub make_math_function( $name, $expression ) {

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

    # Wrap the user's expression in a standard C function
    # We include math.h to give them access to sin, cos, pow, etc.
    # Note the leading backslash: inline source must be passed as a SCALAR reference.
    $c->add( \<<~"END", lang => 'c' );
        #include <math.h>
        double $name(double x, double y) {
            return $expression;
        }
    END

    # Compile and link immediately
    my $lib = $c->link;

    # Bind the new symbol
    affix $lib, $name, [ Double, Double ] => Double;
}
#
print "Enter a C math expression (using variables 'x' and 'y'):\n> ";

# Example: (x * x) + sqrt(y)
my $formula = <STDIN>;
chomp $formula;
say "Compiling native optimizer for '$formula'...";
make_math_function( 'my_jit_func', $formula );
say "\nTesting with x=5, y=10:";
my $result = my_jit_func( 5, 10 );
say 'Result: ' . $result;
say "\nRunning 1,000,000 iterations...";
my $start = time();
my $sum   = 0;
$sum += my_jit_func( $_, 0.5 ) for 1 .. 1_000_000;
say 'Finished in ' . ( time() - $start ) . ' seconds.'

How It Works

Kitchen Reminders