NAME
Affix::Build - Robust, Polyglot Build System for FFI Extensions
SYNOPSIS
use v5.40;
use Affix::Build;
use Affix;
# Example 1: Single Language (Rust)
my $rust = Affix::Build->new( name => 'my_rust_lib' );
$rust->add( \<<~'RUST', lang => 'rust' );
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b }
RUST
my $rust_dll = $rust->link();
# Example 2: Polyglot (C and Go)
my $mix = Affix::Build->new(
name => 'hybrid_lib',
flags => { cflags => '-O3', ldflags => '-L/opt/lib' },
debug => 1
);
# Add file with per-file compiler overrides
$mix->add('src/wrapper.c', flags => '-DDEBUG');
$mix->add('src/core.go');
my $poly_dll = $mix->link();
DESCRIPTION
Affix::Build is a cross-platform compilation utility designed to generate shared libraries (.dll, .so, .dylib) from source code in over 20 different programming languages.
While originally developed to compile test fixtures for the Affix suite, it has evolved into a robust tool for creating polyglot extensions. It abstracts away the complexity of invoking various compilers, normalizing object file extensions, handling platform-specific linker flags (such as MinGW vs. MSVC on Windows), and ensuring that language runtimes (like the Go GC or .NET Runtime) are correctly initialized.
It serves as a powerful, polyglot alternative to Inline::* modules—allowing you to write native code in your language of choice and instantly bind to it from Perl using Affix.
Build Strategies
The builder automatically selects the optimal strategy based on the input sources:
- 1. Native Toolchain Strategy (Single Language)
-
If you provide source files for only one language,
Affix::Builddelegates the entire build process to that language's native toolchain (e.g.,go build -buildmode=c-shared,rustc --crate-type cdylib,dotnet publish). This ensures that the language's standard library and runtime environment are configured exactly as intended by its maintainers. - 2. Polyglot Aggregation Strategy (Mixed Languages)
-
If you provide source files from multiple languages (e.g., C code calling into a Rust library), the builder switches to an aggregation strategy:
CONSTRUCTOR
my $builder = Affix::Build->new( %params );
Creates a new compiler instance.
name: The base name of the resulting library (default:'affix_lib'). The compiler will automatically append the OS-specific extension (.dllon Windows,.dylibon macOS,.soon Linux).version: Optional version string to append to the library name.build_dir: The directory where intermediate artifacts and the final library will be written. If not provided, a temporary directory is created via Path::Tiny.clean: If true, the generatedbuild_dirand all its contents will be deleted when the object is destroyed (default:0).debug: If true, the exact system commands executed by the compiler will be printed toSTDERR(default:0).flags: A HashRef of global flags applied across all files. Keys can becflags,cxxflags, andldflags.os: Override the detected operating system (defaults to$^O).
METHODS
add( $input, %args )
Adds a source file to the build manifest.
$builder->add( 'path/to/file.c' );
$builder->add( 'file.c', flags => ['-DDEBUG', '-Wall'] );
$builder->add( \"int main(){}", lang => 'c' );
File Path: If
$inputis a string, it is treated as a file path. The compiler auto-detects the language based on the extension.Inline Code: If
$inputis a SCALAR reference, you must provide thelangargument (e.g.,'c','rust') so the compiler knows how to handle it.flags: An ArrayRef or space-separated string of compiler flags specific to this source file.
compile_and_link( )
Performs the build process:
- 1. Inspects added sources to determine the Build Strategy.
- 2. Compiles all sources to their appropriate intermediate or final formats.
Returns a Path::Tiny object pointing to the generated shared library. Dies with a detailed error message (including STDOUT/STDERR of the failed command) if compilation fails.
link( )
An alias for compile_and_link(). Safe to call multiple times; it will return the cached library handle if the build has already completed.
SUPPORTED LANGUAGES
Affix::Build attempts to locate the necessary binaries in your system PATH.
C / C++
Automatically handles -fPIC on non-Windows platforms.
Extensions:
.c,.cpp,.cxx,.ccKnown Compilers:
cc,gcc,clang,cl(MSVC),c++,g++,icx.
Rust
Extensions:
.rsCompiler:
rustc
Windows Note: If running under Strawberry Perl (MinGW), you must have the GNU ABI target installed via rustup so the objects can link against Perl's GCC:
rustup target add x86_64-pc-windows-gnu
C# / F#
Uses NativeAOT to compile .NET code directly to unmanaged machine code. Your C# source must tag exported methods with [UnmanagedCallersOnly].
Extensions:
.cs,.fsCompiler:
dotnet(SDK 8.0 or newer required)
Go
Extensions:
.goCompiler:
goorgccgo
Caveats:
In Polyglot mode, requires
gccgoor standardgowithc-archivesupport.The Go runtime spins up background threads (for GC and scheduling) that do not shut down cleanly when a shared library is unloaded. This can cause access violations on Windows during program exit. If you encounter segmentation faults during global destruction, you can force a safe exit using
POSIX::_exit(0)to skip global destructors.
Zig
Extensions:
.zigCompiler:
zig
Fortran
Extensions:
.f,.f90,.f95,.forCompilers:
gfortran,ifx,ifort
Assembly
Correctly handles ARM64 (AArch64) via the system compiler and x86_64 via NASM.
Extensions:
.asm(Intel syntax),.s(AT&T/GNU syntax)Compilers:
nasm(for .asm), Systemcc(for .s)
Other Languages
Support is also included for:
Odin (
.odin)D (
.d) - viadmd,ldc2, orgdcNim (
.nim)V (
.v)Swift (
.swift)Pascal (
.pas,.pp) - viafpc(Free Pascal)Crystal (
.cr)Haskell (
.hs) - viaghcCobol (
.cob,.cbl) - viacobc(GnuCOBOL)OCaml (
.ml) - viaocamloptEiffel (
.e) - viase(SmartEiffel)Futhark (
.fut) - Transpiles to C automatically
PLATFORM NOTES
Windows (MinGW / Strawberry Perl)
This environment is notoriously considered "Polyglot Hard Mode." Affix::Build performs several behind-the-scenes tricks to make it work:
- 1. Rust Compatibility: Forces
rustcto use thex86_64-pc-windows-gnutarget to ensure the resulting static libraries can link against Perl's GCC. - 3. Exports: Automatically adds
-Wl,--export-all-symbolswhen linking to ensure Fortran/Assembly symbols are visible without explicit decoration.
AUTHOR
Sanko Robinson <sanko@cpan.org>
COPYRIGHT
Copyright (C) 2023-2026 by Sanko Robinson.
This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.