From 9f2fd4ecc55dfcd1ec7da09b02e12846aefe2c5b Mon Sep 17 00:00:00 2001 From: Puneet Kaushik Date: Fri, 5 Jul 2019 14:56:48 -0700 Subject: [PATCH] getdeps: Add subclass to copy dependencies for PE executables on Windows Summary: This adds a subclass to copy the dynamic dependencies on Windows. Reviewed By: wez Differential Revision: D16110433 fbshipit-source-id: 14d876947f3ec504382fef0d459367a7119ff6cb --- build/fbcode_builder/getdeps/dyndeps.py | 84 ++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/build/fbcode_builder/getdeps/dyndeps.py b/build/fbcode_builder/getdeps/dyndeps.py index 9cd113eb1..d300ddaeb 100644 --- a/build/fbcode_builder/getdeps/dyndeps.py +++ b/build/fbcode_builder/getdeps/dyndeps.py @@ -8,6 +8,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals +import glob import os import re import shutil @@ -94,7 +95,7 @@ class DepBase(object): return dep d = os.path.basename(dep) for inst_dir in self.install_dirs: - for libdir in ["lib", "lib64"]: + for libdir in ["bin", "lib", "lib64"]: candidate = os.path.join(inst_dir, libdir, d) if os.path.exists(candidate): return candidate @@ -112,6 +113,85 @@ class DepBase(object): return True +class WinDeps(DepBase): + def __init__(self, buildopts, install_dirs): + super(WinDeps, self).__init__(buildopts, install_dirs) + self.dumpbin = self.find_dumpbin() + + def find_dumpbin(self): + # Looking for dumpbin in the following hardcoded paths. + # The registry option to find the install dir doesn't work anymore. + globs = [ + ( + "C:/Program Files (x86)/" + "Microsoft Visual Studio/" + "*/BuildTools/VC/Tools/" + "MSVC/*/bin/Hostx64/x64/dumpbin.exe" + ), + ( + "C:/Program Files (x86)/" + "Microsoft Visual Studio/" + "*/Community/VC/Tools/" + "MSVC/*/bin/Hostx64/x64/dumpbin.exe" + ), + ( + "C:/Program Files (x86)/" + "Common Files/" + "Microsoft/Visual C++ for Python/*/" + "VC/bin/dumpbin.exe" + ), + ("c:/Program Files (x86)/Microsoft Visual Studio */VC/bin/dumpbin.exe"), + ] + for pattern in globs: + for exe in glob.glob(pattern): + return exe + + raise RuntimeError("could not find dumpbin.exe") + + def list_dynamic_deps(self, exe): + deps = [] + print("Resolve deps for %s" % exe) + output = subprocess.check_output( + [self.dumpbin, "/nologo", "/dependents", exe] + ).decode("utf-8") + + lines = output.split("\n") + for line in lines: + m = re.match("\\s+(\\S+.dll)", line, re.IGNORECASE) + if m: + deps.append(m.group(1).lower()) + + return deps + + def rewrite_dep(self, objfile, depname, old_dep, new_dep): + # We can't rewrite on windows, but we will + # place the deps alongside the exe so that + # they end up in the search path + pass + + # These are the Windows system dll, which we don't want to copy while + # packaging. + SYSTEM_DLLS = set( # noqa: C405 + [ + "advapi32.dll", + "dbghelp.dll", + "kernel32.dll", + "msvcp140.dll", + "vcruntime140.dll", + "ws2_32.dll", + "ntdll.dll", + "shlwapi.dll", + ] + ) + + def interesting_dep(self, d): + if "api-ms-win-crt" in d: + return False + if d in self.SYSTEM_DLLS: + return False + return True + + class ElfDeps(DepBase): def __init__(self, buildopts, install_dirs): super(ElfDeps, self).__init__(buildopts, install_dirs) @@ -199,4 +279,4 @@ def create_dyn_dep_munger(buildopts, install_dirs): if buildopts.is_darwin(): return MachDeps(buildopts, install_dirs) if buildopts.is_windows(): - return DepBase(buildopts, install_dirs) + return WinDeps(buildopts, install_dirs)