forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			4.3 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)
 | 
						|
    deps = []
 | 
						|
    for line in proc.stdout:
 | 
						|
        match = re.match('\s+DLL Name: (\S+)', line)
 | 
						|
        if match:
 | 
						|
            deps.append(match.group(1))
 | 
						|
    proc.wait()
 | 
						|
    return deps
 | 
						|
 | 
						|
def dependentlibs_readelf(lib):
 | 
						|
    '''Returns the list of dependencies declared in the given ELF .so'''
 | 
						|
    proc = subprocess.Popen([substs.get('TOOLCHAIN_PREFIX', '') + 'readelf', '-d', lib], stdout = subprocess.PIPE)
 | 
						|
    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.split(' ', 3)
 | 
						|
        if len(tmp) > 3 and 'NEEDED' in tmp[2]:
 | 
						|
            # 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)
 | 
						|
    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).
 | 
						|
                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 = 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()
 |