💾 Archived View for ajdiaz.me › doc › 2015 › 09101-python-binaries.txt captured on 2022-06-04 at 00:44:35.

View Raw

More Information

-=-=-=-=-=-=-

A procedure to package python applications as static-linked binaries.
http://ajdiaz.me/doc/2015/09101-python-binaries.txt
Version: 2015-09-10


One of the major problems with python applications is that they required
to install the entire python virtual machine and core library to run. This
is not a problem in most cases, but sometimes could be annoying, specially
in machines with few resources.

This paper explorer the idea to create a binary, statically linked, which
can run a python application.

The main idea behind this approach is based in two well-known behaviour of
python and ZIP format. Almost since python2, the virtual machine has the
ability to run a ZIP file as any other module, if `__main__.py` file exists
inside. On the other hand, ZIP files allow some garbage before the ZIP
header, and in that case, the parser must ignore that garbage. So, using
this two behaviours, we can create a zip file with our application (let's
call app.zip), and then create a macro binary in the form:

cat /usr/bin/python app.zip > myexe

And run ./myexe myexe. That's fine, but is far away that we want. But, it's
easy to recompile python statically (some minor patch needs to be apply),
and modify `main()` function to execute PyInit over the argv[0], that is,
interpreting the self binary as application.

Doing this modifications, whe can create new executable:

cat ./static-python app.zip > myexe

In that case when we run `myexe`, probably we got a number of errors,
because the core library is not included, but is easy to solve, adding the
core library to the zipfile.

This approach has some advantages in comparisson with others. The first one
is that we do not need to change the normal behaviour of python virtual
machine (except to compile it statically), the second one is that any other
data file required by the app could be added to the app.zip package.

The big problem is that some modules wants to open files relatively to the
module python file (i.e. open from __file__ path), which cannot work since
the path is now the binary file. In this case we need to perform some kind
of monkey patching to subsitute the open call to a pkgresource call and read
the file using the proper function.