You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 functionsubmake_math_function( $name, $expression ) {
# Spin up the JIT compilermy$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 immediatelymy$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
1. The Polyglot Builder Affix::Build doesn't care that your script is already running. It invokes the system's C compiler in a background process, generates a new dynamic library, and returns its path.
2. Symbol Binding
Because affix can load any library at any time, we simply point it at the newly created .so or .dll file. The function we just "invented" becomes a first-class Perl subroutine.
3. Performance Gain
The user's formula is compiled by your system's C compiler at its default optimization level (you can request -O3 by passing flags => { cflags => '-O3' } to Affix::Build->new). Constant folding, loop unrolling, and vectorization are applied to the user's logic before it even runs. For heavy math, this can be 100x to 500x faster than a Perl eval loop.
Kitchen Reminders
Security WARNING: This recipe allows the user to run arbitrary C code on your system. Only use this technique if you trust the input source, or if you are running in a strictly sandboxed environment. A user could enter system("rm -rf /") instead of a math formula!
Caching
Compiling a DLL takes time (usually 200-500ms). Don't use this for one-off calculations. Use it when you need to run the same complex logic millions of times.
Cleanup
By default, Affix::Build keeps its temporary build directory on disk. Pass clean => 1 to Affix::Build->new if you want the directory removed when the script exits. If you generate many functions in a long-running process, decide which behavior you want up front.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
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,evalis 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.
How It Works
1. The Polyglot Builder
Affix::Builddoesn't care that your script is already running. It invokes the system's C compiler in a background process, generates a new dynamic library, and returns its path.2. Symbol Binding
Because
affixcan load any library at any time, we simply point it at the newly created.soor.dllfile. The function we just "invented" becomes a first-class Perl subroutine.3. Performance Gain
The user's formula is compiled by your system's C compiler at its default optimization level (you can request
-O3by passingflags => { cflags => '-O3' }toAffix::Build->new). Constant folding, loop unrolling, and vectorization are applied to the user's logic before it even runs. For heavy math, this can be 100x to 500x faster than a Perlevalloop.Kitchen Reminders
Security
WARNING: This recipe allows the user to run arbitrary C code on your system. Only use this technique if you trust the input source, or if you are running in a strictly sandboxed environment. A user could enter
system("rm -rf /")instead of a math formula!Caching
Compiling a DLL takes time (usually 200-500ms). Don't use this for one-off calculations. Use it when you need to run the same complex logic millions of times.
Cleanup
By default,
Affix::Buildkeeps its temporary build directory on disk. Passclean => 1toAffix::Build->newif you want the directory removed when the script exits. If you generate many functions in a long-running process, decide which behavior you want up front.All reactions