当前位置: 首页 > news >正文

(17)python开发经验 --- Python查找dll exe依赖缺失

文章目录

    • @[toc]
    • 概述
    • 适用于windows
    • 适用于linux

更多精彩内容
👉内容导航 👈
👉Qt开发 👈
👉python开发 👈

概述

使用Python调用可执行程序或者dll动态库时如果依赖出现缺失则会导致调用失败;

在调用前可通过代码检查依赖是否完整,以确保成功调用,或者调用失败自动给出异常详细。

  • load_dll_with_dependency_check函数中尝试加载指定路径的 DLL 文件,并检查其依赖项是否缺失。
  • check_exe_missing_dependencies函数中检查指定 exe 文件的缺失依赖项。

适用于windows

在这里插入图片描述

  • pip install pefile
import ctypes
import pefile
import os
from functools import lru_cachedef is_dll_in_path(dll_name):"""检查系统 PATH 环境变量中是否存在指定名称的 DLL 文件。参数:dll_name (str): 要查找的 DLL 名称(不带路径)。返回:bool: 如果找到该 DLL 返回 True,否则返回 False。"""path_env = os.getenv("PATH")if not path_env:return False# 分割 PATH 为多个路径paths = path_env.split(os.pathsep)# 自动补全 .dll 后缀,避免用户遗漏if not dll_name.lower().endswith(".dll"):dll_name += ".dll"for path in paths:full_path = os.path.join(path, dll_name)if os.path.exists(full_path):return Truereturn False@lru_cache(maxsize=128) # 缓存最多 128 个 DLL 查找结果
def cached_is_dll_in_path(dll_name):"""缓存的结果,避免重复查找相同 DLL,提升性能。参数:dll_name (str): 要查找的 DLL 名称。返回:bool: 是否在系统 PATH 中找到该 DLL。"""return is_dll_in_path(dll_name)def scan_paths_for_dll(dll_name, paths):"""在指定路径列表中查找是否存在某个 DLL 文件。参数:dll_name (str): 要查找的 DLL 名称。paths (list): 包含路径的列表。返回:bool: 如果在任意路径中找到该 DLL 返回 True,否则返回 False。"""if not dll_name.lower().endswith(".dll"):dll_name += ".dll"for path in paths:full_path = os.path.join(path, dll_name)if os.path.exists(full_path):return Truereturn Falsedef get_missing_dependencies(dll_path, search_paths=None):"""解析 PE 文件(DLL 或 EXE),找出其依赖的其他 DLL,并检查这些依赖是否缺失。参数:dll_path (str): 目标 DLL 文件路径。search_paths (str or list): 附加的依赖查找路径。返回:list: 缺失的 DLL 名称列表。"""try:pe = pefile.PE(dll_path)except pefile.PEFormatError as e:raise ValueError(f"Invalid PE file format: {e}") from eexcept Exception as e:raise RuntimeError(f"Failed to parse PE file: {e}") from emissing = set()default_paths = ["."]  # 默认从当前目录查找依赖# 确保 search_paths 是列表形式if isinstance(search_paths, str):search_paths = [search_paths]elif search_paths is None:search_paths = []all_search_paths = default_paths + list(search_paths)# 检查是否有导入表(即依赖项)if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):for entry in pe.DIRECTORY_ENTRY_IMPORT:try:dll_name = entry.dll.decode('utf-8')except UnicodeDecodeError:continue  # 忽略无法解码的 DLL 名称# 统一大小写进行比较,增强兼容性normalized_name = os.path.normcase(dll_name)# 查找当前路径和指定路径中的 DLLif scan_paths_for_dll(normalized_name, all_search_paths) or cached_is_dll_in_path(normalized_name):continuemissing.add(dll_name)return list(missing)def load_dll_with_dependency_check(dll_path, search_paths=None):"""尝试加载指定路径的 DLL 文件,并检查其依赖项是否缺失。参数:dll_path (str): 要加载的 DLL 文件路径。search_paths (str or list): 可选,用于查找依赖 DLL 的额外搜索路径(可以是字符串或列表)。返回:bool: 加载成功返回 True,失败返回 False。"""if not os.path.exists(dll_path):print(f"❌ {dll_path} does not exist.")return Falsetry:# 使用 ctypes.CDLL 加载 DLL 文件ctypes.CDLL(dll_path)print(f"✅ Successfully loaded {dll_path}")return Trueexcept OSError as e:# 如果加载失败,捕获异常并输出错误信息print(f"❌ Failed to load {dll_path}: {e}")# 获取缺失的依赖项missing_deps = get_missing_dependencies(dll_path, search_paths)if missing_deps:print("Missing dependencies:")for dep in missing_deps:print(f" ❌ {dep}")else:print("No missing dependencies found. Possible reason: wrong architecture or runtime error.")return Falsedef check_exe_missing_dependencies(exe_path, search_paths=None):"""检查指定 exe 文件的缺失依赖项。参数:exe_path (str): 要检查的 exe 文件路径。search_paths (str or list): 可选,用于查找依赖 DLL 的额外搜索路径。"""if not os.path.exists(exe_path):print(f"❌ {exe_path} does not exist.")return# 获取缺失的依赖项missing_deps = get_missing_dependencies(exe_path, search_paths)print(missing_deps)if missing_deps:print(f"❌ Failed to load {exe_path}")print("Missing dependencies:")for dep in missing_deps:print(f" ❌ {dep}")# 示例调用
dll_path = 'E:/lib/libusb/VS2017/MS64/dll/libusb-1.0.dll'
load_dll_with_dependency_check(dll_path, "E:/lib/libusb/VS2017/MS64/dll")
check_exe_missing_dependencies("D:/Typora/Typora.exe", "D:/Typora/")

适用于linux

  • pip install pyelftools lief
import os
import subprocess
from functools import lru_cache
from elftools.elf.elffile import ELFFile
from elftools.elf.dynamic import DynamicSection
from elftools.common.exceptions import ELFError
import ctypes# 常量定义
LDCONFIG_PATH = "/sbin/ldconfig"
DEFAULT_CACHE_SIZE = 128def is_so_in_ldpath(so_name):"""检查系统 LD_LIBRARY_PATH 或 /etc/ld.so.cache 是否存在指定名称的 .so 文件。参数:so_name (str): 要查找的 .so 名称(不带路径)。返回:bool: 如果找到该 .so 返回 True,否则返回 False。"""if '.so' not in so_name:so_name += ".so"# 检查 LD_LIBRARY_PATHld_path = os.getenv("LD_LIBRARY_PATH", "")paths = ld_path.split(os.pathsep) if ld_path else []for path in paths:full_path = os.path.join(path, so_name)if os.path.exists(full_path):return True# 尝试用 `ldconfig -p` 查询全局缓存(更准确)try:output = subprocess.check_output([LDCONFIG_PATH, "-p"]).decode()return so_name in outputexcept Exception:passreturn False@lru_cache(maxsize=DEFAULT_CACHE_SIZE)
def cached_is_so_in_path(so_name):return is_so_in_ldpath(so_name)def scan_paths_for_so(so_name, paths):"""在指定路径列表中查找是否存在某个 .so 文件。参数:so_name (str): 要查找的 .so 名称。paths (list): 包含路径的列表。返回:bool: 如果在任意路径中找到该 .so 返回 True,否则返回 False。"""if not so_name.endswith(".so"):so_name += ".so"for path in paths:if not os.path.isdir(path):print(f"⚠️ Skipping invalid path: {path}")continuefull_path = os.path.join(path, so_name)if os.path.exists(full_path):return Truereturn Falsedef get_missing_dependencies_elf(elf_path, search_paths=None):"""解析 ELF 文件(.so 或可执行文件),找出其依赖的其他 .so,并检查是否缺失。参数:elf_path (str): 目标 ELF 文件路径。search_paths (str or list): 附加的依赖查找路径。返回:list: 缺失的 .so 名称列表。"""missing = set()# 统一 search_paths 为列表if isinstance(search_paths, str):search_paths = [search_paths]elif search_paths is None:search_paths = []all_search_paths = list(set(["."] + search_paths))try:with open(elf_path, "rb") as f:elf = ELFFile(f)# 遍历动态段查找 NEEDED 项for section in elf.iter_sections():if isinstance(section, DynamicSection):for tag in section.iter_tags():if tag.entry.d_tag == 'DT_NEEDED':so_name = tag.needed# 查找当前路径和指定路径中的 .soif scan_paths_for_so(so_name, all_search_paths) or cached_is_so_in_path(so_name):continuemissing.add(so_name)except ELFError as e:print(f"❌ Invalid ELF file: {e}")return []except Exception as e:print(f"❌ Unexpected error while parsing ELF: {e}")return []return list(missing)def load_so_with_dependency_check(so_path, search_paths=None):"""尝试加载指定路径的 .so 文件,并检查其依赖项是否缺失。参数:so_path (str): 要加载的 .so 文件路径。search_paths (str or list): 可选,用于查找依赖 .so 的额外搜索路径。返回:bool: 加载成功返回 True,失败返回 False。"""try:ctypes.CDLL(so_path)print(f"✅ Successfully loaded {so_path}")return Trueexcept OSError as e:print(f"❌ Failed to load {so_path}: {e}")missing_deps = get_missing_dependencies_elf(so_path, search_paths)if missing_deps:print("Missing dependencies:")for dep in missing_deps:print(f" ❌ {dep}")else:print("No missing dependencies found. Possible reason: wrong architecture or runtime error.")return Falseif __name__ == "__main__":so_path = 'Release/libburn.so'load_so_with_dependency_check(so_path, "Release")


http://www.dtcms.com/a/605841.html

相关文章:

  • (第五篇)Spring AI 基础入门之嵌入模型与向量基础:AI 理解世界的方式
  • 基于RTDS与DIgSILENT联合仿真的电力系统薄弱点识别及光伏控制策略优化
  • 在俄罗斯用钱让女性做h事情的网站wordpress post模板
  • 网站地区分站系统自助注册搭建网站
  • 自适应残差卷积网络 + 斑马优化:让图像更清晰的“智慧组合“
  • 图形化android可视化开机观测工具bootchart
  • 网站建设网站推广服务公司阿里云买域名
  • 时间复杂度(按增长速度从低到高排序)包括以下几类,用于描述算法执行时间随输入规模 n 增长的变化趋势:
  • 免费如何做网页或网站asp网站部署
  • 基于YOLO11-Hyper的油罐车类型识别与状态检测系统_1
  • 时间的幻觉:当你不在时,宇宙按下暂停键
  • AI入门知识之RAG技术树全景解析:从基础架构到智能演进的演进路径
  • 做网站的数据库万维设计
  • 马尾网站建设郑州网络推广哪家厉害
  • 【Java SE 基础学习打卡】13 Java 开发工具
  • 【文献阅读】网络复杂系统演化历史的重建
  • 编译型语言的两个步骤 | 了解编译与执行过程
  • 基于FP7153的超小封装5V/3A自行车车灯驱动方案
  • Rust入门:运算符和数据类型应用
  • 易语言DLL反编译 | 深入解析反编译技术与应用
  • 官方网站建设有限公司百度推广关键词排名在哪看
  • 有什么办法做自己的网站成都哪些地方好玩
  • 自适应导航网站模板电商网站建设技术员的工作职责
  • Prompts for Chat Models in LangChain
  • 【音视频】AI自适应均衡器的调节精度提升方法
  • vscode编译C语言 | 在VSCode中配置编译环境与常见问题解决
  • 「腾讯云NoSQL」技术之向量数据库篇:腾讯云向量数据库如何实现召回不变,成本减半?
  • Window系统,Unity编辑器中播放HEVC/H265编码的视频报错问题:WindowsVideoMedia error OxcOOdOO1a
  • 专业集团门户网站建设重庆网站备案必须到核验点
  • PotPlayer播放器下载安装教程 - 媒体观影神器