forked from mirrors/gecko-dev
		
	 8335566fdb
			
		
	
	
		8335566fdb
		
	
	
	
	
		
			
			Update dependentlibs.py to account for the earlier change in bug 1770484 that replaced use of @executable_path with @rpath. Differential Revision: https://phabricator.services.mozilla.com/D200497
		
			
				
	
	
		
			151 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # This Source Code Form is subject to the terms of the Mozilla Public
 | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
| 
 | |
| """Given a library, dependentlibs.py prints the list of libraries it depends
 | |
| upon that are in the same directory, followed by the library itself.
 | |
| """
 | |
| 
 | |
| import os
 | |
| import re
 | |
| import subprocess
 | |
| import sys
 | |
| import mozpack.path as mozpath
 | |
| from collections import OrderedDict
 | |
| from mozpack.executables import (
 | |
|     get_type,
 | |
|     ELF,
 | |
|     MACHO,
 | |
| )
 | |
| from buildconfig import substs
 | |
| 
 | |
| 
 | |
| def dependentlibs_win32_objdump(lib):
 | |
|     proc = subprocess.Popen(
 | |
|         [substs["LLVM_OBJDUMP"], "--private-headers", lib],
 | |
|         stdout=subprocess.PIPE,
 | |
|         universal_newlines=True,
 | |
|     )
 | |
|     deps = []
 | |
|     for line in proc.stdout:
 | |
|         match = re.match(r"\s+DLL Name: (\S+)", line)
 | |
|         if match:
 | |
|             # The DLL Name found might be mixed-case or upper-case. When cross-compiling,
 | |
|             # the actual DLLs in dist/bin are all lowercase, whether they are produced
 | |
|             # by the build system or copied from WIN32_REDIST_DIR. By turning everything
 | |
|             # to lowercase, we ensure we always find the files.
 | |
|             # At runtime, when Firefox reads the dependentlibs.list file on Windows, the
 | |
|             # case doesn't matter.
 | |
|             deps.append(match.group(1).lower())
 | |
|     proc.wait()
 | |
|     return deps
 | |
| 
 | |
| 
 | |
| def dependentlibs_readelf(lib):
 | |
|     """Returns the list of dependencies declared in the given ELF .so"""
 | |
|     proc = subprocess.Popen(
 | |
|         [substs.get("READELF", "readelf"), "-d", lib],
 | |
|         stdout=subprocess.PIPE,
 | |
|         universal_newlines=True,
 | |
|     )
 | |
|     deps = []
 | |
|     for line in proc.stdout:
 | |
|         # Each line has the following format:
 | |
|         #  tag (TYPE)          value
 | |
|         # or with BSD readelf:
 | |
|         #  tag TYPE            value
 | |
|         # Looking for NEEDED type entries
 | |
|         tmp = line.strip().split(" ", 3)
 | |
|         if len(tmp) > 3 and "NEEDED" in tmp[1]:
 | |
|             # NEEDED lines look like:
 | |
|             # 0x00000001 (NEEDED)             Shared library: [libname]
 | |
|             # or with BSD readelf:
 | |
|             # 0x00000001 NEEDED               Shared library: [libname]
 | |
|             match = re.search(r"\[(.*)\]", tmp[3])
 | |
|             if match:
 | |
|                 deps.append(match.group(1))
 | |
|     proc.wait()
 | |
|     return deps
 | |
| 
 | |
| 
 | |
| def dependentlibs_mac_objdump(lib):
 | |
|     """Returns the list of dependencies declared in the given MACH-O dylib"""
 | |
|     proc = subprocess.Popen(
 | |
|         [substs["LLVM_OBJDUMP"], "--private-headers", lib],
 | |
|         stdout=subprocess.PIPE,
 | |
|         universal_newlines=True,
 | |
|     )
 | |
|     deps = []
 | |
|     cmd = None
 | |
|     for line in proc.stdout:
 | |
|         # llvm-objdump --private-headers output contains many different
 | |
|         # things. The interesting data
 | |
|         # is under "Load command n" sections, with the content:
 | |
|         #           cmd LC_LOAD_DYLIB
 | |
|         #       cmdsize 56
 | |
|         #          name libname (offset 24)
 | |
|         tmp = line.split()
 | |
|         if len(tmp) < 2:
 | |
|             continue
 | |
|         if tmp[0] == "cmd":
 | |
|             cmd = tmp[1]
 | |
|         elif cmd == "LC_LOAD_DYLIB" and tmp[0] == "name":
 | |
|             deps.append(re.sub("@(?:rpath|executable_path)/", "", tmp[1]))
 | |
|     proc.wait()
 | |
|     return deps
 | |
| 
 | |
| 
 | |
| def dependentlibs(lib, libpaths, func):
 | |
|     """For a given library, returns the list of recursive dependencies that can
 | |
|     be found in the given list of paths, followed by the library itself."""
 | |
|     assert libpaths
 | |
|     assert isinstance(libpaths, list)
 | |
|     deps = OrderedDict()
 | |
|     for dep in func(lib):
 | |
|         if dep in deps or os.path.isabs(dep):
 | |
|             continue
 | |
|         for dir in libpaths:
 | |
|             deppath = os.path.join(dir, dep)
 | |
|             if os.path.exists(deppath):
 | |
|                 deps.update(dependentlibs(deppath, libpaths, func))
 | |
|                 # Black list the ICU data DLL because preloading it at startup
 | |
|                 # leads to startup performance problems because of its excessive
 | |
|                 # size (around 10MB).
 | |
|                 if not dep.startswith(("icu")):
 | |
|                     deps[dep] = deppath
 | |
|                 break
 | |
| 
 | |
|     return deps
 | |
| 
 | |
| 
 | |
| def gen_list(output, lib):
 | |
|     libpaths = [os.path.join(substs["DIST"], "bin")]
 | |
|     binary_type = get_type(lib)
 | |
|     if binary_type == ELF:
 | |
|         func = dependentlibs_readelf
 | |
|     elif binary_type == MACHO:
 | |
|         func = dependentlibs_mac_objdump
 | |
|     else:
 | |
|         ext = os.path.splitext(lib)[1]
 | |
|         assert ext == ".dll"
 | |
|         func = dependentlibs_win32_objdump
 | |
| 
 | |
|     deps = dependentlibs(lib, libpaths, func)
 | |
|     base_lib = mozpath.basename(lib)
 | |
|     deps[base_lib] = mozpath.join(libpaths[0], base_lib)
 | |
|     output.write("\n".join(deps.keys()) + "\n")
 | |
| 
 | |
|     with open(output.name + ".gtest", "w") as gtest_out:
 | |
|         libs = list(deps.keys())
 | |
|         libs[-1] = "gtest/" + libs[-1]
 | |
|         gtest_out.write("\n".join(libs) + "\n")
 | |
| 
 | |
|     return set(deps.values())
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     gen_list(sys.stdout, sys.argv[1])
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |