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 glob | |
11 import logging | 10 import logging |
12 import os | 11 import os |
13 import re | 12 import re |
14 import shutil | 13 import shutil |
15 import subprocess | 14 import subprocess |
16 import sys | 15 import sys |
17 import zipfile | 16 import zipfile |
18 | 17 |
19 _BUILD_ANDROID = os.path.join(os.path.dirname(__file__), os.pardir) | 18 _BUILD_ANDROID = os.path.join(os.path.dirname(__file__), os.pardir) |
20 sys.path.append(_BUILD_ANDROID) | 19 sys.path.append(_BUILD_ANDROID) |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 libraries += entry.BuildConfig().get('native', {}).get('libraries', []) | 251 libraries += entry.BuildConfig().get('native', {}).get('libraries', []) |
253 if libraries: | 252 if libraries: |
254 return _CreateJniLibsDir(constants.GetOutDirectory(), | 253 return _CreateJniLibsDir(constants.GetOutDirectory(), |
255 self.EntryOutputDir(root_entry), libraries) | 254 self.EntryOutputDir(root_entry), libraries) |
256 return [] | 255 return [] |
257 | 256 |
258 def _GenJavaDirs(self, root_entry): | 257 def _GenJavaDirs(self, root_entry): |
259 java_files = [] | 258 java_files = [] |
260 for entry in self._GetEntries(root_entry): | 259 for entry in self._GetEntries(root_entry): |
261 java_files += entry.JavaFiles() | 260 java_files += entry.JavaFiles() |
262 java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes( | 261 java_dirs, single_files = _ComputeJavaSourceDirsAndFiles( |
263 constants.GetOutDirectory(), java_files) | 262 constants.GetOutDirectory(), java_files) |
264 return java_dirs, excludes | 263 return java_dirs, single_files |
265 | 264 |
266 def _GenCustomManifest(self, entry): | 265 def _GenCustomManifest(self, entry): |
267 """Returns the path to the generated AndroidManifest.xml. | 266 """Returns the path to the generated AndroidManifest.xml. |
268 | 267 |
269 Gradle uses package id from manifest when generating R.class. So, we need | 268 Gradle uses package id from manifest when generating R.class. So, we need |
270 to generate a custom manifest if we let gradle process resources. We cannot | 269 to generate a custom manifest if we let gradle process resources. We cannot |
271 simply set android.defaultConfig.applicationId because it is not supported | 270 simply set android.defaultConfig.applicationId because it is not supported |
272 for library targets.""" | 271 for library targets.""" |
273 resource_packages = entry.Javac().get('resource_packages') | 272 resource_packages = entry.Javac().get('resource_packages') |
274 if not resource_packages: | 273 if not resource_packages: |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 generated_inputs.update(self.AllSrcjars(root_entry)) | 325 generated_inputs.update(self.AllSrcjars(root_entry)) |
327 for entry in self._GetEntries(root_entry): | 326 for entry in self._GetEntries(root_entry): |
328 generated_inputs.update(entry.GeneratedJavaFiles()) | 327 generated_inputs.update(entry.GeneratedJavaFiles()) |
329 generated_inputs.update(entry.PrebuiltJars()) | 328 generated_inputs.update(entry.PrebuiltJars()) |
330 return set(generated_inputs) | 329 return set(generated_inputs) |
331 | 330 |
332 def Generate(self, root_entry): | 331 def Generate(self, root_entry): |
333 # TODO(agrieve): Add an option to use interface jars and see if that speeds | 332 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
334 # things up at all. | 333 # things up at all. |
335 variables = {} | 334 variables = {} |
336 java_dirs, excludes = self._GenJavaDirs(root_entry) | 335 java_dirs, java_files = self._GenJavaDirs(root_entry) |
337 java_dirs.sort() | 336 java_dirs.sort() |
338 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) | 337 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) |
339 variables['java_dirs'].append(_SRCJARS_SUBDIR) | 338 variables['java_dirs'].append(_SRCJARS_SUBDIR) |
340 variables['java_excludes'] = excludes | 339 variables['java_files'] = self._Relativize(root_entry, java_files) |
341 variables['jni_libs'] = self._Relativize( | 340 variables['jni_libs'] = self._Relativize( |
342 root_entry, set(self._GenJniLibs(root_entry))) | 341 root_entry, set(self._GenJniLibs(root_entry))) |
343 variables['prebuilts'] = [ | 342 variables['prebuilts'] = [ |
344 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] | 343 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] |
345 variables['res_dirs'] = [ | 344 variables['res_dirs'] = [ |
346 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] | 345 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] |
347 for entry in self._GetEntries(root_entry): | 346 for entry in self._GetEntries(root_entry): |
348 variables['prebuilts'] += entry.PrebuiltJars() | 347 variables['prebuilts'] += entry.PrebuiltJars() |
349 variables['res_dirs'] += entry.ResDirs() | 348 variables['res_dirs'] += entry.ResDirs() |
350 variables['prebuilts'] = self._Relativize( | 349 variables['prebuilts'] = self._Relativize( |
(...skipping 30 matching lines...) Expand all Loading... |
381 break | 380 break |
382 if basename in ('javax', 'org', 'com'): | 381 if basename in ('javax', 'org', 'com'): |
383 path_root = os.path.dirname(path_root) | 382 path_root = os.path.dirname(path_root) |
384 break | 383 break |
385 if path_root not in found_roots: | 384 if path_root not in found_roots: |
386 found_roots[path_root] = [] | 385 found_roots[path_root] = [] |
387 found_roots[path_root].append(path) | 386 found_roots[path_root].append(path) |
388 return found_roots | 387 return found_roots |
389 | 388 |
390 | 389 |
391 def _ComputeExcludeFilters(wanted_files, unwanted_files, parent_dir): | 390 def _ComputeJavaSourceDirsAndFiles(output_dir, java_files): |
392 """Returns exclude patters to exclude unwanted files but keep wanted files. | 391 """Computes the list of java source directories and single files. |
393 | |
394 - Shortens exclude list by globbing if possible. | |
395 - Exclude patterns are relative paths from the parent directory. | |
396 """ | |
397 excludes = [] | |
398 files_to_include = set(wanted_files) | |
399 files_to_exclude = set(unwanted_files) | |
400 while files_to_exclude: | |
401 unwanted_file = files_to_exclude.pop() | |
402 target_exclude = os.path.join( | |
403 os.path.dirname(unwanted_file), '*.java') | |
404 found_files = set(glob.glob(target_exclude)) | |
405 valid_files = found_files & files_to_include | |
406 if valid_files: | |
407 excludes.append(os.path.relpath(unwanted_file, parent_dir)) | |
408 else: | |
409 excludes.append(os.path.relpath(target_exclude, parent_dir)) | |
410 files_to_exclude -= found_files | |
411 return excludes | |
412 | |
413 | |
414 def _ComputeJavaSourceDirsAndExcludes(output_dir, java_files): | |
415 """Computes the list of java source directories and exclude patterns. | |
416 | 392 |
417 1. Computes the root java source directories from the list of files. | 393 1. Computes the root java source directories from the list of files. |
418 2. Compute exclude patterns that exclude all extra files only. | 394 2. Compute single files that are not included in full directories. |
419 3. Returns the list of java source directories and exclude patterns. | 395 3. Returns the list of java source directories and single files. |
420 """ | 396 """ |
421 java_dirs = [] | 397 java_dirs = [] |
422 excludes = [] | 398 single_files = set() |
423 if java_files: | 399 if java_files: |
424 java_files = _RebasePath(java_files) | 400 java_files = _RebasePath(java_files) |
425 computed_dirs = _ComputeJavaSourceDirs(java_files) | 401 computed_dirs = _ComputeJavaSourceDirs(java_files) |
426 java_dirs = computed_dirs.keys() | |
427 all_found_java_files = set() | 402 all_found_java_files = set() |
428 | 403 |
429 for directory, files in computed_dirs.iteritems(): | 404 for directory, files in computed_dirs.iteritems(): |
430 found_java_files = build_utils.FindInDirectory(directory, '*.java') | 405 found_java_files = build_utils.FindInDirectory(directory, '*.java') |
431 all_found_java_files.update(found_java_files) | 406 all_found_java_files.update(found_java_files) |
432 unwanted_java_files = set(found_java_files) - set(files) | 407 unwanted_java_files = set(found_java_files) - set(files) |
433 if unwanted_java_files: | 408 if unwanted_java_files: |
434 logging.debug('Directory requires excludes: %s', directory) | 409 logging.debug('Directory requires single files: %s', directory) |
435 excludes.extend( | 410 single_files.update(files) |
436 _ComputeExcludeFilters(files, unwanted_java_files, directory)) | 411 else: |
| 412 java_dirs.append(directory) |
437 | 413 |
438 missing_java_files = set(java_files) - all_found_java_files | 414 missing_java_files = set(java_files) - all_found_java_files |
439 # Warn only about non-generated files that are missing. | 415 # Warn only about non-generated files that are missing. |
440 missing_java_files = [p for p in missing_java_files | 416 missing_java_files = [p for p in missing_java_files |
441 if not p.startswith(output_dir)] | 417 if not p.startswith(output_dir)] |
442 if missing_java_files: | 418 if missing_java_files: |
443 logging.warning( | 419 logging.error( |
444 'Some java files were not found: %s', missing_java_files) | 420 'Some java files were not found: %s', missing_java_files) |
445 | 421 |
446 return java_dirs, excludes | 422 return java_dirs, list(single_files) |
447 | 423 |
448 | 424 |
449 def _CreateRelativeSymlink(target_path, link_path): | 425 def _CreateRelativeSymlink(target_path, link_path): |
450 link_dir = os.path.dirname(link_path) | 426 link_dir = os.path.dirname(link_path) |
451 relpath = os.path.relpath(target_path, link_dir) | 427 relpath = os.path.relpath(target_path, link_dir) |
452 logging.debug('Creating symlink %s -> %s', link_path, relpath) | 428 logging.debug('Creating symlink %s -> %s', link_path, relpath) |
453 os.symlink(relpath, link_path) | 429 os.symlink(relpath, link_path) |
454 | 430 |
455 | 431 |
456 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): | 432 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 return None | 488 return None |
513 | 489 |
514 variables['target_name'] = os.path.splitext(deps_info['name'])[0] | 490 variables['target_name'] = os.path.splitext(deps_info['name'])[0] |
515 variables['template_type'] = target_type | 491 variables['template_type'] = target_type |
516 variables['use_gradle_process_resources'] = ( | 492 variables['use_gradle_process_resources'] = ( |
517 generator.use_gradle_process_resources) | 493 generator.use_gradle_process_resources) |
518 source_properties = _ReadPropertiesFile( | 494 source_properties = _ReadPropertiesFile( |
519 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], | 495 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], |
520 'source.properties'))) | 496 'source.properties'))) |
521 variables['build_tools_version'] = source_properties['Pkg.Revision'] | 497 variables['build_tools_version'] = source_properties['Pkg.Revision'] |
| 498 # TODO(wnwen): Remove this line once http://crbug.com/688263 is fixed. |
| 499 variables['build_tools_version'] = '25.0.0' |
522 variables['compile_sdk_version'] = ( | 500 variables['compile_sdk_version'] = ( |
523 'android-%s' % build_vars['android_sdk_version']) | 501 'android-%s' % build_vars['android_sdk_version']) |
524 variables['main'] = generator.Generate(entry) | 502 variables['main'] = generator.Generate(entry) |
525 bootclasspath = gradle.get('bootclasspath') | 503 bootclasspath = gradle.get('bootclasspath') |
526 if bootclasspath: | 504 if bootclasspath: |
527 # Must use absolute path here. | 505 # Must use absolute path here. |
528 variables['bootclasspath'] = _RebasePath(bootclasspath) | 506 variables['bootclasspath'] = _RebasePath(bootclasspath) |
529 if entry.android_test_entry: | 507 if entry.android_test_entry: |
530 variables['android_test'] = generator.Generate( | 508 variables['android_test'] = generator.Generate( |
531 entry.android_test_entry) | 509 entry.android_test_entry) |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 | 709 |
732 if generated_inputs: | 710 if generated_inputs: |
733 logging.warning('Building generated source files...') | 711 logging.warning('Building generated source files...') |
734 targets = _RebasePath(generated_inputs, output_dir) | 712 targets = _RebasePath(generated_inputs, output_dir) |
735 _RunNinja(output_dir, targets) | 713 _RunNinja(output_dir, targets) |
736 | 714 |
737 if zip_tuples: | 715 if zip_tuples: |
738 _ExtractZips(generator.project_dir, zip_tuples) | 716 _ExtractZips(generator.project_dir, zip_tuples) |
739 | 717 |
740 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 718 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
741 logging.warning('Generated projects work best with Android Studio 2.2') | 719 logging.warning('Generated projects are targeting Android Studio 2.3') |
742 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 720 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
743 '/src.git/+/master/docs/android_studio.md') | 721 '/src.git/+/master/docs/android_studio.md') |
744 | 722 |
745 | 723 |
746 if __name__ == '__main__': | 724 if __name__ == '__main__': |
747 main() | 725 main() |
OLD | NEW |