OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2014 The Chromium Authors. All rights reserved. | 3 # Copyright 2014 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 a build_config file. | 7 """Writes a build_config file. |
8 | 8 |
9 The build_config file for a target is a json file containing information about | 9 The build_config file for a target is a json file containing information about |
10 how to build that target based on the target's dependencies. This includes | 10 how to build that target based on the target's dependencies. This includes |
(...skipping 11 matching lines...) Expand all Loading... |
22 1. inputs/deps of the action ensure that the files are available the first | 22 1. inputs/deps of the action ensure that the files are available the first |
23 time the action runs. | 23 time the action runs. |
24 2. Either (a) or (b) | 24 2. Either (a) or (b) |
25 a. inputs/deps ensure that the action runs whenever one of the files changes | 25 a. inputs/deps ensure that the action runs whenever one of the files changes |
26 b. the files are added to the action's depfile | 26 b. the files are added to the action's depfile |
27 """ | 27 """ |
28 | 28 |
29 import optparse | 29 import optparse |
30 import os | 30 import os |
31 import sys | 31 import sys |
| 32 import xml.dom.minidom |
32 | 33 |
33 from util import build_utils | 34 from util import build_utils |
34 | 35 |
35 import write_ordered_libraries | 36 import write_ordered_libraries |
36 | 37 |
| 38 class AndroidManifest(object): |
| 39 def __init__(self, path): |
| 40 self.path = path |
| 41 dom = xml.dom.minidom.parse(path) |
| 42 manifests = dom.getElementsByTagName('manifest') |
| 43 assert len(manifests) == 1 |
| 44 self.manifest = manifests[0] |
| 45 |
| 46 def GetInstrumentation(self): |
| 47 instrumentation_els = self.manifest.getElementsByTagName('instrumentation') |
| 48 if len(instrumentation_els) == 0: |
| 49 return None |
| 50 if len(instrumentation_els) != 1: |
| 51 raise Exception( |
| 52 'More than one <instrumentation> element found in %s' % self.path) |
| 53 return instrumentation_els[0] |
| 54 |
| 55 def CheckInstrumentation(self, expected_package): |
| 56 instr = self.GetInstrumentation() |
| 57 if not instr: |
| 58 raise Exception('No <instrumentation> elements found in %s' % self.path) |
| 59 instrumented_package = instr.getAttributeNS( |
| 60 'http://schemas.android.com/apk/res/android', 'targetPackage') |
| 61 if instrumented_package != expected_package: |
| 62 raise Exception( |
| 63 'Wrong instrumented package. Expected %s, got %s' |
| 64 % (expected_package, instrumented_package)) |
| 65 |
| 66 def GetPackageName(self): |
| 67 return self.manifest.getAttribute('package') |
| 68 |
37 | 69 |
38 dep_config_cache = {} | 70 dep_config_cache = {} |
39 def GetDepConfig(path): | 71 def GetDepConfig(path): |
40 if not path in dep_config_cache: | 72 if not path in dep_config_cache: |
41 dep_config_cache[path] = build_utils.ReadJson(path)['deps_info'] | 73 dep_config_cache[path] = build_utils.ReadJson(path)['deps_info'] |
42 return dep_config_cache[path] | 74 return dep_config_cache[path] |
43 | 75 |
44 | 76 |
45 def DepsOfType(wanted_type, configs): | 77 def DepsOfType(wanted_type, configs): |
46 return [c for c in configs if c['type'] == wanted_type] | 78 return [c for c in configs if c['type'] == wanted_type] |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 parser.add_option('--bypass-platform-checks', action='store_true', | 113 parser.add_option('--bypass-platform-checks', action='store_true', |
82 help='Bypass checks for support/require Android platform.') | 114 help='Bypass checks for support/require Android platform.') |
83 | 115 |
84 # android library options | 116 # android library options |
85 parser.add_option('--dex-path', help='Path to target\'s dex output.') | 117 parser.add_option('--dex-path', help='Path to target\'s dex output.') |
86 | 118 |
87 # native library options | 119 # native library options |
88 parser.add_option('--native-libs', help='List of top-level native libs.') | 120 parser.add_option('--native-libs', help='List of top-level native libs.') |
89 parser.add_option('--readelf-path', help='Path to toolchain\'s readelf.') | 121 parser.add_option('--readelf-path', help='Path to toolchain\'s readelf.') |
90 | 122 |
| 123 parser.add_option('--tested-apk-config', |
| 124 help='Path to the build config of the tested apk (for an instrumentation ' |
| 125 'test apk).') |
| 126 |
91 options, args = parser.parse_args(argv) | 127 options, args = parser.parse_args(argv) |
92 | 128 |
93 if args: | 129 if args: |
94 parser.error('No positional arguments should be given.') | 130 parser.error('No positional arguments should be given.') |
95 | 131 |
96 | 132 |
97 if not options.type in [ | 133 if not options.type in [ |
98 'java_library', 'android_resources', 'android_apk', 'deps_dex']: | 134 'java_library', 'android_resources', 'android_apk', 'deps_dex']: |
99 raise Exception('Unknown type: <%s>' % options.type) | 135 raise Exception('Unknown type: <%s>' % options.type) |
100 | 136 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 config = { | 183 config = { |
148 'deps_info': { | 184 'deps_info': { |
149 'name': os.path.basename(options.build_config), | 185 'name': os.path.basename(options.build_config), |
150 'path': options.build_config, | 186 'path': options.build_config, |
151 'type': options.type, | 187 'type': options.type, |
152 'deps_configs': direct_deps_config_paths, | 188 'deps_configs': direct_deps_config_paths, |
153 } | 189 } |
154 } | 190 } |
155 deps_info = config['deps_info'] | 191 deps_info = config['deps_info'] |
156 | 192 |
157 | |
158 if options.type == 'java_library' and not options.bypass_platform_checks: | 193 if options.type == 'java_library' and not options.bypass_platform_checks: |
159 deps_info['requires_android'] = options.requires_android | 194 deps_info['requires_android'] = options.requires_android |
160 deps_info['supports_android'] = options.supports_android | 195 deps_info['supports_android'] = options.supports_android |
161 | 196 |
162 deps_require_android = (all_resources_deps + | 197 deps_require_android = (all_resources_deps + |
163 [d['name'] for d in all_library_deps if d['requires_android']]) | 198 [d['name'] for d in all_library_deps if d['requires_android']]) |
164 deps_not_support_android = ( | 199 deps_not_support_android = ( |
165 [d['name'] for d in all_library_deps if not d['supports_android']]) | 200 [d['name'] for d in all_library_deps if not d['supports_android']]) |
166 | 201 |
167 if deps_require_android and not options.requires_android: | 202 if deps_require_android and not options.requires_android: |
168 raise Exception('Some deps require building for the Android platform: ' + | 203 raise Exception('Some deps require building for the Android platform: ' + |
169 str(deps_require_android)) | 204 str(deps_require_android)) |
170 | 205 |
171 if deps_not_support_android and options.supports_android: | 206 if deps_not_support_android and options.supports_android: |
172 raise Exception('Not all deps support the Android platform: ' + | 207 raise Exception('Not all deps support the Android platform: ' + |
173 str(deps_not_support_android)) | 208 str(deps_not_support_android)) |
174 | 209 |
175 | |
176 if options.type in ['java_library', 'android_apk']: | 210 if options.type in ['java_library', 'android_apk']: |
177 javac_classpath = [c['jar_path'] for c in direct_library_deps] | 211 javac_classpath = [c['jar_path'] for c in direct_library_deps] |
178 java_full_classpath = [c['jar_path'] for c in all_library_deps] | 212 java_full_classpath = [c['jar_path'] for c in all_library_deps] |
179 deps_info['resources_deps'] = [c['path'] for c in all_resources_deps] | 213 deps_info['resources_deps'] = [c['path'] for c in all_resources_deps] |
180 deps_info['jar_path'] = options.jar_path | 214 deps_info['jar_path'] = options.jar_path |
181 if options.type == 'android_apk' or options.supports_android: | 215 if options.type == 'android_apk' or options.supports_android: |
182 deps_info['dex_path'] = options.dex_path | 216 deps_info['dex_path'] = options.dex_path |
183 config['javac'] = { | 217 config['javac'] = { |
184 'classpath': javac_classpath, | 218 'classpath': javac_classpath, |
185 } | 219 } |
(...skipping 23 matching lines...) Expand all Loading... |
209 if options.type == 'android_resources' or options.type == 'android_apk': | 243 if options.type == 'android_resources' or options.type == 'android_apk': |
210 config['resources'] = {} | 244 config['resources'] = {} |
211 config['resources']['dependency_zips'] = [ | 245 config['resources']['dependency_zips'] = [ |
212 c['resources_zip'] for c in all_resources_deps] | 246 c['resources_zip'] for c in all_resources_deps] |
213 config['resources']['extra_package_names'] = [] | 247 config['resources']['extra_package_names'] = [] |
214 | 248 |
215 if options.type == 'android_apk': | 249 if options.type == 'android_apk': |
216 config['resources']['extra_package_names'] = [ | 250 config['resources']['extra_package_names'] = [ |
217 c['package_name'] for c in all_resources_deps if 'package_name' in c] | 251 c['package_name'] for c in all_resources_deps if 'package_name' in c] |
218 | 252 |
| 253 if options.type in ['android_apk', 'deps_dex']: |
| 254 deps_dex_files = [c['dex_path'] for c in all_library_deps] |
| 255 |
| 256 # An instrumentation test apk should exclude the dex files that are in the apk |
| 257 # under test. |
| 258 if options.type == 'android_apk' and options.tested_apk_config: |
| 259 tested_apk_config_paths = GetAllDepsConfigsInOrder( |
| 260 [options.tested_apk_config]) |
| 261 tested_apk_configs = [GetDepConfig(p) for p in tested_apk_config_paths] |
| 262 tested_apk_library_deps = DepsOfType('java_library', tested_apk_configs) |
| 263 tested_apk_deps_dex_files = [c['dex_path'] for c in tested_apk_library_deps] |
| 264 deps_dex_files = [ |
| 265 p for p in deps_dex_files if not p in tested_apk_deps_dex_files] |
| 266 |
| 267 tested_apk_config = GetDepConfig(options.tested_apk_config) |
| 268 expected_tested_package = tested_apk_config['package_name'] |
| 269 AndroidManifest(options.android_manifest).CheckInstrumentation( |
| 270 expected_tested_package) |
219 | 271 |
220 # Dependencies for the final dex file of an apk or a 'deps_dex'. | 272 # Dependencies for the final dex file of an apk or a 'deps_dex'. |
221 if options.type in ['android_apk', 'deps_dex']: | 273 if options.type in ['android_apk', 'deps_dex']: |
222 config['final_dex'] = {} | 274 config['final_dex'] = {} |
223 dex_config = config['final_dex'] | 275 dex_config = config['final_dex'] |
224 # TODO(cjhopman): proguard version | 276 # TODO(cjhopman): proguard version |
225 dex_deps_files = [c['dex_path'] for c in all_library_deps] | 277 dex_config['dependency_dex_files'] = deps_dex_files |
226 dex_config['dependency_dex_files'] = dex_deps_files | |
227 | 278 |
228 if options.type == 'android_apk': | 279 if options.type == 'android_apk': |
229 config['dist_jar'] = { | 280 config['dist_jar'] = { |
230 'dependency_jars': [ | 281 'dependency_jars': [ |
231 c['jar_path'] for c in all_library_deps | 282 c['jar_path'] for c in all_library_deps |
232 ] | 283 ] |
233 } | 284 } |
| 285 manifest = AndroidManifest(options.android_manifest) |
| 286 deps_info['package_name'] = manifest.GetPackageName() |
| 287 if not options.tested_apk_config and manifest.GetInstrumentation(): |
| 288 # This must then have instrumentation only for itself. |
| 289 manifest.CheckInstrumentation(manifest.GetPackageName()) |
234 | 290 |
235 library_paths = [] | 291 library_paths = [] |
236 java_libraries_list = [] | 292 java_libraries_list = [] |
237 if options.native_libs: | 293 if options.native_libs: |
238 libraries = build_utils.ParseGypList(options.native_libs) | 294 libraries = build_utils.ParseGypList(options.native_libs) |
239 if libraries: | 295 if libraries: |
240 libraries_dir = os.path.dirname(libraries[0]) | 296 libraries_dir = os.path.dirname(libraries[0]) |
241 write_ordered_libraries.SetReadelfPath(options.readelf_path) | 297 write_ordered_libraries.SetReadelfPath(options.readelf_path) |
242 write_ordered_libraries.SetLibraryDirs([libraries_dir]) | 298 write_ordered_libraries.SetLibraryDirs([libraries_dir]) |
243 all_native_library_deps = ( | 299 all_native_library_deps = ( |
(...skipping 14 matching lines...) Expand all Loading... |
258 build_utils.WriteJson(config, options.build_config, only_if_changed=True) | 314 build_utils.WriteJson(config, options.build_config, only_if_changed=True) |
259 | 315 |
260 if options.depfile: | 316 if options.depfile: |
261 build_utils.WriteDepfile( | 317 build_utils.WriteDepfile( |
262 options.depfile, | 318 options.depfile, |
263 all_deps_config_paths + build_utils.GetPythonDependencies()) | 319 all_deps_config_paths + build_utils.GetPythonDependencies()) |
264 | 320 |
265 | 321 |
266 if __name__ == '__main__': | 322 if __name__ == '__main__': |
267 sys.exit(main(sys.argv[1:])) | 323 sys.exit(main(sys.argv[1:])) |
OLD | NEW |