Strada - Perl XS Module
Version 1.0
This Perl XS module allows Perl programs to load and call functions from compiled Strada shared libraries.
Overview
The Strada module provides a bridge from Perl to Strada, enabling you to:
- Load Strada shared libraries (.so files)
- Call Strada functions with automatic type conversion
- Pass Perl scalars, arrays, and hashes to Strada (arrays/hashes map to Strada references)
- Receive Strada return values as Perl types
- Call functions with any number of arguments (with libffi), including variadic functions and constructors
- Construct Strada objects and call methods on them (
Strada::Object) - Catch Strada exceptions as Perl
die(eval/Try::Tiny) - Inspect library metadata (version, function signatures)
Installation
Prerequisites
- Perl 5.10 or later
- Strada compiler and runtime (from parent directory)
- C compiler (gcc)
- libffi (optional) —
libffi-dev/libffi-devel. When present,call()accepts any number of arguments; without it, calls are capped at 4.
Build Steps
cd perl/Strada
perl Makefile.PL
make
make test
make install # optional, installs system-wide
Specifying Strada Location
By default, the build looks for the Strada runtime in these locations (in order):
STRADA_ROOTenvironment variableSTRADA_ROOT=command line argument- System install (
/usr/local/include/stradaor/usr/include/strada) - Source tree (
../..- assumes building from within the Strada repo)
If Strada is installed elsewhere, specify the path:
# Via command line argument
perl Makefile.PL STRADA_ROOT=/path/to/strada
# Via environment variable
STRADA_ROOT=/path/to/strada perl Makefile.PL
The path should point to either:
- The Strada source directory (containing
runtime/strada_runtime.h) - An installed location (containing
strada_runtime.hdirectly)
Usage
High-Level API (Recommended)
use Strada;
# Load a Strada shared library
my $lib = Strada::Library->new('./libmath.so');
# Get library info
print "Version: ", $lib->version(), "\n";
print $lib->describe(), "\n";
# Call functions using package::function syntax (recommended)
my $sum = $lib->call('math_lib::add', 10, 20); # 30
my $greeting = $lib->call('math_lib::greet', 'Perl'); # "Hello, Perl!"
# Or use the C-style name directly
my $sum2 = $lib->call('math_lib_add', 10, 20); # 30
# Pass arrays
my $total = $lib->call('math_lib::sum_array', [1, 2, 3, 4, 5]);
# Pass hashes
my $desc = $lib->call('math_lib::describe_person', { name => 'Alice', age => 30 });
# Receive arrays
my $nums = $lib->call('math_lib::get_numbers'); # Returns arrayref
# Receive hashes
my $person = $lib->call('math_lib::get_person'); # Returns hashref
# Unload when done
$lib->unload();
Inspecting Library Functions
use Strada;
my $lib = Strada::Library->new('./libmath.so');
# Get formatted description (like strada-soinfo tool)
print $lib->describe();
# Output:
# # Strada Library: ./libmath.so
# # Version: 1.0.0
# # Functions: 3
# #
# # func math_lib_add(int $a, int $b) int
# # func math_lib_greet(str $a) str
# # func math_lib_sum_array(scalar $a) int
# Get function details programmatically
my $funcs = $lib->functions();
for my $name (sort keys %$funcs) {
my $f = $funcs->{$name};
print "Function: $name\n";
print " Returns: $f->{return}\n";
print " Params: ", join(", ", @{$f->{params}}), "\n";
}
Low-Level API
use Strada;
# Load library, get handle
my $handle = Strada::load('./libmath.so');
die "Failed to load" unless $handle;
# Get function pointer
my $func = Strada::get_func($handle, 'math_lib_add');
die "Function not found" unless $func;
# Call function
my $result = Strada::call($func, 2, 3);
print "2 + 3 = $result\n";
# Unload
Strada::unload($handle);
Creating Strada Shared Libraries
1. Write a Strada Library
# math_lib.strada
package math_lib;
version "1.0.0";
func add(int $a, int $b) int {
return $a + $b;
}
func greet(str $name) str {
return "Hello, " . $name . "!";
}
func sum_array(scalar $arr) int {
my int $total = 0;
my int $len = length($arr);
my int $i = 0;
while ($i < $len) {
$total = $total + $arr->[$i];
$i = $i + 1;
}
return $total;
}
2. Compile as Shared Library
./strada --shared math_lib.strada
# Creates: math_lib.so
3. Use from Perl
use Strada;
my $lib = Strada::Library->new('./math_lib.so');
print $lib->call('math_lib::add', 1, 2), "\n"; # 3
$lib->unload();
Function Naming Convention
Strada functions are exported with the naming pattern:
<package>_<function>
For example:
package math_lib+func add()=math_lib_addpackage utils+func format_date()=utils_format_date
When calling from Perl, you can use either format:
$lib->call('math_lib_add', ...)- C-style name$lib->call('math_lib::add', ...)- Perl/Strada style (automatically converted)
Type Conversion
| Strada Type | Perl Type |
|-------------|-----------|
| int | IV (integer) |
| num | NV (floating point) |
| str | PV (string) |
| array | Array reference |
| hash | Hash reference |
| undef | undef |
| ref | Dereferenced value |
| blessed object | Strada::Object (see below) |
Objects and Methods
A blessed Strada object returned from the runtime comes back as a
Strada::Object — a wrapper that dispatches method calls back into Strada
(rather than flattening to a plain hashref and losing the class). Construct
objects with new_object (sugar for calling Class::new) and call methods
directly:
my $lib = Strada::Library->new('./example/math_lib.so');
my $c = $lib->new_object('Counter', count => 10, name => 'hits');
# (equivalent to: my $c = $lib->call('Counter::new', count => 10, name => 'hits'))
$c->increment; # method dispatch -> 11
$c->add(5); # method with arguments -> 16
print $c->describe, "\n"; # "hits=16"
$c->strada_class; # "Counter" (the Strada package)
$c->isa('Counter'); # true (checks the Strada class hierarchy)
# A Strada::Object can be passed back into the runtime as an argument:
my $d = $lib->new_object('Counter', count => 2);
$c->merge($d); # $d is handed straight through to the method
The wrapper holds a reference to the underlying value and releases it on
DESTROY. isa/can check the Perl class first, then the Strada hierarchy.
Limitations
- Without libffi, a function call is limited to 4 arguments (calls with more
croak). Build with libffi (see Prerequisites) for unlimited arguments. - Argument conversion is by value: mutations a Strada function makes to an array/hash argument are not reflected back in the Perl data structure.
- The deep array/hash converter does not detect reference cycles; converting a self-referential Perl (or Strada) structure will recurse without bound.
- Typed numeric widths (
int8,uint64,float, …) round-trip as Perl IV/NV; the specific C width is not preserved across the boundary. - A blessed Perl object other than a
Strada::Objectis converted as a plain hash — its Perl class is not carried into Strada. - The Strada runtime is single-threaded; do not call into Strada concurrently from multiple Perl threads.
Example Directory
The example/ subdirectory contains:
math_lib.strada- Example Strada library sourcebuild.sh- Script to compile the example library- The compiled
libmath.soafter running build.sh
API Reference
Low-Level Functions
Strada::load($path)
Load a Strada shared library. Returns a handle (integer) on success, 0 on failure.
Strada::unload($handle)
Unload a previously loaded library.
Strada::get_func($handle, $name)
Get a function pointer by name. Returns the pointer on success, 0 if not found.
Strada::call($func, @args)
Call a Strada function. With libffi, any number of arguments is supported;
without it, 0-4 arguments (more will croak). Returns the result converted to Perl.
Strada::get_export_info($handle)
Get the raw export metadata string from a Strada library. Returns empty string for non-Strada libraries.
Strada::get_version($handle)
Get the version string from a Strada library. Returns empty string if not available.
High-Level OO Interface
Strada::Library->new($path)
Create a Library object, loading the specified shared library. Dies on failure.
$lib->call($func_name, @args)
Call a function by name with arguments. Supports both package_func and package::func naming styles. Caches function pointers for efficiency.
$lib->version()
Returns the library version string, or empty string if not set.
$lib->functions()
Returns a hash reference describing all exported functions:
{
'math_lib_add' => {
return => 'int',
param_count => 2,
params => ['int', 'int'],
},
...
}
$lib->describe()
Returns a formatted string describing all functions (similar to strada-soinfo output):
# Strada Library: ./math_lib.so
# Version: 1.0.0
# Functions: 3
#
# func math_lib_add(int $a, int $b) int
# func math_lib_greet(str $a) str
# func math_lib_sum_array(scalar $a) int
$lib->unload()
Unload the library and clear cached function pointers.
See Also
- Strada Website - Official Strada language website
- Cannoli - Preforking web server and framework for Strada
lib/perl5/- The reverse integration (calling Perl from Strada)docs/LANGUAGE_GUIDE.md- Strada language documentationdocs/RUNTIME_API.md- Strada runtime API referencestrada-soinfo- Command-line tool to inspect Strada shared libraries