3 # The MIT License (MIT)
5 # Copyright (c) 2015 Martin Preisler
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included in all
15 # copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 # The mingw path matches where Fedora 21 installs mingw32
32 default_path_prefixes = [
33 "", "/usr/bin", "/usr/i686-w64-mingw32/sys-root/mingw/bin", "/mingw64/bin",
36 # This blacklist may need extending
38 "advapi32.dll", "kernel32.dll", "msvcrt.dll", "ole32.dll", "user32.dll",
39 "ws2_32.dll", "comdlg32.dll", "gdi32.dll", "imm32.dll", "oleaut32.dll",
40 "shell32.dll", "winmm.dll", "winspool.drv", "wldap32.dll",
41 "ntdll.dll", "d3d9.dll", "mpr.dll", "crypt32.dll", "dnsapi.dll",
42 "shlwapi.dll", "version.dll", "iphlpapi.dll",
46 def find_full_path(filename, path_prefixes):
49 for path_prefix in path_prefixes:
50 path_candidate = os.path.join(path_prefix, filename)
52 if os.path.exists(path_candidate):
58 "Can't find " + filename + ". If it is an inbuilt Windows DLL, "
59 "please add it to the blacklist variable in the script and send "
66 def gather_deps(path, path_prefixes, seen):
68 output = subprocess.check_output(["objdump", "-p", path]).decode('utf-8').split("\n")
70 if not line.startswith("\tDLL Name: "):
73 dep = line.split("DLL Name: ")[1].strip()
82 dep_path = find_full_path(dep, path_prefixes)
84 subdeps = gather_deps(dep_path, path_prefixes, seen)
91 parser = argparse.ArgumentParser()
95 help="EXE or DLL file that you need to bundle dependencies for"
100 help="In addition to printing out the dependencies, also copy them next to the exe_file"
105 help="Only valid if --copy is provided. Run UPX on all the DLLs and EXE."
107 args = parser.parse_args()
109 if args.upx and not args.copy:
110 raise RuntimeError("Can't run UPX if --copy hasn't been provided.")
114 for exe in args.exe_file:
115 all_deps.extend(set(gather_deps(exe, default_path_prefixes, seen)))
116 for exe in args.exe_file:
119 print("\n".join(all_deps))
122 print("Copying enabled, will now copy all dependencies next to the exe_file.\n")
124 parent_dir = os.path.dirname(os.path.abspath(args.exe_file))
127 target = os.path.join(parent_dir, os.path.basename(dep))
128 print("Copying '%s' to '%s'" % (dep, target))
129 shutil.copy(dep, parent_dir)
132 subprocess.call(["upx", target])
135 if __name__ == "__main__":