blob: 0fc9a8ca3ef2de04b7283362603ed4556d94c354 [file] [log] [blame]
Ben Murdoch097c5b22016-05-18 11:27:45 +01001#!/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>.+)\]')
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(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 out_json = {
123 'libraries': libraries,
124 'lib_paths': [FullLibraryPath(l) for l in libraries],
125 'java_libraries_list': java_libraries_list
126 }
127 build_utils.WriteJson(
128 out_json,
129 options.output,
130 only_if_changed=True)
131
132 if options.stamp:
133 build_utils.Touch(options.stamp)
134
135 if options.depfile:
136 build_utils.WriteDepfile(
137 options.depfile,
138 libraries + build_utils.GetPythonDependencies())
139
140
141if __name__ == '__main__':
142 sys.exit(main())
143
144