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 应用程序。它变得非常有趣。
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 应用程序。它变得非常有趣。