1#!/usr/bin/env python 2# 3# Copyright 2013 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Writes dependency ordered list of native libraries. 8 9The list excludes any Android system libraries, as those are not bundled with 10the APK. 11 12This list of libraries is used for several steps of building an APK. 13In the component build, the --input-libraries only needs to be the top-level 14library (i.e. libcontent_shell_content_view). This will then use readelf to 15inspect the shared libraries and determine the full list of (non-system) 16libraries that should be included in the APK. 17""" 18 19# TODO(cjhopman): See if we can expose the list of library dependencies from 20# gyp, rather than calculating it ourselves. 21# http://crbug.com/225558 22 23import optparse 24import os 25import re 26import sys 27 28from util import build_utils 29 30_readelf = None 31_library_dirs = None 32 33_library_re = re.compile( 34 '.*NEEDED.*Shared library: \[(?P<library_name>[\w/.]+)\]') 35 36 37def SetReadelfPath(path): 38 global _readelf 39 _readelf = path 40 41 42def SetLibraryDirs(dirs): 43 global _library_dirs 44 _library_dirs = dirs 45 46 47def FullLibraryPath(library_name): 48 assert _library_dirs is not None 49 for directory in _library_dirs: 50 path = '%s/%s' % (directory, library_name) 51 if os.path.exists(path): 52 return path 53 return library_name 54 55 56def IsSystemLibrary(library_name): 57 # If the library doesn't exist in the libraries directory, assume that it is 58 # an Android system library. 59 return not os.path.exists(FullLibraryPath(library_name)) 60 61 62def CallReadElf(library_or_executable): 63 assert _readelf is not None 64 readelf_cmd = [_readelf, 65 '-d', 66 FullLibraryPath(library_or_executable)] 67 return build_utils.CheckOutput(readelf_cmd) 68 69 70def GetDependencies(library_or_executable): 71 elf = CallReadElf(library_or_executable) 72 return set(_library_re.findall(elf)) 73 74 75def GetNonSystemDependencies(library_name): 76 all_deps = GetDependencies(FullLibraryPath(library_name)) 77 return set((lib for lib in all_deps if not IsSystemLibrary(lib))) 78 79 80def GetSortedTransitiveDependencies(libraries): 81 """Returns all transitive library dependencies in dependency order.""" 82 return build_utils.GetSortedTransitiveDependencies( 83 libraries, GetNonSystemDependencies) 84 85 86def GetSortedTransitiveDependenciesForBinaries(binaries): 87 if binaries[0].endswith('.so'): 88 libraries = [os.path.basename(lib) for lib in binaries] 89 else: 90 assert len(binaries) == 1 91 all_deps = GetDependencies(binaries[0]) 92 libraries = [lib for lib in all_deps if not IsSystemLibrary(lib)] 93 94 return GetSortedTransitiveDependencies(libraries) 95 96 97def main(): 98 parser = optparse.OptionParser() 99 build_utils.AddDepfileOption(parser) 100 101 parser.add_option('--input-libraries', 102 help='A list of top-level input libraries.') 103 parser.add_option('--libraries-dir', 104 help='The directory which contains shared libraries.') 105 parser.add_option('--readelf', help='Path to the readelf binary.') 106 parser.add_option('--output', help='Path to the generated .json file.') 107 parser.add_option('--stamp', help='Path to touch on success.') 108 109 options, _ = parser.parse_args() 110 111 SetReadelfPath(options.readelf) 112 SetLibraryDirs(options.libraries_dir.split(',')) 113 114 libraries = build_utils.ParseGypList(options.input_libraries) 115 if len(libraries): 116 libraries = GetSortedTransitiveDependenciesForBinaries(libraries) 117 118 # Convert to "base" library names: e.g. libfoo.so -> foo 119 java_libraries_list = ( 120 '{%s}' % ','.join(['"%s"' % s[3:-3] for s in libraries])) 121 122 build_utils.WriteJson( 123 {'libraries': libraries, 'java_libraries_list': java_libraries_list}, 124 options.output, 125 only_if_changed=True) 126 127 if options.stamp: 128 build_utils.Touch(options.stamp) 129 130 if options.depfile: 131 print libraries 132 build_utils.WriteDepfile( 133 options.depfile, 134 libraries + build_utils.GetPythonDependencies()) 135 136 137if __name__ == '__main__': 138 sys.exit(main()) 139 140 141