| OLD | NEW | 
| (Empty) |  | 
 |    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  | 
 |    9 The list excludes any Android system libraries, as those are not bundled with | 
 |   10 the APK. | 
 |   11  | 
 |   12 This list of libraries is used for several steps of building an APK. | 
 |   13 In the component build, the --input-libraries only needs to be the top-level | 
 |   14 library (i.e. libcontent_shell_content_view). This will then use readelf to | 
 |   15 inspect the shared libraries and determine the full list of (non-system) | 
 |   16 libraries 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  | 
 |   23 import json | 
 |   24 import optparse | 
 |   25 import os | 
 |   26 import re | 
 |   27 import sys | 
 |   28  | 
 |   29 BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') | 
 |   30 sys.path.append(BUILD_ANDROID_DIR) | 
 |   31  | 
 |   32 from pylib import build_utils | 
 |   33  | 
 |   34  | 
 |   35 _options = None | 
 |   36 _libraries_dir = None | 
 |   37 _library_re = re.compile( | 
 |   38     '.*NEEDED.*Shared library: \[(?P<library_name>[\w/.]+)\]') | 
 |   39  | 
 |   40  | 
 |   41 def FullLibraryPath(library_name): | 
 |   42   return '%s/%s' % (_libraries_dir, library_name) | 
 |   43  | 
 |   44  | 
 |   45 def IsSystemLibrary(library_name): | 
 |   46   # If the library doesn't exist in the libraries directory, assume that it is | 
 |   47   # an Android system library. | 
 |   48   return not os.path.exists(FullLibraryPath(library_name)) | 
 |   49  | 
 |   50  | 
 |   51 def CallReadElf(library_name): | 
 |   52   readelf_cmd = [_options.readelf, | 
 |   53                  '-d', | 
 |   54                  FullLibraryPath(library_name)] | 
 |   55   return build_utils.CheckCallDie(readelf_cmd) | 
 |   56  | 
 |   57  | 
 |   58 def GetDependencies(library_name): | 
 |   59   elf = CallReadElf(library_name) | 
 |   60   return set(_library_re.findall(elf)) | 
 |   61  | 
 |   62  | 
 |   63 def GetNonSystemDependencies(library_name): | 
 |   64   all_deps = GetDependencies(library_name) | 
 |   65   return set((lib for lib in all_deps if not IsSystemLibrary(lib))) | 
 |   66  | 
 |   67  | 
 |   68 def GetSortedTransitiveDependencies(libraries): | 
 |   69   """Returns all transitive library dependencies in dependency order.""" | 
 |   70   def GraphNode(library): | 
 |   71     return (library, GetNonSystemDependencies(library)) | 
 |   72  | 
 |   73   # First: find all library dependencies. | 
 |   74   unchecked_deps = libraries | 
 |   75   all_deps = set(libraries) | 
 |   76   while unchecked_deps: | 
 |   77     lib = unchecked_deps.pop() | 
 |   78     new_deps = GetNonSystemDependencies(lib).difference(all_deps) | 
 |   79     unchecked_deps.extend(new_deps) | 
 |   80     all_deps = all_deps.union(new_deps) | 
 |   81  | 
 |   82   # Then: simple, slow topological sort. | 
 |   83   sorted_deps = [] | 
 |   84   unsorted_deps = dict(map(GraphNode, all_deps)) | 
 |   85   while unsorted_deps: | 
 |   86     for library, dependencies in unsorted_deps.items(): | 
 |   87       if not dependencies.intersection(unsorted_deps.keys()): | 
 |   88         sorted_deps.append(library) | 
 |   89         del unsorted_deps[library] | 
 |   90  | 
 |   91   return sorted_deps | 
 |   92  | 
 |   93  | 
 |   94 def main(argv): | 
 |   95   parser = optparse.OptionParser() | 
 |   96  | 
 |   97   parser.add_option('--input-libraries', | 
 |   98       help='A list of top-level input libraries.') | 
 |   99   parser.add_option('--readelf', help='Path to the readelf binary.') | 
 |  100   parser.add_option('--output', help='Path to the generated .json file.') | 
 |  101   parser.add_option('--stamp', help='Path to touch on success.') | 
 |  102  | 
 |  103   global _options | 
 |  104   _options, _ = parser.parse_args() | 
 |  105  | 
 |  106   libraries = build_utils.ParseGypList(_options.input_libraries) | 
 |  107   global _libraries_dir | 
 |  108   _libraries_dir = os.path.dirname(libraries[0]) | 
 |  109   libraries = [os.path.basename(lib) for lib in libraries] | 
 |  110  | 
 |  111   libraries = GetSortedTransitiveDependencies(libraries) | 
 |  112  | 
 |  113   with open(_options.output, 'w') as outfile: | 
 |  114     json.dump(libraries, outfile) | 
 |  115  | 
 |  116   if _options.stamp: | 
 |  117     build_utils.Touch(_options.stamp) | 
 |  118  | 
 |  119  | 
 |  120 if __name__ == '__main__': | 
 |  121   sys.exit(main(sys.argv)) | 
 |  122  | 
 |  123  | 
| OLD | NEW |