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 | 10 import glob |
(...skipping 17 matching lines...) Expand all Loading... | |
28 from util import build_utils | 28 from util import build_utils |
29 | 29 |
30 | 30 |
31 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( | 31 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( |
32 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') | 32 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') |
33 _FILE_DIR = os.path.dirname(__file__) | 33 _FILE_DIR = os.path.dirname(__file__) |
34 _SRCJARS_SUBDIR = 'extracted-srcjars' | 34 _SRCJARS_SUBDIR = 'extracted-srcjars' |
35 _JNI_LIBS_SUBDIR = 'symlinked-libs' | 35 _JNI_LIBS_SUBDIR = 'symlinked-libs' |
36 _ARMEABI_SUBDIR = 'armeabi' | 36 _ARMEABI_SUBDIR = 'armeabi' |
37 _RES_SUBDIR = 'extracted-res' | 37 _RES_SUBDIR = 'extracted-res' |
38 _GRADLE_BUILD_FILE = 'build.gradle' | |
39 _PSEUDO_NAME = 'a_pseudo_module' | |
agrieve
2017/04/12 19:36:29
nit: is the "a" need to be there so it comes alpha
Peter Wen
2017/04/13 17:23:16
Added comment, changed to _all
| |
38 | 40 |
39 _DEFAULT_TARGETS = [ | 41 _DEFAULT_TARGETS = [ |
40 # TODO(agrieve): .build_config seem not quite right for this target | 42 # TODO(agrieve): .build_config seem not quite right for this target |
41 # because it has resources as deps of android_apk() rather than using an | 43 # because it has resources as deps of android_apk() rather than using an |
42 # android_library() intermediate target. | 44 # android_library() intermediate target. |
43 # '//android_webview:system_webview_apk', | 45 # '//android_webview:system_webview_apk', |
44 '//android_webview/test:android_webview_apk', | 46 '//android_webview/test:android_webview_apk', |
45 '//android_webview/test:android_webview_test_apk', | 47 '//android_webview/test:android_webview_test_apk', |
46 '//base:base_junit_tests', | 48 '//base:base_junit_tests', |
47 '//chrome/android:chrome_junit_tests', | 49 '//chrome/android:chrome_junit_tests', |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
230 for p in self.Gradle()['dependent_java_projects']) | 232 for p in self.Gradle()['dependent_java_projects']) |
231 all_entries = set() | 233 all_entries = set() |
232 for dep in deps: | 234 for dep in deps: |
233 all_entries.update(dep.AllEntries()) | 235 all_entries.update(dep.AllEntries()) |
234 all_entries.add(self) | 236 all_entries.add(self) |
235 self._all_entries = list(all_entries) | 237 self._all_entries = list(all_entries) |
236 return self._all_entries | 238 return self._all_entries |
237 | 239 |
238 | 240 |
239 class _ProjectContextGenerator(object): | 241 class _ProjectContextGenerator(object): |
242 | |
243 java_dirs = set() | |
agrieve
2017/04/12 19:36:29
This is a singleton class, so it's a bit confusing
Peter Wen
2017/04/13 17:23:17
Done.
| |
244 prebuilts = set() | |
245 | |
240 """Helper class to generate gradle build files""" | 246 """Helper class to generate gradle build files""" |
241 def __init__(self, project_dir, build_vars, use_gradle_process_resources, | 247 def __init__(self, project_dir, build_vars, use_gradle_process_resources, |
242 jinja_processor, split_projects): | 248 jinja_processor, split_projects): |
243 self.project_dir = project_dir | 249 self.project_dir = project_dir |
244 self.build_vars = build_vars | 250 self.build_vars = build_vars |
245 self.use_gradle_process_resources = use_gradle_process_resources | 251 self.use_gradle_process_resources = use_gradle_process_resources |
246 self.jinja_processor = jinja_processor | 252 self.jinja_processor = jinja_processor |
247 self.split_projects = split_projects | 253 self.split_projects = split_projects |
248 | 254 |
249 def _GenJniLibs(self, root_entry): | 255 def _GenJniLibs(self, root_entry): |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 for entry in self._GetEntries(root_entry): | 333 for entry in self._GetEntries(root_entry): |
328 generated_inputs.update(entry.GeneratedJavaFiles()) | 334 generated_inputs.update(entry.GeneratedJavaFiles()) |
329 generated_inputs.update(entry.PrebuiltJars()) | 335 generated_inputs.update(entry.PrebuiltJars()) |
330 return set(generated_inputs) | 336 return set(generated_inputs) |
331 | 337 |
332 def Generate(self, root_entry): | 338 def Generate(self, root_entry): |
333 # TODO(agrieve): Add an option to use interface jars and see if that speeds | 339 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
334 # things up at all. | 340 # things up at all. |
335 variables = {} | 341 variables = {} |
336 java_dirs, excludes = self._GenJavaDirs(root_entry) | 342 java_dirs, excludes = self._GenJavaDirs(root_entry) |
343 java_dirs.append( | |
344 os.path.join(self.EntryOutputDir(root_entry), _SRCJARS_SUBDIR)) | |
345 self.java_dirs.update(java_dirs) | |
337 java_dirs.sort() | 346 java_dirs.sort() |
338 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) | 347 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) |
339 variables['java_dirs'].append(_SRCJARS_SUBDIR) | |
340 variables['java_excludes'] = excludes | 348 variables['java_excludes'] = excludes |
341 variables['jni_libs'] = self._Relativize( | 349 variables['jni_libs'] = self._Relativize( |
342 root_entry, set(self._GenJniLibs(root_entry))) | 350 root_entry, set(self._GenJniLibs(root_entry))) |
343 variables['prebuilts'] = [ | 351 variables['prebuilts'] = [ |
344 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] | 352 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] |
353 self.prebuilts.update(variables['prebuilts']) | |
345 variables['res_dirs'] = [ | 354 variables['res_dirs'] = [ |
346 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] | 355 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] |
347 for entry in self._GetEntries(root_entry): | 356 for entry in self._GetEntries(root_entry): |
348 variables['prebuilts'] += entry.PrebuiltJars() | 357 variables['prebuilts'] += entry.PrebuiltJars() |
349 variables['res_dirs'] += entry.ResDirs() | 358 variables['res_dirs'] += entry.ResDirs() |
350 variables['prebuilts'] = self._Relativize( | 359 variables['prebuilts'] = self._Relativize( |
351 root_entry, set(variables['prebuilts'])) | 360 root_entry, set(variables['prebuilts'])) |
352 variables['res_dirs'] = self._Relativize( | 361 variables['res_dirs'] = self._Relativize( |
353 root_entry, set(variables['res_dirs'])) | 362 root_entry, set(variables['res_dirs'])) |
354 variables['res_dirs'].append(_RES_SUBDIR) | 363 variables['res_dirs'].append(_RES_SUBDIR) |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 entry.android_test_entry) | 540 entry.android_test_entry) |
532 for key, value in variables['android_test'].iteritems(): | 541 for key, value in variables['android_test'].iteritems(): |
533 if isinstance(value, list): | 542 if isinstance(value, list): |
534 variables['android_test'][key] = list( | 543 variables['android_test'][key] = list( |
535 set(value) - set(variables['main'][key])) | 544 set(value) - set(variables['main'][key])) |
536 | 545 |
537 return jinja_processor.Render( | 546 return jinja_processor.Render( |
538 _TemplatePath(target_type.split('_')[0]), variables) | 547 _TemplatePath(target_type.split('_')[0]), variables) |
539 | 548 |
540 | 549 |
550 def _GeneratePseudoModule(gradle_output_dir, generator, build_vars, | |
551 jinja_processor): | |
552 """Returns the data for a pseudo build.gradle of all dirs.""" | |
agrieve
2017/04/12 19:36:29
what makes it pseudo? Is it not a real module? May
Peter Wen
2017/04/13 17:23:17
Changed name to "All"
| |
553 | |
554 variables = { | |
555 'sourceSetName': 'main', | |
556 'depCompileName': 'compile', | |
557 'target_name': _PSEUDO_NAME, | |
558 } | |
559 target_type = 'android_apk' | |
560 variables['template_type'] = target_type | |
561 variables['use_gradle_process_resources'] = ( | |
562 generator.use_gradle_process_resources) | |
563 source_properties = _ReadPropertiesFile( | |
agrieve
2017/04/12 19:36:29
Please figure out how to re-use rather than copy &
Peter Wen
2017/04/13 17:23:17
Done.
| |
564 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], | |
565 'source.properties'))) | |
566 variables['build_tools_version'] = source_properties['Pkg.Revision'] | |
567 variables['compile_sdk_version'] = ( | |
568 'android-%s' % build_vars['android_sdk_version']) | |
569 def Relativize(paths): | |
570 return _RebasePath(paths, os.path.join(gradle_output_dir, _PSEUDO_NAME)) | |
571 java_dirs = list(_ProjectContextGenerator.java_dirs) | |
572 java_dirs.sort() | |
573 prebuilts = list(_ProjectContextGenerator.prebuilts) | |
574 prebuilts.sort() | |
575 variables['main'] = { | |
576 'android_manifest': Relativize(_DEFAULT_ANDROID_MANIFEST_PATH), | |
577 'java_dirs': Relativize(java_dirs), | |
578 'prebuilts': Relativize(prebuilts), | |
579 'java_excludes': ['**/*.java'], | |
580 # TODO(wnwen): exclude everything | |
581 } | |
582 data = jinja_processor.Render( | |
583 _TemplatePath(target_type.split('_')[0]), variables) | |
584 _WriteFile( | |
585 os.path.join(gradle_output_dir, _PSEUDO_NAME, _GRADLE_BUILD_FILE), data) | |
586 | |
587 | |
541 def _GenerateRootGradle(jinja_processor): | 588 def _GenerateRootGradle(jinja_processor): |
542 """Returns the data for the root project's build.gradle.""" | 589 """Returns the data for the root project's build.gradle.""" |
543 return jinja_processor.Render(_TemplatePath('root')) | 590 return jinja_processor.Render(_TemplatePath('root')) |
544 | 591 |
545 | 592 |
546 def _GenerateSettingsGradle(project_entries): | 593 def _GenerateSettingsGradle(project_entries, avoid_pseudo_module): |
547 """Returns the data for settings.gradle.""" | 594 """Returns the data for settings.gradle.""" |
548 project_name = os.path.basename(os.path.dirname(host_paths.DIR_SOURCE_ROOT)) | 595 project_name = os.path.basename(os.path.dirname(host_paths.DIR_SOURCE_ROOT)) |
549 lines = [] | 596 lines = [] |
550 lines.append('// Generated by //build/android/gradle/generate_gradle.py') | 597 lines.append('// Generated by //build/android/gradle/generate_gradle.py') |
551 lines.append('rootProject.name = "%s"' % project_name) | 598 lines.append('rootProject.name = "%s"' % project_name) |
552 lines.append('rootProject.projectDir = settingsDir') | 599 lines.append('rootProject.projectDir = settingsDir') |
553 lines.append('') | 600 lines.append('') |
554 | 601 |
602 if not avoid_pseudo_module: | |
603 lines.append('include ":{0}"'.format(_PSEUDO_NAME)) | |
604 lines.append( | |
605 'project(":{0}").projectDir = new File(settingsDir, "{0}")'.format( | |
606 _PSEUDO_NAME)) | |
555 for entry in project_entries: | 607 for entry in project_entries: |
556 # Example target: android_webview:android_webview_java__build_config | 608 # Example target: android_webview:android_webview_java__build_config |
557 lines.append('include ":%s"' % entry.ProjectName()) | 609 lines.append('include ":%s"' % entry.ProjectName()) |
558 lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' % | 610 lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' % |
559 (entry.ProjectName(), entry.GradleSubdir())) | 611 (entry.ProjectName(), entry.GradleSubdir())) |
560 return '\n'.join(lines) | 612 return '\n'.join(lines) |
561 | 613 |
562 | 614 |
563 def _ExtractFile(zip_path, extracted_path): | 615 def _ExtractFile(zip_path, extracted_path): |
564 logging.info('Extracting %s to %s', zip_path, extracted_path) | 616 logging.info('Extracting %s to %s', zip_path, extracted_path) |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 parser.add_argument('--all', | 698 parser.add_argument('--all', |
647 action='store_true', | 699 action='store_true', |
648 help='Generate all java targets (slows down IDE)') | 700 help='Generate all java targets (slows down IDE)') |
649 parser.add_argument('--use-gradle-process-resources', | 701 parser.add_argument('--use-gradle-process-resources', |
650 action='store_true', | 702 action='store_true', |
651 help='Have gradle generate R.java rather than ninja') | 703 help='Have gradle generate R.java rather than ninja') |
652 parser.add_argument('--split-projects', | 704 parser.add_argument('--split-projects', |
653 action='store_true', | 705 action='store_true', |
654 help='Split projects by their gn deps rather than ' | 706 help='Split projects by their gn deps rather than ' |
655 'combining all the dependencies of each target') | 707 'combining all the dependencies of each target') |
708 parser.add_argument('--avoid-pseudo-module', | |
709 action='store_true', | |
710 help='Prevent an overall pseudo module from being ' | |
agrieve
2017/04/12 19:36:29
Please explain why you might ever want to do this
Peter Wen
2017/04/13 17:23:16
Removed.
Hmm... just an escape hatch I added, not
| |
711 'generated (not applicable to split projects)') | |
656 args = parser.parse_args() | 712 args = parser.parse_args() |
657 if args.output_directory: | 713 if args.output_directory: |
658 constants.SetOutputDirectory(args.output_directory) | 714 constants.SetOutputDirectory(args.output_directory) |
659 constants.CheckOutputDirectory() | 715 constants.CheckOutputDirectory() |
660 output_dir = constants.GetOutDirectory() | 716 output_dir = constants.GetOutDirectory() |
661 devil_chromium.Initialize(output_directory=output_dir) | 717 devil_chromium.Initialize(output_directory=output_dir) |
662 run_tests_helper.SetLogLevel(args.verbose_count) | 718 run_tests_helper.SetLogLevel(args.verbose_count) |
663 | 719 |
664 # TODO(wnwen): Fix packaging so that gradle resources work in this case. | 720 # TODO(wnwen): Fix packaging so that gradle resources work in this case. |
665 if args.use_gradle_process_resources: | 721 if args.split_projects: |
666 assert args.split_projects, ( | 722 args.avoid_pseudo_module = True |
667 'Gradle resources does not yet work without --split-projects.') | 723 assert not args.use_gradle_process_resources, ( |
724 'Gradle resources does not work without --split-projects.') | |
668 | 725 |
669 _gradle_output_dir = os.path.abspath( | 726 _gradle_output_dir = os.path.abspath( |
670 args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir)) | 727 args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir)) |
671 jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) | 728 jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) |
672 build_vars = _ReadPropertiesFile(os.path.join(output_dir, 'build_vars.txt')) | 729 build_vars = _ReadPropertiesFile(os.path.join(output_dir, 'build_vars.txt')) |
673 generator = _ProjectContextGenerator(_gradle_output_dir, build_vars, | 730 generator = _ProjectContextGenerator(_gradle_output_dir, build_vars, |
674 args.use_gradle_process_resources, jinja_processor, args.split_projects) | 731 args.use_gradle_process_resources, jinja_processor, args.split_projects) |
675 logging.warning('Creating project at: %s', generator.project_dir) | 732 logging.warning('Creating project at: %s', generator.project_dir) |
676 | 733 |
677 if args.all: | 734 if args.all: |
(...skipping 11 matching lines...) Expand all Loading... | |
689 for t in targets] | 746 for t in targets] |
690 | 747 |
691 main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets] | 748 main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets] |
692 | 749 |
693 logging.warning('Building .build_config files...') | 750 logging.warning('Building .build_config files...') |
694 _RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries]) | 751 _RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries]) |
695 | 752 |
696 # There are many unused libraries, so restrict to those that are actually used | 753 # There are many unused libraries, so restrict to those that are actually used |
697 # when using --all. | 754 # when using --all. |
698 if args.all: | 755 if args.all: |
699 main_entries = [e for e in main_entries if e.GetType() == 'android_apk'] | 756 main_entries = [e for e in main_entries if ( |
757 e.GetType() == 'android_apk' or | |
758 e.GnTarget().endswith('_test_apk__apk') or | |
759 e.GnTarget().endswith('_junit_tests__java_binary'))] | |
700 | 760 |
701 if args.split_projects: | 761 if args.split_projects: |
702 main_entries = _FindAllProjectEntries(main_entries) | 762 main_entries = _FindAllProjectEntries(main_entries) |
703 logging.info('Found %d dependent build_config targets.', len(main_entries)) | 763 logging.info('Found %d dependent build_config targets.', len(main_entries)) |
704 entries = _CombineTestEntries(main_entries) | 764 entries = _CombineTestEntries(main_entries) |
705 logging.info('Creating %d projects for targets.', len(entries)) | 765 logging.info('Creating %d projects for targets.', len(entries)) |
706 | 766 |
707 logging.warning('Writing .gradle files...') | 767 logging.warning('Writing .gradle files...') |
708 project_entries = [] | 768 project_entries = [] |
709 zip_tuples = [] | 769 zip_tuples = [] |
710 generated_inputs = [] | 770 generated_inputs = [] |
711 for entry in entries: | 771 for entry in entries: |
712 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'): | 772 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'): |
713 continue | 773 continue |
714 | 774 |
715 data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor) | 775 data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor) |
716 if data: | 776 if data: |
717 project_entries.append(entry) | 777 project_entries.append(entry) |
718 # Build all paths references by .gradle that exist within output_dir. | 778 # Build all paths references by .gradle that exist within output_dir. |
719 generated_inputs.extend(generator.GeneratedInputs(entry)) | 779 generated_inputs.extend(generator.GeneratedInputs(entry)) |
720 zip_tuples.extend( | 780 zip_tuples.extend( |
721 (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) | 781 (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) |
722 for s in generator.AllSrcjars(entry)) | 782 for s in generator.AllSrcjars(entry)) |
723 zip_tuples.extend( | 783 zip_tuples.extend( |
724 (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR)) | 784 (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR)) |
725 for s in generator.AllResZips(entry)) | 785 for s in generator.AllResZips(entry)) |
726 _WriteFile( | 786 _WriteFile( |
727 os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data) | 787 os.path.join(generator.EntryOutputDir(entry), _GRADLE_BUILD_FILE), |
788 data) | |
728 | 789 |
729 _WriteFile(os.path.join(generator.project_dir, 'build.gradle'), | 790 if not args.avoid_pseudo_module: |
791 _GeneratePseudoModule( | |
792 _gradle_output_dir, generator, build_vars, jinja_processor) | |
793 | |
794 _WriteFile(os.path.join(generator.project_dir, _GRADLE_BUILD_FILE), | |
730 _GenerateRootGradle(jinja_processor)) | 795 _GenerateRootGradle(jinja_processor)) |
731 | 796 |
732 _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'), | 797 _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'), |
733 _GenerateSettingsGradle(project_entries)) | 798 _GenerateSettingsGradle(project_entries, args.avoid_pseudo_module)) |
734 | 799 |
735 sdk_path = _RebasePath(build_vars['android_sdk_root']) | 800 sdk_path = _RebasePath(build_vars['android_sdk_root']) |
736 _WriteFile(os.path.join(generator.project_dir, 'local.properties'), | 801 _WriteFile(os.path.join(generator.project_dir, 'local.properties'), |
737 _GenerateLocalProperties(sdk_path)) | 802 _GenerateLocalProperties(sdk_path)) |
738 | 803 |
739 if generated_inputs: | 804 if generated_inputs: |
740 logging.warning('Building generated source files...') | 805 logging.warning('Building generated source files...') |
741 targets = _RebasePath(generated_inputs, output_dir) | 806 targets = _RebasePath(generated_inputs, output_dir) |
742 _RunNinja(output_dir, targets) | 807 _RunNinja(output_dir, targets) |
743 | 808 |
744 if zip_tuples: | 809 if zip_tuples: |
745 _ExtractZips(generator.project_dir, zip_tuples) | 810 _ExtractZips(generator.project_dir, zip_tuples) |
746 | 811 |
747 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 812 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
748 logging.warning('Generated projects work with Android Studio 2.3') | 813 logging.warning('Generated projects work with Android Studio 2.3') |
749 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 814 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
750 '/src.git/+/master/docs/android_studio.md') | 815 '/src.git/+/master/docs/android_studio.md') |
751 | 816 |
752 | 817 |
753 if __name__ == '__main__': | 818 if __name__ == '__main__': |
754 main() | 819 main() |
OLD | NEW |