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
- gcc (or a recent clang). Perla calls the C compiler to produce the final binary.
- MySQL client headers (
libmysqlclient-devon Debian/Ubuntu) if you'll use the DBI bridge. - zlib and OpenSSL if you'll compile programs that do compression or TLS.
- A real perl binary on
$PATHhelps — Perla probesperl -Vfor@INCfallback. SetPERLA_PERL=/path/to/perlif it's not on PATH.
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:
| Flag | Compile time (gcc phase) | Runtime perf |
|---|---|---|
-O0 (default) | Fast (~15s) | Slower |
-O2 | ~100s | Fast |
-O3 | ~100s | Fastest (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.