Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(705)

Side by Side Diff: build/android/gradle/generate_gradle.py

Issue 2708133002: Android: Android studio single module per target (Closed)
Patch Set: Rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/android/gradle/dependencies.jinja ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 return self.BuildConfig()['gradle'] 190 return self.BuildConfig()['gradle']
191 191
192 def Javac(self): 192 def Javac(self):
193 return self.BuildConfig()['javac'] 193 return self.BuildConfig()['javac']
194 194
195 def GetType(self): 195 def GetType(self):
196 """Returns the target type from its .build_config.""" 196 """Returns the target type from its .build_config."""
197 return self.DepsInfo()['type'] 197 return self.DepsInfo()['type']
198 198
199 def ResZips(self): 199 def ResZips(self):
200 return self.DepsInfo().get('owned_resources_zips') 200 return self.DepsInfo().get('owned_resources_zips', [])
201
202 def ResDirs(self):
203 return self.DepsInfo().get('owned_resources_dirs', [])
201 204
202 def JavaFiles(self): 205 def JavaFiles(self):
203 if self._java_files is None: 206 if self._java_files is None:
204 java_sources_file = self.Gradle().get('java_sources_file') 207 java_sources_file = self.Gradle().get('java_sources_file')
205 java_files = [] 208 java_files = []
206 if java_sources_file: 209 if java_sources_file:
207 java_sources_file = _RebasePath(java_sources_file) 210 java_sources_file = _RebasePath(java_sources_file)
208 java_files = build_utils.ReadSourcesList(java_sources_file) 211 java_files = build_utils.ReadSourcesList(java_sources_file)
209 self._java_files = java_files 212 self._java_files = java_files
210 return self._java_files 213 return self._java_files
211 214
212 def GeneratedJavaFiles(self): 215 def GeneratedJavaFiles(self):
213 return [p for p in self.JavaFiles() if not p.startswith('..')] 216 return [p for p in self.JavaFiles() if not p.startswith('..')]
214 217
215 def PrebuiltJars(self): 218 def PrebuiltJars(self):
216 return self.Gradle()['dependent_prebuilt_jars'] 219 return self.Gradle().get('dependent_prebuilt_jars', [])
217 220
218 def AllEntries(self): 221 def AllEntries(self):
219 """Returns a list of all entries that the current entry depends on. 222 """Returns a list of all entries that the current entry depends on.
220 223
221 This includes the entry itself to make iterating simpler.""" 224 This includes the entry itself to make iterating simpler."""
222 if self._all_entries is None: 225 if self._all_entries is None:
223 logging.debug('Generating entries for %s', self.GnTarget()) 226 logging.debug('Generating entries for %s', self.GnTarget())
224 deps = [_ProjectEntry.FromBuildConfigPath(p) 227 deps = [_ProjectEntry.FromBuildConfigPath(p)
225 for p in self.Gradle()['dependent_android_projects']] 228 for p in self.Gradle()['dependent_android_projects']]
226 deps.extend(_ProjectEntry.FromBuildConfigPath(p) 229 deps.extend(_ProjectEntry.FromBuildConfigPath(p)
227 for p in self.Gradle()['dependent_java_projects']) 230 for p in self.Gradle()['dependent_java_projects'])
228 all_entries = set() 231 all_entries = set()
229 for dep in deps: 232 for dep in deps:
230 all_entries.update(dep.AllEntries()) 233 all_entries.update(dep.AllEntries())
231 all_entries.add(self) 234 all_entries.add(self)
232 self._all_entries = list(all_entries) 235 self._all_entries = list(all_entries)
233 return self._all_entries 236 return self._all_entries
234 237
235 238
236 class _ProjectContextGenerator(object): 239 class _ProjectContextGenerator(object):
237 """Helper class to generate gradle build files""" 240 """Helper class to generate gradle build files"""
238 def __init__(self, project_dir, build_vars, use_gradle_process_resources, 241 def __init__(self, project_dir, build_vars, use_gradle_process_resources,
239 jinja_processor): 242 jinja_processor, split_projects):
240 self.project_dir = project_dir 243 self.project_dir = project_dir
241 self.build_vars = build_vars 244 self.build_vars = build_vars
242 self.use_gradle_process_resources = use_gradle_process_resources 245 self.use_gradle_process_resources = use_gradle_process_resources
243 self.jinja_processor = jinja_processor 246 self.jinja_processor = jinja_processor
247 self.split_projects = split_projects
244 248
245 def _GenJniLibs(self, entry): 249 def _GenJniLibs(self, root_entry):
246 native_section = entry.BuildConfig().get('native') 250 libraries = []
247 if native_section: 251 for entry in self._GetEntries(root_entry):
248 jni_libs = _CreateJniLibsDir( 252 libraries += entry.BuildConfig().get('native', [])
249 constants.GetOutDirectory(), self.EntryOutputDir(entry), 253 if libraries:
250 native_section.get('libraries')) 254 return _CreateJniLibsDir(constants.GetOutDirectory(),
251 else: 255 self.EntryOutputDir(root_entry), libraries)
252 jni_libs = [] 256 return []
253 return jni_libs
254 257
255 def _GenJavaDirs(self, entry): 258 def _GenJavaDirs(self, root_entry):
259 java_files = []
260 for entry in self._GetEntries(root_entry):
261 java_files += entry.JavaFiles()
256 java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes( 262 java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes(
257 constants.GetOutDirectory(), entry.JavaFiles()) 263 constants.GetOutDirectory(), java_files)
258 if self.Srcjars(entry):
259 java_dirs.append(
260 os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR))
261 return java_dirs, excludes 264 return java_dirs, excludes
262 265
263 def _GenResDirs(self, entry):
264 res_dirs = list(entry.DepsInfo().get('owned_resources_dirs', []))
265 if entry.ResZips():
266 res_dirs.append(os.path.join(self.EntryOutputDir(entry), _RES_SUBDIR))
267 return res_dirs
268
269 def _GenCustomManifest(self, entry): 266 def _GenCustomManifest(self, entry):
270 """Returns the path to the generated AndroidManifest.xml. 267 """Returns the path to the generated AndroidManifest.xml.
271 268
272 Gradle uses package id from manifest when generating R.class. So, we need 269 Gradle uses package id from manifest when generating R.class. So, we need
273 to generate a custom manifest if we let gradle process resources. We cannot 270 to generate a custom manifest if we let gradle process resources. We cannot
274 simply set android.defaultConfig.applicationId because it is not supported 271 simply set android.defaultConfig.applicationId because it is not supported
275 for library targets.""" 272 for library targets."""
276 resource_packages = entry.Javac().get('resource_packages') 273 resource_packages = entry.Javac().get('resource_packages')
277 if not resource_packages: 274 if not resource_packages:
278 logging.debug('Target ' + entry.GnTarget() + ' includes resources from ' 275 logging.debug('Target ' + entry.GnTarget() + ' includes resources from '
(...skipping 11 matching lines...) Expand all
290 output_file = os.path.join( 287 output_file = os.path.join(
291 self.EntryOutputDir(entry), 'AndroidManifest.xml') 288 self.EntryOutputDir(entry), 'AndroidManifest.xml')
292 data = self.jinja_processor.Render(_TemplatePath('manifest'), variables) 289 data = self.jinja_processor.Render(_TemplatePath('manifest'), variables)
293 _WriteFile(output_file, data) 290 _WriteFile(output_file, data)
294 291
295 return output_file 292 return output_file
296 293
297 def _Relativize(self, entry, paths): 294 def _Relativize(self, entry, paths):
298 return _RebasePath(paths, self.EntryOutputDir(entry)) 295 return _RebasePath(paths, self.EntryOutputDir(entry))
299 296
300 def EntryOutputDir(self, entry): 297 def _Srcjars(self, entry):
301 return os.path.join(self.project_dir, entry.GradleSubdir())
302
303 def Srcjars(self, entry):
304 srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) 298 srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', []))
305 if not self.use_gradle_process_resources: 299 if not self.use_gradle_process_resources:
306 srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) 300 srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars'])
307 return srcjars 301 return srcjars
308 302
309 def GeneratedInputs(self, entry): 303 def _GetEntries(self, entry):
310 generated_inputs = [] 304 if self.split_projects:
311 generated_inputs.extend(self.Srcjars(entry)) 305 return [entry]
312 generated_inputs.extend(_RebasePath(entry.ResZips())) 306 return entry.AllEntries()
313 generated_inputs.extend(entry.GeneratedJavaFiles())
314 generated_inputs.extend(entry.PrebuiltJars())
315 return generated_inputs
316 307
317 def Generate(self, entry): 308 def EntryOutputDir(self, entry):
318 variables = {} 309 return os.path.join(self.project_dir, entry.GradleSubdir())
319 java_dirs, excludes = self._GenJavaDirs(entry) 310
320 variables['java_dirs'] = self._Relativize(entry, java_dirs) 311 def AllSrcjars(self, root_entry):
321 variables['java_excludes'] = excludes 312 srcjars = []
322 variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) 313 for entry in self._GetEntries(root_entry):
323 variables['res_dirs'] = self._Relativize(entry, self._GenResDirs(entry)) 314 srcjars += self._Srcjars(entry)
324 android_manifest = entry.Gradle().get('android_manifest') 315 return set(srcjars)
325 if not android_manifest: 316
326 android_manifest = self._GenCustomManifest(entry) 317 def AllResZips(self, root_entry):
327 variables['android_manifest'] = self._Relativize(entry, android_manifest) 318 res_zips = []
319 for entry in self._GetEntries(root_entry):
320 res_zips += entry.ResZips()
321 return set(_RebasePath(res_zips))
322
323 def GeneratedInputs(self, root_entry):
324 generated_inputs = set(self.AllResZips(root_entry))
325 generated_inputs.update(self.AllSrcjars(root_entry))
326 for entry in self._GetEntries(root_entry):
327 generated_inputs.update(entry.GeneratedJavaFiles())
328 generated_inputs.update(entry.PrebuiltJars())
329 return set(generated_inputs)
330
331 def Generate(self, root_entry):
328 # 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
329 # things up at all. 333 # things up at all.
330 variables['prebuilts'] = self._Relativize(entry, entry.PrebuiltJars()) 334 variables = {}
331 deps = [_ProjectEntry.FromBuildConfigPath(p) 335 java_dirs, excludes = self._GenJavaDirs(root_entry)
332 for p in entry.Gradle()['dependent_android_projects']] 336 java_dirs.sort()
333 variables['android_project_deps'] = [d.ProjectName() for d in deps] 337 variables['java_dirs'] = self._Relativize(root_entry, java_dirs)
334 deps = [_ProjectEntry.FromBuildConfigPath(p) 338 variables['java_dirs'].append(_SRCJARS_SUBDIR)
335 for p in entry.Gradle()['dependent_java_projects']] 339 variables['java_excludes'] = excludes
336 variables['java_project_deps'] = [d.ProjectName() for d in deps] 340 variables['jni_libs'] = self._Relativize(
341 root_entry, set(self._GenJniLibs(root_entry)))
342 variables['prebuilts'] = [
343 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()]
344 variables['res_dirs'] = [
345 p for e in self._GetEntries(root_entry) for p in e.ResDirs()]
346 for entry in self._GetEntries(root_entry):
347 variables['prebuilts'] += entry.PrebuiltJars()
348 variables['res_dirs'] += entry.ResDirs()
349 variables['prebuilts'] = self._Relativize(
350 root_entry, set(variables['prebuilts']))
351 variables['res_dirs'] = self._Relativize(
352 root_entry, set(variables['res_dirs']))
353 variables['res_dirs'].append(_RES_SUBDIR)
354 android_manifest = root_entry.Gradle().get('android_manifest')
355 if not android_manifest:
356 android_manifest = self._GenCustomManifest(root_entry)
357 variables['android_manifest'] = self._Relativize(
358 root_entry, android_manifest)
359 if self.split_projects:
360 deps = [_ProjectEntry.FromBuildConfigPath(p)
361 for p in root_entry.Gradle()['dependent_android_projects']]
362 variables['android_project_deps'] = [d.ProjectName() for d in deps]
363 deps = [_ProjectEntry.FromBuildConfigPath(p)
364 for p in root_entry.Gradle()['dependent_java_projects']]
365 variables['java_project_deps'] = [d.ProjectName() for d in deps]
337 return variables 366 return variables
338 367
339 368
340 def _ComputeJavaSourceDirs(java_files): 369 def _ComputeJavaSourceDirs(java_files):
341 """Returns a dictionary of source dirs with each given files in one.""" 370 """Returns a dictionary of source dirs with each given files in one."""
342 found_roots = {} 371 found_roots = {}
343 for path in java_files: 372 for path in java_files:
344 path_root = path 373 path_root = path
345 # Recognize these tokens as top-level. 374 # Recognize these tokens as top-level.
346 while True: 375 while True:
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 'May be repeated.') 633 'May be repeated.')
605 parser.add_argument('--project-dir', 634 parser.add_argument('--project-dir',
606 help='Root of the output project.', 635 help='Root of the output project.',
607 default=os.path.join('$CHROMIUM_OUTPUT_DIR', 'gradle')) 636 default=os.path.join('$CHROMIUM_OUTPUT_DIR', 'gradle'))
608 parser.add_argument('--all', 637 parser.add_argument('--all',
609 action='store_true', 638 action='store_true',
610 help='Generate all java targets (slows down IDE)') 639 help='Generate all java targets (slows down IDE)')
611 parser.add_argument('--use-gradle-process-resources', 640 parser.add_argument('--use-gradle-process-resources',
612 action='store_true', 641 action='store_true',
613 help='Have gradle generate R.java rather than ninja') 642 help='Have gradle generate R.java rather than ninja')
643 parser.add_argument('--split-projects',
644 action='store_true',
645 help='Split projects by their gn deps rather than '
646 'combining all the dependencies of each target')
614 args = parser.parse_args() 647 args = parser.parse_args()
615 if args.output_directory: 648 if args.output_directory:
616 constants.SetOutputDirectory(args.output_directory) 649 constants.SetOutputDirectory(args.output_directory)
617 constants.CheckOutputDirectory() 650 constants.CheckOutputDirectory()
618 output_dir = constants.GetOutDirectory() 651 output_dir = constants.GetOutDirectory()
619 devil_chromium.Initialize(output_directory=output_dir) 652 devil_chromium.Initialize(output_directory=output_dir)
620 run_tests_helper.SetLogLevel(args.verbose_count) 653 run_tests_helper.SetLogLevel(args.verbose_count)
621 654
655 # TODO(wnwen): Fix packaging so that gradle resources work in this case.
656 if args.use_gradle_process_resources:
657 assert args.split_projects, (
658 'Gradle resources does not yet work without --split-projects.')
659
622 _gradle_output_dir = os.path.abspath( 660 _gradle_output_dir = os.path.abspath(
623 args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir)) 661 args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir))
624 jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) 662 jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR)
625 build_vars = _ReadBuildVars(output_dir) 663 build_vars = _ReadBuildVars(output_dir)
626 generator = _ProjectContextGenerator(_gradle_output_dir, build_vars, 664 generator = _ProjectContextGenerator(_gradle_output_dir, build_vars,
627 args.use_gradle_process_resources, jinja_processor) 665 args.use_gradle_process_resources, jinja_processor, args.split_projects)
628 logging.warning('Creating project at: %s', generator.project_dir) 666 logging.warning('Creating project at: %s', generator.project_dir)
629 667
630 if args.all: 668 if args.all:
631 # Run GN gen if necessary (faster than running "gn gen" in the no-op case). 669 # Run GN gen if necessary (faster than running "gn gen" in the no-op case).
632 _RunNinja(constants.GetOutDirectory(), ['build.ninja']) 670 _RunNinja(constants.GetOutDirectory(), ['build.ninja'])
633 # Query ninja for all __build_config targets. 671 # Query ninja for all __build_config targets.
634 targets = _QueryForAllGnTargets(output_dir) 672 targets = _QueryForAllGnTargets(output_dir)
635 else: 673 else:
636 targets = args.targets or _DEFAULT_TARGETS 674 targets = args.targets or _DEFAULT_TARGETS
637 targets = [re.sub(r'_test_apk$', '_test_apk__apk', t) for t in targets] 675 targets = [re.sub(r'_test_apk$', '_test_apk__apk', t) for t in targets]
638 # TODO(wnwen): Utilize Gradle's test constructs for our junit tests? 676 # TODO(wnwen): Utilize Gradle's test constructs for our junit tests?
639 targets = [re.sub(r'_junit_tests$', '_junit_tests__java_binary', t) 677 targets = [re.sub(r'_junit_tests$', '_junit_tests__java_binary', t)
640 for t in targets] 678 for t in targets]
641 679
642 main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets] 680 main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets]
643 681
644 logging.warning('Building .build_config files...') 682 logging.warning('Building .build_config files...')
645 _RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries]) 683 _RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries])
646 684
647 # There are many unused libraries, so restrict to those that are actually used 685 # There are many unused libraries, so restrict to those that are actually used
648 # when using --all. 686 # when using --all.
649 if args.all: 687 if args.all:
650 main_entries = [e for e in main_entries if e.GetType() == 'android_apk'] 688 main_entries = [e for e in main_entries if e.GetType() == 'android_apk']
651 689
652 all_entries = _FindAllProjectEntries(main_entries) 690 if args.split_projects:
653 logging.info('Found %d dependent build_config targets.', len(all_entries)) 691 main_entries = _FindAllProjectEntries(main_entries)
654 entries = _CombineTestEntries(all_entries) 692 logging.info('Found %d dependent build_config targets.', len(main_entries))
693 entries = _CombineTestEntries(main_entries)
655 logging.info('Creating %d projects for targets.', len(entries)) 694 logging.info('Creating %d projects for targets.', len(entries))
656 695
657 logging.warning('Writing .gradle files...') 696 logging.warning('Writing .gradle files...')
658 project_entries = [] 697 project_entries = []
659 zip_tuples = [] 698 zip_tuples = []
660 generated_inputs = [] 699 generated_inputs = []
661 for entry in entries: 700 for entry in entries:
662 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'): 701 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'):
663 continue 702 continue
664 703
665 data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor) 704 data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor)
666 if data: 705 if data:
667 project_entries.append(entry) 706 project_entries.append(entry)
668 # Build all paths references by .gradle that exist within output_dir. 707 # Build all paths references by .gradle that exist within output_dir.
669 generated_inputs.extend(generator.GeneratedInputs(entry)) 708 generated_inputs.extend(generator.GeneratedInputs(entry))
670 zip_tuples.extend( 709 zip_tuples.extend(
671 (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) 710 (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR))
672 for s in generator.Srcjars(entry)) 711 for s in generator.AllSrcjars(entry))
673 zip_tuples.extend( 712 zip_tuples.extend(
674 (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR)) 713 (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR))
675 for s in _RebasePath(entry.ResZips())) 714 for s in generator.AllResZips(entry))
676 _WriteFile( 715 _WriteFile(
677 os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data) 716 os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data)
678 717
679 _WriteFile(os.path.join(generator.project_dir, 'build.gradle'), 718 _WriteFile(os.path.join(generator.project_dir, 'build.gradle'),
680 _GenerateRootGradle(jinja_processor)) 719 _GenerateRootGradle(jinja_processor))
681 720
682 _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'), 721 _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'),
683 _GenerateSettingsGradle(project_entries)) 722 _GenerateSettingsGradle(project_entries))
684 723
685 sdk_path = _RebasePath(build_vars['android_sdk_root']) 724 sdk_path = _RebasePath(build_vars['android_sdk_root'])
686 _WriteFile(os.path.join(generator.project_dir, 'local.properties'), 725 _WriteFile(os.path.join(generator.project_dir, 'local.properties'),
687 _GenerateLocalProperties(sdk_path)) 726 _GenerateLocalProperties(sdk_path))
688 727
689 if generated_inputs: 728 if generated_inputs:
690 logging.warning('Building generated source files...') 729 logging.warning('Building generated source files...')
691 targets = _RebasePath(generated_inputs, output_dir) 730 targets = _RebasePath(generated_inputs, output_dir)
692 _RunNinja(output_dir, targets) 731 _RunNinja(output_dir, targets)
693 732
694 if zip_tuples: 733 if zip_tuples:
695 _ExtractZips(generator.project_dir, zip_tuples) 734 _ExtractZips(generator.project_dir, zip_tuples)
696 735
697 logging.warning('Project created! (%d subprojects)', len(project_entries)) 736 logging.warning('Project created! (%d subprojects)', len(project_entries))
698 logging.warning('Generated projects work best with Android Studio 2.2') 737 logging.warning('Generated projects work best with Android Studio 2.2')
699 logging.warning('For more tips: https://chromium.googlesource.com/chromium' 738 logging.warning('For more tips: https://chromium.googlesource.com/chromium'
700 '/src.git/+/master/docs/android_studio.md') 739 '/src.git/+/master/docs/android_studio.md')
701 740
702 741
703 if __name__ == '__main__': 742 if __name__ == '__main__':
704 main() 743 main()
OLDNEW
« no previous file with comments | « build/android/gradle/dependencies.jinja ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698