PyInstaller OS 库依赖和 Chroot

PyInstaller OS Library Dependencies and Chroot

PyInstaller documentation 声明

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.

但是目标环境可能安装了同一组库的不同版本。有没有办法找出 pyisntaller 生成的二进制文件所依赖的所有 OS 库?

我使用 pyisntaller 创建了一个二进制文件 my_app/myapp。然后用ldd列出它所依赖的所有.so文件,全部复制到分发目录下。在我的假设中,生成的 dist 目录可以用作 chroot 环境的根目录。但是它不起作用。

来自 ldd 输出:

# 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)

看起来只有这些库是必需的依赖项:

# 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

当我运行chroot ./ /lib/ld-2.27.so /my_app/my_app时,屏幕显示

[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

最后一行应该是 [99] PyInstaller Bootloader 3.x,程序应该从那里继续。

我知道 chroot 会起作用,因为它会在复制整个 / 时起作用。

错误消息 Failed to exec: No such file or directory 是由于 ld 必须位于路径 /lib64/ld-linux-x86-64.so.2。尽管它指向的实际文件确实是 ld-2.27.so:

ls -l /lib64/
/lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.27.so

修复后,一条新的错误消息更有意义,指向缺失的 libpthread...

深入了解 PyInstaller 内部,它至少打包了三个其他二进制可执行文件:一个 python 解释器和两个用于引导加载程序的二进制文件。因此,PyInstaller 使用的 python 上的 运行 ldd,以及在站点包目录下找到的那两个引导加载程序,将是所需的所有依赖项。 python解释器需要上面的libpthread...

并且 ldd 输出显示它希望库文件位于 /lib/x86_64-linux-gnu/ 而不是 /lib/ 下。

lib/lib64/的最终内容是:

# 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

这似乎运作良好。

此目录可能 运行 在内核的裸机之上,而不包括 rootfs 中的其他用户 space 应用程序。它变得非常有趣。