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