Warning, /pim/trojita/packaging/mingw-bundledlls is written in an unsupported language. File is not indexed.

0001 #!/usr/bin/python3
0002 
0003 # The MIT License (MIT)
0004 #
0005 # Copyright (c) 2015 Martin Preisler
0006 #
0007 # Permission is hereby granted, free of charge, to any person obtaining a copy
0008 # of this software and associated documentation files (the "Software"), to deal
0009 # in the Software without restriction, including without limitation the rights
0010 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0011 # copies of the Software, and to permit persons to whom the Software is
0012 # furnished to do so, subject to the following conditions:
0013 #
0014 # The above copyright notice and this permission notice shall be included in all
0015 # copies or substantial portions of the Software.
0016 #
0017 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0018 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0019 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0020 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0021 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0022 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0023 # SOFTWARE.
0024 
0025 
0026 import subprocess
0027 import os.path
0028 import argparse
0029 import shutil
0030 
0031 # The mingw path matches where Fedora 21 installs mingw32
0032 default_path_prefixes = [
0033     "", "/usr/bin", "/usr/i686-w64-mingw32/sys-root/mingw/bin", "/mingw64/bin",
0034 ]
0035 
0036 # This blacklist may need extending
0037 blacklist = [
0038     "advapi32.dll", "kernel32.dll", "msvcrt.dll", "ole32.dll", "user32.dll",
0039     "ws2_32.dll", "comdlg32.dll", "gdi32.dll", "imm32.dll", "oleaut32.dll",
0040     "shell32.dll", "winmm.dll", "winspool.drv", "wldap32.dll",
0041     "ntdll.dll", "d3d9.dll", "mpr.dll", "crypt32.dll", "dnsapi.dll",
0042     "shlwapi.dll", "version.dll", "iphlpapi.dll",
0043 ]
0044 
0045 
0046 def find_full_path(filename, path_prefixes):
0047     path = None
0048 
0049     for path_prefix in path_prefixes:
0050         path_candidate = os.path.join(path_prefix, filename)
0051 
0052         if os.path.exists(path_candidate):
0053             path = path_candidate
0054             break
0055 
0056     if path is None:
0057         raise RuntimeError(
0058             "Can't find " + filename + ". If it is an inbuilt Windows DLL, "
0059             "please add it to the blacklist variable in the script and send "
0060             "a pull request!"
0061         )
0062 
0063     return path
0064 
0065 
0066 def gather_deps(path, path_prefixes, seen):
0067     ret = [path]
0068     output = subprocess.check_output(["objdump", "-p", path]).decode('utf-8').split("\n")
0069     for line in output:
0070         if not line.startswith("\tDLL Name: "):
0071             continue
0072 
0073         dep = line.split("DLL Name: ")[1].strip()
0074         ldep = dep.lower()
0075 
0076         if ldep in blacklist:
0077             continue
0078 
0079         if ldep in seen:
0080             continue
0081 
0082         dep_path = find_full_path(dep, path_prefixes)
0083         seen.extend([ldep])
0084         subdeps = gather_deps(dep_path, path_prefixes, seen)
0085         ret.extend(subdeps)
0086 
0087     return ret
0088 
0089 
0090 def main():
0091     parser = argparse.ArgumentParser()
0092     parser.add_argument(
0093         "exe_file",
0094         nargs='+',
0095         help="EXE or DLL file that you need to bundle dependencies for"
0096     )
0097     parser.add_argument(
0098         "--copy",
0099         action="store_true",
0100         help="In addition to printing out the dependencies, also copy them next to the exe_file"
0101     )
0102     parser.add_argument(
0103         "--upx",
0104         action="store_true",
0105         help="Only valid if --copy is provided. Run UPX on all the DLLs and EXE."
0106     )
0107     args = parser.parse_args()
0108 
0109     if args.upx and not args.copy:
0110         raise RuntimeError("Can't run UPX if --copy hasn't been provided.")
0111 
0112     seen = []
0113     all_deps = []
0114     for exe in args.exe_file:
0115         all_deps.extend(set(gather_deps(exe, default_path_prefixes, seen)))
0116     for exe in args.exe_file:
0117         all_deps.remove(exe)
0118 
0119     print("\n".join(all_deps))
0120 
0121     if args.copy:
0122         print("Copying enabled, will now copy all dependencies next to the exe_file.\n")
0123 
0124         parent_dir = os.path.dirname(os.path.abspath(args.exe_file))
0125 
0126         for dep in all_deps:
0127             target = os.path.join(parent_dir, os.path.basename(dep))
0128             print("Copying '%s' to '%s'" % (dep, target))
0129             shutil.copy(dep, parent_dir)
0130 
0131             if args.upx:
0132                 subprocess.call(["upx", target])
0133 
0134 
0135 if __name__ == "__main__":
0136     main()