view release on metacpan or search on metacpan
infix/src/jit/trampoline.c
lib/Affix.c
lib/Affix.h
lib/Affix.pm
lib/Affix.pod
lib/Affix/Build.pm
lib/Affix/Build.pod
lib/Affix/Platform/BSD.pm
lib/Affix/Platform/MacOS.pm
lib/Affix/Platform/Solaris.pm
lib/Affix/Platform/Unix.pm
lib/Affix/Platform/Windows.pm
lib/Affix/Wrap.pm
lib/Affix/Wrap.pod
lib/Test2/Tools/Affix.pm
t/001_affix.t
t/002_synopsis.t
t/003_pin.t
t/004_typedef.t
t/005_varargs.t
t/006_out_params.t
Loading dynamic libraries across different operating systems (Windows, macOS, Linux, BSD) can be a nightmare of varying
extensions, prefixes, and search paths. Affix abstracts this complexity away with a smart library discovery engine.
## Library Discovery
When you provide a bare library name (e.g., `'z'`, `'ssl'`, `'user32'`) rather than an absolute path, Affix
automatically formats the name for the current platform (e.g., `libz.so`, `libz.dylib`, `z.dll`) and searches the
following locations in order:
- 1. **Standard System Paths:** Windows `System32`/`SysWOW64`; Unix `/usr/local/lib`, `/usr/lib`, `/lib`, `/usr/lib/system`.
- 2. **Environment Variables:** Paths defined in `LD_LIBRARY_PATH`, `DYLD_LIBRARY_PATH`, `DYLD_FALLBACK_LIBRARY_PATH`, or `PATH`.
- 3. **Local Paths:** The current working directory (`.`) and its `lib/` subdirectory.
## Functions
### `load_library( $path_or_name )`
Locates and loads a dynamic library into memory, returning an opaque `Affix::Lib` handle.
```perl
# ERROR HANDLING & DEBUGGING
Bridging two entirely different runtimes can lead to spectacular crashes if types or memory boundaries are mismatched.
Affix provides built-in tools to help you identify what went wrong.
## Error Handling
### `errno()`
Accesses the system error code from the most recent FFI or standard library call (reads `errno` on Unix and
`GetLastError` on Windows).
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();
infix/src/common/double_tap.h view on Meta::CPAN
*/
#pragma once
#ifdef DBLTAP_ENABLE
#define TAP_VERSION 13
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__unix__) || defined(__APPLE__) || defined(__OpenBSD__)
#include <unistd.h>
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#include <windows.h>
#elif (defined(__unix__) || defined(__APPLE__)) && !defined(__OpenBSD__)
// Do not include pthread.h on OpenBSD to prevent linking/cleanup issues if -pthread is not used.
#include <pthread.h>
#endif
// C++ Headers must be included BEFORE extern "C"
#if defined(__cplusplus)
#include <atomic>
#endif
#ifdef __cplusplus
infix/src/common/double_tap.h view on Meta::CPAN
#define TAP_THREAD_LOCAL
#elif defined(__cplusplus)
#define TAP_THREAD_LOCAL thread_local
#elif defined(_MSC_VER)
// Microsoft Visual C++
#define TAP_THREAD_LOCAL __declspec(thread)
#elif defined(_WIN32) && defined(__clang__)
// Clang on Windows
#define TAP_THREAD_LOCAL __declspec(thread)
#elif defined(__GNUC__) || defined(__clang__)
// GCC (including MinGW) and Clang on *nix
#define TAP_THREAD_LOCAL __thread
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
#define TAP_THREAD_LOCAL _Thread_local
#else
#define TAP_THREAD_LOCAL
#if !defined(_MSC_VER)
#warning "Compiler does not support thread-local storage; tests will not be thread-safe."
#endif
#endif
infix/src/common/double_tap.h view on Meta::CPAN
#if defined(_WIN32) || defined(__CYGWIN__)
static INIT_ONCE g_tap_init_once = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK _tap_init_routine(PINIT_ONCE initOnce, PVOID param, PVOID * context) {
(void)initOnce;
(void)param;
(void)context;
printf("TAP version %d\n", TAP_VERSION);
fflush(stdout);
return TRUE;
}
#elif (defined(__unix__) || defined(__APPLE__)) && !defined(__OpenBSD__)
static pthread_once_t g_tap_init_once = PTHREAD_ONCE_INIT;
static void _tap_init_routine(void) {
printf("TAP version %d\n", TAP_VERSION);
fflush(stdout);
}
#else // OpenBSD or other platforms without robust pthread_once support in this context
static bool g_tap_initialized = false;
#endif
/**
* @internal
* @brief Ensures the TAP header has been printed and thread-local state is initialized.
* Uses `pthread_once` or `InitOnceExecuteOnce` to guarantee the TAP version header
* is printed exactly once per process, even with multiple threads. It also initializes
* the thread-local state for the current thread if it's the first test call on that thread.
*/
static void _tap_ensure_initialized(void) {
#if defined(_WIN32) || defined(__CYGWIN__)
InitOnceExecuteOnce(&g_tap_init_once, _tap_init_routine, NULL, NULL);
#elif (defined(__unix__) || defined(__APPLE__)) && !defined(__OpenBSD__)
pthread_once(&g_tap_init_once, _tap_init_routine);
#else
// Fallback for OpenBSD/single-threaded builds
if (!g_tap_initialized) {
printf("TAP version %d\n", TAP_VERSION);
fflush(stdout);
g_tap_initialized = true;
}
#endif
if (!current_state) {
infix/src/core/error.c view on Meta::CPAN
// Disable TLS entirely on this platform to ensure stability, at the cost of thread-safety.
#define INFIX_TLS
#elif defined(INFIX_COMPILER_MSVC)
// Microsoft Visual C++
#define INFIX_TLS __declspec(thread)
#elif defined(INFIX_OS_WINDOWS) && defined(INFIX_COMPILER_CLANG)
// Clang on Windows: check if behaving like MSVC or GCC.
// If using MSVC codegen/headers, use declspec.
#define INFIX_TLS __declspec(thread)
#elif defined(INFIX_COMPILER_GCC)
// MinGW (GCC on Windows) and standard GCC/Clang on *nix.
// MinGW prefers __thread or _Thread_local over __declspec(thread).
#define INFIX_TLS __thread
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
// Fallback to C11 standard
#define INFIX_TLS _Thread_local
#else
// Fallback for compilers that do not support TLS. This is not thread-safe.
#warning "Compiler does not support thread-local storage; error handling will not be thread-safe."
#define INFIX_TLS
#endif
lib/Affix.pm view on Meta::CPAN
BEGIN {
use XSLoader;
$DynaLoad::dl_debug = $DynaLoad::dl_debug = 1;
$okay = XSLoader::load();
my $platform
= 'Affix::Platform::' .
( ( $^O eq 'MSWin32' ) ? 'Windows' :
$^O eq 'darwin' ? 'MacOS' :
( $^O eq 'freebsd' || $^O eq 'openbsd' || $^O eq 'netbsd' || $^O eq 'dragonfly' ) ? 'BSD' :
'Unix' );
#~ warn $platform;
#~ use base $platform;
eval 'use ' . $platform . ' qw[:all];';
$@ && die $@;
our @ISA = ($platform);
}
push @{ $EXPORT_TAGS{lib} }, qw[libm libc];
$EXPORT_TAGS{types} = [
qw[ typedef
lib/Affix.pod view on Meta::CPAN
extensions, prefixes, and search paths. Affix abstracts this complexity away with a smart library discovery engine.
=head2 Library Discovery
When you provide a bare library name (e.g., C<'z'>, C<'ssl'>, C<'user32'>) rather than an absolute path, Affix
automatically formats the name for the current platform (e.g., C<libz.so>, C<libz.dylib>, C<z.dll>) and searches the
following locations in order:
=over
=item 1. B<Standard System Paths:> Windows C<System32>/C<SysWOW64>; Unix C</usr/local/lib>, C</usr/lib>, C</lib>, C</usr/lib/system>.
=item 2. B<Environment Variables:> Paths defined in C<LD_LIBRARY_PATH>, C<DYLD_LIBRARY_PATH>, C<DYLD_FALLBACK_LIBRARY_PATH>, or C<PATH>.
=item 3. B<Local Paths:> The current working directory (C<.>) and its C<lib/> subdirectory.
=back
=head2 Functions
=head3 C<load_library( $path_or_name )>
lib/Affix.pod view on Meta::CPAN
=head1 ERROR HANDLING & DEBUGGING
Bridging two entirely different runtimes can lead to spectacular crashes if types or memory boundaries are mismatched.
Affix provides built-in tools to help you identify what went wrong.
=head2 Error Handling
=head3 C<errno()>
Accesses the system error code from the most recent FFI or standard library call (reads C<errno> on Unix and
C<GetLastError> on Windows).
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();
lib/Affix/Build.pm view on Meta::CPAN
# Cached Flag Arrays
field @cflags;
field @cxxflags;
field @ldflags;
field $_lib;
#
ADJUST {
my $so_ext = $Config{so} // 'so';
$build_dir = Path::Tiny->new($build_dir) unless builtin::blessed $build_dir;
# Standard convention: Windows DLLs don't need 'lib' prefix, Unix SOs do.
my $prefix = ( $os eq 'MSWin32' || $name =~ /^lib/ ) ? '' : 'lib';
my $suffix = defined $version ? ".$version" : '';
$libname = $build_dir->child("$prefix$name.$so_ext$suffix")->absolute;
# We prefer C++ drivers (g++, clang++) to handle standard libraries for mixed code (C+Rust, C+C++)
$linker = $self->_can_run(qw[g++ clang++ c++ icpx]) || $self->_can_run(qw[cc gcc clang icx cl]) || 'c++';
# Parse global flags...
@cflags = map { chomp; $_ } grep { defined && length } Text::ParseWords::parse_line( q/ /, 1, $flags->{cflags} // '' );
@cxxflags = map { chomp; $_ } grep { defined && length } Text::ParseWords::parse_line( q/ /, 1, $flags->{cxxflags} // '' );
lib/Affix/Platform/BSD.pm view on Meta::CPAN
package Affix::Platform::BSD v0.12.0 {
use v5.40;
use parent 'Affix::Platform::Unix';
use parent 'Exporter';
our @EXPORT_OK = qw[find_library];
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
sub find_library ( $name, $version //= '' ) { # TODO: actually feed version to diff methods
if ( -f $name ) {
$name = readlink $name if -l $name; # Handle symbolic links
return $name # if is_elf($name);
}
CORE::state $cache;
lib/Affix/Platform/MacOS.pm view on Meta::CPAN
package Affix::Platform::MacOS v0.12.0 {
use v5.40;
use DynaLoader;
use parent 'Affix::Platform::Unix';
use parent 'Exporter';
our @EXPORT_OK = qw[find_library];
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
sub find_library ($name) {
return $name if -f $name;
for my $file ( "lib$name.dylib", "$name.dylib", "$name.framework/$name" ) {
my $path = DynaLoader::dl_findfile($file);
return $path if $path;
}
lib/Affix/Platform/Solaris.pm view on Meta::CPAN
package Affix::Platform::Solaris v0.12.0 {
use v5.40;
use parent 'Affix::Platform::Unix';
use parent 'Exporter';
our @EXPORT_OK = qw[find_library];
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
};
1;
lib/Affix/Platform/Unix.pm view on Meta::CPAN
package Affix::Platform::Unix v0.12.0 {
use v5.40;
use Path::Tiny qw[path];
use Config qw[%Config];
use DynaLoader;
use parent 'Exporter';
our @EXPORT_OK = qw[find_library];
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
my $so = $Config{so};
sub is_elf ($filename) {