NAME
Affix::Build - Robust, Polyglot Build System for FFI Extensions
SYNOPSIS
use Affix::Build;
# Builds a shared library using Rust's native toolchain configuration.
my $rust = Affix::Build->new( name => 'my_rust_lib' );
$rust->add('src/logic.rs');
my $lib_path = $rust->compile_and_link(); # Returns path to .so/.dll (e.g., /tmp/.../my_rust_lib.dll)
# Compiles C and Go separately, then links them into a single library.
my $mix = Affix::Build->new(
name => 'hybrid_lib',
build_dir => 'build/',
flags => { cflags => '-O3', ldflags => '-L/opt/lib' },
debug => 1
);
$mix->add('src/wrapper.c', flags => '-DDEBUG'); # Per-file overrides
$mix->add('src/core.go');
my $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 15 different programming languages.
It is specifically engineered to support Foreign Function Interface (FFI) development. 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.
To be honest, this might be an easy backdoor way to get the functionality of an Inline module but I wrote it to test against compiled libs in the Affix test suite.
Build Strategies
The compiler automatically selects the best build strategy based on the input sources:
- 1. Native/Dynamic 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 is the preferred method as it guarantees the language's standard library and runtime environment are configured exactly as the language maintainers intended.
- 2. Polyglot/Static Strategy (Mixed Languages)
-
If you provide source files from multiple languages (e.g., C calling into Rust), the compiler switches to an aggregation strategy:
CONSTRUCTOR
my $c = Affix::Build->new( %params );
Creates a new compiler instance.
name(Default:'affix_lib')-
The base name of the resulting library. The compiler will automatically append the OS-specific extension (
.dllon Windows,.dylibon macOS,.soon Linux). build_dir(Default: Temporary Directory)-
The directory where intermediate artifacts and the final library will be written. If not provided, a temporary directory is created via Path::Tiny and cleaned up when the object is destroyed.
debug(Default: 0)-
If set to true, the exact system commands executed by the compiler will be printed to STDERR.
flags(Default:{})-
Hashref of global flags:
cflags,cxxflags,ldflags. os(Default:$^O)-
Override the detected operating system (useful for testing).
METHODS
add( ... )
$c->add( 'path/to/file.c' );
$c->add( 'path/to/logic.rs' );
$c->add( 'file.c', flags => '-DDEBUG' );
$c->add( \'int main(){}', lang => 'c' );
Adds a source file to the build manifest. The compiler auto-detects the language based on the file extension.
You can also pass raw source code as a SCALAR reference; in this case, the lang argument is required (e.g., 'c', 'rust', 'go'). See "SUPPORTED LANGUAGES" for a list of recognized extensions.
Optionally, this method accepts a flags argument (string or arrayref) to pass specific flags to the compiler for this file.
See "SUPPORTED LANGUAGES" for a list of recognized extensions.
compile_and_link( )
my $path_object = $c->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( )" but only compiles and links if the state hasn't changed since the last build.
SUPPORTED LANGUAGES
Affix::Build attempts to locate the necessary binaries in your PATH.
C / C++
Automatically handles -fPIC on non-Windows platforms.
Supported extensions: .c, .cpp, .cxx, .cc
Known compilers: cc, gcc, clang, cl (MSVC), c++, g++.
Rust
Extensions: .rs
Compiler: rustc
Windows Note: If running under Strawberry Perl (MinGW), you must have the GNU ABI target installed via rustup:
> rustup target add x86_64-pc-windows-gnu
C# / F#
Uses **NativeAOT** to compile C# code directly to machine code. The source must use [UnmanagedCallersOnly].
Extensions: .cs, .fs
Compiler: dotnet (SDK 8.0 or newer required)
Go
Extensions: .go
Compiler: go or gccgo
Notes:
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 often causes access violations on Windows during program exit.
Affix attempts to detect Go libraries (by looking for the
_cgo_dummy_exportsymbol) and keep them in memory to prevent this crash. However, if you still encounter segmentation faults during global destruction, you can force a safe exit usingPOSIX::_exit(0)which skips global destructors.
Zig
Extensions: .zig
Compiler: zig
Fortran
Extensions: .f, .f90, .f95, .for
Compiler: gfortran, ifx, ifort
Assembly
Extensions: .asm (Intel syntax), .s (AT&T/GNU syntax)
Compilers: nasm (for .asm), System cc (for .s)
Notes: Correctly handles ARM64 (AArch64) via the system compiler and x86_64 via NASM.
Other Languages
Support is also included for:
- Odin (
.odin) - D (
.d) - Nim (
.nim) - V (
.v) - Swift (
.swift) - Pascal (
.pas,.pp) - via Free Pascal - Crystal (
.cr) - Haskell (
.hs) - via GHC - Cobol (
.cob,.cbl) - via GnuCOBOL - OCaml (
.ml) - Eiffel (
.e) - via SmartEiffel - Futhark (
.fut) - Transpiles to C
Platform Notes
Windows (MinGW / Strawberry Perl)
This environment is "Polyglot Hard Mode." Affix::Build performs several tricks to make it work:
- 1. Rust Compatibility: Forces
rustcto use the GNU ABI target 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.