Install

Perla ships with the Strada repo. Clone, build Strada, then build Perla:

$ git clone https://github.com/strada-lang/strada-lang
$ cd strada
$ make
$ make -C perla

You should now have ./perla/perla. Either add that directory to your PATH or call it with a full path.

Prerequisites

Quick sanity check:

$ ./perla/perla -e 'print "hello from perla\n"'
hello from perla

If that works, you're done installing.

Your first program

Create a file hello.pl:

# hello.pl
use strict;
use warnings;

sub fib {
    my $n = shift;
    return $n if $n < 2;
    return fib($n - 1) + fib($n - 2);
}

for my $i (0..10) {
    print "fib($i) = ", fib($i), "\n";
}

Compile and run

$ ./perla/perla hello.pl
fib(0) = 0
fib(1) = 1
fib(2) = 1
...
fib(10) = 55

Default ./perla foo.pl compiles and runs, cleaning up the binary after. To keep the executable:

$ ./perla/perla -o hello hello.pl
$ ./hello
$ file hello
hello: ELF 64-bit LSB pie executable, x86-64, statically linked

One file. No perl required on the target. Ship it.

Optimization levels

Default is -O0 — fast compile, slow binary. For release, use -O2 or -O3:

$ ./perla/perla -O2 -o app app.pl          # -O2 + -flto
$ ./perla/perla -O3 -o app app.pl          # adds -march=native

For a typical web-app-size program the difference is:

FlagCompile time (gcc phase)Runtime perf
-O0 (default)Fast (~15s)Slower
-O2~100sFast
-O3~100sFastest (native CPU)

When you have modules

Perla handles use Module::Name the way you'd expect — the module's source is found on the search path and included. The search path is built from the input file's directory, ., $PERL5LIB, and any use lib "..." statements.

$ mkdir -p lib/My
$ cat > lib/My/Greeter.pm <<'EOF'
package My::Greeter;
use strict;
sub hello { return "Hello, $_[0]!"; }
1;
EOF
$ cat > greet.pl <<'EOF'
use lib 'lib';
use My::Greeter;
print My::Greeter::hello("Perla"), "\n";
EOF
$ ./perla/perla greet.pl
Hello, Perla!

Precompile for faster iteration

When your module tree gets large, compiling the script repeatedly means re-parsing every .pm every time. Precompile them once:

$ ./perla/perla -M lib/My/Greeter.pm
Compiled lib/My/Greeter.pm.o (module: My::Greeter, init: perla_mod_init_My_Greeter)

$ ./perla/perla greet.pl          # now uses cached .pm.o
Hello, Perla!

Or precompile a whole directory recursively:

$ ./perla/perla -M lib/
[perla] precompiling 42 .pm files under lib/
[perla] [1/42] ok lib/My/Greeter.pm
...
[perla] precompile done: 42 built, 0 skipped, 0 failed

It's idempotent — already-built modules are skipped on re-runs. Force a rebuild with --force-rebuild.

Make targets for larger projects: if you're shipping something huge, add these to your Makefile:

PERLA ?= /path/to/perla

precompile:
	$(PERLA) -M lib/

precompile-force:
	$(PERLA) --force-rebuild -M lib/

precompile-clean:
	find lib -type f \( -name '*.pm.o' -o -name '*.pm.so' -o -name '*.pm.deps' \) -delete

Debugging what Perla is doing

The --debug flag prints every compile-time decision (module search, cache hits, auto-builds) plus the exact gcc invocation:

$ ./perla/perla --debug -o app app.pl 2>&1 | head -20
[perla] debug mode enabled
[perla] cc: gcc
[perla] compile-time lib paths (5):
[perla]   [0] .
[perla]   [1] /opt/bzperl/lib/site_perl/5.42.0
...
[perla] use Carp
[perla]   Carp: cache HIT /opt/bzperl/.../Carp.pm [.pm.o (static)]
[perla] use File::Spec
[perla]   File::Spec: cache MISS /opt/bzperl/.../File/Spec.pm — auto-building via perla -M
...
[cc] gcc -O0 -w -o app app.c /opt/bzperl/.../Carp.pm.o ... 2>&1
[cc] done in 16.03s (ok)

Use this when a use resolves to an unexpected file, when you want to see what the compiler spawned, or when compile time is surprising.

--keep to inspect the generated C

If something compiles but behaves weirdly, keep the intermediate .c:

$ ./perla/perla --keep -o app app.pl
[perla] kept C file: app.c
$ grep 'perla_sub_main_' app.c    # see what each sub compiled to

Dropping into C

For FFI or performance-critical sections, Perla supports __C__ blocks:

use strict;

# file-scope __C__: #includes, statics
__C__ {
    #include <sys/time.h>
}

sub ms_now {
    my $ms = 0;
    __C__ {
        /* Perl $foo → C var v_foo. Block is emitted verbatim. */
        struct timeval tv;
        gettimeofday(&tv, NULL);
        strada_decref(v_ms);
        v_ms = strada_new_int((int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000);
    }
    return $ms;
}

print "now: ", ms_now(), "ms\n";

See the full __C__ guide for the variable-name mapping, runtime helpers you can call, and memory rules.

Running under Cannoli (web apps)

Compile your Perl app as a .pm.so and serve it via Cannoli's preforking HTTP server:

$ ./perla/perla -M MyApp.pm
Compiled MyApp.pm.so (module: MyApp, init: perla_mod_init_MyApp)

$ cannoli --library "./cannoli_perla.so:\
    so=$(pwd)/MyApp.pm.so;\
    init=perla_mod_init_MyApp;\
    handler=perla_sub_MyApp_handle" --dev -p 8080

The cannoli_perla.so bridge is under cannoli/lib/perla/ in the Cannoli repo.

Where to next

Full Documentation →

Compile flags, optimization, module cache, __C__ reference, module search paths, common failure modes.

Porting from Perl →

Converting Perl scripts to Strada source directly (alternative path — for when you want to embrace Strada's type annotations).

Cannoli Web Server →

The preforking web server Perla-compiled handlers plug into.

Source on GitHub →

Browse the Perla compiler, runtime, and test suite.