App-Staticperl

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

       staticperl mkperl <bundle-args...>   # see documentation
       staticperl mkapp appname <bundle-args...> # see documentation

    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

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 uClibc and 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 <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:

    *   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 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, staticperl can strip perl sources much more effectively
        than PAR.

    *   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).

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

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

    *   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 staticperl, the burden is mostly with the developer - only
        direct compile-time dependencies and 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.

    *   PAR works out of the box, staticperl does not.

        Maintaining your own custom perl build can be a pain in the ass, and
        while 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,
        staticperl does work out of the box, as they don't count "fiddling
        with module use lists" against it, but nevertheless, staticperl is
        certainly a bit more difficult to use.

HOW DOES IT WORK?
    Simple: staticperl downloads, compile and installs a perl version of
    your choice in ~/.staticperl. You can add extra modules either by
    letting 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.

THE STATICPERL SCRIPT
    This module installs a script called 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 "App::Staticperl" distribution tarball as
    bin/staticperl, without any installation. The newest (possibly alpha)
    version can also be downloaded from
    <http://staticperl.schmorp.de/staticperl>.

    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.

  PHASE 1 COMMANDS: INSTALLING PERL
    The most important command is install, which does basically everything.
    The default is to download and install perl 5.12.3 and a few modules

README  view on Meta::CPAN


               # shell command
               staticperl mkbundle -MConfig_heavy.pl

               # bundle specification file
               use Config_heavy.pl

            The "-M"module syntax is included as a convenience that might be
            easier to remember than "--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.

        "--eval" "perl code" | "-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 "--eval" to
            execute some perl snippet or set some variables or whatever you
            need. All files "require"'d or "use"'d while executing the
            snippet are included in the final bundle.

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

            Example: force 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 "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

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

        "--incglob" pattern
            This goes through all standard library directories and tries to
            match any .pm and .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. 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'

        "--add" file | "--add" "file alias"
            Adds the given (perl) file into the bundle (and optionally call
            it "alias"). The 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 @INC searches, otherwise
            the path file will be used as the internal name.

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

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

               staticperl mkperl --add "httpd httpd.pm"

               # can be accessed via "use httpd"

            Example: add a file 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";

        "--addbin" file | "--addbin" "file alias"
            Just like "--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 "/" prefix to
            avoid clashing with embedded perl files (whose paths never start
            with "/"), and/or use a special directory prefix, such as
            "/res/name".

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

            An alternative way to embed binary files is to convert them to
            perl and use "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

README  view on Meta::CPAN


    !   All files that typically cannot be loaded from memory (such as
        dynamic objects or shared libraries), but have to reside in the
        filesystem, are prefixed with !. Typically these files get written
        out to some (semi-)temporary directory shortly after program
        startup, or before being used.

    !boot
        The bootstrap file, if specified during bundling.

    !auto/
        Shared objects or dlls corresponding to dynamically-linked perl
        extensions are stored with an !auto/ prefix.

    !lib/
        External shared libraries are stored in this directory.

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

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

   FUNCTIONS
    $file = static::find $path
        Returns the data associated with the given $path (e.g.
        "Digest/MD5.pm", "auto/POSIX/autosplit.ix").

        Returns "undef" if the file isn't embedded.

    @paths = static::list
        Returns the list of all paths embedded in this binary.

  EXTRA FEATURES
    In addition, for the embedded loading of perl files to work, staticperl
    overrides the @INC array.

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
    (<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.

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.

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

           -Mutf8_heavy.pl

        Many Unicode properties in turn are defined in separate modules,
        such as "unicore/Heavy.pl" and more specific data tables such as
        "unicore/To/Digit.pl" or "unicore/lib/Perl/Word.pl". These tables
        are big (7MB uncompressed, although 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'

    AnyEvent
        AnyEvent needs a backend implementation that it will load in a
        delayed fashion. The 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. EV (POE...), then you need to
        include the AnyEvent::Impl::EV (AnyEvent::Impl::POE...) backend as
        well.

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

        Or you can use "--usepacklists" and specify "-MAnyEvent" to include
        everything.

    Cairo
        See Glib, same problem, same solution.

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

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

    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. staticperl tries to work around this by forcing
        "MAN1PODS" and "MAN3PODS" to be empty via the "PERL_MM_OPT"
        environment variable.

    Gtk2
        See Pango, same problems, same solution.

    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 "postinstall" hook which
        patches Net::SSLeay after installation, which happens to work most
        of the time:

           postinstall() {
              # first install it
              instcpan Net::SSLeay
              # then add -ldl for future linking
              chmod u+w "$PERL_PREFIX"/lib/auto/Net/SSLeay/extralibs.ld
              echo " -ldl" >>"$PERL_PREFIX"/lib/auto/Net/SSLeay/extralibs.ld



( run in 2.416 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )