App-Staticperl

 view release on metacpan or  search on metacpan

staticperl.pod  view on Meta::CPAN


Typical Examples:

   staticperl install   # fetch, configure, build and install perl
   staticperl cpan      # run interactive cpan shell
   staticperl mkperl -MConfig_heavy.pl # build a perl that supports -V
   staticperl mkperl -MAnyEvent::Impl::Perl -MAnyEvent::HTTPD -MURI -MURI::http
                        # build a perl with the above modules linked in
   staticperl mkapp myapp --boot mainprog mymodules
                        # build a binary "myapp" from mainprog and mymodules

=head1 DESCRIPTION

This script helps you to create single-file perl interpreters
or applications, or embedding a perl interpreter in your
applications. Single-file means that it is fully self-contained - no
separate shared objects, no autoload fragments, no .pm or .pl files are
needed. And when linking statically, you can create (or embed) a single
file that contains perl interpreter, libc, all the modules you need, all
the libraries you need and of course your actual program.

With F<uClibc> and F<upx> on x86, you can create a single 500kb binary
that contains perl and 100 modules such as POSIX, AnyEvent, EV, IO::AIO,
Coro and so on. Or any other choice of modules (and some other size :).

To see how this turns out, you can try out smallperl and bigperl, two
pre-built static and compressed perl binaries with many and even more
modules: just follow the links at L<http://staticperl.schmorp.de/>.

The created files do not need write access to the file system (like PAR
does). In fact, since this script is in many ways similar to PAR::Packer,
here are the differences:

=over 4

=item * The generated executables are much smaller than PAR created ones.

Shared objects and the perl binary contain a lot of extra info, while
the static nature of F<staticperl> allows the linker to remove all
functionality and meta-info not required by the final executable. Even
extensions statically compiled into perl at build time will only be
present in the final executable when needed.

In addition, F<staticperl> can strip perl sources much more effectively
than PAR.

=item * The generated executables start much faster.

There is no need to unpack files, or even to parse Zip archives (which is
slow and memory-consuming business).

=item * The generated executables don't need a writable filesystem.

F<staticperl> loads all required files directly from memory. There is no
need to unpack files into a temporary directory.

=item * More control over included files, more burden.

PAR tries to be maintenance and hassle-free - it tries to include more
files than necessary to make sure everything works out of the box. It
mostly succeeds at this, but he extra files (such as the unicode database)
can take substantial amounts of memory and file size.

With F<staticperl>, the burden is mostly with the developer - only direct
compile-time dependencies and L<AutoLoader> are handled automatically.
This means the modules to include often need to be tweaked manually.

All this does not preclude more permissive modes to be implemented in
the future, but right now, you have to resolve hidden dependencies
manually.

=item * PAR works out of the box, F<staticperl> does not.

Maintaining your own custom perl build can be a pain in the ass, and while
F<staticperl> tries to make this easy, it still requires a custom perl
build and possibly fiddling with some modules. PAR is likely to produce
results faster.

Ok, PAR never has worked for me out of the box, and for some people,
F<staticperl> does work out of the box, as they don't count "fiddling with
module use lists" against it, but nevertheless, F<staticperl> is certainly
a bit more difficult to use.

=back

=head1 HOW DOES IT WORK?

Simple: F<staticperl> downloads, compile and installs a perl version of
your choice in F<~/.staticperl>. You can add extra modules either by
letting F<staticperl> install them for you automatically, or by using CPAN
and doing it interactively. This usually takes 5-10 minutes, depending on
the speed of your computer and your internet connection.

It is possible to do program development at this stage, too.

Afterwards, you create a list of files and modules you want to include,
and then either build a new perl binary (that acts just like a normal perl
except everything is compiled in), or you create bundle files (basically C
sources you can use to embed all files into your project).

This step is very fast (a few seconds if PPI is not used for stripping, or
the stripped files are in the cache), and can be tweaked and repeated as
often as necessary.

=head1 THE F<STATICPERL> SCRIPT

This module installs a script called F<staticperl> into your perl
binary directory. The script is fully self-contained, and can be
used without perl (for example, in an uClibc chroot environment). In
fact, it can be extracted from the C<App::Staticperl> distribution
tarball as F<bin/staticperl>, without any installation. The
newest (possibly alpha) version can also be downloaded from
L<http://staticperl.schmorp.de/staticperl>.

F<staticperl> interprets the first argument as a command to execute,
optionally followed by any parameters.

There are two command categories: the "phase 1" commands which deal with
installing perl and perl modules, and the "phase 2" commands, which deal
with creating binaries and bundle files.

staticperl.pod  view on Meta::CPAN

glory (F<Config.pm> is included automatically by the dependency tracker).

   # shell command
   staticperl mkbundle -MConfig_heavy.pl

   # bundle specification file
   use Config_heavy.pl

The C<-M>module syntax is included as a convenience that might be easier
to remember than C<--use> - it's the same switch as perl itself uses
to load modules. Or maybe it confuses people. Time will tell. Or maybe
not. Sigh.

=item C<--eval> "perl code" | C<-e> "perl code"

Sometimes it is easier (or necessary) to specify dependencies using perl
code, or maybe one of the modules you use need a special use statement. In
that case, you can use C<--eval> to execute some perl snippet or set some
variables or whatever you need. All files C<require>'d or C<use>'d while
executing the snippet are included in the final bundle.

Keep in mind that F<mkbundle> will not import any symbols from the modules
named by the C<--use> option, so do not expect the symbols from modules
you C<--use>'d earlier on the command line to be available.

Example: force L<AnyEvent> to detect a backend and therefore include it
in the final bundle.

   staticperl mkbundle --eval 'use AnyEvent; AnyEvent::detect'

   # or like this
   staticperl mkbundle -MAnyEvent --eval 'AnyEvent::detect'

Example: use a separate "bootstrap" script that C<use>'s lots of modules
and also include this in the final bundle, to be executed automatically
when the interpreter is initialised.

   staticperl mkbundle --eval 'do "bootstrap"' --boot bootstrap

=item C<--boot> F<filename>

Include the given file in the bundle and arrange for it to be
executed (using C<require>) before the main program when the new perl
is initialised. This can be used to modify C<@INC> or do similar
modifications before the perl interpreter executes scripts given on the
command line (or via C<-e>). This works even in an embedded interpreter -
the file will be executed during interpreter initialisation in that case.

=item C<--incglob> pattern

This goes through all standard library directories and tries to match any
F<.pm> and F<.pl> files against the extended glob pattern (see below). If
a file matches, it is added. The pattern is matched against the full path
of the file (sans the library directory prefix), e.g. F<Sys/Syslog.pm>.

This is very useful to include "everything":

   --incglob '*'

It is also useful for including perl libraries, or trees of those, such as
the unicode database files needed by some perl built-ins, the regex engine
and other modules.

   --incglob '/unicore/**.pl'

=item C<--add> F<file> | C<--add> "F<file> alias"

Adds the given (perl) file into the bundle (and optionally call it
"alias"). The F<file> is either an absolute path or a path relative to the
current directory. If an alias is specified, then this is the name it will
use for C<@INC> searches, otherwise the path F<file> will be used as the
internal name.

This switch is used to include extra files into the bundle.

Example: embed the file F<httpd> in the current directory as F<httpd.pm>
when creating the bundle.

   staticperl mkperl --add "httpd httpd.pm"

   # can be accessed via "use httpd"

Example: add a file F<initcode> from the current directory.

   staticperl mkperl --add 'initcode &initcode'

   # can be accessed via "do '&initcode'"

Example: add local files as extra modules in the bundle.

   # specification file
   add file1 myfiles/file1.pm
   add file2 myfiles/file2.pm
   add file3 myfiles/file3.pl

   # then later, in perl, use
   use myfiles::file1;
   require myfiles::file2;
   my $res = do "myfiles/file3.pl";

=item C<--addbin> F<file> | C<--addbin> "F<file> alias"

Just like C<--add>, except that it treats the file as binary and adds it
without any postprocessing (perl files might get stripped to reduce their
size).

If you specify an alias you should probably add a C</> prefix to avoid
clashing with embedded perl files (whose paths never start with C</>),
and/or use a special directory prefix, such as C</res/name>.

You can later get a copy of these files by calling C<static::find
"alias">.

An alternative way to embed binary files is to convert them to perl and
use C<do> to get the contents - this method is a bit cumbersome, but works
both inside and outside of a staticperl bundle, without extra ado:

   # a "binary" file, call it "bindata.pl"
   <<'SOME_MARKER'
   binary data NOT containing SOME_MARKER
   SOME_MARKER

staticperl.pod  view on Meta::CPAN

=item any letter

Any path starting with a letter is a perl library file. For example,
F<Coro/AIO.pm> corresponds to the file loaded by C<use Coro::AIO>, and
F<Coro/jit.pl> corresponds to C<require "Coro/jit.pl">. 

Obviously, module names shouldn't start with any other characters than
letters :)

=back

=head3 FUNCTIONS

=over 4

=item $file = static::find $path

Returns the data associated with the given C<$path>
(e.g. C<Digest/MD5.pm>, C<auto/POSIX/autosplit.ix>).

Returns C<undef> if the file isn't embedded.

=item @paths = static::list

Returns the list of all paths embedded in this binary.

=back

=head2 EXTRA FEATURES

In addition, for the embedded loading of perl files to work, F<staticperl>
overrides the C<@INC> array.

=head1 FULLY STATIC BINARIES - ALPINE LINUX

This section once contained a way to build fully static (including
uClibc) binaries with buildroot. Unfortunately, buildroot no longer
supports a compiler, so I recommend using alpine linux instead
(L<http://alpinelinux.org/>). Get yourself a VM (e.g. with qemu), run an
older alpine linux verison in it (e.g. 2.4), copy staticperl inside and
use it.

The reason you might want an older alpine linux is that uClibc can be
quite dependent on kernel versions, so the newest version of alpine linux
might need a newer kernel then you might want for, if you plan to run your
binaries on on other kernels.

=head1 RECIPES / SPECIFIC MODULES

This section contains some common(?) recipes and information about
problems with some common modules or perl constructs that require extra
files to be included.

=head2 MODULES

=over 4

=item utf8

Some functionality in the utf8 module, such as swash handling (used
for unicode character ranges in regexes) is implemented in the
C<"utf8_heavy.pl"> library:

   -Mutf8_heavy.pl

Many Unicode properties in turn are defined in separate modules,
such as C<"unicore/Heavy.pl"> and more specific data tables such as
C<"unicore/To/Digit.pl"> or C<"unicore/lib/Perl/Word.pl">. These tables
are big (7MB uncompressed, although F<staticperl> contains special
handling for those files), so including them only on demand in your
application might pay off.

To simply include the whole unicode database, use:

   --incglob '/unicore/**.pl'

=item AnyEvent

AnyEvent needs a backend implementation that it will load in a delayed
fashion. The L<AnyEvent::Impl::Perl> backend is the default choice
for AnyEvent if it can't find anything else, and is usually a safe
fallback. If you plan to use e.g. L<EV> (L<POE>...), then you need to
include the L<AnyEvent::Impl::EV> (L<AnyEvent::Impl::POE>...) backend as
well.

If you want to handle IRIs or IDNs (L<AnyEvent::Util> punycode and idn
functions), you also need to include C<"AnyEvent/Util/idna.pl"> and
C<"AnyEvent/Util/uts46data.pl">.

Or you can use C<--usepacklists> and specify C<-MAnyEvent> to include
everything.

=item Cairo

See Glib, same problem, same solution.

=item Carp

Carp had (in older versions of perl) a dependency on L<Carp::Heavy>. As of
perl 5.12.2 (maybe earlier), this dependency no longer exists.

=item Config

The F<perl -V> switch (as well as many modules) needs L<Config>, which in
turn might need L<"Config_heavy.pl">. Including the latter gives you
both.

=item Glib

Glib literally requires Glib to be installed already to build - it tries
to fake this by running Glib out of the build directory before being
built. F<staticperl> tries to work around this by forcing C<MAN1PODS> and
C<MAN3PODS> to be empty via the C<PERL_MM_OPT> environment variable.

=item Gtk2

See Pango, same problems, same solution.

=item Net::SSLeay

This module hasn't been significantly updated since OpenSSL is called
OpenSSL, and fails to properly link against dependent libraries, most
commonly, it forgets to specify -ldl when linking.

On GNU/Linux systems this usually goes undetected, as perl usually links
against -ldl itself and OpenSSL just happens to pick it up that way, by
chance.

For static builds, you either have to configure -ldl manually, or you
cna use the following snippet in your C<postinstall> hook which patches
Net::SSLeay after installation, which happens to work most of the time:

   postinstall() {



( run in 0.601 second using v1.01-cache-2.11-cpan-39bf76dae61 )