NAME
Perl::Dist::APPerl - Actually Portable Perl
DESCRIPTION
Actually Portable Perl (APPerl) is a distribution of Perl the runs on several x86_64 operating systems via the same binary. It builds to a single binary with perl modules packed inside of it.
Cross-platform, single binary, standalone Perl applications can be made by building custom versions of APPerl, with and without compiling Perl from scratch, so it can be used an alternative to PAR::Packer. APPerl could also easily be added to development SDKs, carried on your USB drive, or just allow you to run the exact same perl on all your PCs multiple computers.
This package documentation covers the apperlm tool for building APPerl, APPerl usage, and how to create applications with APPerl. To handle the chicken-and egg-situation of needing Perl to build APPerl, APPerl may be bootstrapped from an existing build of APPerl. See README.md for instructions.
Information on the creation of APPerl can be found in this blog post: https://computoid.com/posts/Perl-is-Actually-Portable.html.
SYNOPSIS
apperlm install-build-deps
apperlm-list
apperlm configure
apperlm build
./perl.com /zip/bin/perldoc Perl::Dist::APPerl
cp perl.com perl
./perl --assimilate
ln -s perl perldoc
./perldoc perlcosmo
To build small APPerl from scratch:
apperlm install-build-deps
apperlm checkout small
apperlm configure
apperlm build
To start an APPerl project from an existing APPerl and build it:
mkdir src
mv perl.com src/
apperlm init --name your_config_name --base nobuild-v0.1.0
apperlm build
To start an APPerl project and build from scratch:
apperlm install-build-deps
apperlm init --name your_config_name --base v5.36.0-small-v0.1.0
apperlm configure
apperlm build
apperlm
The apperlm
(APPerl Manager) script is a CLI interface to configuring and building APPerl.
COMMAND REFERENCE
apperlm install-build-deps
installs APPerl build dependencies, currently, a fork of the perl5 source and the Cosmopolitan Libc. This is only necessary if you are building APPerl from scratch (not using a nobuild configuration). Initialization of the repos can be skipped by passing the path to them locally. The cosmopolitan repo initialization can be skipped with -c <path_to_repo> . The perl5 repo initialization can be skipped with -p <path_to_repo>. This install is done user specific, installs to $XDG_CONFIG_HOME/apperl .apperlm init
creates an APPerl project,apperl-project.json
. The project default configuration may to specified with -n <name>. If the configuration does not exist, a new configuration will be created, and then the base of the configuration may be specified with -b <base_config_name>. The default configuration is then checked out.apperlm list
lists the available APPerl configs. If a current config is set it is denoted with a*
. Project configs are labeled PROJECT. The exact configuration of a STABLE config may change from release to release of Perl::Dist::APPerl, but only non-breaking changes should occur. ROLLING configurations are always the latest STABLE configurations, but breaking changes may occur from release to release of Perl::Dist::APPerl.apperlm checkout
sets the current APPerl config, this includes amake veryclean
in the Perl repo andgit checkout
in both Perl and cosmo repos. The current config name is written to.apperl/user-project.json
.apperlm new-config
creates a new config and adds to to the project config. -n specifies the name of the new config and must be provided. -b specifies the base of the new config.apperlm configure
builds cosmopolitan for the current APPerl config and runs Perl'sConfigure
apperlm build
make
s perl and builds apperl. The output binary by default is copied toperl.com
in the current directory, set dest inapperl-project.json
to customize output binary path and name.
USAGE
APPerl doesn't need to be installed, the output perl.com
binary can be copied between computers and ran without installation. However, in certain cases such as magic (modifying $0, etc.) The binary must be assimilated for it to work properly. Note, you likely want to copy before this operation as it modifies the binary in-place to be bound to the current environment. cp perl.com perl ./perl --assimilate
For the most part, APPerl works like normal perl, however it has a couple additional features.
/zip/
filesystem - The APPerl binary is also a ZIP file. Paths starting with/zip/
refer to files compressed in the binary itself. At runtime the zip filesystem is readonly, but additional modules and scripts can be added just by adding them to the zip file. For example, perldoc and the other standard scripts are shipped inside of /zip/bin./perl.com /zip/bin/perldoc perlcosmo
argv[0]
script execution - this allows making single binary perl applications! APPerl built with the APPerl additions (found in cosmo-apperl branches) attempts to load the argv[0] basename without extension from /zip/binln -s perl.com perldoc.com ./perldoc.com perlcosmo
CREATING APPLICATIONS WITH APPERL
RATONALE
APPerl wasn't developed to be the 'hack of the day', but provide real world utility by easing using Perl in user environments.
Unfortunately, scripting languages are often a second class citizen on user environments due to them not being installed by default or only broken/old/incomplete versions installed, and sometimes not being the easiest to install. Providing native perl binaries with solutions like PAR::Packer is possible, but that requires juggling binaries for every desired target and packing.
The idea of APPerl applications is that you can handcraft the desired Perl environment with your application and then ship it as one portable binary for all targets.
Building an APPerl application does nothing to ofuscate or hide your source code, it is a feature that APPerl binaries are also zip files, allowing for easy retrieval of Perl scripts and modules.
BUILDING AN APPLICATION FROM EXISTING APPERL
The easiest way to build an APPerl application is to build it from existing APPerl. If your application doesn't depend on non-standard C or XS extensions, it can be built from one of the official APPerl builds, skipping the need for building Perl from scratch.
Enter your projects directory, create it if it doesn't exists. Download or copy in an existing version of APPerl you wish to build off of. Official builds are available on the APPerl web page: https://computoid.com/APPerl/. Create a new nobuild APPerl project and build it.
cd projectdir
mkdir src
cp ./perl.com src/
apperlm init --name my_nobuild_config
apperlm build
Now you should have a newly built perl.com inside the current directory. However, this isn't very exciting as it's identical to the one you copied into src. Let's create a script.
printf "%s\n" \
'#!/usr/bin/perl' \
'use strict; use warnings;' \
'print "Hello, World!\n";' > src/hello
To add it open apperl-project.json and add the following to my_nobuild_config:
"zip_extra_files" : { "bin" : ["src/hello"] }
Rebuild and try loading the newly added script
apperlm build
./perl.com /zip/bin/hello
You have embedded a script inside APPerl, however running it is a little awkward. What if you could run it by the name of the script?
ln -s perl.com hello
./hello
More details on the argv[0] script execution is in "USAGE". Now, what about Perl modules? Perl modules can be packed in the same way, but to ease setting the correct directory to packing them into, the magic prefix __perllib__ can be used in the destination. Note, you may have to add items to the MANIFEST key if the MANIFEST isn't set permissively already.
"zip_extra_files" : { "__perllib__/Your" : ["Module.pm"] }
BUILDING AN APPLICATION FROM SCRATCH
If your application requires non-standard C or XS extensions, APPerl must be built from scratch as it does not support dynamic libraries, only static linking. This tutorial assumes you already have an APPerl project, possibly from following the "BUILDING AN APPLICATION FROM EXISTING APPERL" tutorial.
First install the APPerl build dependencies and create a new config based on the current small config, checkout, configure, and build.
apperlm install-build-deps
apperlm new-config --name my_src_build_config --base v5.36.0-small-v0.1.0
apperlm checkout my_src_build_config
apperlm configure
apperlm build
If all goes well you should have compiled APPerl from source!
./perl-small.com -V
stat perl-small.com
Now let's create a very basic C extension.
mkdir MyCExtension
printf "%s\n" \
"package MyCExtension;" \
"use strict; use warnings;" \
"our \$VERSION = '0.0';" \
"require XSLoader;" \
'XSLoader::load("MyCExtension", $VERSION);' \
"1;" > MyCExtension/MyCExtension.pm
printf "%s\n" \
'#define PERL_NO_GET_CONTEXT' \
'#include "EXTERN.h"' \
'#include "perl.h"' \
'#include "XSUB.h"' \
'#include <stdio.h>' \
'' \
'MODULE = MyCExtension PACKAGE = MyCExtension' \
'' \
'void' \
'helloworld()' \
' CODE:' \
' printf("Hello, World!\n");' > MyCExtension/MyCExtension.xs
Add it to my_src_build_config in apperl-project.json . Keys that begin with '+' will be merged with the non-plus variant of the parent config. Keys the begin with '-' will be removed from the non-minus variant of the parent config.
"perl_repo_files" : { "ext" : [
"MyCExtension"
]},
"+MANIFEST" : ["__perlarchlib__/MyCExtension.pm"],
"+perl_onlyextensions" : ["MyCExtension"]
Build it and try it out. apperlm checkout is needed as Perl must be rebuilt from scratch as the Configure flags changed and new files were added to the perl5 repo.
apperlm checkout my_src_build_config
apperlm configure
apperlm build
./perl-small.com -MMyCExtension -e 'MyCExtension::helloworld();'
Now for completeness sake, let's turn this custom build of APPerl into an application that calls the extension function we just added. First make the application main script.
printf "%s\n" \
'#!/usr/bin/perl' \
'use strict; use warnings;' \
'use MyCExtension;' \
'MyCExtension::helloworld();' > helloext
Then, add it the project config and set the dest binary name to match the script so that it will launch the script.
"dest" : "helloext.com",
"+MANIFEST" : ["__perlarchlib__/MyCExtension.pm", "bin/helloext"],
"zip_extra_files" : { "bin" : ["helloext"] }
Build and test it.
apperlm build
./helloext.com
SUPPORT AND DOCUMENTATION
APPerl web page: https://computoid.com/APPerl/
Support and bug reports can be found at the repository https://github.com/G4Vi/Perl-Dist-APPerl
ACKNOWLEDGEMENTS
The Cosmopolitan Libc (https://github.com/jart/cosmopolitan) contributors, especially Justine Tunney (https://justine.lol/) and Gautham Venkatasubramanian (https://ahgamut.github.io). APPerl wouldn't be possible without Actually Portable Executables and polyfills of several Linux and POSIX APIs for other platforms. Gautham's Python port (https://ahgamut.github.io/2021/07/13/ape-python/) inspired this project.
AUTHOR
Gavin Hayes, <gahayes at cpan.org>
LICENSE AND COPYRIGHT
This software is copyright (c) 2022 by Gavin Hayes.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.