| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """Writes dependency ordered list of native libraries. | 7 """Writes dependency ordered list of native libraries. |
| 8 | 8 |
| 9 The list excludes any Android system libraries, as those are not bundled with | 9 The list excludes any Android system libraries, as those are not bundled with |
| 10 the APK. | 10 the APK. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 # http://crbug.com/225558 | 21 # http://crbug.com/225558 |
| 22 | 22 |
| 23 import json | 23 import json |
| 24 import optparse | 24 import optparse |
| 25 import os | 25 import os |
| 26 import re | 26 import re |
| 27 import sys | 27 import sys |
| 28 | 28 |
| 29 from util import build_utils | 29 from util import build_utils |
| 30 | 30 |
| 31 | |
| 32 _options = None | 31 _options = None |
| 33 _libraries_dir = None | |
| 34 _library_re = re.compile( | 32 _library_re = re.compile( |
| 35 '.*NEEDED.*Shared library: \[(?P<library_name>[\w/.]+)\]') | 33 '.*NEEDED.*Shared library: \[(?P<library_name>[\w/.]+)\]') |
| 36 | 34 |
| 37 | 35 |
| 38 def FullLibraryPath(library_name): | 36 def FullLibraryPath(library_name): |
| 39 return '%s/%s' % (_libraries_dir, library_name) | 37 return '%s/%s' % (_options.libraries_dir, library_name) |
| 40 | 38 |
| 41 | 39 |
| 42 def IsSystemLibrary(library_name): | 40 def IsSystemLibrary(library_name): |
| 43 # If the library doesn't exist in the libraries directory, assume that it is | 41 # If the library doesn't exist in the libraries directory, assume that it is |
| 44 # an Android system library. | 42 # an Android system library. |
| 45 return not os.path.exists(FullLibraryPath(library_name)) | 43 return not os.path.exists(FullLibraryPath(library_name)) |
| 46 | 44 |
| 47 | 45 |
| 48 def CallReadElf(library_name): | 46 def CallReadElf(library_or_executable): |
| 49 readelf_cmd = [_options.readelf, | 47 readelf_cmd = [_options.readelf, |
| 50 '-d', | 48 '-d', |
| 51 FullLibraryPath(library_name)] | 49 library_or_executable] |
| 52 return build_utils.CheckCallDie(readelf_cmd, suppress_output=True) | 50 return build_utils.CheckCallDie(readelf_cmd, suppress_output=True) |
| 53 | 51 |
| 54 | 52 |
| 55 def GetDependencies(library_name): | 53 def GetDependencies(library_or_executable): |
| 56 elf = CallReadElf(library_name) | 54 elf = CallReadElf(library_or_executable) |
| 57 return set(_library_re.findall(elf)) | 55 return set(_library_re.findall(elf)) |
| 58 | 56 |
| 59 | 57 |
| 60 def GetNonSystemDependencies(library_name): | 58 def GetNonSystemDependencies(library_name): |
| 61 all_deps = GetDependencies(library_name) | 59 all_deps = GetDependencies(FullLibraryPath(library_name)) |
| 62 return set((lib for lib in all_deps if not IsSystemLibrary(lib))) | 60 return set((lib for lib in all_deps if not IsSystemLibrary(lib))) |
| 63 | 61 |
| 64 | 62 |
| 65 def GetSortedTransitiveDependencies(libraries): | 63 def GetSortedTransitiveDependencies(libraries): |
| 66 """Returns all transitive library dependencies in dependency order.""" | 64 """Returns all transitive library dependencies in dependency order.""" |
| 67 def GraphNode(library): | 65 def GraphNode(library): |
| 68 return (library, GetNonSystemDependencies(library)) | 66 return (library, GetNonSystemDependencies(library)) |
| 69 | 67 |
| 70 # First: find all library dependencies. | 68 # First: find all library dependencies. |
| 71 unchecked_deps = libraries | 69 unchecked_deps = libraries |
| 72 all_deps = set(libraries) | 70 all_deps = set(libraries) |
| 73 while unchecked_deps: | 71 while unchecked_deps: |
| 74 lib = unchecked_deps.pop() | 72 lib = unchecked_deps.pop() |
| 75 new_deps = GetNonSystemDependencies(lib).difference(all_deps) | 73 new_deps = GetNonSystemDependencies(lib).difference(all_deps) |
| 76 unchecked_deps.extend(new_deps) | 74 unchecked_deps.extend(new_deps) |
| 77 all_deps = all_deps.union(new_deps) | 75 all_deps = all_deps.union(new_deps) |
| 78 | 76 |
| 79 # Then: simple, slow topological sort. | 77 # Then: simple, slow topological sort. |
| 80 sorted_deps = [] | 78 sorted_deps = [] |
| 81 unsorted_deps = dict(map(GraphNode, all_deps)) | 79 unsorted_deps = dict(map(GraphNode, all_deps)) |
| 82 while unsorted_deps: | 80 while unsorted_deps: |
| 83 for library, dependencies in unsorted_deps.items(): | 81 for library, dependencies in unsorted_deps.items(): |
| 84 if not dependencies.intersection(unsorted_deps.keys()): | 82 if not dependencies.intersection(unsorted_deps.keys()): |
| 85 sorted_deps.append(library) | 83 sorted_deps.append(library) |
| 86 del unsorted_deps[library] | 84 del unsorted_deps[library] |
| 87 | 85 |
| 88 return sorted_deps | 86 return sorted_deps |
| 89 | 87 |
| 88 def GetSortedTransitiveDependenciesForExecutable(executable): |
| 89 """Returns all transitive library dependencies in dependency order.""" |
| 90 all_deps = GetDependencies(executable) |
| 91 libraries = [lib for lib in all_deps if not IsSystemLibrary(lib)] |
| 92 return GetSortedTransitiveDependencies(libraries) |
| 93 |
| 90 | 94 |
| 91 def main(argv): | 95 def main(argv): |
| 92 parser = optparse.OptionParser() | 96 parser = optparse.OptionParser() |
| 93 | 97 |
| 94 parser.add_option('--input-libraries', | 98 parser.add_option('--input-libraries', |
| 95 help='A list of top-level input libraries.') | 99 help='A list of top-level input libraries.') |
| 100 parser.add_option('--libraries-dir', |
| 101 help='The directory which contains shared libraries.') |
| 96 parser.add_option('--readelf', help='Path to the readelf binary.') | 102 parser.add_option('--readelf', help='Path to the readelf binary.') |
| 97 parser.add_option('--output', help='Path to the generated .json file.') | 103 parser.add_option('--output', help='Path to the generated .json file.') |
| 98 parser.add_option('--stamp', help='Path to touch on success.') | 104 parser.add_option('--stamp', help='Path to touch on success.') |
| 99 | 105 |
| 100 global _options | 106 global _options |
| 101 _options, _ = parser.parse_args() | 107 _options, _ = parser.parse_args() |
| 102 | 108 |
| 103 libraries = build_utils.ParseGypList(_options.input_libraries) | 109 libraries = build_utils.ParseGypList(_options.input_libraries) |
| 104 global _libraries_dir | 110 if libraries[0].endswith('.so'): |
| 105 _libraries_dir = os.path.dirname(libraries[0]) | 111 libraries = [os.path.basename(lib) for lib in libraries] |
| 106 libraries = [os.path.basename(lib) for lib in libraries] | 112 libraries = GetSortedTransitiveDependencies(libraries) |
| 107 | 113 else: |
| 108 libraries = GetSortedTransitiveDependencies(libraries) | 114 libraries = GetSortedTransitiveDependenciesForExecutable(libraries[0]) |
| 109 | 115 |
| 110 with open(_options.output, 'w') as outfile: | 116 with open(_options.output, 'w') as outfile: |
| 111 json.dump(libraries, outfile) | 117 json.dump(libraries, outfile) |
| 112 | 118 |
| 113 if _options.stamp: | 119 if _options.stamp: |
| 114 build_utils.Touch(_options.stamp) | 120 build_utils.Touch(_options.stamp) |
| 115 | 121 |
| 116 | 122 |
| 117 if __name__ == '__main__': | 123 if __name__ == '__main__': |
| 118 sys.exit(main(sys.argv)) | 124 sys.exit(main(sys.argv)) |
| 119 | 125 |
| 120 | 126 |
| OLD | NEW |