OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Generates an Android Studio project from a GN target.""" | 6 """Generates an Android Studio project from a GN target.""" |
7 | 7 |
8 import argparse | 8 import argparse |
9 import codecs | 9 import codecs |
10 import logging | 10 import logging |
(...skipping 16 matching lines...) Expand all Loading... |
27 from util import build_utils | 27 from util import build_utils |
28 | 28 |
29 | 29 |
30 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( | 30 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( |
31 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') | 31 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') |
32 _JINJA_TEMPLATE_PATH = os.path.join( | 32 _JINJA_TEMPLATE_PATH = os.path.join( |
33 os.path.dirname(__file__), 'build.gradle.jinja') | 33 os.path.dirname(__file__), 'build.gradle.jinja') |
34 | 34 |
35 _JAVA_SUBDIR = 'symlinked-java' | 35 _JAVA_SUBDIR = 'symlinked-java' |
36 _SRCJARS_SUBDIR = 'extracted-srcjars' | 36 _SRCJARS_SUBDIR = 'extracted-srcjars' |
| 37 _JNI_LIBS_SUBDIR = 'symlinked-libs' |
| 38 _ARMEABI_SUBDIR = 'armeabi' |
37 | 39 |
38 _DEFAULT_TARGETS = [ | 40 _DEFAULT_TARGETS = [ |
39 # TODO(agrieve): Requires alternate android.jar to compile. | 41 # TODO(agrieve): Requires alternate android.jar to compile. |
40 # '//android_webview:system_webview_apk', | 42 # '//android_webview:system_webview_apk', |
41 '//android_webview/test:android_webview_apk', | 43 '//android_webview/test:android_webview_apk', |
42 '//android_webview/test:android_webview_test_apk', | 44 '//android_webview/test:android_webview_test_apk', |
43 '//base:base_junit_tests', | 45 '//base:base_junit_tests', |
44 '//chrome/android:chrome_junit_tests', | 46 '//chrome/android:chrome_junit_tests', |
45 '//chrome/android:chrome_public_apk', | 47 '//chrome/android:chrome_public_apk', |
46 '//chrome/android:chrome_public_test_apk', | 48 '//chrome/android:chrome_public_test_apk', |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 assert basename, 'Failed to find source dir for ' + path | 178 assert basename, 'Failed to find source dir for ' + path |
177 if basename in ('java', 'src'): | 179 if basename in ('java', 'src'): |
178 break | 180 break |
179 if basename in ('javax', 'org', 'com'): | 181 if basename in ('javax', 'org', 'com'): |
180 path_root = os.path.dirname(path_root) | 182 path_root = os.path.dirname(path_root) |
181 break | 183 break |
182 found_roots.add(path_root) | 184 found_roots.add(path_root) |
183 return list(found_roots) | 185 return list(found_roots) |
184 | 186 |
185 | 187 |
| 188 def _CreateRelativeSymlink(target_path, link_path): |
| 189 link_dir = os.path.dirname(link_path) |
| 190 relpath = os.path.relpath(target_path, link_dir) |
| 191 logging.debug('Creating symlink %s -> %s', link_path, relpath) |
| 192 os.symlink(relpath, link_path) |
| 193 |
| 194 |
186 def _CreateSymlinkTree(entry_output_dir, symlink_dir, desired_files, | 195 def _CreateSymlinkTree(entry_output_dir, symlink_dir, desired_files, |
187 parent_dirs): | 196 parent_dirs): |
188 """Creates a directory tree of symlinks to the given files. | 197 """Creates a directory tree of symlinks to the given files. |
189 | 198 |
190 The idea here is to replicate a directory tree while leaving out files within | 199 The idea here is to replicate a directory tree while leaving out files within |
191 it not listed by |desired_files|. | 200 it not listed by |desired_files|. |
192 """ | 201 """ |
193 assert _IsSubpathOf(symlink_dir, entry_output_dir) | 202 assert _IsSubpathOf(symlink_dir, entry_output_dir) |
194 | 203 |
195 for target_path in desired_files: | 204 for target_path in desired_files: |
196 prefix = next(d for d in parent_dirs if target_path.startswith(d)) | 205 prefix = next(d for d in parent_dirs if target_path.startswith(d)) |
197 subpath = os.path.relpath(target_path, prefix) | 206 subpath = os.path.relpath(target_path, prefix) |
198 symlinked_path = os.path.join(symlink_dir, subpath) | 207 symlinked_path = os.path.join(symlink_dir, subpath) |
199 symlinked_dir = os.path.dirname(symlinked_path) | 208 symlinked_dir = os.path.dirname(symlinked_path) |
200 if not os.path.exists(symlinked_dir): | 209 if not os.path.exists(symlinked_dir): |
201 os.makedirs(symlinked_dir) | 210 os.makedirs(symlinked_dir) |
202 relpath = os.path.relpath(target_path, symlinked_dir) | 211 _CreateRelativeSymlink(target_path, symlinked_path) |
203 logging.debug('Creating symlink %s -> %s', symlinked_path, relpath) | |
204 os.symlink(relpath, symlinked_path) | |
205 | 212 |
206 | 213 |
207 def _CreateJavaSourceDir(output_dir, entry_output_dir, java_files): | 214 def _CreateJavaSourceDir(output_dir, entry_output_dir, java_files): |
208 """Computes and constructs when necessary the list of java source directories. | 215 """Computes and constructs when necessary the list of java source directories. |
209 | 216 |
210 1. Computes the root java source directories from the list of files. | 217 1. Computes the root java source directories from the list of files. |
211 2. Determines whether there are any .java files in them that are not included | 218 2. Determines whether there are any .java files in them that are not included |
212 in |java_files|. | 219 in |java_files|. |
213 3. If not, returns the list of java source directories. If so, constructs a | 220 3. If not, returns the list of java source directories. If so, constructs a |
214 tree of symlinks within |entry_output_dir| of all files in |java_files|. | 221 tree of symlinks within |entry_output_dir| of all files in |java_files|. |
(...skipping 17 matching lines...) Expand all Loading... |
232 logging.debug('Target requires .java symlinks: %s', entry_output_dir) | 239 logging.debug('Target requires .java symlinks: %s', entry_output_dir) |
233 _CreateSymlinkTree(entry_output_dir, symlink_dir, java_files, java_dirs) | 240 _CreateSymlinkTree(entry_output_dir, symlink_dir, java_files, java_dirs) |
234 java_dirs = [symlink_dir] | 241 java_dirs = [symlink_dir] |
235 | 242 |
236 if missing_java_files: | 243 if missing_java_files: |
237 logging.warning('Some java files were not found: %s', missing_java_files) | 244 logging.warning('Some java files were not found: %s', missing_java_files) |
238 | 245 |
239 return java_dirs | 246 return java_dirs |
240 | 247 |
241 | 248 |
| 249 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): |
| 250 """Creates directory with symlinked .so files if necessary. |
| 251 |
| 252 Returns list of JNI libs directories.""" |
| 253 |
| 254 if so_files: |
| 255 symlink_dir = os.path.join(entry_output_dir, _JNI_LIBS_SUBDIR) |
| 256 shutil.rmtree(symlink_dir, True) |
| 257 abi_dir = os.path.join(symlink_dir, _ARMEABI_SUBDIR) |
| 258 if not os.path.exists(abi_dir): |
| 259 os.makedirs(abi_dir) |
| 260 for so_file in so_files: |
| 261 target_path = os.path.join(output_dir, so_file) |
| 262 symlinked_path = os.path.join(abi_dir, so_file) |
| 263 _CreateRelativeSymlink(target_path, symlinked_path) |
| 264 |
| 265 return [symlink_dir] |
| 266 |
| 267 return [] |
| 268 |
| 269 |
242 def _GenerateLocalProperties(sdk_dir): | 270 def _GenerateLocalProperties(sdk_dir): |
243 """Returns the data for project.properties as a string.""" | 271 """Returns the data for project.properties as a string.""" |
244 return '\n'.join([ | 272 return '\n'.join([ |
245 '# Generated by //build/android/gradle/generate_gradle.py', | 273 '# Generated by //build/android/gradle/generate_gradle.py', |
246 'sdk.dir=%s' % sdk_dir, | 274 'sdk.dir=%s' % sdk_dir, |
247 '']) | 275 '']) |
248 | 276 |
249 | 277 |
250 def _GenerateGradleFile(build_config, build_vars, java_dirs, relativize, | 278 def _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs, |
251 use_gradle_process_resources, jinja_processor): | 279 relativize, use_gradle_process_resources, |
| 280 jinja_processor): |
252 """Returns the data for a project's build.gradle.""" | 281 """Returns the data for a project's build.gradle.""" |
253 deps_info = build_config['deps_info'] | 282 deps_info = build_config['deps_info'] |
254 gradle = build_config['gradle'] | 283 gradle = build_config['gradle'] |
255 | 284 |
256 variables = { | 285 variables = { |
257 'sourceSetName': 'main', | 286 'sourceSetName': 'main', |
258 'depCompileName': 'compile', | 287 'depCompileName': 'compile', |
259 } | 288 } |
260 if deps_info['type'] == 'android_apk': | 289 if deps_info['type'] == 'android_apk': |
261 target_type = 'android_apk' | 290 target_type = 'android_apk' |
(...skipping 19 matching lines...) Expand all Loading... |
281 variables['target_name'] = os.path.splitext(deps_info['name'])[0] | 310 variables['target_name'] = os.path.splitext(deps_info['name'])[0] |
282 variables['template_type'] = target_type | 311 variables['template_type'] = target_type |
283 variables['use_gradle_process_resources'] = use_gradle_process_resources | 312 variables['use_gradle_process_resources'] = use_gradle_process_resources |
284 variables['build_tools_version'] = ( | 313 variables['build_tools_version'] = ( |
285 build_vars['android_sdk_build_tools_version']) | 314 build_vars['android_sdk_build_tools_version']) |
286 variables['compile_sdk_version'] = build_vars['android_sdk_version'] | 315 variables['compile_sdk_version'] = build_vars['android_sdk_version'] |
287 android_manifest = gradle.get('android_manifest', | 316 android_manifest = gradle.get('android_manifest', |
288 _DEFAULT_ANDROID_MANIFEST_PATH) | 317 _DEFAULT_ANDROID_MANIFEST_PATH) |
289 variables['android_manifest'] = relativize(android_manifest) | 318 variables['android_manifest'] = relativize(android_manifest) |
290 variables['java_dirs'] = relativize(java_dirs) | 319 variables['java_dirs'] = relativize(java_dirs) |
| 320 variables['jni_libs'] = relativize(jni_libs) |
291 # TODO(agrieve): Add an option to use interface jars and see if that speeds | 321 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
292 # things up at all. | 322 # things up at all. |
293 variables['prebuilts'] = relativize(gradle['dependent_prebuilt_jars']) | 323 variables['prebuilts'] = relativize(gradle['dependent_prebuilt_jars']) |
294 deps = [_ProjectEntry.FromBuildConfigPath(p) | 324 deps = [_ProjectEntry.FromBuildConfigPath(p) |
295 for p in gradle['dependent_android_projects']] | 325 for p in gradle['dependent_android_projects']] |
296 | 326 |
297 variables['android_project_deps'] = [d.ProjectName() for d in deps] | 327 variables['android_project_deps'] = [d.ProjectName() for d in deps] |
298 deps = [_ProjectEntry.FromBuildConfigPath(p) | 328 deps = [_ProjectEntry.FromBuildConfigPath(p) |
299 for p in gradle['dependent_java_projects']] | 329 for p in gradle['dependent_java_projects']] |
300 variables['java_project_deps'] = [d.ProjectName() for d in deps] | 330 variables['java_project_deps'] = [d.ProjectName() for d in deps] |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 java_sources_file = build_config['gradle'].get('java_sources_file') | 467 java_sources_file = build_config['gradle'].get('java_sources_file') |
438 java_files = [] | 468 java_files = [] |
439 if java_sources_file: | 469 if java_sources_file: |
440 java_sources_file = _RebasePath(java_sources_file) | 470 java_sources_file = _RebasePath(java_sources_file) |
441 java_files = build_utils.ReadSourcesList(java_sources_file) | 471 java_files = build_utils.ReadSourcesList(java_sources_file) |
442 | 472 |
443 java_dirs = _CreateJavaSourceDir(output_dir, entry_output_dir, java_files) | 473 java_dirs = _CreateJavaSourceDir(output_dir, entry_output_dir, java_files) |
444 if srcjars: | 474 if srcjars: |
445 java_dirs.append(os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) | 475 java_dirs.append(os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) |
446 | 476 |
447 data = _GenerateGradleFile(build_config, build_vars, java_dirs, relativize, | 477 native_section = build_config.get('native') |
448 args.use_gradle_process_resources, | 478 if native_section: |
| 479 jni_libs = _CreateJniLibsDir( |
| 480 output_dir, entry_output_dir, native_section.get('libraries')) |
| 481 else: |
| 482 jni_libs = [] |
| 483 |
| 484 data = _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs, |
| 485 relativize, args.use_gradle_process_resources, |
449 jinja_processor) | 486 jinja_processor) |
450 if data: | 487 if data: |
451 project_entries.append(entry) | 488 project_entries.append(entry) |
452 # Build all paths references by .gradle that exist within output_dir. | 489 # Build all paths references by .gradle that exist within output_dir. |
453 generated_inputs.extend(srcjars) | 490 generated_inputs.extend(srcjars) |
454 generated_inputs.extend(p for p in java_files if not p.startswith('..')) | 491 generated_inputs.extend(p for p in java_files if not p.startswith('..')) |
455 generated_inputs.extend(build_config['gradle']['dependent_prebuilt_jars']) | 492 generated_inputs.extend(build_config['gradle']['dependent_prebuilt_jars']) |
456 | 493 |
457 srcjar_tuples.extend( | 494 srcjar_tuples.extend( |
458 (s, os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) for s in srcjars) | 495 (s, os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) for s in srcjars) |
(...skipping 18 matching lines...) Expand all Loading... |
477 _ExtractSrcjars(gradle_output_dir, srcjar_tuples) | 514 _ExtractSrcjars(gradle_output_dir, srcjar_tuples) |
478 | 515 |
479 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 516 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
480 logging.warning('Generated projects work best with Android Studio 2.2') | 517 logging.warning('Generated projects work best with Android Studio 2.2') |
481 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 518 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
482 '/src.git/+/master/docs/android_studio.md') | 519 '/src.git/+/master/docs/android_studio.md') |
483 | 520 |
484 | 521 |
485 if __name__ == '__main__': | 522 if __name__ == '__main__': |
486 main() | 523 main() |
OLD | NEW |