1# -*- coding: utf-8 -*- 2# Copyright 2016 Christoph Reiter 3# 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 2 of the License, or 7# (at your option) any later version. 8 9""" 10Deletes unneeded DLLs and checks DLL dependencies. 11Execute with the build python, will figure out the rest. 12""" 13 14import subprocess 15import os 16import sys 17 18import gi 19gi.require_version("GIRepository", "2.0") 20from gi.repository import GIRepository 21 22 23def get_required_by_typelibs(): 24 deps = set() 25 repo = GIRepository.Repository() 26 for tl in os.listdir(repo.get_search_path()[0]): 27 namespace, version = os.path.splitext(tl)[0].split("-", 1) 28 repo.require(namespace, version, 0) 29 lib = repo.get_shared_library(namespace) 30 if lib: 31 deps.update(lib.split(",")) 32 return deps 33 34 35EXTENSIONS = [".exe", ".pyd", ".dll"] 36SYSTEM_LIBS = ['advapi32.dll', 37 "cabinet.dll", "comctl32.dll", "comdlg32.dll", "crypt32.dll", "d3d9.dll", 38 "dnsapi.dll", "dsound.dll", "dwmapi.dll", "gdi32.dll", "imm32.dll", 39 "iphlpapi.dll", "kernel32.dll", "ksuser.dll", "msi.dll", "msimg32.dll", 40 "msvcr71.dll", "msvcr80.dll", "msvcrt.dll", "ole32.dll", "oleaut32.dll", 41 "opengl32.dll", "rpcrt4.dll", "setupapi.dll", "shell32.dll", "user32.dll", 42 "usp10.dll", "winmm.dll", "winspool.drv", "wldap32.dll", "ws2_32.dll", 43 "wsock32.dll", "shlwapi.dll" 44] 45 46 47def get_dependencies(filename): 48 deps = [] 49 try: 50 data = subprocess.getoutput("objdump -p %s" % filename) 51 except Exception as error: 52 print(error) 53 return deps 54 55 for line in data.splitlines(): 56 line = line.strip() 57 if line.startswith("DLL Name:"): 58 deps.append(line.split(":", 1)[-1].strip().lower()) 59 return deps 60 61 62def find_lib(root, name): 63 search_path = os.path.join(root, "bin") 64 if os.path.exists(os.path.join(search_path, name)): 65 return os.path.join(search_path, name) 66 elif name in SYSTEM_LIBS: 67 return name 68 69 70def get_things_to_delete(root): 71 all_libs = set() 72 needed = set() 73 for base, dirs, files in os.walk(root): 74 for f in files: 75 path = os.path.join(base, f) 76 if os.path.splitext(path)[-1].lower() in EXTENSIONS: 77 all_libs.add(f.lower()) 78 for lib in get_dependencies(path): 79 all_libs.add(lib) 80 needed.add(lib) 81 if not find_lib(root, lib): 82 print("MISSING:", path, lib) 83 84 for lib in get_required_by_typelibs(): 85 needed.add(lib) 86 if not find_lib(root, lib): 87 print("MISSING:", path, lib) 88 89 # get rid of things not in the search path, 90 # maybe loaded through other means? 91 not_needed = filter( 92 lambda l: find_lib(root, l) and \ 93 os.path.splitext(l)[-1].lower() != ".exe", all_libs - needed) 94 95 return [find_lib(root, l) for l in not_needed] 96 97 98def main(): 99 libs = get_things_to_delete(sys.prefix) 100 while libs: 101 for l in libs: 102 print("DELETE:", l) 103 os.unlink(l) 104 libs = get_things_to_delete(sys.prefix) 105 106 107if __name__ == "__main__": 108 main() 109