Guide

Hello World [Perl]

Introduction

The Perl binding calls the prebuilt libazul native library through FFI::Platypus 2.x — no XS or native compile step. Idiomatic wrappers live under Azul::<Type>; the raw C-ABI surface is under Azul::FFI::*. Callbacks route through libazul's host-invoker plumbing so FFI::Platypus never has to synthesize a struct-by-value trampoline.

Installation

You need Perl 5.30+ and FFI::Platypus 2.x, plus the native libazul library. On macOS use Homebrew Perl (system Perl can't write to its site_perl):

cpanm FFI::Platypus
cp /path/to/target/release/libazul.dylib examples/perl/

Running

The loader finds the library via AZ_LIB_DIR (or the directory holding Azul.pm):

cd examples/perl
AZ_LIB_DIR=. perl -Ilib hello-world.pl

The program

examples/perl/hello-world.pl builds a counter: a 32px label showing the count and an „Increase counter“ button that bumps it.

use FindBin qw($Bin);
use lib "$Bin/lib";
use Azul;
use FFI::Platypus::Buffer qw(scalar_to_buffer);

my $model = { counter => 5 };            # any Perl ref works as the data model

my $on_click = sub {
    my ($data, $info) = @_;
    my $m = Azul::refany_get($data);
    return Azul::AzUpdate::DoNothing() unless defined $m;
    $m->{counter}++;
    return Azul::AzUpdate::RefreshDom();
};

my $layout = sub {
    my ($data, $info) = @_;
    my $m = Azul::refany_get($data);
    my $body = Azul::FFI::AzDom_createBody();
    return $body unless defined $m;
    # ... build div{font-size:32px} > text(counter) + Button ...
    return $body;                         # returns a raw AzDom record
};

How callbacks work

  • Azul::refany_create($value) wraps a Perl value in an AzRefAny (an opaque host handle); Azul::refany_get($data) recovers it inside a callback. Pass the same model to the app and to the button so both see the same counter.
  • Azul::register_callback('<Kind>', $sub) returns the matching Az<Kind> record. The generated invoker fires $sub and writes its return value back through the callback out-pointer for you — a layout callback just returns a Dom, an on-click callback returns an AzUpdate.
  • The LayoutCallback is installed into window_state.layout_callback before App::run.

Build the DOM with the raw Azul::FFI::AzDom_* / Azul::FFI::AzButton_* calls (as the example does): these are the exact by-value struct calls the host-invoker thunks expect, and the raw records carry no destructor, so the moved-out structs are never double-freed.

Status

The full counter demo passes the headless E2E (scripts/e2e_language_matrix.sh perl✓ WORKS, counter 5 → 6 → 8). See examples/perl/README.md for the internals (sticky-closure trampolines, real-size return writeback, sentinel-probed layout-callback splice) and the one remaining codegen limitation (over-sized Perl tagged-union records).