xref: /aosp_15_r20/external/angle/build/android/gradle/generate_gradle.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2016 The Chromium Authors
3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker
6*8975f5c5SAndroid Build Coastguard Worker"""Generates an Android Studio project from a GN target."""
7*8975f5c5SAndroid Build Coastguard Worker
8*8975f5c5SAndroid Build Coastguard Workerimport argparse
9*8975f5c5SAndroid Build Coastguard Workerimport codecs
10*8975f5c5SAndroid Build Coastguard Workerimport collections
11*8975f5c5SAndroid Build Coastguard Workerimport glob
12*8975f5c5SAndroid Build Coastguard Workerimport json
13*8975f5c5SAndroid Build Coastguard Workerimport logging
14*8975f5c5SAndroid Build Coastguard Workerimport os
15*8975f5c5SAndroid Build Coastguard Workerimport pathlib
16*8975f5c5SAndroid Build Coastguard Workerimport re
17*8975f5c5SAndroid Build Coastguard Workerimport shlex
18*8975f5c5SAndroid Build Coastguard Workerimport shutil
19*8975f5c5SAndroid Build Coastguard Workerimport subprocess
20*8975f5c5SAndroid Build Coastguard Workerimport sys
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Worker_BUILD_ANDROID = os.path.join(os.path.dirname(__file__), os.pardir)
23*8975f5c5SAndroid Build Coastguard Workersys.path.append(_BUILD_ANDROID)
24*8975f5c5SAndroid Build Coastguard Workerimport devil_chromium
25*8975f5c5SAndroid Build Coastguard Workerfrom devil.utils import run_tests_helper
26*8975f5c5SAndroid Build Coastguard Workerfrom pylib import constants
27*8975f5c5SAndroid Build Coastguard Workerfrom pylib.constants import host_paths
28*8975f5c5SAndroid Build Coastguard Worker
29*8975f5c5SAndroid Build Coastguard Workersys.path.append(os.path.join(_BUILD_ANDROID, 'gyp'))
30*8975f5c5SAndroid Build Coastguard Workerimport jinja_template
31*8975f5c5SAndroid Build Coastguard Workerfrom util import build_utils
32*8975f5c5SAndroid Build Coastguard Workerfrom util import resource_utils
33*8975f5c5SAndroid Build Coastguard Worker
34*8975f5c5SAndroid Build Coastguard Workersys.path.append(os.path.dirname(_BUILD_ANDROID))
35*8975f5c5SAndroid Build Coastguard Workerimport gn_helpers
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker# Typically these should track the versions that works on the slowest release
38*8975f5c5SAndroid Build Coastguard Worker# channel, i.e. Android Studio stable.
39*8975f5c5SAndroid Build Coastguard Worker_DEFAULT_ANDROID_GRADLE_PLUGIN_VERSION = '7.3.1'
40*8975f5c5SAndroid Build Coastguard Worker_DEFAULT_KOTLIN_GRADLE_PLUGIN_VERSION = '1.8.0'
41*8975f5c5SAndroid Build Coastguard Worker_DEFAULT_GRADLE_WRAPPER_VERSION = '7.4'
42*8975f5c5SAndroid Build Coastguard Worker
43*8975f5c5SAndroid Build Coastguard Worker_DEPOT_TOOLS_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party',
44*8975f5c5SAndroid Build Coastguard Worker                                 'depot_tools')
45*8975f5c5SAndroid Build Coastguard Worker_DEFAULT_ANDROID_MANIFEST_PATH = os.path.join(
46*8975f5c5SAndroid Build Coastguard Worker    host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'gradle',
47*8975f5c5SAndroid Build Coastguard Worker    'AndroidManifest.xml')
48*8975f5c5SAndroid Build Coastguard Worker_FILE_DIR = os.path.dirname(__file__)
49*8975f5c5SAndroid Build Coastguard Worker_GENERATED_JAVA_SUBDIR = 'generated_java'
50*8975f5c5SAndroid Build Coastguard Worker_JNI_LIBS_SUBDIR = 'symlinked-libs'
51*8975f5c5SAndroid Build Coastguard Worker_ARMEABI_SUBDIR = 'armeabi'
52*8975f5c5SAndroid Build Coastguard Worker_GRADLE_BUILD_FILE = 'build.gradle'
53*8975f5c5SAndroid Build Coastguard Worker_CMAKE_FILE = 'CMakeLists.txt'
54*8975f5c5SAndroid Build Coastguard Worker# This needs to come first alphabetically among all modules.
55*8975f5c5SAndroid Build Coastguard Worker_MODULE_ALL = '_all'
56*8975f5c5SAndroid Build Coastguard Worker_INSTRUMENTATION_TARGET_SUFFIX = '_test_apk__test_apk'
57*8975f5c5SAndroid Build Coastguard Worker
58*8975f5c5SAndroid Build Coastguard Worker_DEFAULT_TARGETS = [
59*8975f5c5SAndroid Build Coastguard Worker    '//android_webview/test/embedded_test_server:aw_net_test_support_apk',
60*8975f5c5SAndroid Build Coastguard Worker    '//android_webview/test:webview_instrumentation_apk',
61*8975f5c5SAndroid Build Coastguard Worker    '//android_webview/test:webview_instrumentation_test_apk',
62*8975f5c5SAndroid Build Coastguard Worker    '//base:base_junit_tests',
63*8975f5c5SAndroid Build Coastguard Worker    '//chrome/android:chrome_junit_tests',
64*8975f5c5SAndroid Build Coastguard Worker    '//chrome/android:chrome_public_apk',
65*8975f5c5SAndroid Build Coastguard Worker    '//chrome/android:chrome_public_test_apk',
66*8975f5c5SAndroid Build Coastguard Worker    '//chrome/android:chrome_public_unit_test_apk',
67*8975f5c5SAndroid Build Coastguard Worker    '//content/public/android:content_junit_tests',
68*8975f5c5SAndroid Build Coastguard Worker    '//content/shell/android:content_shell_apk',
69*8975f5c5SAndroid Build Coastguard Worker    # Below must be included even with --all since they are libraries.
70*8975f5c5SAndroid Build Coastguard Worker    '//base/android/jni_generator:jni_processor',
71*8975f5c5SAndroid Build Coastguard Worker    '//tools/android/errorprone_plugin:errorprone_plugin_java',
72*8975f5c5SAndroid Build Coastguard Worker]
73*8975f5c5SAndroid Build Coastguard Worker
74*8975f5c5SAndroid Build Coastguard Worker
75*8975f5c5SAndroid Build Coastguard Workerdef _TemplatePath(name):
76*8975f5c5SAndroid Build Coastguard Worker  return os.path.join(_FILE_DIR, '{}.jinja'.format(name))
77*8975f5c5SAndroid Build Coastguard Worker
78*8975f5c5SAndroid Build Coastguard Worker
79*8975f5c5SAndroid Build Coastguard Workerdef _RebasePath(path_or_list, new_cwd=None, old_cwd=None):
80*8975f5c5SAndroid Build Coastguard Worker  """Makes the given path(s) relative to new_cwd, or absolute if not specified.
81*8975f5c5SAndroid Build Coastguard Worker
82*8975f5c5SAndroid Build Coastguard Worker  If new_cwd is not specified, absolute paths are returned.
83*8975f5c5SAndroid Build Coastguard Worker  If old_cwd is not specified, constants.GetOutDirectory() is assumed.
84*8975f5c5SAndroid Build Coastguard Worker  """
85*8975f5c5SAndroid Build Coastguard Worker  if path_or_list is None:
86*8975f5c5SAndroid Build Coastguard Worker    return []
87*8975f5c5SAndroid Build Coastguard Worker  if not isinstance(path_or_list, str):
88*8975f5c5SAndroid Build Coastguard Worker    return [_RebasePath(p, new_cwd, old_cwd) for p in path_or_list]
89*8975f5c5SAndroid Build Coastguard Worker  if old_cwd is None:
90*8975f5c5SAndroid Build Coastguard Worker    old_cwd = constants.GetOutDirectory()
91*8975f5c5SAndroid Build Coastguard Worker  old_cwd = os.path.abspath(old_cwd)
92*8975f5c5SAndroid Build Coastguard Worker  if new_cwd:
93*8975f5c5SAndroid Build Coastguard Worker    new_cwd = os.path.abspath(new_cwd)
94*8975f5c5SAndroid Build Coastguard Worker    return os.path.relpath(os.path.join(old_cwd, path_or_list), new_cwd)
95*8975f5c5SAndroid Build Coastguard Worker  return os.path.abspath(os.path.join(old_cwd, path_or_list))
96*8975f5c5SAndroid Build Coastguard Worker
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Workerdef _WriteFile(path, data):
99*8975f5c5SAndroid Build Coastguard Worker  """Writes |data| to |path|, constucting parent directories if necessary."""
100*8975f5c5SAndroid Build Coastguard Worker  logging.info('Writing %s', path)
101*8975f5c5SAndroid Build Coastguard Worker  dirname = os.path.dirname(path)
102*8975f5c5SAndroid Build Coastguard Worker  if not os.path.exists(dirname):
103*8975f5c5SAndroid Build Coastguard Worker    os.makedirs(dirname)
104*8975f5c5SAndroid Build Coastguard Worker  with codecs.open(path, 'w', 'utf-8') as output_file:
105*8975f5c5SAndroid Build Coastguard Worker    output_file.write(data)
106*8975f5c5SAndroid Build Coastguard Worker
107*8975f5c5SAndroid Build Coastguard Worker
108*8975f5c5SAndroid Build Coastguard Workerdef _RunGnGen(output_dir, args=None):
109*8975f5c5SAndroid Build Coastguard Worker  cmd = [os.path.join(_DEPOT_TOOLS_PATH, 'gn'), 'gen', output_dir]
110*8975f5c5SAndroid Build Coastguard Worker  if args:
111*8975f5c5SAndroid Build Coastguard Worker    cmd.extend(args)
112*8975f5c5SAndroid Build Coastguard Worker  logging.info('Running: %r', cmd)
113*8975f5c5SAndroid Build Coastguard Worker  subprocess.check_call(cmd)
114*8975f5c5SAndroid Build Coastguard Worker
115*8975f5c5SAndroid Build Coastguard Worker
116*8975f5c5SAndroid Build Coastguard Workerdef _BuildTargets(output_dir, args):
117*8975f5c5SAndroid Build Coastguard Worker  cmd = gn_helpers.CreateBuildCommand(output_dir)
118*8975f5c5SAndroid Build Coastguard Worker  cmd.extend(args)
119*8975f5c5SAndroid Build Coastguard Worker  logging.info('Running: %s', shlex.join(cmd))
120*8975f5c5SAndroid Build Coastguard Worker  subprocess.check_call(cmd)
121*8975f5c5SAndroid Build Coastguard Worker
122*8975f5c5SAndroid Build Coastguard Worker
123*8975f5c5SAndroid Build Coastguard Workerdef _QueryForAllGnTargets(output_dir):
124*8975f5c5SAndroid Build Coastguard Worker  cmd = [
125*8975f5c5SAndroid Build Coastguard Worker      os.path.join(_BUILD_ANDROID, 'list_java_targets.py'), '--gn-labels',
126*8975f5c5SAndroid Build Coastguard Worker      '--nested', '--build', '--output-directory', output_dir
127*8975f5c5SAndroid Build Coastguard Worker  ]
128*8975f5c5SAndroid Build Coastguard Worker  logging.info('Running: %r', cmd)
129*8975f5c5SAndroid Build Coastguard Worker  return subprocess.check_output(cmd, encoding='UTF-8').splitlines()
130*8975f5c5SAndroid Build Coastguard Worker
131*8975f5c5SAndroid Build Coastguard Worker
132*8975f5c5SAndroid Build Coastguard Workerclass _ProjectEntry:
133*8975f5c5SAndroid Build Coastguard Worker  """Helper class for project entries."""
134*8975f5c5SAndroid Build Coastguard Worker
135*8975f5c5SAndroid Build Coastguard Worker  _cached_entries = {}
136*8975f5c5SAndroid Build Coastguard Worker
137*8975f5c5SAndroid Build Coastguard Worker  def __init__(self, gn_target):
138*8975f5c5SAndroid Build Coastguard Worker    # Use _ProjectEntry.FromGnTarget instead for caching.
139*8975f5c5SAndroid Build Coastguard Worker    self._gn_target = gn_target
140*8975f5c5SAndroid Build Coastguard Worker    self._build_config = None
141*8975f5c5SAndroid Build Coastguard Worker    self._java_files = None
142*8975f5c5SAndroid Build Coastguard Worker    self._all_entries = None
143*8975f5c5SAndroid Build Coastguard Worker    self.android_test_entries = []
144*8975f5c5SAndroid Build Coastguard Worker
145*8975f5c5SAndroid Build Coastguard Worker  @classmethod
146*8975f5c5SAndroid Build Coastguard Worker  def FromGnTarget(cls, gn_target):
147*8975f5c5SAndroid Build Coastguard Worker    assert gn_target.startswith('//'), gn_target
148*8975f5c5SAndroid Build Coastguard Worker    if ':' not in gn_target:
149*8975f5c5SAndroid Build Coastguard Worker      gn_target = '%s:%s' % (gn_target, os.path.basename(gn_target))
150*8975f5c5SAndroid Build Coastguard Worker    if gn_target not in cls._cached_entries:
151*8975f5c5SAndroid Build Coastguard Worker      cls._cached_entries[gn_target] = cls(gn_target)
152*8975f5c5SAndroid Build Coastguard Worker    return cls._cached_entries[gn_target]
153*8975f5c5SAndroid Build Coastguard Worker
154*8975f5c5SAndroid Build Coastguard Worker  @classmethod
155*8975f5c5SAndroid Build Coastguard Worker  def FromBuildConfigPath(cls, path):
156*8975f5c5SAndroid Build Coastguard Worker    prefix = 'gen/'
157*8975f5c5SAndroid Build Coastguard Worker    suffix = '.build_config.json'
158*8975f5c5SAndroid Build Coastguard Worker    assert path.startswith(prefix) and path.endswith(suffix), path
159*8975f5c5SAndroid Build Coastguard Worker    subdir = path[len(prefix):-len(suffix)]
160*8975f5c5SAndroid Build Coastguard Worker    gn_target = '//%s:%s' % (os.path.split(subdir))
161*8975f5c5SAndroid Build Coastguard Worker    return cls.FromGnTarget(gn_target)
162*8975f5c5SAndroid Build Coastguard Worker
163*8975f5c5SAndroid Build Coastguard Worker  def __hash__(self):
164*8975f5c5SAndroid Build Coastguard Worker    return hash(self._gn_target)
165*8975f5c5SAndroid Build Coastguard Worker
166*8975f5c5SAndroid Build Coastguard Worker  def __eq__(self, other):
167*8975f5c5SAndroid Build Coastguard Worker    return self._gn_target == other.GnTarget()
168*8975f5c5SAndroid Build Coastguard Worker
169*8975f5c5SAndroid Build Coastguard Worker  def GnTarget(self):
170*8975f5c5SAndroid Build Coastguard Worker    return self._gn_target
171*8975f5c5SAndroid Build Coastguard Worker
172*8975f5c5SAndroid Build Coastguard Worker  def NinjaTarget(self):
173*8975f5c5SAndroid Build Coastguard Worker    return self._gn_target[2:]
174*8975f5c5SAndroid Build Coastguard Worker
175*8975f5c5SAndroid Build Coastguard Worker  def BuildConfigPath(self):
176*8975f5c5SAndroid Build Coastguard Worker    return os.path.join('gen', self.GradleSubdir() + '.build_config.json')
177*8975f5c5SAndroid Build Coastguard Worker
178*8975f5c5SAndroid Build Coastguard Worker  def GradleSubdir(self):
179*8975f5c5SAndroid Build Coastguard Worker    """Returns the output subdirectory."""
180*8975f5c5SAndroid Build Coastguard Worker    ninja_target = self.NinjaTarget()
181*8975f5c5SAndroid Build Coastguard Worker    # Support targets at the root level. e.g. //:foo
182*8975f5c5SAndroid Build Coastguard Worker    if ninja_target[0] == ':':
183*8975f5c5SAndroid Build Coastguard Worker      ninja_target = ninja_target[1:]
184*8975f5c5SAndroid Build Coastguard Worker    return ninja_target.replace(':', os.path.sep)
185*8975f5c5SAndroid Build Coastguard Worker
186*8975f5c5SAndroid Build Coastguard Worker  def GeneratedJavaSubdir(self):
187*8975f5c5SAndroid Build Coastguard Worker    return _RebasePath(
188*8975f5c5SAndroid Build Coastguard Worker        os.path.join('gen', self.GradleSubdir(), _GENERATED_JAVA_SUBDIR))
189*8975f5c5SAndroid Build Coastguard Worker
190*8975f5c5SAndroid Build Coastguard Worker  def ProjectName(self):
191*8975f5c5SAndroid Build Coastguard Worker    """Returns the Gradle project name."""
192*8975f5c5SAndroid Build Coastguard Worker    return self.GradleSubdir().replace(os.path.sep, '.')
193*8975f5c5SAndroid Build Coastguard Worker
194*8975f5c5SAndroid Build Coastguard Worker  def BuildConfig(self):
195*8975f5c5SAndroid Build Coastguard Worker    """Reads and returns the project's .build_config.json JSON."""
196*8975f5c5SAndroid Build Coastguard Worker    if not self._build_config:
197*8975f5c5SAndroid Build Coastguard Worker      with open(_RebasePath(self.BuildConfigPath())) as jsonfile:
198*8975f5c5SAndroid Build Coastguard Worker        self._build_config = json.load(jsonfile)
199*8975f5c5SAndroid Build Coastguard Worker    return self._build_config
200*8975f5c5SAndroid Build Coastguard Worker
201*8975f5c5SAndroid Build Coastguard Worker  def DepsInfo(self):
202*8975f5c5SAndroid Build Coastguard Worker    return self.BuildConfig()['deps_info']
203*8975f5c5SAndroid Build Coastguard Worker
204*8975f5c5SAndroid Build Coastguard Worker  def Gradle(self):
205*8975f5c5SAndroid Build Coastguard Worker    return self.BuildConfig()['gradle']
206*8975f5c5SAndroid Build Coastguard Worker
207*8975f5c5SAndroid Build Coastguard Worker  def Javac(self):
208*8975f5c5SAndroid Build Coastguard Worker    return self.BuildConfig()['javac']
209*8975f5c5SAndroid Build Coastguard Worker
210*8975f5c5SAndroid Build Coastguard Worker  def GetType(self):
211*8975f5c5SAndroid Build Coastguard Worker    """Returns the target type from its .build_config."""
212*8975f5c5SAndroid Build Coastguard Worker    return self.DepsInfo()['type']
213*8975f5c5SAndroid Build Coastguard Worker
214*8975f5c5SAndroid Build Coastguard Worker  def IsValid(self):
215*8975f5c5SAndroid Build Coastguard Worker    return self.GetType() in (
216*8975f5c5SAndroid Build Coastguard Worker        'android_apk',
217*8975f5c5SAndroid Build Coastguard Worker        'android_app_bundle_module',
218*8975f5c5SAndroid Build Coastguard Worker        'java_library',
219*8975f5c5SAndroid Build Coastguard Worker        "java_annotation_processor",
220*8975f5c5SAndroid Build Coastguard Worker        'java_binary',
221*8975f5c5SAndroid Build Coastguard Worker        'robolectric_binary',
222*8975f5c5SAndroid Build Coastguard Worker    )
223*8975f5c5SAndroid Build Coastguard Worker
224*8975f5c5SAndroid Build Coastguard Worker  def ResSources(self):
225*8975f5c5SAndroid Build Coastguard Worker    return self.DepsInfo().get('lint_resource_sources', [])
226*8975f5c5SAndroid Build Coastguard Worker
227*8975f5c5SAndroid Build Coastguard Worker  def JavaFiles(self):
228*8975f5c5SAndroid Build Coastguard Worker    if self._java_files is None:
229*8975f5c5SAndroid Build Coastguard Worker      target_sources_file = self.DepsInfo().get('target_sources_file')
230*8975f5c5SAndroid Build Coastguard Worker      java_files = []
231*8975f5c5SAndroid Build Coastguard Worker      if target_sources_file:
232*8975f5c5SAndroid Build Coastguard Worker        target_sources_file = _RebasePath(target_sources_file)
233*8975f5c5SAndroid Build Coastguard Worker        java_files = build_utils.ReadSourcesList(target_sources_file)
234*8975f5c5SAndroid Build Coastguard Worker      self._java_files = java_files
235*8975f5c5SAndroid Build Coastguard Worker    return self._java_files
236*8975f5c5SAndroid Build Coastguard Worker
237*8975f5c5SAndroid Build Coastguard Worker  def PrebuiltJars(self):
238*8975f5c5SAndroid Build Coastguard Worker    return self.Gradle().get('dependent_prebuilt_jars', [])
239*8975f5c5SAndroid Build Coastguard Worker
240*8975f5c5SAndroid Build Coastguard Worker  def AllEntries(self):
241*8975f5c5SAndroid Build Coastguard Worker    """Returns a list of all entries that the current entry depends on.
242*8975f5c5SAndroid Build Coastguard Worker
243*8975f5c5SAndroid Build Coastguard Worker    This includes the entry itself to make iterating simpler."""
244*8975f5c5SAndroid Build Coastguard Worker    if self._all_entries is None:
245*8975f5c5SAndroid Build Coastguard Worker      logging.debug('Generating entries for %s', self.GnTarget())
246*8975f5c5SAndroid Build Coastguard Worker      deps = [_ProjectEntry.FromBuildConfigPath(p)
247*8975f5c5SAndroid Build Coastguard Worker          for p in self.Gradle()['dependent_android_projects']]
248*8975f5c5SAndroid Build Coastguard Worker      deps.extend(_ProjectEntry.FromBuildConfigPath(p)
249*8975f5c5SAndroid Build Coastguard Worker          for p in self.Gradle()['dependent_java_projects'])
250*8975f5c5SAndroid Build Coastguard Worker      all_entries = set()
251*8975f5c5SAndroid Build Coastguard Worker      for dep in deps:
252*8975f5c5SAndroid Build Coastguard Worker        all_entries.update(dep.AllEntries())
253*8975f5c5SAndroid Build Coastguard Worker      all_entries.add(self)
254*8975f5c5SAndroid Build Coastguard Worker      self._all_entries = list(all_entries)
255*8975f5c5SAndroid Build Coastguard Worker    return self._all_entries
256*8975f5c5SAndroid Build Coastguard Worker
257*8975f5c5SAndroid Build Coastguard Worker
258*8975f5c5SAndroid Build Coastguard Workerclass _ProjectContextGenerator:
259*8975f5c5SAndroid Build Coastguard Worker  """Helper class to generate gradle build files"""
260*8975f5c5SAndroid Build Coastguard Worker  def __init__(self, project_dir, build_vars, use_gradle_process_resources,
261*8975f5c5SAndroid Build Coastguard Worker               jinja_processor, split_projects):
262*8975f5c5SAndroid Build Coastguard Worker    self.project_dir = project_dir
263*8975f5c5SAndroid Build Coastguard Worker    self.build_vars = build_vars
264*8975f5c5SAndroid Build Coastguard Worker    self.use_gradle_process_resources = use_gradle_process_resources
265*8975f5c5SAndroid Build Coastguard Worker    self.jinja_processor = jinja_processor
266*8975f5c5SAndroid Build Coastguard Worker    self.split_projects = split_projects
267*8975f5c5SAndroid Build Coastguard Worker    self.processed_java_dirs = set()
268*8975f5c5SAndroid Build Coastguard Worker    self.processed_prebuilts = set()
269*8975f5c5SAndroid Build Coastguard Worker    self.processed_res_dirs = set()
270*8975f5c5SAndroid Build Coastguard Worker
271*8975f5c5SAndroid Build Coastguard Worker  def _GenJniLibs(self, root_entry):
272*8975f5c5SAndroid Build Coastguard Worker    libraries = []
273*8975f5c5SAndroid Build Coastguard Worker    for entry in self._GetEntries(root_entry):
274*8975f5c5SAndroid Build Coastguard Worker      libraries += entry.BuildConfig().get('native', {}).get('libraries', [])
275*8975f5c5SAndroid Build Coastguard Worker    if libraries:
276*8975f5c5SAndroid Build Coastguard Worker      return _CreateJniLibsDir(constants.GetOutDirectory(),
277*8975f5c5SAndroid Build Coastguard Worker          self.EntryOutputDir(root_entry), libraries)
278*8975f5c5SAndroid Build Coastguard Worker    return []
279*8975f5c5SAndroid Build Coastguard Worker
280*8975f5c5SAndroid Build Coastguard Worker  def _GenJavaDirs(self, root_entry):
281*8975f5c5SAndroid Build Coastguard Worker    java_files = []
282*8975f5c5SAndroid Build Coastguard Worker    for entry in self._GetEntries(root_entry):
283*8975f5c5SAndroid Build Coastguard Worker      java_files += entry.JavaFiles()
284*8975f5c5SAndroid Build Coastguard Worker    java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes(
285*8975f5c5SAndroid Build Coastguard Worker        constants.GetOutDirectory(), java_files)
286*8975f5c5SAndroid Build Coastguard Worker    return java_dirs, excludes
287*8975f5c5SAndroid Build Coastguard Worker
288*8975f5c5SAndroid Build Coastguard Worker  def _GenCustomManifest(self, entry):
289*8975f5c5SAndroid Build Coastguard Worker    """Returns the path to the generated AndroidManifest.xml.
290*8975f5c5SAndroid Build Coastguard Worker
291*8975f5c5SAndroid Build Coastguard Worker    Gradle uses package id from manifest when generating R.class. So, we need
292*8975f5c5SAndroid Build Coastguard Worker    to generate a custom manifest if we let gradle process resources. We cannot
293*8975f5c5SAndroid Build Coastguard Worker    simply set android.defaultConfig.applicationId because it is not supported
294*8975f5c5SAndroid Build Coastguard Worker    for library targets."""
295*8975f5c5SAndroid Build Coastguard Worker    resource_packages = entry.Javac().get('resource_packages')
296*8975f5c5SAndroid Build Coastguard Worker    if not resource_packages:
297*8975f5c5SAndroid Build Coastguard Worker      logging.debug(
298*8975f5c5SAndroid Build Coastguard Worker          'Target %s includes resources from unknown package. '
299*8975f5c5SAndroid Build Coastguard Worker          'Unable to process with gradle.', entry.GnTarget())
300*8975f5c5SAndroid Build Coastguard Worker      return _DEFAULT_ANDROID_MANIFEST_PATH
301*8975f5c5SAndroid Build Coastguard Worker    if len(resource_packages) > 1:
302*8975f5c5SAndroid Build Coastguard Worker      logging.debug(
303*8975f5c5SAndroid Build Coastguard Worker          'Target %s includes resources from multiple packages. '
304*8975f5c5SAndroid Build Coastguard Worker          'Unable to process with gradle.', entry.GnTarget())
305*8975f5c5SAndroid Build Coastguard Worker      return _DEFAULT_ANDROID_MANIFEST_PATH
306*8975f5c5SAndroid Build Coastguard Worker
307*8975f5c5SAndroid Build Coastguard Worker    variables = {'package': resource_packages[0]}
308*8975f5c5SAndroid Build Coastguard Worker    data = self.jinja_processor.Render(_TemplatePath('manifest'), variables)
309*8975f5c5SAndroid Build Coastguard Worker    output_file = os.path.join(
310*8975f5c5SAndroid Build Coastguard Worker        self.EntryOutputDir(entry), 'AndroidManifest.xml')
311*8975f5c5SAndroid Build Coastguard Worker    _WriteFile(output_file, data)
312*8975f5c5SAndroid Build Coastguard Worker
313*8975f5c5SAndroid Build Coastguard Worker    return output_file
314*8975f5c5SAndroid Build Coastguard Worker
315*8975f5c5SAndroid Build Coastguard Worker  def _Relativize(self, entry, paths):
316*8975f5c5SAndroid Build Coastguard Worker    return _RebasePath(paths, self.EntryOutputDir(entry))
317*8975f5c5SAndroid Build Coastguard Worker
318*8975f5c5SAndroid Build Coastguard Worker  def _GetEntries(self, entry):
319*8975f5c5SAndroid Build Coastguard Worker    if self.split_projects:
320*8975f5c5SAndroid Build Coastguard Worker      return [entry]
321*8975f5c5SAndroid Build Coastguard Worker    return entry.AllEntries()
322*8975f5c5SAndroid Build Coastguard Worker
323*8975f5c5SAndroid Build Coastguard Worker  def EntryOutputDir(self, entry):
324*8975f5c5SAndroid Build Coastguard Worker    return os.path.join(self.project_dir, entry.GradleSubdir())
325*8975f5c5SAndroid Build Coastguard Worker
326*8975f5c5SAndroid Build Coastguard Worker  def GeneratedInputs(self, root_entry):
327*8975f5c5SAndroid Build Coastguard Worker    generated_inputs = set()
328*8975f5c5SAndroid Build Coastguard Worker    for entry in self._GetEntries(root_entry):
329*8975f5c5SAndroid Build Coastguard Worker      generated_inputs.update(entry.PrebuiltJars())
330*8975f5c5SAndroid Build Coastguard Worker    return generated_inputs
331*8975f5c5SAndroid Build Coastguard Worker
332*8975f5c5SAndroid Build Coastguard Worker  def GenerateManifest(self, root_entry):
333*8975f5c5SAndroid Build Coastguard Worker    android_manifest = root_entry.DepsInfo().get('android_manifest')
334*8975f5c5SAndroid Build Coastguard Worker    if not android_manifest:
335*8975f5c5SAndroid Build Coastguard Worker      android_manifest = self._GenCustomManifest(root_entry)
336*8975f5c5SAndroid Build Coastguard Worker    return self._Relativize(root_entry, android_manifest)
337*8975f5c5SAndroid Build Coastguard Worker
338*8975f5c5SAndroid Build Coastguard Worker  def Generate(self, root_entry):
339*8975f5c5SAndroid Build Coastguard Worker    # TODO(agrieve): Add an option to use interface jars and see if that speeds
340*8975f5c5SAndroid Build Coastguard Worker    # things up at all.
341*8975f5c5SAndroid Build Coastguard Worker    variables = {}
342*8975f5c5SAndroid Build Coastguard Worker    java_dirs, excludes = self._GenJavaDirs(root_entry)
343*8975f5c5SAndroid Build Coastguard Worker    java_dirs.extend(
344*8975f5c5SAndroid Build Coastguard Worker        e.GeneratedJavaSubdir() for e in self._GetEntries(root_entry))
345*8975f5c5SAndroid Build Coastguard Worker    self.processed_java_dirs.update(java_dirs)
346*8975f5c5SAndroid Build Coastguard Worker    java_dirs.sort()
347*8975f5c5SAndroid Build Coastguard Worker    variables['java_dirs'] = self._Relativize(root_entry, java_dirs)
348*8975f5c5SAndroid Build Coastguard Worker    variables['java_excludes'] = excludes
349*8975f5c5SAndroid Build Coastguard Worker    variables['jni_libs'] = self._Relativize(
350*8975f5c5SAndroid Build Coastguard Worker        root_entry, set(self._GenJniLibs(root_entry)))
351*8975f5c5SAndroid Build Coastguard Worker    prebuilts = set(
352*8975f5c5SAndroid Build Coastguard Worker        p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars())
353*8975f5c5SAndroid Build Coastguard Worker    self.processed_prebuilts.update(prebuilts)
354*8975f5c5SAndroid Build Coastguard Worker    variables['prebuilts'] = self._Relativize(root_entry, prebuilts)
355*8975f5c5SAndroid Build Coastguard Worker    res_sources_files = _RebasePath(
356*8975f5c5SAndroid Build Coastguard Worker        set(p for e in self._GetEntries(root_entry) for p in e.ResSources()))
357*8975f5c5SAndroid Build Coastguard Worker    res_sources = []
358*8975f5c5SAndroid Build Coastguard Worker    for res_sources_file in res_sources_files:
359*8975f5c5SAndroid Build Coastguard Worker      res_sources.extend(build_utils.ReadSourcesList(res_sources_file))
360*8975f5c5SAndroid Build Coastguard Worker    res_dirs = resource_utils.DeduceResourceDirsFromFileList(res_sources)
361*8975f5c5SAndroid Build Coastguard Worker    # Do not add generated resources for the all module since it creates many
362*8975f5c5SAndroid Build Coastguard Worker    # duplicates, and currently resources are only used for editing.
363*8975f5c5SAndroid Build Coastguard Worker    self.processed_res_dirs.update(res_dirs)
364*8975f5c5SAndroid Build Coastguard Worker    variables['res_dirs'] = self._Relativize(root_entry, res_dirs)
365*8975f5c5SAndroid Build Coastguard Worker    if self.split_projects:
366*8975f5c5SAndroid Build Coastguard Worker      deps = [_ProjectEntry.FromBuildConfigPath(p)
367*8975f5c5SAndroid Build Coastguard Worker              for p in root_entry.Gradle()['dependent_android_projects']]
368*8975f5c5SAndroid Build Coastguard Worker      variables['android_project_deps'] = [d.ProjectName() for d in deps]
369*8975f5c5SAndroid Build Coastguard Worker      deps = [_ProjectEntry.FromBuildConfigPath(p)
370*8975f5c5SAndroid Build Coastguard Worker              for p in root_entry.Gradle()['dependent_java_projects']]
371*8975f5c5SAndroid Build Coastguard Worker      variables['java_project_deps'] = [d.ProjectName() for d in deps]
372*8975f5c5SAndroid Build Coastguard Worker    return variables
373*8975f5c5SAndroid Build Coastguard Worker
374*8975f5c5SAndroid Build Coastguard Worker
375*8975f5c5SAndroid Build Coastguard Workerdef _ComputeJavaSourceDirs(java_files):
376*8975f5c5SAndroid Build Coastguard Worker  """Returns a dictionary of source dirs with each given files in one."""
377*8975f5c5SAndroid Build Coastguard Worker  found_roots = {}
378*8975f5c5SAndroid Build Coastguard Worker  for path in java_files:
379*8975f5c5SAndroid Build Coastguard Worker    path_root = path
380*8975f5c5SAndroid Build Coastguard Worker    # Recognize these tokens as top-level.
381*8975f5c5SAndroid Build Coastguard Worker    while True:
382*8975f5c5SAndroid Build Coastguard Worker      path_root = os.path.dirname(path_root)
383*8975f5c5SAndroid Build Coastguard Worker      basename = os.path.basename(path_root)
384*8975f5c5SAndroid Build Coastguard Worker      assert basename, 'Failed to find source dir for ' + path
385*8975f5c5SAndroid Build Coastguard Worker      if basename in ('java', 'src'):
386*8975f5c5SAndroid Build Coastguard Worker        break
387*8975f5c5SAndroid Build Coastguard Worker      if basename in ('javax', 'org', 'com'):
388*8975f5c5SAndroid Build Coastguard Worker        path_root = os.path.dirname(path_root)
389*8975f5c5SAndroid Build Coastguard Worker        break
390*8975f5c5SAndroid Build Coastguard Worker    if path_root not in found_roots:
391*8975f5c5SAndroid Build Coastguard Worker      found_roots[path_root] = []
392*8975f5c5SAndroid Build Coastguard Worker    found_roots[path_root].append(path)
393*8975f5c5SAndroid Build Coastguard Worker  return found_roots
394*8975f5c5SAndroid Build Coastguard Worker
395*8975f5c5SAndroid Build Coastguard Worker
396*8975f5c5SAndroid Build Coastguard Workerdef _ComputeExcludeFilters(wanted_files, unwanted_files, parent_dir):
397*8975f5c5SAndroid Build Coastguard Worker  """Returns exclude patters to exclude unwanted files but keep wanted files.
398*8975f5c5SAndroid Build Coastguard Worker
399*8975f5c5SAndroid Build Coastguard Worker  - Shortens exclude list by globbing if possible.
400*8975f5c5SAndroid Build Coastguard Worker  - Exclude patterns are relative paths from the parent directory.
401*8975f5c5SAndroid Build Coastguard Worker  """
402*8975f5c5SAndroid Build Coastguard Worker  excludes = []
403*8975f5c5SAndroid Build Coastguard Worker  files_to_include = set(wanted_files)
404*8975f5c5SAndroid Build Coastguard Worker  files_to_exclude = set(unwanted_files)
405*8975f5c5SAndroid Build Coastguard Worker  while files_to_exclude:
406*8975f5c5SAndroid Build Coastguard Worker    unwanted_file = files_to_exclude.pop()
407*8975f5c5SAndroid Build Coastguard Worker    target_exclude = os.path.join(
408*8975f5c5SAndroid Build Coastguard Worker        os.path.dirname(unwanted_file), '*.java')
409*8975f5c5SAndroid Build Coastguard Worker    found_files = set(glob.glob(target_exclude))
410*8975f5c5SAndroid Build Coastguard Worker    valid_files = found_files & files_to_include
411*8975f5c5SAndroid Build Coastguard Worker    if valid_files:
412*8975f5c5SAndroid Build Coastguard Worker      excludes.append(os.path.relpath(unwanted_file, parent_dir))
413*8975f5c5SAndroid Build Coastguard Worker    else:
414*8975f5c5SAndroid Build Coastguard Worker      excludes.append(os.path.relpath(target_exclude, parent_dir))
415*8975f5c5SAndroid Build Coastguard Worker      files_to_exclude -= found_files
416*8975f5c5SAndroid Build Coastguard Worker  return excludes
417*8975f5c5SAndroid Build Coastguard Worker
418*8975f5c5SAndroid Build Coastguard Worker
419*8975f5c5SAndroid Build Coastguard Workerdef _ComputeJavaSourceDirsAndExcludes(output_dir, source_files):
420*8975f5c5SAndroid Build Coastguard Worker  """Computes the list of java source directories and exclude patterns.
421*8975f5c5SAndroid Build Coastguard Worker
422*8975f5c5SAndroid Build Coastguard Worker  This includes both Java and Kotlin files since both are listed in the same
423*8975f5c5SAndroid Build Coastguard Worker  "java" section for gradle.
424*8975f5c5SAndroid Build Coastguard Worker
425*8975f5c5SAndroid Build Coastguard Worker  1. Computes the root source directories from the list of files.
426*8975f5c5SAndroid Build Coastguard Worker  2. Compute exclude patterns that exclude all extra files only.
427*8975f5c5SAndroid Build Coastguard Worker  3. Returns the list of source directories and exclude patterns.
428*8975f5c5SAndroid Build Coastguard Worker  """
429*8975f5c5SAndroid Build Coastguard Worker  java_dirs = []
430*8975f5c5SAndroid Build Coastguard Worker  excludes = []
431*8975f5c5SAndroid Build Coastguard Worker  if source_files:
432*8975f5c5SAndroid Build Coastguard Worker    source_files = _RebasePath(source_files)
433*8975f5c5SAndroid Build Coastguard Worker    computed_dirs = _ComputeJavaSourceDirs(source_files)
434*8975f5c5SAndroid Build Coastguard Worker    java_dirs = list(computed_dirs.keys())
435*8975f5c5SAndroid Build Coastguard Worker    all_found_source_files = set()
436*8975f5c5SAndroid Build Coastguard Worker
437*8975f5c5SAndroid Build Coastguard Worker    for directory, files in computed_dirs.items():
438*8975f5c5SAndroid Build Coastguard Worker      found_source_files = (build_utils.FindInDirectory(directory, '*.java') +
439*8975f5c5SAndroid Build Coastguard Worker                            build_utils.FindInDirectory(directory, '*.kt'))
440*8975f5c5SAndroid Build Coastguard Worker      all_found_source_files.update(found_source_files)
441*8975f5c5SAndroid Build Coastguard Worker      unwanted_source_files = set(found_source_files) - set(files)
442*8975f5c5SAndroid Build Coastguard Worker      if unwanted_source_files:
443*8975f5c5SAndroid Build Coastguard Worker        logging.debug('Directory requires excludes: %s', directory)
444*8975f5c5SAndroid Build Coastguard Worker        excludes.extend(
445*8975f5c5SAndroid Build Coastguard Worker            _ComputeExcludeFilters(files, unwanted_source_files, directory))
446*8975f5c5SAndroid Build Coastguard Worker
447*8975f5c5SAndroid Build Coastguard Worker    missing_source_files = set(source_files) - all_found_source_files
448*8975f5c5SAndroid Build Coastguard Worker    # Warn only about non-generated files that are missing.
449*8975f5c5SAndroid Build Coastguard Worker    missing_source_files = [
450*8975f5c5SAndroid Build Coastguard Worker        p for p in missing_source_files if not p.startswith(output_dir)
451*8975f5c5SAndroid Build Coastguard Worker    ]
452*8975f5c5SAndroid Build Coastguard Worker    if missing_source_files:
453*8975f5c5SAndroid Build Coastguard Worker      logging.warning('Some source files were not found: %s',
454*8975f5c5SAndroid Build Coastguard Worker                      missing_source_files)
455*8975f5c5SAndroid Build Coastguard Worker
456*8975f5c5SAndroid Build Coastguard Worker  return java_dirs, excludes
457*8975f5c5SAndroid Build Coastguard Worker
458*8975f5c5SAndroid Build Coastguard Worker
459*8975f5c5SAndroid Build Coastguard Workerdef _CreateRelativeSymlink(target_path, link_path):
460*8975f5c5SAndroid Build Coastguard Worker  link_dir = os.path.dirname(link_path)
461*8975f5c5SAndroid Build Coastguard Worker  relpath = os.path.relpath(target_path, link_dir)
462*8975f5c5SAndroid Build Coastguard Worker  logging.debug('Creating symlink %s -> %s', link_path, relpath)
463*8975f5c5SAndroid Build Coastguard Worker  os.symlink(relpath, link_path)
464*8975f5c5SAndroid Build Coastguard Worker
465*8975f5c5SAndroid Build Coastguard Worker
466*8975f5c5SAndroid Build Coastguard Workerdef _CreateJniLibsDir(output_dir, entry_output_dir, so_files):
467*8975f5c5SAndroid Build Coastguard Worker  """Creates directory with symlinked .so files if necessary.
468*8975f5c5SAndroid Build Coastguard Worker
469*8975f5c5SAndroid Build Coastguard Worker  Returns list of JNI libs directories."""
470*8975f5c5SAndroid Build Coastguard Worker
471*8975f5c5SAndroid Build Coastguard Worker  if so_files:
472*8975f5c5SAndroid Build Coastguard Worker    symlink_dir = os.path.join(entry_output_dir, _JNI_LIBS_SUBDIR)
473*8975f5c5SAndroid Build Coastguard Worker    shutil.rmtree(symlink_dir, True)
474*8975f5c5SAndroid Build Coastguard Worker    abi_dir = os.path.join(symlink_dir, _ARMEABI_SUBDIR)
475*8975f5c5SAndroid Build Coastguard Worker    if not os.path.exists(abi_dir):
476*8975f5c5SAndroid Build Coastguard Worker      os.makedirs(abi_dir)
477*8975f5c5SAndroid Build Coastguard Worker    for so_file in so_files:
478*8975f5c5SAndroid Build Coastguard Worker      target_path = os.path.join(output_dir, so_file)
479*8975f5c5SAndroid Build Coastguard Worker      symlinked_path = os.path.join(abi_dir, so_file)
480*8975f5c5SAndroid Build Coastguard Worker      _CreateRelativeSymlink(target_path, symlinked_path)
481*8975f5c5SAndroid Build Coastguard Worker
482*8975f5c5SAndroid Build Coastguard Worker    return [symlink_dir]
483*8975f5c5SAndroid Build Coastguard Worker
484*8975f5c5SAndroid Build Coastguard Worker  return []
485*8975f5c5SAndroid Build Coastguard Worker
486*8975f5c5SAndroid Build Coastguard Worker
487*8975f5c5SAndroid Build Coastguard Workerdef _ParseVersionFromFile(file_path, version_regex_string, default_version):
488*8975f5c5SAndroid Build Coastguard Worker  if os.path.exists(file_path):
489*8975f5c5SAndroid Build Coastguard Worker    content = pathlib.Path(file_path).read_text()
490*8975f5c5SAndroid Build Coastguard Worker    match = re.search(version_regex_string, content)
491*8975f5c5SAndroid Build Coastguard Worker    if match:
492*8975f5c5SAndroid Build Coastguard Worker      version = match.group(1)
493*8975f5c5SAndroid Build Coastguard Worker      logging.info('Using existing version %s in %s.', version, file_path)
494*8975f5c5SAndroid Build Coastguard Worker      return version
495*8975f5c5SAndroid Build Coastguard Worker    logging.warning('Unable to find %s in %s:\n%s', version_regex_string,
496*8975f5c5SAndroid Build Coastguard Worker                    file_path, content)
497*8975f5c5SAndroid Build Coastguard Worker  return default_version
498*8975f5c5SAndroid Build Coastguard Worker
499*8975f5c5SAndroid Build Coastguard Worker
500*8975f5c5SAndroid Build Coastguard Workerdef _GenerateLocalProperties(sdk_dir):
501*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for local.properties as a string."""
502*8975f5c5SAndroid Build Coastguard Worker  return '\n'.join([
503*8975f5c5SAndroid Build Coastguard Worker      '# Generated by //build/android/gradle/generate_gradle.py',
504*8975f5c5SAndroid Build Coastguard Worker      'sdk.dir=%s' % sdk_dir,
505*8975f5c5SAndroid Build Coastguard Worker      '',
506*8975f5c5SAndroid Build Coastguard Worker  ])
507*8975f5c5SAndroid Build Coastguard Worker
508*8975f5c5SAndroid Build Coastguard Worker
509*8975f5c5SAndroid Build Coastguard Workerdef _GenerateGradleWrapperProperties(file_path):
510*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for gradle-wrapper.properties as a string."""
511*8975f5c5SAndroid Build Coastguard Worker
512*8975f5c5SAndroid Build Coastguard Worker  version = _ParseVersionFromFile(file_path,
513*8975f5c5SAndroid Build Coastguard Worker                                  r'/distributions/gradle-([\d.]+)-all.zip',
514*8975f5c5SAndroid Build Coastguard Worker                                  _DEFAULT_GRADLE_WRAPPER_VERSION)
515*8975f5c5SAndroid Build Coastguard Worker
516*8975f5c5SAndroid Build Coastguard Worker  return '\n'.join([
517*8975f5c5SAndroid Build Coastguard Worker      '# Generated by //build/android/gradle/generate_gradle.py',
518*8975f5c5SAndroid Build Coastguard Worker      ('distributionUrl=https\\://services.gradle.org'
519*8975f5c5SAndroid Build Coastguard Worker       f'/distributions/gradle-{version}-all.zip'),
520*8975f5c5SAndroid Build Coastguard Worker      '',
521*8975f5c5SAndroid Build Coastguard Worker  ])
522*8975f5c5SAndroid Build Coastguard Worker
523*8975f5c5SAndroid Build Coastguard Worker
524*8975f5c5SAndroid Build Coastguard Workerdef _GenerateGradleProperties():
525*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for gradle.properties as a string."""
526*8975f5c5SAndroid Build Coastguard Worker  return '\n'.join([
527*8975f5c5SAndroid Build Coastguard Worker      '# Generated by //build/android/gradle/generate_gradle.py',
528*8975f5c5SAndroid Build Coastguard Worker      '',
529*8975f5c5SAndroid Build Coastguard Worker      '# Tells Gradle to show warnings during project sync.',
530*8975f5c5SAndroid Build Coastguard Worker      'org.gradle.warning.mode=all',
531*8975f5c5SAndroid Build Coastguard Worker      '',
532*8975f5c5SAndroid Build Coastguard Worker  ])
533*8975f5c5SAndroid Build Coastguard Worker
534*8975f5c5SAndroid Build Coastguard Worker
535*8975f5c5SAndroid Build Coastguard Workerdef _GenerateBaseVars(generator, build_vars):
536*8975f5c5SAndroid Build Coastguard Worker  variables = {}
537*8975f5c5SAndroid Build Coastguard Worker  # Avoid pre-release SDKs since Studio might not know how to download them.
538*8975f5c5SAndroid Build Coastguard Worker  variables['compile_sdk_version'] = (
539*8975f5c5SAndroid Build Coastguard Worker      'android-%s' % build_vars['android_sdk_platform_version'])
540*8975f5c5SAndroid Build Coastguard Worker  target_sdk_version = build_vars['android_sdk_platform_version']
541*8975f5c5SAndroid Build Coastguard Worker  if str(target_sdk_version).isalpha():
542*8975f5c5SAndroid Build Coastguard Worker    target_sdk_version = '"{}"'.format(target_sdk_version)
543*8975f5c5SAndroid Build Coastguard Worker  variables['target_sdk_version'] = target_sdk_version
544*8975f5c5SAndroid Build Coastguard Worker  variables['min_sdk_version'] = build_vars['default_min_sdk_version']
545*8975f5c5SAndroid Build Coastguard Worker  variables['use_gradle_process_resources'] = (
546*8975f5c5SAndroid Build Coastguard Worker      generator.use_gradle_process_resources)
547*8975f5c5SAndroid Build Coastguard Worker  return variables
548*8975f5c5SAndroid Build Coastguard Worker
549*8975f5c5SAndroid Build Coastguard Worker
550*8975f5c5SAndroid Build Coastguard Workerdef _GenerateGradleFile(entry, generator, build_vars, jinja_processor):
551*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for a project's build.gradle."""
552*8975f5c5SAndroid Build Coastguard Worker  deps_info = entry.DepsInfo()
553*8975f5c5SAndroid Build Coastguard Worker  variables = _GenerateBaseVars(generator, build_vars)
554*8975f5c5SAndroid Build Coastguard Worker  sourceSetName = 'main'
555*8975f5c5SAndroid Build Coastguard Worker
556*8975f5c5SAndroid Build Coastguard Worker  if deps_info['type'] == 'android_apk':
557*8975f5c5SAndroid Build Coastguard Worker    target_type = 'android_apk'
558*8975f5c5SAndroid Build Coastguard Worker  elif deps_info['type'] in ('java_library', 'java_annotation_processor'):
559*8975f5c5SAndroid Build Coastguard Worker    is_prebuilt = deps_info.get('is_prebuilt', False)
560*8975f5c5SAndroid Build Coastguard Worker    gradle_treat_as_prebuilt = deps_info.get('gradle_treat_as_prebuilt', False)
561*8975f5c5SAndroid Build Coastguard Worker    if is_prebuilt or gradle_treat_as_prebuilt:
562*8975f5c5SAndroid Build Coastguard Worker      return None
563*8975f5c5SAndroid Build Coastguard Worker    if deps_info['requires_android']:
564*8975f5c5SAndroid Build Coastguard Worker      target_type = 'android_library'
565*8975f5c5SAndroid Build Coastguard Worker    else:
566*8975f5c5SAndroid Build Coastguard Worker      target_type = 'java_library'
567*8975f5c5SAndroid Build Coastguard Worker  elif deps_info['type'] == 'java_binary':
568*8975f5c5SAndroid Build Coastguard Worker    target_type = 'java_binary'
569*8975f5c5SAndroid Build Coastguard Worker    variables['main_class'] = deps_info.get('main_class')
570*8975f5c5SAndroid Build Coastguard Worker  elif deps_info['type'] == 'robolectric_binary':
571*8975f5c5SAndroid Build Coastguard Worker    target_type = 'android_junit'
572*8975f5c5SAndroid Build Coastguard Worker    sourceSetName = 'test'
573*8975f5c5SAndroid Build Coastguard Worker  else:
574*8975f5c5SAndroid Build Coastguard Worker    return None
575*8975f5c5SAndroid Build Coastguard Worker
576*8975f5c5SAndroid Build Coastguard Worker  variables['target_name'] = os.path.splitext(deps_info['name'])[0]
577*8975f5c5SAndroid Build Coastguard Worker  variables['template_type'] = target_type
578*8975f5c5SAndroid Build Coastguard Worker  variables['main'] = {}
579*8975f5c5SAndroid Build Coastguard Worker  variables[sourceSetName] = generator.Generate(entry)
580*8975f5c5SAndroid Build Coastguard Worker  variables['main']['android_manifest'] = generator.GenerateManifest(entry)
581*8975f5c5SAndroid Build Coastguard Worker
582*8975f5c5SAndroid Build Coastguard Worker  if entry.android_test_entries:
583*8975f5c5SAndroid Build Coastguard Worker    variables['android_test'] = []
584*8975f5c5SAndroid Build Coastguard Worker    for e in entry.android_test_entries:
585*8975f5c5SAndroid Build Coastguard Worker      test_entry = generator.Generate(e)
586*8975f5c5SAndroid Build Coastguard Worker      test_entry['android_manifest'] = generator.GenerateManifest(e)
587*8975f5c5SAndroid Build Coastguard Worker      variables['android_test'].append(test_entry)
588*8975f5c5SAndroid Build Coastguard Worker      for key, value in test_entry.items():
589*8975f5c5SAndroid Build Coastguard Worker        if isinstance(value, list):
590*8975f5c5SAndroid Build Coastguard Worker          test_entry[key] = sorted(set(value) - set(variables['main'][key]))
591*8975f5c5SAndroid Build Coastguard Worker
592*8975f5c5SAndroid Build Coastguard Worker  return jinja_processor.Render(
593*8975f5c5SAndroid Build Coastguard Worker      _TemplatePath(target_type.split('_')[0]), variables)
594*8975f5c5SAndroid Build Coastguard Worker
595*8975f5c5SAndroid Build Coastguard Worker
596*8975f5c5SAndroid Build Coastguard Worker# Example: //chrome/android:monochrome
597*8975f5c5SAndroid Build Coastguard Workerdef _GetNative(relative_func, target_names):
598*8975f5c5SAndroid Build Coastguard Worker  """Returns an object containing native c++ sources list and its included path
599*8975f5c5SAndroid Build Coastguard Worker
600*8975f5c5SAndroid Build Coastguard Worker  Iterate through all target_names and their deps to get the list of included
601*8975f5c5SAndroid Build Coastguard Worker  paths and sources."""
602*8975f5c5SAndroid Build Coastguard Worker  out_dir = constants.GetOutDirectory()
603*8975f5c5SAndroid Build Coastguard Worker  with open(os.path.join(out_dir, 'project.json'), 'r') as project_file:
604*8975f5c5SAndroid Build Coastguard Worker    projects = json.load(project_file)
605*8975f5c5SAndroid Build Coastguard Worker  project_targets = projects['targets']
606*8975f5c5SAndroid Build Coastguard Worker  root_dir = projects['build_settings']['root_path']
607*8975f5c5SAndroid Build Coastguard Worker  includes = set()
608*8975f5c5SAndroid Build Coastguard Worker  processed_target = set()
609*8975f5c5SAndroid Build Coastguard Worker  targets_stack = list(target_names)
610*8975f5c5SAndroid Build Coastguard Worker  sources = []
611*8975f5c5SAndroid Build Coastguard Worker
612*8975f5c5SAndroid Build Coastguard Worker  while targets_stack:
613*8975f5c5SAndroid Build Coastguard Worker    target_name = targets_stack.pop()
614*8975f5c5SAndroid Build Coastguard Worker    if target_name in processed_target:
615*8975f5c5SAndroid Build Coastguard Worker      continue
616*8975f5c5SAndroid Build Coastguard Worker    processed_target.add(target_name)
617*8975f5c5SAndroid Build Coastguard Worker    target = project_targets[target_name]
618*8975f5c5SAndroid Build Coastguard Worker    includes.update(target.get('include_dirs', []))
619*8975f5c5SAndroid Build Coastguard Worker    targets_stack.extend(target.get('deps', []))
620*8975f5c5SAndroid Build Coastguard Worker    # Ignore generated files
621*8975f5c5SAndroid Build Coastguard Worker    sources.extend(f for f in target.get('sources', [])
622*8975f5c5SAndroid Build Coastguard Worker                   if f.endswith('.cc') and not f.startswith('//out'))
623*8975f5c5SAndroid Build Coastguard Worker
624*8975f5c5SAndroid Build Coastguard Worker  def process_paths(paths):
625*8975f5c5SAndroid Build Coastguard Worker    # Ignores leading //
626*8975f5c5SAndroid Build Coastguard Worker    return relative_func(
627*8975f5c5SAndroid Build Coastguard Worker        sorted(os.path.join(root_dir, path[2:]) for path in paths))
628*8975f5c5SAndroid Build Coastguard Worker
629*8975f5c5SAndroid Build Coastguard Worker  return {
630*8975f5c5SAndroid Build Coastguard Worker      'sources': process_paths(sources),
631*8975f5c5SAndroid Build Coastguard Worker      'includes': process_paths(includes),
632*8975f5c5SAndroid Build Coastguard Worker  }
633*8975f5c5SAndroid Build Coastguard Worker
634*8975f5c5SAndroid Build Coastguard Worker
635*8975f5c5SAndroid Build Coastguard Workerdef _GenerateModuleAll(gradle_output_dir, generator, build_vars,
636*8975f5c5SAndroid Build Coastguard Worker                       jinja_processor, native_targets):
637*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for a pseudo build.gradle of all dirs.
638*8975f5c5SAndroid Build Coastguard Worker
639*8975f5c5SAndroid Build Coastguard Worker  See //docs/android_studio.md for more details."""
640*8975f5c5SAndroid Build Coastguard Worker  variables = _GenerateBaseVars(generator, build_vars)
641*8975f5c5SAndroid Build Coastguard Worker  target_type = 'android_apk'
642*8975f5c5SAndroid Build Coastguard Worker  variables['target_name'] = _MODULE_ALL
643*8975f5c5SAndroid Build Coastguard Worker  variables['template_type'] = target_type
644*8975f5c5SAndroid Build Coastguard Worker  java_dirs = sorted(generator.processed_java_dirs)
645*8975f5c5SAndroid Build Coastguard Worker  prebuilts = sorted(generator.processed_prebuilts)
646*8975f5c5SAndroid Build Coastguard Worker  res_dirs = sorted(generator.processed_res_dirs)
647*8975f5c5SAndroid Build Coastguard Worker  def Relativize(paths):
648*8975f5c5SAndroid Build Coastguard Worker    return _RebasePath(paths, os.path.join(gradle_output_dir, _MODULE_ALL))
649*8975f5c5SAndroid Build Coastguard Worker
650*8975f5c5SAndroid Build Coastguard Worker  # As after clank modularization, the java and javatests code will live side by
651*8975f5c5SAndroid Build Coastguard Worker  # side in the same module, we will list both of them in the main target here.
652*8975f5c5SAndroid Build Coastguard Worker  main_java_dirs = [d for d in java_dirs if 'junit/' not in d]
653*8975f5c5SAndroid Build Coastguard Worker  junit_test_java_dirs = [d for d in java_dirs if 'junit/' in d]
654*8975f5c5SAndroid Build Coastguard Worker  variables['main'] = {
655*8975f5c5SAndroid Build Coastguard Worker      'android_manifest': Relativize(_DEFAULT_ANDROID_MANIFEST_PATH),
656*8975f5c5SAndroid Build Coastguard Worker      'java_dirs': Relativize(main_java_dirs),
657*8975f5c5SAndroid Build Coastguard Worker      'prebuilts': Relativize(prebuilts),
658*8975f5c5SAndroid Build Coastguard Worker      'java_excludes': ['**/*.java', '**/*.kt'],
659*8975f5c5SAndroid Build Coastguard Worker      'res_dirs': Relativize(res_dirs),
660*8975f5c5SAndroid Build Coastguard Worker  }
661*8975f5c5SAndroid Build Coastguard Worker  variables['android_test'] = [{
662*8975f5c5SAndroid Build Coastguard Worker      'java_dirs': Relativize(junit_test_java_dirs),
663*8975f5c5SAndroid Build Coastguard Worker      'java_excludes': ['**/*.java', '**/*.kt'],
664*8975f5c5SAndroid Build Coastguard Worker  }]
665*8975f5c5SAndroid Build Coastguard Worker  if native_targets:
666*8975f5c5SAndroid Build Coastguard Worker    variables['native'] = _GetNative(
667*8975f5c5SAndroid Build Coastguard Worker        relative_func=Relativize, target_names=native_targets)
668*8975f5c5SAndroid Build Coastguard Worker  data = jinja_processor.Render(
669*8975f5c5SAndroid Build Coastguard Worker      _TemplatePath(target_type.split('_')[0]), variables)
670*8975f5c5SAndroid Build Coastguard Worker  _WriteFile(
671*8975f5c5SAndroid Build Coastguard Worker      os.path.join(gradle_output_dir, _MODULE_ALL, _GRADLE_BUILD_FILE), data)
672*8975f5c5SAndroid Build Coastguard Worker  if native_targets:
673*8975f5c5SAndroid Build Coastguard Worker    cmake_data = jinja_processor.Render(_TemplatePath('cmake'), variables)
674*8975f5c5SAndroid Build Coastguard Worker    _WriteFile(
675*8975f5c5SAndroid Build Coastguard Worker        os.path.join(gradle_output_dir, _MODULE_ALL, _CMAKE_FILE), cmake_data)
676*8975f5c5SAndroid Build Coastguard Worker
677*8975f5c5SAndroid Build Coastguard Worker
678*8975f5c5SAndroid Build Coastguard Workerdef _GenerateRootGradle(jinja_processor, file_path):
679*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for the root project's build.gradle."""
680*8975f5c5SAndroid Build Coastguard Worker  android_gradle_plugin_version = _ParseVersionFromFile(
681*8975f5c5SAndroid Build Coastguard Worker      file_path, r'com.android.tools.build:gradle:([\d.]+)',
682*8975f5c5SAndroid Build Coastguard Worker      _DEFAULT_ANDROID_GRADLE_PLUGIN_VERSION)
683*8975f5c5SAndroid Build Coastguard Worker  kotlin_gradle_plugin_version = _ParseVersionFromFile(
684*8975f5c5SAndroid Build Coastguard Worker      file_path, r'org.jetbrains.kotlin:kotlin-gradle-plugin:([\d.]+)',
685*8975f5c5SAndroid Build Coastguard Worker      _DEFAULT_KOTLIN_GRADLE_PLUGIN_VERSION)
686*8975f5c5SAndroid Build Coastguard Worker
687*8975f5c5SAndroid Build Coastguard Worker  return jinja_processor.Render(
688*8975f5c5SAndroid Build Coastguard Worker      _TemplatePath('root'), {
689*8975f5c5SAndroid Build Coastguard Worker          'android_gradle_plugin_version': android_gradle_plugin_version,
690*8975f5c5SAndroid Build Coastguard Worker          'kotlin_gradle_plugin_version': kotlin_gradle_plugin_version,
691*8975f5c5SAndroid Build Coastguard Worker      })
692*8975f5c5SAndroid Build Coastguard Worker
693*8975f5c5SAndroid Build Coastguard Worker
694*8975f5c5SAndroid Build Coastguard Workerdef _GenerateSettingsGradle(project_entries):
695*8975f5c5SAndroid Build Coastguard Worker  """Returns the data for settings.gradle."""
696*8975f5c5SAndroid Build Coastguard Worker  project_name = os.path.basename(os.path.dirname(host_paths.DIR_SOURCE_ROOT))
697*8975f5c5SAndroid Build Coastguard Worker  lines = []
698*8975f5c5SAndroid Build Coastguard Worker  lines.append('// Generated by //build/android/gradle/generate_gradle.py')
699*8975f5c5SAndroid Build Coastguard Worker  lines.append('rootProject.name = "%s"' % project_name)
700*8975f5c5SAndroid Build Coastguard Worker  lines.append('rootProject.projectDir = settingsDir')
701*8975f5c5SAndroid Build Coastguard Worker  lines.append('')
702*8975f5c5SAndroid Build Coastguard Worker  for name, subdir in project_entries:
703*8975f5c5SAndroid Build Coastguard Worker    # Example target:
704*8975f5c5SAndroid Build Coastguard Worker    # android_webview:android_webview_java__build_config_crbug_908819
705*8975f5c5SAndroid Build Coastguard Worker    lines.append('include ":%s"' % name)
706*8975f5c5SAndroid Build Coastguard Worker    lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' %
707*8975f5c5SAndroid Build Coastguard Worker                 (name, subdir))
708*8975f5c5SAndroid Build Coastguard Worker  return '\n'.join(lines)
709*8975f5c5SAndroid Build Coastguard Worker
710*8975f5c5SAndroid Build Coastguard Worker
711*8975f5c5SAndroid Build Coastguard Workerdef _FindAllProjectEntries(main_entries):
712*8975f5c5SAndroid Build Coastguard Worker  """Returns the list of all _ProjectEntry instances given the root project."""
713*8975f5c5SAndroid Build Coastguard Worker  found = set()
714*8975f5c5SAndroid Build Coastguard Worker  to_scan = list(main_entries)
715*8975f5c5SAndroid Build Coastguard Worker  while to_scan:
716*8975f5c5SAndroid Build Coastguard Worker    cur_entry = to_scan.pop()
717*8975f5c5SAndroid Build Coastguard Worker    if cur_entry in found:
718*8975f5c5SAndroid Build Coastguard Worker      continue
719*8975f5c5SAndroid Build Coastguard Worker    found.add(cur_entry)
720*8975f5c5SAndroid Build Coastguard Worker    sub_config_paths = cur_entry.DepsInfo()['deps_configs']
721*8975f5c5SAndroid Build Coastguard Worker    to_scan.extend(
722*8975f5c5SAndroid Build Coastguard Worker        _ProjectEntry.FromBuildConfigPath(p) for p in sub_config_paths)
723*8975f5c5SAndroid Build Coastguard Worker  return list(found)
724*8975f5c5SAndroid Build Coastguard Worker
725*8975f5c5SAndroid Build Coastguard Worker
726*8975f5c5SAndroid Build Coastguard Workerdef _CombineTestEntries(entries):
727*8975f5c5SAndroid Build Coastguard Worker  """Combines test apks into the androidTest source set of their target.
728*8975f5c5SAndroid Build Coastguard Worker
729*8975f5c5SAndroid Build Coastguard Worker  - Speeds up android studio
730*8975f5c5SAndroid Build Coastguard Worker  - Adds proper dependency between test and apk_under_test
731*8975f5c5SAndroid Build Coastguard Worker  - Doesn't work for junit yet due to resulting circular dependencies
732*8975f5c5SAndroid Build Coastguard Worker    - e.g. base_junit_tests > base_junit_test_support > base_java
733*8975f5c5SAndroid Build Coastguard Worker  """
734*8975f5c5SAndroid Build Coastguard Worker  combined_entries = []
735*8975f5c5SAndroid Build Coastguard Worker  android_test_entries = collections.defaultdict(list)
736*8975f5c5SAndroid Build Coastguard Worker  for entry in entries:
737*8975f5c5SAndroid Build Coastguard Worker    target_name = entry.GnTarget()
738*8975f5c5SAndroid Build Coastguard Worker    if (target_name.endswith(_INSTRUMENTATION_TARGET_SUFFIX)
739*8975f5c5SAndroid Build Coastguard Worker        and 'apk_under_test' in entry.Gradle()):
740*8975f5c5SAndroid Build Coastguard Worker      apk_name = entry.Gradle()['apk_under_test']
741*8975f5c5SAndroid Build Coastguard Worker      android_test_entries[apk_name].append(entry)
742*8975f5c5SAndroid Build Coastguard Worker    else:
743*8975f5c5SAndroid Build Coastguard Worker      combined_entries.append(entry)
744*8975f5c5SAndroid Build Coastguard Worker  for entry in combined_entries:
745*8975f5c5SAndroid Build Coastguard Worker    target_name = entry.DepsInfo()['name']
746*8975f5c5SAndroid Build Coastguard Worker    if target_name in android_test_entries:
747*8975f5c5SAndroid Build Coastguard Worker      entry.android_test_entries = android_test_entries[target_name]
748*8975f5c5SAndroid Build Coastguard Worker      del android_test_entries[target_name]
749*8975f5c5SAndroid Build Coastguard Worker  # Add unmatched test entries as individual targets.
750*8975f5c5SAndroid Build Coastguard Worker  combined_entries.extend(e for l in android_test_entries.values() for e in l)
751*8975f5c5SAndroid Build Coastguard Worker  return combined_entries
752*8975f5c5SAndroid Build Coastguard Worker
753*8975f5c5SAndroid Build Coastguard Worker
754*8975f5c5SAndroid Build Coastguard Workerdef main():
755*8975f5c5SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
756*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--output-directory',
757*8975f5c5SAndroid Build Coastguard Worker                      help='Path to the root build directory.')
758*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('-v',
759*8975f5c5SAndroid Build Coastguard Worker                      '--verbose',
760*8975f5c5SAndroid Build Coastguard Worker                      dest='verbose_count',
761*8975f5c5SAndroid Build Coastguard Worker                      default=0,
762*8975f5c5SAndroid Build Coastguard Worker                      action='count',
763*8975f5c5SAndroid Build Coastguard Worker                      help='Verbose level')
764*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--target',
765*8975f5c5SAndroid Build Coastguard Worker                      dest='targets',
766*8975f5c5SAndroid Build Coastguard Worker                      action='append',
767*8975f5c5SAndroid Build Coastguard Worker                      help='GN target to generate project for. Replaces set of '
768*8975f5c5SAndroid Build Coastguard Worker                           'default targets. May be repeated.')
769*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--extra-target',
770*8975f5c5SAndroid Build Coastguard Worker                      dest='extra_targets',
771*8975f5c5SAndroid Build Coastguard Worker                      action='append',
772*8975f5c5SAndroid Build Coastguard Worker                      help='GN target to generate project for, in addition to '
773*8975f5c5SAndroid Build Coastguard Worker                           'the default ones. May be repeated.')
774*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--project-dir',
775*8975f5c5SAndroid Build Coastguard Worker                      help='Root of the output project.',
776*8975f5c5SAndroid Build Coastguard Worker                      default=os.path.join('$CHROMIUM_OUTPUT_DIR', 'gradle'))
777*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--all',
778*8975f5c5SAndroid Build Coastguard Worker                      action='store_true',
779*8975f5c5SAndroid Build Coastguard Worker                      help='Include all .java files reachable from any '
780*8975f5c5SAndroid Build Coastguard Worker                           'apk/test/binary target. On by default unless '
781*8975f5c5SAndroid Build Coastguard Worker                           '--split-projects is used (--split-projects can '
782*8975f5c5SAndroid Build Coastguard Worker                           'slow down Studio given too many targets).')
783*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--use-gradle-process-resources',
784*8975f5c5SAndroid Build Coastguard Worker                      action='store_true',
785*8975f5c5SAndroid Build Coastguard Worker                      help='Have gradle generate R.java rather than ninja')
786*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--split-projects',
787*8975f5c5SAndroid Build Coastguard Worker                      action='store_true',
788*8975f5c5SAndroid Build Coastguard Worker                      help='Split projects by their gn deps rather than '
789*8975f5c5SAndroid Build Coastguard Worker                           'combining all the dependencies of each target')
790*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--native-target',
791*8975f5c5SAndroid Build Coastguard Worker                      dest='native_targets',
792*8975f5c5SAndroid Build Coastguard Worker                      action='append',
793*8975f5c5SAndroid Build Coastguard Worker                      help='GN native targets to generate for. May be '
794*8975f5c5SAndroid Build Coastguard Worker                           'repeated.')
795*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument(
796*8975f5c5SAndroid Build Coastguard Worker      '--sdk-path',
797*8975f5c5SAndroid Build Coastguard Worker      default=os.path.expanduser('~/Android/Sdk'),
798*8975f5c5SAndroid Build Coastguard Worker      help='The path to use as the SDK root, overrides the '
799*8975f5c5SAndroid Build Coastguard Worker      'default at ~/Android/Sdk.')
800*8975f5c5SAndroid Build Coastguard Worker  args = parser.parse_args()
801*8975f5c5SAndroid Build Coastguard Worker  if args.output_directory:
802*8975f5c5SAndroid Build Coastguard Worker    constants.SetOutputDirectory(args.output_directory)
803*8975f5c5SAndroid Build Coastguard Worker  constants.CheckOutputDirectory()
804*8975f5c5SAndroid Build Coastguard Worker  output_dir = constants.GetOutDirectory()
805*8975f5c5SAndroid Build Coastguard Worker  devil_chromium.Initialize(output_directory=output_dir)
806*8975f5c5SAndroid Build Coastguard Worker  run_tests_helper.SetLogLevel(args.verbose_count)
807*8975f5c5SAndroid Build Coastguard Worker
808*8975f5c5SAndroid Build Coastguard Worker  if args.use_gradle_process_resources:
809*8975f5c5SAndroid Build Coastguard Worker    assert args.split_projects, (
810*8975f5c5SAndroid Build Coastguard Worker        'Gradle resources does not work without --split-projects.')
811*8975f5c5SAndroid Build Coastguard Worker
812*8975f5c5SAndroid Build Coastguard Worker  _gradle_output_dir = os.path.abspath(
813*8975f5c5SAndroid Build Coastguard Worker      args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir))
814*8975f5c5SAndroid Build Coastguard Worker  logging.warning('Creating project at: %s', _gradle_output_dir)
815*8975f5c5SAndroid Build Coastguard Worker
816*8975f5c5SAndroid Build Coastguard Worker  # Generate for "all targets" by default when not using --split-projects (too
817*8975f5c5SAndroid Build Coastguard Worker  # slow), and when no --target has been explicitly set. "all targets" means all
818*8975f5c5SAndroid Build Coastguard Worker  # java targets that are depended on by an apk or java_binary (leaf
819*8975f5c5SAndroid Build Coastguard Worker  # java_library targets will not be included).
820*8975f5c5SAndroid Build Coastguard Worker  args.all = args.all or (not args.split_projects and not args.targets)
821*8975f5c5SAndroid Build Coastguard Worker
822*8975f5c5SAndroid Build Coastguard Worker  targets_from_args = set(args.targets or _DEFAULT_TARGETS)
823*8975f5c5SAndroid Build Coastguard Worker  if args.extra_targets:
824*8975f5c5SAndroid Build Coastguard Worker    targets_from_args.update(args.extra_targets)
825*8975f5c5SAndroid Build Coastguard Worker
826*8975f5c5SAndroid Build Coastguard Worker  if args.all:
827*8975f5c5SAndroid Build Coastguard Worker    if args.native_targets:
828*8975f5c5SAndroid Build Coastguard Worker      _RunGnGen(output_dir, ['--ide=json'])
829*8975f5c5SAndroid Build Coastguard Worker    elif not os.path.exists(os.path.join(output_dir, 'build.ninja')):
830*8975f5c5SAndroid Build Coastguard Worker      _RunGnGen(output_dir)
831*8975f5c5SAndroid Build Coastguard Worker    else:
832*8975f5c5SAndroid Build Coastguard Worker      # Faster than running "gn gen" in the no-op case.
833*8975f5c5SAndroid Build Coastguard Worker      _BuildTargets(output_dir, ['build.ninja'])
834*8975f5c5SAndroid Build Coastguard Worker    # Query ninja for all __build_config_crbug_908819 targets.
835*8975f5c5SAndroid Build Coastguard Worker    targets = _QueryForAllGnTargets(output_dir)
836*8975f5c5SAndroid Build Coastguard Worker  else:
837*8975f5c5SAndroid Build Coastguard Worker    assert not args.native_targets, 'Native editing requires --all.'
838*8975f5c5SAndroid Build Coastguard Worker    targets = [
839*8975f5c5SAndroid Build Coastguard Worker        re.sub(r'_test_apk$', _INSTRUMENTATION_TARGET_SUFFIX, t)
840*8975f5c5SAndroid Build Coastguard Worker        for t in targets_from_args
841*8975f5c5SAndroid Build Coastguard Worker    ]
842*8975f5c5SAndroid Build Coastguard Worker    # Necessary after "gn clean"
843*8975f5c5SAndroid Build Coastguard Worker    if not os.path.exists(
844*8975f5c5SAndroid Build Coastguard Worker        os.path.join(output_dir, gn_helpers.BUILD_VARS_FILENAME)):
845*8975f5c5SAndroid Build Coastguard Worker      _RunGnGen(output_dir)
846*8975f5c5SAndroid Build Coastguard Worker
847*8975f5c5SAndroid Build Coastguard Worker  main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets]
848*8975f5c5SAndroid Build Coastguard Worker  if not args.all:
849*8975f5c5SAndroid Build Coastguard Worker    # list_java_targets.py takes care of building .build_config.json in the
850*8975f5c5SAndroid Build Coastguard Worker    # --all case.
851*8975f5c5SAndroid Build Coastguard Worker    _BuildTargets(output_dir, [t.BuildConfigPath() for t in main_entries])
852*8975f5c5SAndroid Build Coastguard Worker
853*8975f5c5SAndroid Build Coastguard Worker  build_vars = gn_helpers.ReadBuildVars(output_dir)
854*8975f5c5SAndroid Build Coastguard Worker  jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR)
855*8975f5c5SAndroid Build Coastguard Worker  generator = _ProjectContextGenerator(_gradle_output_dir, build_vars,
856*8975f5c5SAndroid Build Coastguard Worker                                       args.use_gradle_process_resources,
857*8975f5c5SAndroid Build Coastguard Worker                                       jinja_processor, args.split_projects)
858*8975f5c5SAndroid Build Coastguard Worker
859*8975f5c5SAndroid Build Coastguard Worker  if args.all:
860*8975f5c5SAndroid Build Coastguard Worker    # There are many unused libraries, so restrict to those that are actually
861*8975f5c5SAndroid Build Coastguard Worker    # used by apks/bundles/binaries/tests or that are explicitly mentioned in
862*8975f5c5SAndroid Build Coastguard Worker    # --targets.
863*8975f5c5SAndroid Build Coastguard Worker    BASE_TYPES = ('android_apk', 'android_app_bundle_module', 'java_binary',
864*8975f5c5SAndroid Build Coastguard Worker                  'robolectric_binary')
865*8975f5c5SAndroid Build Coastguard Worker    main_entries = [
866*8975f5c5SAndroid Build Coastguard Worker        e for e in main_entries
867*8975f5c5SAndroid Build Coastguard Worker        if (e.GetType() in BASE_TYPES or e.GnTarget() in targets_from_args
868*8975f5c5SAndroid Build Coastguard Worker            or e.GnTarget().endswith(_INSTRUMENTATION_TARGET_SUFFIX))
869*8975f5c5SAndroid Build Coastguard Worker    ]
870*8975f5c5SAndroid Build Coastguard Worker
871*8975f5c5SAndroid Build Coastguard Worker  if args.split_projects:
872*8975f5c5SAndroid Build Coastguard Worker    main_entries = _FindAllProjectEntries(main_entries)
873*8975f5c5SAndroid Build Coastguard Worker
874*8975f5c5SAndroid Build Coastguard Worker  logging.info('Generating for %d targets.', len(main_entries))
875*8975f5c5SAndroid Build Coastguard Worker
876*8975f5c5SAndroid Build Coastguard Worker  entries = [e for e in _CombineTestEntries(main_entries) if e.IsValid()]
877*8975f5c5SAndroid Build Coastguard Worker  logging.info('Creating %d projects for targets.', len(entries))
878*8975f5c5SAndroid Build Coastguard Worker
879*8975f5c5SAndroid Build Coastguard Worker  logging.warning('Writing .gradle files...')
880*8975f5c5SAndroid Build Coastguard Worker  project_entries = []
881*8975f5c5SAndroid Build Coastguard Worker  # When only one entry will be generated we want it to have a valid
882*8975f5c5SAndroid Build Coastguard Worker  # build.gradle file with its own AndroidManifest.
883*8975f5c5SAndroid Build Coastguard Worker  for entry in entries:
884*8975f5c5SAndroid Build Coastguard Worker    data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor)
885*8975f5c5SAndroid Build Coastguard Worker    if data and not args.all:
886*8975f5c5SAndroid Build Coastguard Worker      project_entries.append((entry.ProjectName(), entry.GradleSubdir()))
887*8975f5c5SAndroid Build Coastguard Worker      _WriteFile(
888*8975f5c5SAndroid Build Coastguard Worker          os.path.join(generator.EntryOutputDir(entry), _GRADLE_BUILD_FILE),
889*8975f5c5SAndroid Build Coastguard Worker          data)
890*8975f5c5SAndroid Build Coastguard Worker  if args.all:
891*8975f5c5SAndroid Build Coastguard Worker    project_entries.append((_MODULE_ALL, _MODULE_ALL))
892*8975f5c5SAndroid Build Coastguard Worker    _GenerateModuleAll(_gradle_output_dir, generator, build_vars,
893*8975f5c5SAndroid Build Coastguard Worker                       jinja_processor, args.native_targets)
894*8975f5c5SAndroid Build Coastguard Worker
895*8975f5c5SAndroid Build Coastguard Worker  root_gradle_path = os.path.join(generator.project_dir, _GRADLE_BUILD_FILE)
896*8975f5c5SAndroid Build Coastguard Worker  _WriteFile(root_gradle_path,
897*8975f5c5SAndroid Build Coastguard Worker             _GenerateRootGradle(jinja_processor, root_gradle_path))
898*8975f5c5SAndroid Build Coastguard Worker
899*8975f5c5SAndroid Build Coastguard Worker  _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'),
900*8975f5c5SAndroid Build Coastguard Worker             _GenerateSettingsGradle(project_entries))
901*8975f5c5SAndroid Build Coastguard Worker
902*8975f5c5SAndroid Build Coastguard Worker  # Ensure the Android Studio sdk is correctly initialized.
903*8975f5c5SAndroid Build Coastguard Worker  if not os.path.exists(args.sdk_path):
904*8975f5c5SAndroid Build Coastguard Worker    # Help first-time users avoid Android Studio forcibly changing back to
905*8975f5c5SAndroid Build Coastguard Worker    # the previous default due to not finding a valid sdk under this dir.
906*8975f5c5SAndroid Build Coastguard Worker    shutil.copytree(_RebasePath(build_vars['android_sdk_root']), args.sdk_path)
907*8975f5c5SAndroid Build Coastguard Worker  _WriteFile(
908*8975f5c5SAndroid Build Coastguard Worker      os.path.join(generator.project_dir, 'local.properties'),
909*8975f5c5SAndroid Build Coastguard Worker      _GenerateLocalProperties(args.sdk_path))
910*8975f5c5SAndroid Build Coastguard Worker  _WriteFile(os.path.join(generator.project_dir, 'gradle.properties'),
911*8975f5c5SAndroid Build Coastguard Worker             _GenerateGradleProperties())
912*8975f5c5SAndroid Build Coastguard Worker
913*8975f5c5SAndroid Build Coastguard Worker  wrapper_properties = os.path.join(generator.project_dir, 'gradle', 'wrapper',
914*8975f5c5SAndroid Build Coastguard Worker                                    'gradle-wrapper.properties')
915*8975f5c5SAndroid Build Coastguard Worker  _WriteFile(wrapper_properties,
916*8975f5c5SAndroid Build Coastguard Worker             _GenerateGradleWrapperProperties(wrapper_properties))
917*8975f5c5SAndroid Build Coastguard Worker
918*8975f5c5SAndroid Build Coastguard Worker  generated_inputs = set()
919*8975f5c5SAndroid Build Coastguard Worker  for entry in entries:
920*8975f5c5SAndroid Build Coastguard Worker    entries_to_gen = [entry]
921*8975f5c5SAndroid Build Coastguard Worker    entries_to_gen.extend(entry.android_test_entries)
922*8975f5c5SAndroid Build Coastguard Worker    for entry_to_gen in entries_to_gen:
923*8975f5c5SAndroid Build Coastguard Worker      # Build all paths references by .gradle that exist within output_dir.
924*8975f5c5SAndroid Build Coastguard Worker      generated_inputs.update(generator.GeneratedInputs(entry_to_gen))
925*8975f5c5SAndroid Build Coastguard Worker  if generated_inputs:
926*8975f5c5SAndroid Build Coastguard Worker    # Skip targets outside the output_dir since those are not generated.
927*8975f5c5SAndroid Build Coastguard Worker    targets = [
928*8975f5c5SAndroid Build Coastguard Worker        p for p in _RebasePath(generated_inputs, output_dir)
929*8975f5c5SAndroid Build Coastguard Worker        if not p.startswith(os.pardir)
930*8975f5c5SAndroid Build Coastguard Worker    ]
931*8975f5c5SAndroid Build Coastguard Worker    _BuildTargets(output_dir, targets)
932*8975f5c5SAndroid Build Coastguard Worker
933*8975f5c5SAndroid Build Coastguard Worker  print('Generated projects for Android Studio.')
934*8975f5c5SAndroid Build Coastguard Worker  print('** Building using Android Studio / Gradle does not work.')
935*8975f5c5SAndroid Build Coastguard Worker  print('** This project is only for IDE editing & tools.')
936*8975f5c5SAndroid Build Coastguard Worker  print('Note: Generated files will appear only if they have been built')
937*8975f5c5SAndroid Build Coastguard Worker  print('For more tips: https://chromium.googlesource.com/chromium/src.git/'
938*8975f5c5SAndroid Build Coastguard Worker        '+/main/docs/android_studio.md')
939*8975f5c5SAndroid Build Coastguard Worker
940*8975f5c5SAndroid Build Coastguard Worker
941*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__':
942*8975f5c5SAndroid Build Coastguard Worker  main()
943