Affix

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

# SYNOPSIS

```perl
use v5.40;
use Affix qw[:all];

# Bind a function and call it natively.
# Here, we use libm which might be in libm.so, msvcrt.dll, etc.
# C: double pow(double x, double y);
affix libm(), 'pow', [ Double, Double ] => Double;
say pow( 2.0, 10.0 ); # 1024

# Working with C structs is easy
# C: typedef struct { int x; int y; } Point;
#    void draw_point(Point p);
typedef Point => Struct[ x => Int, y => Int ];
affix $lib, 'draw_point', [ Point() ] => Void;
draw_point( { x => 10, y => 20 } );

# We can also allocate and manage raw memory and write data to it
my $ptr = Affix::malloc(1024);

README.md  view on Meta::CPAN

### `Pointer[ $type ]`

A pointer to another type. When used as an argument, you can pass a **reference to a scalar** for automatic temporary
allocation and write-back.

```perl
# C: void get_val(int *val);
affix $lib, 'get_val', [ Pointer[Int] ] => Void;
my $val = 0;
get_val(\$val);
say $val; # Updated by C
```

### Specialized Pointers

- **`File`** / **`PerlIO`**: Maps Perl filehandles (Globs or IO objects) to `FILE*` or `PerlIO*`. **Must** be wrapped in a pointer: `Pointer[File]`.
- **`SockAddr`**: Specialized marshalling for packed socket strings (e.g., from `Socket::pack_sockaddr_in`) to `struct sockaddr*`.
- **`SV`**: Direct, low-level access to Perl's internal Interpreter Object (`SV*`). **Must** be wrapped in a pointer: `Pointer[SV]`.

## Aggregate Types

README.md  view on Meta::CPAN

$live->{x} = 42; # Updates C memory
```

### Unified Access

`Affix::Pointer` objects for aggregates allow direct field access (`$p->{field}`) without explicit casting.

```perl
affix $lib, 'get_ptr', [] => Pointer[Point];
my $p = get_ptr();
say $p->{x};  # Unified access! Reads directly from C memory.
$p->{y} = 50; # Writes directly to C memory.
```

## Callbacks & Functions

- **`Callback[ [$params] => $ret ]`**: Defines the signature of a C function pointer. Allows you to pass Perl subroutines into C functions.

    ```perl
    # C: void set_handler( void (*cb)(int) );
    affix $lib, 'set_handler', [ Callback[ [Int] => Void ] ] => Void;

README.md  view on Meta::CPAN

```

# POINTER UTILITIES

### `address( $ptr )`

Returns the virtual memory address of the pointer as a Perl Unsigned Integer (`UInt64`). Useful for passing addresses
to other FFI libraries or debugging.

```
say sprintf("Address: 0x%X", address($ptr));
```

### `ptr_add( $ptr, $offset_bytes )`

Returns a new **unmanaged alias Pin** offset by `$offset_bytes`.

```perl
my $int_arr   = calloc(10, Int);
my $next_elem = ptr_add($int_arr, sizeof(Int));
```

README.md  view on Meta::CPAN


### `locate_lib( $name, [$version] )`

Searches for a library using Affix's discovery engine and returns its absolute file path as a string. It **does not**
load the library into memory. This is useful if you need to pass the library path to another tool or check for its
existence.

```perl
# Find libssl.so.1.1 or libssl.1.1.dylib
my $path = locate_lib('ssl', '1.1');
say "Found SSL at: $path" if $path;
```

### `find_symbol( $lib_handle, $symbol_name )`

Looks up an exported symbol (function or global variable) inside an already-loaded `Affix::Lib` handle. Returns an
unmanaged `Affix::Pointer` (Pin) of type `Pointer[Void]` pointing to the memory address of the symbol.

```perl
my $lib = load_library('m');

# Get the raw memory address of the 'pow' function
my $pow_ptr = find_symbol($lib, 'pow');

if ($pow_ptr) {
    say sprintf("pow() is located at: 0x%X", address($pow_ptr));
}
```

Returns `undef` if the symbol cannot be found.

### `libc()` and `libm()`

Helper functions that locate and return the file paths to the standard C library and the standard math library for the
current platform. Because platform implementations differ wildly (e.g., MSVCRT on Windows, glibc on Linux, libSystem on
macOS), using these helpers guarantees you get the correct library.

README.md  view on Meta::CPAN


When working with C APIs, you often need to know exactly how much memory a structure consumes or where a specific field
is located within a block of memory. Affix provides compiler-grade type introspection.

### `sizeof( $type )`

Returns the size, in bytes, of any Affix Type object or registered `typedef` name.

```
# C: sizeof(int);
say sizeof( Int ); # 4 (usually)

# C: sizeof(Point);
say sizeof( Point() ); # 8
```

### `alignof( $type )`

Returns the alignment boundary (in bytes) required by the C ABI for the given type.

```perl
say alignof( Int64 ); # 8 (usually)

# Struct alignment is dictated by its largest member
typedef Mixed => Struct[ a => Char, b => Double ];
say alignof( Mixed() ); # 8
```

### `offsetof( $struct_or_union, $field_name )`

Returns the byte offset of a named field within an Aggregate type (Struct or Union). This is incredibly useful for
manual pointer arithmetic.

```perl
typedef Rect => Struct[ x => Int, y => Int, w => Int, h => Int ];

# C: offsetof(Rect, w);
say offsetof( Rect(), 'w' ); # 8 (skips x and y, 4 bytes each)
```

### `types()`

Returns a list of all custom type names currently registered in Affix's global type registry via `typedef`. In scalar
context, returns the total number of registered types.

```perl
my @known_types = types();
say "Registered types: " . join(', ', @known_types);
```

# INTERFACING WITH OTHER LANGUAGES

Because Affix dynamically loads symbols according to the C Application Binary Interface (C ABI), it can interact with
libraries written in almost any language, provided they expose their functions correctly. Companion modules like
[Affix::Build](https://metacpan.org/pod/Affix%3A%3ABuild) make compiling these languages seamless.

Here are the requirements and quirks for interfacing with non-C languages.

README.md  view on Meta::CPAN

This function returns a **dualvar**. It behaves as an integer in numeric context, and magically resolves to the
human-readable system error message (via `strerror` or `FormatMessage`) in string context.

```perl
# Suppose a C file-open function fails
my $fd = c_open("/does/not/exist");
if (!$fd) {
    my $err = errno();

    # String context
    say "Failed to open: $err"; # "No such file or directory"

    # Numeric context
    if (int($err) == 2) {
        say "Code 2 specifically triggered.";
    }
}
```

**Note:** You must call `errno()` immediately after the C function invokes, as subsequent Perl operations (like
printing to STDOUT) might overwrite the system's error register.

## Memory Inspection

### `dump( $pin, $length_in_bytes )`

README.md  view on Meta::CPAN

        value => 2,
        next  => {
            value => 3,
            next  => undef # NULL
        }
    }
};

# Passing to a function that processes the head
affix $lib, 'sum_list', [ Pointer[Node()] ] => Int;
say sum_list($list);
```

## Interacting with C++ Classes (vtable)

```perl
# Manual call to a vtable entry
# Suppose $obj_ptr is a pointer to a C++ object
my $vtable = cast($obj_ptr, Pointer[ Pointer[Void] ]);
my $func_ptr = $vtable->[0]; # Get first method address

builder/Affix/Builder.pm  view on Meta::CPAN

    }

    method Build(@args) {
        my $method = $self->can( 'step_' . $action );
        $method // die "No such action '$action'\n";
        exit $method->($self);
    }

    method Build_PL() {
        die "Pure perl Affix? Ha! You wish.\n" if $pureperl;
        say sprintf 'Creating new Build script for %s %s', $meta->name, $meta->version;
        $self->write_file( 'Build', sprintf <<'', $^X, __PACKAGE__, __PACKAGE__ );
#!%s
use lib 'builder';
use %s;
%s->new( @ARGV && $ARGV[0] =~ /\A\w+\z/ ? ( action => shift @ARGV ) : (),
    map { /^--/ ? ( shift(@ARGV) =~ s[^--][]r => 1 ) : /^-/ ? ( shift(@ARGV) =~ s[^-][]r => shift @ARGV ) : () } @ARGV )->Build();

        make_executable('Build');
        my @env = defined $ENV{PERL_MB_OPT} ? split_like_shell( $ENV{PERL_MB_OPT} ) : ();
        $self->write_file( '_build_params', encode_json( [ \@env, \@ARGV ] ) );

lib/Affix.pod  view on Meta::CPAN


=head1 SYNOPSIS

    use v5.40;
    use Affix qw[:all];

    # Bind a function and call it natively.
    # Here, we use libm which might be in libm.so, msvcrt.dll, etc.
    # C: double pow(double x, double y);
    affix libm(), 'pow', [ Double, Double ] => Double;
    say pow( 2.0, 10.0 ); # 1024

    # Working with C structs is easy
    # C: typedef struct { int x; int y; } Point;
    #    void draw_point(Point p);
    typedef Point => Struct[ x => Int, y => Int ];
    affix $lib, 'draw_point', [ Point() ] => Void;
    draw_point( { x => 10, y => 20 } );

    # We can also allocate and manage raw memory and write data to it
    my $ptr = Affix::malloc(1024);

lib/Affix.pod  view on Meta::CPAN


=head3 C<Pointer[ $type ]>

A pointer to another type. When used as an argument, you can pass a B<reference to a scalar> for automatic temporary
allocation and write-back.

    # C: void get_val(int *val);
    affix $lib, 'get_val', [ Pointer[Int] ] => Void;
    my $val = 0;
    get_val(\$val);
    say $val; # Updated by C

=head3 Specialized Pointers

=over

=item * B<C<File>> / B<C<PerlIO>>: Maps Perl filehandles (Globs or IO objects) to C<FILE*> or C<PerlIO*>. B<Must> be wrapped in a pointer: C<Pointer[File]>.

=item * B<C<SockAddr>>: Specialized marshalling for packed socket strings (e.g., from C<Socket::pack_sockaddr_in>) to C<struct sockaddr*>.

=item * B<C<SV>>: Direct, low-level access to Perl's internal Interpreter Object (C<SV*>). B<Must> be wrapped in a pointer: C<Pointer[SV]>.

lib/Affix.pod  view on Meta::CPAN

    # Example: Live view of a struct
    my $live = cast( $ptr, Live[ Struct[ x => Int, y => Int ] ] );
    $live->{x} = 42; # Updates C memory

=head3 Unified Access

C<Affix::Pointer> objects for aggregates allow direct field access (C<< $p->{field} >>) without explicit casting.

    affix $lib, 'get_ptr', [] => Pointer[Point];
    my $p = get_ptr();
    say $p->{x};  # Unified access! Reads directly from C memory.
    $p->{y} = 50; # Writes directly to C memory.

=head2 Callbacks & Functions

=over

=item * B<C<< Callback[ [$params] => $ret ] >>>: Defines the signature of a C function pointer. Allows you to pass Perl subroutines into C functions.

    # C: void set_handler( void (*cb)(int) );
    affix $lib, 'set_handler', [ Callback[ [Int] => Void ] ] => Void;

lib/Affix.pod  view on Meta::CPAN

    # 2. Read the memory immediately as an integer value
    my $val = cast($void_ptr, Int); # Returns 99

=head1 POINTER UTILITIES

=head3 C<address( $ptr )>

Returns the virtual memory address of the pointer as a Perl Unsigned Integer (C<UInt64>). Useful for passing addresses
to other FFI libraries or debugging.

    say sprintf("Address: 0x%X", address($ptr));

=head3 C<ptr_add( $ptr, $offset_bytes )>

Returns a new B<unmanaged alias Pin> offset by C<$offset_bytes>.

    my $int_arr   = calloc(10, Int);
    my $next_elem = ptr_add($int_arr, sizeof(Int));

I<Note: If C<$ptr> is an Array type, C<ptr_add> correctly decays the returned pin into a Pointer to the element type.>

lib/Affix.pod  view on Meta::CPAN

will search the currently running executable process.

=head3 C<locate_lib( $name, [$version] )>

Searches for a library using Affix's discovery engine and returns its absolute file path as a string. It B<does not>
load the library into memory. This is useful if you need to pass the library path to another tool or check for its
existence.

    # Find libssl.so.1.1 or libssl.1.1.dylib
    my $path = locate_lib('ssl', '1.1');
    say "Found SSL at: $path" if $path;

=head3 C<find_symbol( $lib_handle, $symbol_name )>

Looks up an exported symbol (function or global variable) inside an already-loaded C<Affix::Lib> handle. Returns an
unmanaged C<Affix::Pointer> (Pin) of type C<Pointer[Void]> pointing to the memory address of the symbol.

    my $lib = load_library('m');

    # Get the raw memory address of the 'pow' function
    my $pow_ptr = find_symbol($lib, 'pow');

    if ($pow_ptr) {
        say sprintf("pow() is located at: 0x%X", address($pow_ptr));
    }

Returns C<undef> if the symbol cannot be found.

=head3 C<libc()> and C<libm()>

Helper functions that locate and return the file paths to the standard C library and the standard math library for the
current platform. Because platform implementations differ wildly (e.g., MSVCRT on Windows, glibc on Linux, libSystem on
macOS), using these helpers guarantees you get the correct library.

lib/Affix.pod  view on Meta::CPAN

=head1 INTROSPECTION

When working with C APIs, you often need to know exactly how much memory a structure consumes or where a specific field
is located within a block of memory. Affix provides compiler-grade type introspection.

=head3 C<sizeof( $type )>

Returns the size, in bytes, of any Affix Type object or registered C<typedef> name.

    # C: sizeof(int);
    say sizeof( Int ); # 4 (usually)

    # C: sizeof(Point);
    say sizeof( Point() ); # 8

=head3 C<alignof( $type )>

Returns the alignment boundary (in bytes) required by the C ABI for the given type.

    say alignof( Int64 ); # 8 (usually)

    # Struct alignment is dictated by its largest member
    typedef Mixed => Struct[ a => Char, b => Double ];
    say alignof( Mixed() ); # 8

=head3 C<offsetof( $struct_or_union, $field_name )>

Returns the byte offset of a named field within an Aggregate type (Struct or Union). This is incredibly useful for
manual pointer arithmetic.

    typedef Rect => Struct[ x => Int, y => Int, w => Int, h => Int ];

    # C: offsetof(Rect, w);
    say offsetof( Rect(), 'w' ); # 8 (skips x and y, 4 bytes each)

=head3 C<types()>

Returns a list of all custom type names currently registered in Affix's global type registry via C<typedef>. In scalar
context, returns the total number of registered types.

    my @known_types = types();
    say "Registered types: " . join(', ', @known_types);

=head1 INTERFACING WITH OTHER LANGUAGES

Because Affix dynamically loads symbols according to the C Application Binary Interface (C ABI), it can interact with
libraries written in almost any language, provided they expose their functions correctly. Companion modules like
L<Affix::Build> make compiling these languages seamless.

Here are the requirements and quirks for interfacing with non-C languages.

=head2 C++

lib/Affix.pod  view on Meta::CPAN


This function returns a B<dualvar>. It behaves as an integer in numeric context, and magically resolves to the
human-readable system error message (via C<strerror> or C<FormatMessage>) in string context.

    # Suppose a C file-open function fails
    my $fd = c_open("/does/not/exist");
    if (!$fd) {
        my $err = errno();

        # String context
        say "Failed to open: $err"; # "No such file or directory"

        # Numeric context
        if (int($err) == 2) {
            say "Code 2 specifically triggered.";
        }
    }

B<Note:> You must call C<errno()> immediately after the C function invokes, as subsequent Perl operations (like
printing to STDOUT) might overwrite the system's error register.

=head2 Memory Inspection

=head3 C<dump( $pin, $length_in_bytes )>

lib/Affix.pod  view on Meta::CPAN

            value => 2,
            next  => {
                value => 3,
                next  => undef # NULL
            }
        }
    };

    # Passing to a function that processes the head
    affix $lib, 'sum_list', [ Pointer[Node()] ] => Int;
    say sum_list($list);

=head2 Interacting with C++ Classes (vtable)

    # Manual call to a vtable entry
    # Suppose $obj_ptr is a pointer to a C++ object
    my $vtable = cast($obj_ptr, Pointer[ Pointer[Void] ]);
    my $func_ptr = $vtable->[0]; # Get first method address

    # Bind and call
    my $method = wrap undef, $func_ptr, [Pointer[Void], Int] => Void;



( run in 0.902 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )