Index: build/android/gyp/write_ordered_libraries.py |
diff --git a/build/android/gyp/write_ordered_libraries.py b/build/android/gyp/write_ordered_libraries.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..4ca54cd62da4719e7c3158c49d4d89a563fffc8b |
--- /dev/null |
+++ b/build/android/gyp/write_ordered_libraries.py |
@@ -0,0 +1,123 @@ |
+#!/usr/bin/env python |
+# |
+# Copyright 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Writes dependency ordered list of native libraries. |
+ |
+The list excludes any Android system libraries, as those are not bundled with |
+the APK. |
+ |
+This list of libraries is used for several steps of building an APK. |
+In the component build, the --input-libraries only needs to be the top-level |
+library (i.e. libcontent_shell_content_view). This will then use readelf to |
+inspect the shared libraries and determine the full list of (non-system) |
+libraries that should be included in the APK. |
+""" |
+ |
+# TODO(cjhopman): See if we can expose the list of library dependencies from |
+# gyp, rather than calculating it ourselves. |
+# http://crbug.com/225558 |
+ |
+import json |
+import optparse |
+import os |
+import re |
+import sys |
+ |
+BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') |
+sys.path.append(BUILD_ANDROID_DIR) |
+ |
+from pylib import build_utils |
+ |
+ |
+_options = None |
+_libraries_dir = None |
+_library_re = re.compile( |
+ '.*NEEDED.*Shared library: \[(?P<library_name>[\w/.]+)\]') |
+ |
+ |
+def FullLibraryPath(library_name): |
+ return '%s/%s' % (_libraries_dir, library_name) |
+ |
+ |
+def IsSystemLibrary(library_name): |
+ # If the library doesn't exist in the libraries directory, assume that it is |
+ # an Android system library. |
+ return not os.path.exists(FullLibraryPath(library_name)) |
+ |
+ |
+def CallReadElf(library_name): |
+ readelf_cmd = [_options.readelf, |
+ '-d', |
+ FullLibraryPath(library_name)] |
+ return build_utils.CheckCallDie(readelf_cmd) |
+ |
+ |
+def GetDependencies(library_name): |
+ elf = CallReadElf(library_name) |
+ return set(_library_re.findall(elf)) |
+ |
+ |
+def GetNonSystemDependencies(library_name): |
+ all_deps = GetDependencies(library_name) |
+ return set((lib for lib in all_deps if not IsSystemLibrary(lib))) |
+ |
+ |
+def GetSortedTransitiveDependencies(libraries): |
+ """Returns all transitive library dependencies in dependency order.""" |
+ def GraphNode(library): |
+ return (library, GetNonSystemDependencies(library)) |
+ |
+ # First: find all library dependencies. |
+ unchecked_deps = libraries |
+ all_deps = set(libraries) |
+ while unchecked_deps: |
+ lib = unchecked_deps.pop() |
+ new_deps = GetNonSystemDependencies(lib).difference(all_deps) |
+ unchecked_deps.extend(new_deps) |
+ all_deps = all_deps.union(new_deps) |
+ |
+ # Then: simple, slow topological sort. |
+ sorted_deps = [] |
+ unsorted_deps = dict(map(GraphNode, all_deps)) |
+ while unsorted_deps: |
+ for library, dependencies in unsorted_deps.items(): |
+ if not dependencies.intersection(unsorted_deps.keys()): |
+ sorted_deps.append(library) |
+ del unsorted_deps[library] |
+ |
+ return sorted_deps |
+ |
+ |
+def main(argv): |
+ parser = optparse.OptionParser() |
+ |
+ parser.add_option('--input-libraries', |
+ help='A list of top-level input libraries.') |
+ parser.add_option('--readelf', help='Path to the readelf binary.') |
+ parser.add_option('--output', help='Path to the generated .json file.') |
+ parser.add_option('--stamp', help='Path to touch on success.') |
+ |
+ global _options |
+ _options, _ = parser.parse_args() |
+ |
+ libraries = build_utils.ParseGypList(_options.input_libraries) |
+ global _libraries_dir |
+ _libraries_dir = os.path.dirname(libraries[0]) |
+ libraries = [os.path.basename(lib) for lib in libraries] |
+ |
+ libraries = GetSortedTransitiveDependencies(libraries) |
+ |
+ with open(_options.output, 'w') as outfile: |
+ json.dump(libraries, outfile) |
+ |
+ if _options.stamp: |
+ build_utils.Touch(_options.stamp) |
+ |
+ |
+if __name__ == '__main__': |
+ sys.exit(main(sys.argv)) |
+ |
+ |