包装ldd *nix实用工具,以确定程序所需的共享库。
项目描述
pylddwrap
Pylddwrap将ldd *nix实用工具包装起来,以确定程序所需的共享库。
我们需要在部署时动态打包我们系统的一部分子集。因此,我们必须以编程方式确定我们的二进制文件对共享库的依赖性。
ldd Linux命令的输出虽然提供了信息,但结构不足,难以轻松集成到程序中。在撰写本文时,我们在互联网上只找到了两个替代ldd包装器 python-ldd 和 ldd.py,但它们的输出要么对我们用例来说过于简单,要么项目仍然处于初期阶段。
与Pylddwrap相比,它返回一个结构良好的依赖项列表。命令行工具将依赖项输出为表格(用于视觉检查)或JSON格式的字符串(用于与其他工具配合使用)。包含的Python模块lddwrap返回一个带有类型注解的Python对象,以便可以方便地由部署脚本和其他模块使用。
有关ldd工具的更多信息,请参阅ldd手册。
用法
命令行工具pylddwrap
假设我们需要/bin/ls的依赖项。以下命令将它们作为表格输出
pylddwrap /bin/ls
命令的输出如下所示
soname | path | found | mem_address | unused
----------------+---------------------------------------+-------+--------------------+-------
linux-vdso.so.1 | None | True | 0x00007ffd8750f000 | False
libselinux.so.1 | /lib/x86_64-linux-gnu/libselinux.so.1 | True | 0x00007f4e73dc3000 | True
libc.so.6 | /lib/x86_64-linux-gnu/libc.so.6 | True | 0x00007f4e739f9000 | False
libpcre.so.3 | /lib/x86_64-linux-gnu/libpcre.so.3 | True | 0x00007f4e73789000 | False
libdl.so.2 | /lib/x86_64-linux-gnu/libdl.so.2 | True | 0x00007f4e73585000 | False
None | /lib64/ld-linux-x86-64.so.2 | True | 0x00007f4e73fe5000 | False
libpthread.so.0 | /lib/x86_64-linux-gnu/libpthread.so.0 | True | 0x00007f4e73368000 | False
要以JSON格式获取依赖项,请调用
pylddwrap --format json /bin/ls
JSON输出结构如下所示
[
{
"soname": "linux-vdso.so.1",
"path": "None",
"found": true,
"mem_address": "0x00007ffed857f000",
"unused": false
},
...
]
您还可以使用--sorted对表格进行排序,这将按soname排序
pylddwrap /bin/pwd --sorted
Pylddwrap按soname排序表格
soname | path | found | mem_address | unused
----------------+---------------------------------+-------+--------------------+-------
None | /lib64/ld-linux-x86-64.so.2 | True | 0x00007fd54894d000 | False
libc.so.6 | /lib/x86_64-linux-gnu/libc.so.6 | True | 0x00007fd548353000 | False
linux-vdso.so.1 | None | True | 0x00007ffe0953f000 | False
或者,您也可以按其他列排序。例如,要按path排序
pylddwrap /bin/pwd --sorted path
输出将如下所示
soname | path | found | mem_address | unused
----------------+---------------------------------+-------+--------------------+-------
linux-vdso.so.1 | None | True | 0x00007ffe0953f000 | False
libc.so.6 | /lib/x86_64-linux-gnu/libc.so.6 | True | 0x00007fd548353000 | False
None | /lib64/ld-linux-x86-64.so.2 | True | 0x00007fd54894d000 | False
ldwrap Python模块
我们提供了lddwrap Python模块,您可以将其集成到您的部署脚本和其他模块中。
以下示例显示了如何列出/bin/ls的依赖项
import pathlib
import lddwrap
path = pathlib.Path("/bin/ls")
deps = lddwrap.list_dependencies(path=path)
for dep in deps:
print(dep)
"""
soname: linux-vdso.so.1, path: None, found: True, mem_address: (0x00007ffe8e2fb000), unused: None
soname: libselinux.so.1, path: /lib/x86_64-linux-gnu/libselinux.so.1, found: True, mem_address: (0x00007f7759ccc000), unused: None
soname: libc.so.6, path: /lib/x86_64-linux-gnu/libc.so.6, found: True, mem_address: (0x00007f7759902000), unused: None
...
"""
列出/bin/ls实用程序的依赖项,并检查直接依赖项是否使用。如果将list_dependencies设置为False,则不会确定未使用的依赖项变量,因此它们是未知的,并设置为None。否则,将检索直接使用的信息并将其添加到依赖项中。
import pathlib
import lddwrap
path = pathlib.Path("/bin/ls")
deps = lddwrap.list_dependencies(path=path, unused=True)
print(deps[1])
# soname: libselinux.so.1,
# path: /lib/x86_64-linux-gnu/libselinux.so.1,
# found: True,
# mem_address: (0x00007f5a6064a000),
# unused: True
Lddwrap使用调用者的环境变量正常工作。在您的依赖项与当前环境不同的情况下,您将作为参数传递一个单独的环境(字典形式)
import os
import pathlib
import lddwrap
env = os.environ.copy()
env['LD_LIBRARY_PATH'] = "some/important/path"
path = pathlib.Path("/bin/ls")
deps = lddwrap.list_dependencies(path=path, env=env)
安装
使用pip安装pylddwrap
pip3 install pylddwrap
开发
查看仓库。
在仓库根目录下创建虚拟环境
python3 -m venv venv3
激活虚拟环境
source venv3/bin/activate
安装开发依赖项
pip3 install -e .[dev]
可以直接使用unittest运行测试
python3 -m unittest discover tests/
预提交检查
我们提供了一系列预提交检查,用于检查代码格式。
具体来说,我们使用
yapf检查格式。
使用pydocstyle检查文档字符串的样式。
使用mypy进行静态类型分析。
使用pylint进行各种检查。
运行format环境以应用自动格式化
tox -e format
使用tox运行预提交检查和测试
tox
版本控制
我们遵循语义版本控制。版本X.Y.Z表示
X是主要版本(向后不兼容),
Y是次要版本(向后兼容),
Z是补丁版本(向后兼容的bug修复)。