Affix

 view release on metacpan or  search on metacpan

infix/src/arch/aarch64/abi_arm64_emitters.c  view on Meta::CPAN

INFIX_INTERNAL void emit_arm64_arith_imm(
    code_buffer * buf, bool is_sub, bool is64, bool set_flags, arm64_gpr dest, arm64_gpr base, uint32_t imm) {
    uint32_t instr = is_sub ? 0x51000000 : 0x11000000;
    if (is64)
        instr |= (1u << 31);
    if (set_flags)
        instr |= (1u << 29);
    if (imm <= 0xFFF)  // Check for un-shifted 12-bit immediate.
        instr |= (imm & 0xFFF) << 10;
    else if ((imm & 0xFFF) == 0 && (imm >> 12) <= 0xFFF && (imm >> 12) > 0) {  // Check for shifted 12-bit immediate.
        instr |= (1u << 22);                                                   // 'sh' bit selects LSL #12 shift.
        instr |= ((imm >> 12) & 0xFFF) << 10;
    }
    else {
        // Immediate is too large. Load it into a scratch register (X15) and do a register-based operation.
        arm64_gpr scratch_reg = X15_REG;
        emit_arm64_load_u64_immediate(buf, scratch_reg, imm);
        uint32_t reg_instr = is_sub ? 0x4B000000 : 0x0B000000;
        if (is64)
            reg_instr |= (1u << 31);
        if (set_flags)

infix/src/arch/x64/abi_x64_emitters.c  view on Meta::CPAN

                                     bool b,
                                     uint8_t aaa)  // Masking/control bits
{
    emit_byte(buf, 0x62);
    // Byte 2: P0 - R, X, B, R' bits are inverted. 0 means 1, 1 means 0.
    uint8_t p0 = 0;
    p0 |= (R ? 0 : 1) << 7;        // Inverted R bit
    p0 |= (X ? 0 : 1) << 6;        // Inverted X bit
    p0 |= (B ? 0 : 1) << 5;        // Inverted B bit
    p0 |= (R_prime ? 0 : 1) << 4;  // Inverted R' bit
    p0 |= (map & 0x0F);            // Low 4 bits select the opcode map (0F, 0F38, 0F3A)
    emit_byte(buf, p0);
    // Byte 3: P1
    uint8_t p1 = 0;
    p1 |= (pp & 0b11);
    p1 |= (1 << 2);              // ' (marks EVEX), must be 1
    p1 |= ((~vvvv & 0xF) << 3);  // vvvv field is inverted
    p1 |= W ? (1 << 7) : 0;
    emit_byte(buf, p1);
    // Byte 4: P2
    uint8_t p2 = 0;

infix/src/common/infix_config.h  view on Meta::CPAN

/**
 * @file infix_config.h
 * @brief Platform, architecture, and ABI detection macros.
 * @ingroup internal_common
 *
 * @details This header is the first to be included by `infix_internals.h` and is
 * responsible for defining a consistent set of `INFIX_*` macros that describe the
 * build environment. It is the central point of configuration for the entire library,
 * adapting the build to different operating systems, compilers, and CPU architectures.
 *
 * Its most critical function is to select the correct **Application Binary Interface (ABI)**
 * implementation to use for JIT code generation. This is achieved through a cascade
 * of preprocessor checks that can be overridden by the user for cross-compilation.
 * By the end of this file, exactly one `INFIX_ABI_*` macro must be defined, which
 * determines which `abi_*.c` file is included in the unity build.
 *
 * @internal
 */
#pragma once
// System Feature Test Macros
/**

infix/src/jit/trampoline.c  view on Meta::CPAN

extern const infix_direct_forward_abi_spec g_sysv_x64_direct_forward_spec;
#elif defined(INFIX_ABI_AAPCS64)
extern const infix_forward_abi_spec g_arm64_forward_spec;
extern const infix_reverse_abi_spec g_arm64_reverse_spec;
extern const infix_direct_forward_abi_spec g_arm64_direct_forward_spec;
#endif
/**
 * @internal
 * @brief Retrieves a pointer to the ABI specification v-table for forward calls.
 * @details This function is the entry point to the ABI abstraction layer. It uses
 * compile-time preprocessor macros (defined in `infix_config.h`) to select and
 * return the correct v-table for the target platform.
 * @return A pointer to the active `infix_forward_abi_spec`, or `nullptr` if the
 *         platform is unsupported.
 */
const infix_forward_abi_spec * get_current_forward_abi_spec() {
#if defined(INFIX_ABI_WINDOWS_X64)
    return &g_win_x64_forward_spec;
#elif defined(INFIX_ABI_SYSV_X64)
    return &g_sysv_x64_forward_spec;
#elif defined(INFIX_ABI_AAPCS64)

infix/src/jit/trampoline.c  view on Meta::CPAN

#if defined(INFIX_ABI_WINDOWS_X64)
#include "../arch/x64/abi_win_x64.c"
#include "../arch/x64/abi_x64_emitters.c"
#elif defined(INFIX_ABI_SYSV_X64)
#include "../arch/x64/abi_sysv_x64.c"
#include "../arch/x64/abi_x64_emitters.c"
#elif defined(INFIX_ABI_AAPCS64)
#include "../arch/aarch64/abi_arm64.c"
#include "../arch/aarch64/abi_arm64_emitters.c"
#else
#error "No supported ABI was selected for the unity build in trampoline.c."
#endif

lib/Affix/Build.pod  view on Meta::CPAN

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 C<Inline::*> modules—allowing you to write native code in your
language of choice and instantly bind to it from Perl using L<Affix>.

=head2 Build Strategies

The builder automatically selects the optimal strategy based on the input sources:

=over

=item 1. B<Native Toolchain Strategy> (Single Language)

If you provide source files for only B<one> language, C<Affix::Build> delegates the entire build process to that
language's native toolchain (e.g., C<go build -buildmode=c-shared>, C<rustc --crate-type cdylib>, C<dotnet publish>).
This ensures that the language's standard library and runtime environment are configured exactly as intended by its
maintainers.

lib/Affix/Wrap.pod  view on Meta::CPAN

Optional. An array reference of paths to search for C<#include "..."> directives. The directory of every file listed in
C<project_files> is automatically added to this list.

=item C<types>

Optional. A hash reference for manually mapping type names to L<Affix> type objects or definition strings. Very useful
for masking complex internal library structures behind Pointer[Void] handles.

=item C<driver>

Optional. Explicitly select the parser driver. Values are C<'Clang'> or C<'Regex'>. If omitted, C<Affix::Wrap> attempts
to find the C<clang> executable and falls back to Regex if unavailable.

=back

=head1 METHODS

=head2 wrap( $lib, [$target_package] )

    $binder->wrap( $lib );
    $binder->wrap( $lib, 'My::Package' );

t/019_fileio.t  view on Meta::CPAN

        affix $lib, 'c_read_char',      [ Pointer [File] ]         => Int;
        affix $lib, 'c_create_tmpfile', []                         => Pointer [File];
        affix $lib, 'c_is_null_file',   [ Pointer [File] ]         => Int;
        #
        subtest 'Writing to a Perl filehandle from C' => sub {
            my ( $fh, $filename ) = tempfile();

            # Note: We use a real file because PerlIO_findFILE (used internally)
            # requires a valid C-level FILE* which scalar handles (\$) might not provide.
            # Turn off buffering to ensure C sees the file state immediately
            my $old_fh = select($fh);
            $| = 1;
            select($old_fh);
            my $bytes = c_write_to_file( $fh, 'Hello from C' );
            ok $bytes > 0, 'C function returned success count';
            close $fh;

            # Verify content
            open my $check, '<', $filename or die $!;
            my $content = <$check>;
            is $content, 'Hello from C', 'Data written by C appears in file';
            unlink $filename;
        };

t/019_fileio.t  view on Meta::CPAN

    # Define the struct type in Perl.
    # Use Pointer[File] because the C struct member is FILE*.
    typedef Logger => Struct [ log_file => Pointer [File], counter => Int ];

    # Bind functions
    affix $lib, 'init_logger',   [ Pointer [ Logger() ], Pointer [File] ] => Void;
    affix $lib, 'log_message',   [ Pointer [ Logger() ], String ]         => Void;
    affix $lib, 'create_logger', [ Pointer [File] ] => Logger();
    subtest 'File inside Struct (Pointer)' => sub {
        my ( $fh, $filename ) = tempfile();
        my $old_fh = select($fh);
        $| = 1;
        select($old_fh);

        # Allocate struct memory
        my $logger = malloc( sizeof( Logger() ) );

        # Pass filehandle to C to store in struct
        init_logger( $logger, $fh );

        # Verify via C function
        log_message( $logger, 'First message' );
        log_message( $logger, 'Second message' );

t/019_fileio.t  view on Meta::CPAN

        is scalar(@lines), 2, 'File has 2 lines';
        like $lines[0], qr/\[1\] First message/,  'Line 1 matches';
        like $lines[1], qr/\[2\] Second message/, 'Line 2 matches';
        free($logger);

        # Keep $fh alive until test end to avoid closing underneath C
        close $fh;
    };
    subtest 'File inside Struct (Value Return)' => sub {
        my ( $fh, $filename ) = tempfile();
        my $old_fh = select($fh);
        $| = 1;
        select($old_fh);

        # Call C function returning a struct by value
        my $logger_hash = create_logger($fh);
        is $logger_hash->{counter}, 100, 'Counter is correct';
        ok $logger_hash->{log_file}, 'Got filehandle back';
        is ref( $logger_hash->{log_file} ), 'GLOB', 'It is a glob';

        # Write using the returned handle to verify it works
        # Note: $logger_hash->{log_file} wraps the same FILE* as $fh.
        ok syswrite( $logger_hash->{log_file}, "Direct write from Perl\n" ), 'syswrite to the handle from Perl';

t/019_fileio.t  view on Meta::CPAN

        }
        END_C2

        # Array of Pointers to Files (FILE* files[3])
        affix $lib2, 'write_all', [ Array [ Pointer [File], 3 ], String ] => Void;
        my ( $fh1, $f1 ) = tempfile();
        my ( $fh2, $f2 ) = tempfile();
        my ( $fh3, $f3 ) = tempfile();

        # Flush buffers
        for my $h ( $fh1, $fh2, $fh3 ) { my $o = select($h); $| = 1; select($o); }

        # Pass array of handles
        write_all( [ $fh1, $fh2, $fh3 ], 'Broadcast' );
        close $_ for ( $fh1, $fh2, $fh3 );

        # Verify
        for my $f ( $f1, $f2, $f3 ) {
            open my $in, '<', $f;
            is <$in>, 'Broadcast', "File $f written to";
            close $in;



( run in 1.981 second using v1.01-cache-2.11-cpan-39bf76dae61 )