NAME
Affix::Wrap - Frictionless C/C++ Binding Generator for Affix
SYNOPSIS
use Affix::Wrap;
my $wrapper = Affix::Wrap->new(
project_files => ['/usr/include/sqlite3.h'],
include_dirs => ['/usr/include'],
types => {
'sqlite3' => 'Pointer[Void]' # Custom override
}
);
# Option 1: Instantly wrap and inject into the current namespace
# You may call functions exported by the lib immediately
$wrapper->wrap('libsqlite3.so', __PACKAGE__);
# Option 2: Generate a standalone Perl module file to disk
# This should get you started on a library wrapper you'll eventually put on CPAN
$wrapper->generate('libsqlite3.so', 'My::SQLite', 'lib/My/SQLite.pm');
DESCRIPTION
Affix::Wrap is a frictionless binding generator that bridges C/C++ header files and Affix. It parses headers to extract functions, structs, enums, typedefs, macros, and global variables, automatically converting this information into Affix definitions.
It is designed to facilitate two primary developer workflows:
- 1. Rapid Prototyping (Runtime Wrapping)
-
Parse headers on the fly and inject bindings directly into your running Perl environment via
wrap(). This is perfect for private tooling, experimental scripts, or whenever you want to avoid the boilerplate of a dedicated FFI module. - 2. Distribution (Static Generation)
-
Generate standalone .pm files for CPAN via
generate(). This produces a pure-Perl module that depends only on Affix, ensuring fast load times and zero development dependencies (likeClangorAffix::Wrapitself) for your end users.
Parsing Drivers
Affix::Wrap employs a dual-driver strategy:
Clang Driver (Recommended)
The primary driver. It leverages
clang -Xclang -ast-dump=jsonto perform compiler-grade analysis of your headers. It is highly accurate and handles complex C++ templates, macros, and deep inclusion chains with ease.Regex Driver (Fallback)
A pure-Perl heuristic parser. While less capable than the Clang driver (it may struggle with complex macros or nested C++ constructs), it requires no external dependencies and is sufficient for many straightforward C headers.
Supported Features
Affix::Wrap extracts and bridges:
Function signatures (including pointer-to-function arguments)
Nested Structs and Unions
Enums (maps them to Affix Dualvar Enums)
Macros (numeric and string constants)
Typedefs (follows deep typedef chains)
Extern Global Variables (binds them via
Affix::pin)Doxygen/Markdown Comments (extracts to POD when generating modules)
CONSTRUCTOR
new( ... )
my $binder = Affix::Wrap->new(
project_files => [ 'lib.h' ],
include_dirs => [ '/usr/include' ],
types => {
'my_opaque_t' => Pointer[Void],
'my_int_t' => Int64
},
driver => 'Clang'
);
project_files-
Required. An array reference of paths to the C header files (
.h,.hpp,.hxx) you wish to parse. include_dirs-
Optional. An array reference of paths to search for
#include "..."directives. The directory of every file listed inproject_filesis automatically added to this list. types-
Optional. A hash reference for manually mapping type names to Affix type objects or definition strings. Very useful for masking complex internal library structures behind Pointer[Void] handles.
driver-
Optional. Explicitly select the parser driver. Values are
'Clang'or'Regex'. If omitted,Affix::Wrapattempts to find theclangexecutable and falls back to Regex if unavailable.
METHODS
wrap( $lib, [$target_package] )
$binder->wrap( $lib );
$binder->wrap( $lib, 'My::Package' );
Parses the project files and immediately binds all found entities (functions, variables, constants, types) to the target package.
$lib-
The shared library to link the functions against.
$target_package-
Optional. The namespace to inject symbols and types into. Defaults to the caller package.
generate( $lib, $pkg, $output_file )
$binder->generate( 'mylib', 'My::Lib', 'lib/My/Lib.pm' );
Parses the headers and writes a fully functioning, standalone Perl .pm module to disk. This is highly recommended for production modules to avoid the overhead of parsing headers at runtime.
parse( [$entry_point] )
my @nodes = $binder->parse;
Parses the project files and returns a list of Node objects (see Data Model below). Use this if you want to inspect the C header structure or generate code strings for a static Perl module.
The nodes are sorted by file name and line number to ensure deterministic output order.
$entry_point-
Optional. The specific file to start parsing from. Defaults to the first file in
project_files.
Data Model
The parse() method returns a list of objects inheriting from Affix::Wrap::Entity.
All nodes provide at least two key methods:
affix_type: Returns a string of Perl code representing the type or declaration (e.g.,"Int","typedef Foo =Int">). Used for code generation.affix( $lib, $pkg ): Performs the actual binding at runtime. Installs symbols into$pkgusing$lib.
Affix::Wrap::Type
Represents a generic C type (e.g., int, void, size_t).
Affix::Wrap::Type::Pointer
Represents T* types. Wraps another type object.
Affix::Wrap::Type::Array
Represents T[N] fixed-size arrays. Wraps a type object and a count.
Affix::Wrap::Type::CodeRef
Represents function pointers (callbacks), e.g., void (*)(int).
ret: Return type object.params: ArrayRef of argument type objects.affix_type: Returns stringCallback[[Args] => Ret].
Affix::Wrap::Argument
Function arguments. Stringifies to "Type Name".
Affix::Wrap::Member
Struct/Union members.
definition: If the member defines a nested struct/union inline, this holds that definition object.affix_type: Returns the signature of the type OR the nested definition.
Affix::Wrap::Function
A C function declaration.
affix_type: Returns a complete Perl string to bind this function (e.g.,affix $lib, name => ...).affix( $lib, $pkg ): Installs the function into$pkg.
Affix::Wrap::Struct
A C struct or union definition.
tag: Either 'struct' or 'union'.affix_type: Returns signature stringStruct[ ... ]orUnion[ ... ].
Affix::Wrap::Typedef
A name alias for another type.
underlying: The type object being aliased.affix_type: Returns stringtypedef Name => UnderlyingType.
Note: In C, typedef struct { ... } Name; results in a Typedef object where underlying is the Struct object.
Affix::Wrap::Enum
An enumeration.
affix_type: Returns signature stringEnum[ Name => Val, ... ]. String values/expressions in enums are quoted automatically to prevent eval errors.
Affix::Wrap::Variable
A global extern variable.
affix_type: Returns stringpin my $var, $lib, name => Type.affix( $lib, $pkg ): Installs the variable accessor into$pkg.
Affix::Wrap::Macro
A preprocessor #define. Only simple value macros are captured.
affix_type: Returns stringuse constant Name => Value. Expressions (e.g.,A + B) are quoted as strings, while literals are preserved.affix( undef, $pkg ): Installs the constant into$pkg.
Tutorials
Runtime Library Wrappers
If you want to use a C library immediately without creating a separate Perl module file, use the wrap method.
use Affix;
use Affix::Wrap;
my $lib = load_library('demo');
# This parses demo.h and installs subroutines, constants,
# and types directly into the calling package.
Affix::Wrap->new( project_files => ['demo.h'] )->wrap($lib);
# Now you can use them:
my $obj = Demo_CreateStruct();
Manual Control
If you need to filter which functions are bound or rename them, you can iterate over the AST manually instead of calling wrap:
my $binder = Affix::Wrap->new( project_files => ['demo.h'] );
for my $node ( $binder->parse ) {
next if $node->name =~ m[^Internal_]; # Skip internal functions
# Manually bind
if ( $node->can('affix') ) {
$node->affix($lib);
}
}
Generating Affix Modules for CPAN
To create a distributable module (e.g., My::Lib.pm) without requiring your users to have Clang or Affix::Wrap installed at runtime, use the generate method:
use Affix::Wrap;
my $binder = Affix::Wrap->new( project_files => ['mylib.h'] );
# Creates 'lib/My/Lib.pm' which depends only on 'Affix'
$binder->generate( 'mylib', 'My::Lib', 'lib/My/Lib.pm' );
If you need custom behaviors (like filtering functions or adding custom POD), you can iterate over the AST manually as described in parse().
AUTHOR
Sanko Robinson <sanko@cpan.org>
COPYRIGHT
Copyright (C) 2026 by Sanko Robinson.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.