The PyInstaller documentation states
PyInstaller does not include libraries that should exist in any installation of this OS. For example in GNU/Linux, it does not bundle any file from /lib or /usr/lib, assuming these will be found in every system.
However the target environment may have installed a different version of the same set of libraries. Is there a way to find out all the OS libraries a pyisntaller generated binary depends on?
I created a binary my_app/myapp
using pyisntaller. Then used ldd
to list all the .so
files it depends on, and copied all of them into the distribution directory. In my assumption, the resulting dist directory can be used as a root for a chroot environment. However it does not work.
From the ldd
output:
# ldd my_app/my_app
linux-vdso.so.1 (0x00007ffdddc67000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f6d3342f000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f6d33212000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6d32e21000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6d3384e000)
It looks only these libraries are required dependents:
# ls -l lib
-rwxr-xr-x 1 root root 170960 Apr 16 2018 ld-2.27.so
-rwxr-xr-x 1 root root 2030544 Apr 16 2018 libc-2.27.so
lrwxrwxrwx 1 root root 12 Apr 16 2018 libc.so.6 -> libc-2.27.so
-rw-r--r-- 1 root root 14560 Apr 16 2018 libdl-2.27.so
lrwxrwxrwx 1 root root 13 Apr 16 2018 libdl.so.2 -> libdl-2.27.so
lrwxrwxrwx 1 root root 14 May 23 2017 libz.so.1 -> libz.so.1.2.11
-rw-r--r-- 1 root root 116960 May 23 2017 libz.so.1.2.11
When I run chroot ./ /lib/ld-2.27.so /my_app/my_app
, the screen shows
[26499] PyInstaller Bootloader 3.x
[26499] LOADER: Cannot get fullpath for /my_app/my_app
[26499] LOADER: homepath is /my_app
[26499] LOADER: _MEIPASS2 is NULL
[26499] LOADER: archivename is /my_app/my_app
[26499] LOADER: Extracting binaries
[26499] LOADER: Executing self as child
[26499] LOADER: set _MEIPASS2 to /my_app
[26499] LOADER: LD_LIBRARY_PATH=/my_app
[26499] LOADER: Registering signal handlers
[26500] Failed to exec: No such file or directory
Where the last line should be [99] PyInstaller Bootloader 3.x
and from there the program should continue.
I know chroot would work because it does when the whole /
is copied.
The error message Failed to exec: No such file or directory
was due to the ld has to be at the path /lib64/ld-linux-x86-64.so.2
. Despite the actual file it points to is really ld-2.27.so
:
ls -l /lib64/
/lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.27.so
Once that is fixed, a new error message makes more sense, pointing to a missing libpthread...
.
Looked deeper into the PyInstaller internal, it packaged at least three other binary executables inside: A python interpreter, and two binaries for a bootloader. Thus run ldd
on the python which the PyInstaller uses, and on those two bootloaders found under the site packages directory, it will be all the dependencies required. The above libpthread...
is required by the python interpreter.
And the ldd
output shows it wants the library files to be under /lib/x86_64-linux-gnu/
instead of /lib/
.
The final content of lib/
and lib64/
are:
# ls -l lib
-rwxr-xr-x 170960 Apr 16 2018 ld-2.27.so
-rwxr-xr-x 2030544 Apr 16 2018 libc-2.27.so
lrwxrwxrwx 12 Apr 16 2018 libc.so.6 -> libc-2.27.so
-rw-r--r-- 14560 Apr 16 2018 libdl-2.27.so
lrwxrwxrwx 13 Apr 16 2018 libdl.so.2 -> libdl-2.27.so
lrwxrwxrwx 17 Sep 10 11:05 libexpat.so.1 -> libexpat.so.1.6.7
-rw-r--r-- 202880 Sep 10 11:05 libexpat.so.1.6.7
-rw-r--r-- 1700792 Apr 16 2018 libm-2.27.so
lrwxrwxrwx 12 Apr 16 2018 libm.so.6 -> libm-2.27.so
-rwxr-xr-x 144976 Apr 16 2018 libpthread-2.27.so
lrwxrwxrwx 18 Apr 16 2018 libpthread.so.0 -> libpthread-2.27.so
-rw-r--r-- 10592 Apr 16 2018 libutil-2.27.so
lrwxrwxrwx 15 Apr 16 2018 libutil.so.1 -> libutil-2.27.so
lrwxrwxrwx 14 May 23 2017 libz.so.1 -> libz.so.1.2.11
-rw-r--r-- 116960 May 23 2017 libz.so.1.2.11
lrwxrwxrwx 1 Feb 27 17:14 x86_64-linux-gnu -> .
# ls -l lib64
lrwxrwxrwx 32 Apr 16 2018 ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.27.so
This seems to have been working well.
This directory potentially can run on top of the bare metal of a kernel, without including other user space applications in the rootfs. It's becoming very interesting.