forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			153 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
	
		
			5.1 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("\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("\[(.*)\]", 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("^@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).  Same thing with d3dcompiler_47.dll, but
 | 
						|
                # to a lesser extent, and we were going to dynamically load it
 | 
						|
                # anyway.
 | 
						|
                if not dep.startswith(("icu", "d3dcompiler_47")):
 | 
						|
                    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()
 |