• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2014 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""
7cr_cronet.py - cr - like helper tool for cronet developers
8"""
9
10import argparse
11import os
12import pipes
13import re
14import subprocess
15import sys
16
17
18def quoted_args(args):
19  return ' '.join([pipes.quote(arg) for arg in args])
20
21
22def run(command, **kwargs):
23  print(command, kwargs)
24  return subprocess.call(command, **kwargs)
25
26
27def run_shell(command, extra_options=''):
28  command = command + ' ' + extra_options
29  print(command)
30  return os.system(command)
31
32
33def gn(out_dir, gn_args, gn_extra=None):
34  cmd = ['gn', 'gen', out_dir, '--args=%s' % gn_args]
35  if gn_extra:
36    cmd += gn_extra
37  return run(cmd)
38
39
40def build(out_dir, build_target, extra_options=None):
41  cmd = ['ninja', '-C', out_dir, build_target] + get_ninja_jobs_options()
42  if extra_options:
43    cmd += extra_options
44  return run(cmd)
45
46
47def install(out_dir):
48  cmd = ['build/android/adb_install_apk.py']
49  # Propagate PATH to avoid issues with missing tools http://crbug/1217979
50  env = {
51      'BUILDTYPE': out_dir[4:],
52      'PATH': os.environ.get('PATH', '')
53  }
54  return run(cmd + ['CronetTestInstrumentation.apk'], env=env) or \
55      run(cmd + ['ChromiumNetTestSupport.apk'], env=env)
56
57
58def test(out_dir, extra_options):
59  return run([out_dir + '/bin/run_cronet_test_instrumentation_apk'] +
60             extra_options)
61
62
63def unittest(out_dir, extra_options):
64  return run([out_dir + '/bin/run_cronet_unittests_android'] +
65             extra_options)
66
67
68def test_ios(out_dir, extra_options):
69  return run([out_dir + '/iossim', '-c', quoted_args(extra_options),
70             out_dir + '/cronet_test.app'])
71
72
73def unittest_ios(out_dir, extra_options):
74  return run([out_dir + '/iossim', '-c', quoted_args(extra_options),
75             out_dir + '/cronet_unittests_ios.app'])
76
77
78def debug(extra_options):
79  return run(['build/android/adb_gdb', '--start',
80             '--activity=.CronetTestActivity',
81             '--program-name=CronetTest',
82             '--package-name=org.chromium.net'] +
83             extra_options)
84
85
86def stack(out_dir):
87  return run_shell(
88      'adb logcat -d | CHROMIUM_OUTPUT_DIR=' + pipes.quote(out_dir) +
89      ' third_party/android_platform/development/scripts/stack')
90
91
92def use_goma():
93  goma_dir = (subprocess.check_output(['goma_ctl', 'goma_dir'])
94                        .decode('utf-8')
95                        .strip())
96  result = run(['goma_ctl', 'ensure_start'])
97  if not result:
98    return 'use_goma=true goma_dir="' + goma_dir + '" '
99  return ''
100
101
102def get_ninja_jobs_options():
103  if use_goma():
104    return ["-j1000"]
105  return []
106
107
108def map_config_to_android_builder(is_release, target_cpu):
109  target_cpu_to_base_builder = {
110      'x86': 'android-cronet-x86',
111      'arm': 'android-cronet-arm',
112      'arm64': 'android-cronet-arm64',
113  }
114  if target_cpu not in target_cpu_to_base_builder:
115    raise ValueError('Unsupported target CPU')
116
117  builder_name = target_cpu_to_base_builder[target_cpu]
118  if is_release:
119    builder_name += '-rel'
120  else:
121    builder_name += '-dbg'
122  return builder_name
123
124
125def get_ios_gn_args(is_release, target_cpu):
126  print(is_release, target_cpu)
127  gn_args = [
128      'target_os = "ios"',
129      'enable_websockets = false',
130      'disable_file_support = true',
131      'disable_brotli_filter = false',
132      'is_component_build = false',
133      'use_crash_key_stubs = true',
134      'use_partition_alloc = false',
135      'include_transport_security_state_preload_list = false',
136      use_goma(),
137      'use_platform_icu_alternatives = true',
138      'is_cronet_build = true',
139      'enable_remoting = false',
140      'ios_app_bundle_id_prefix = "org.chromium"',
141      'ios_deployment_target = "10.0"',
142      'enable_dsyms = true',
143      'ios_stack_profiler_enabled = false',
144      f'target_cpu = "{target_cpu}"',
145  ]
146  if is_release:
147    gn_args += [
148        'is_debug = false',
149        'is_official_build = true',
150    ],
151  return ' '.join(gn_args)
152
153
154def ios_gn_gen(is_release, target_cpu, out_dir):
155  gn_extra = ['--ide=xcode', '--filters=//components/cronet/*']
156  return gn(out_dir, get_ios_gn_args(is_release, target_cpu), gn_extra)
157
158
159def filter_gn_args(gn_args):
160  gn_arg_matcher = re.compile("^.*=.*$")
161  # `mb_py lookup` prints out a bunch of metadata lines which we don't
162  # care about, we only want the GN args.
163  assert len(gn_args) > 4
164  actual_gn_args = gn_args[1:-3]
165  for line in gn_args:
166    if line in actual_gn_args:
167      assert gn_arg_matcher.match(line), \
168             f'Not dropping {line}, which does not look like a GN arg'
169    else:
170      assert not gn_arg_matcher.match(line), \
171             f'Dropping {line}, which looks like a GN arg'
172
173  return list(filter(lambda string: "remoteexec" not in string, actual_gn_args))
174
175
176def android_gn_gen(is_release, target_cpu, out_dir):
177  group_name = 'chromium.android'
178  mb_script = 'tools/mb/mb.py'
179  builder_name = map_config_to_android_builder(is_release, target_cpu)
180  # Ideally we would call `mb_py gen` directly, but we need to filter out the
181  # use_remoteexec arg, as that cannot be used in a local environment.
182  gn_args = subprocess.check_output([
183      'python', mb_script, 'lookup', '-m', group_name, '-b', builder_name
184  ]).decode('utf-8').strip()
185  gn_args = filter_gn_args(gn_args.split("\n"))
186  return gn(out_dir, ' '.join(gn_args))
187
188
189def gn_gen(is_release, target_cpu, out_dir, is_ios):
190  if is_ios:
191    return ios_gn_gen(is_release, target_cpu, out_dir)
192  return android_gn_gen(is_release, target_cpu, out_dir)
193
194
195def main():
196  is_ios = (sys.platform == 'darwin')
197  parser = argparse.ArgumentParser()
198  parser.add_argument('command',
199                      choices=['gn',
200                               'sync',
201                               'build',
202                               'install',
203                               'proguard',
204                               'test',
205                               'build-test',
206                               'unit',
207                               'build-unit',
208                               'stack',
209                               'debug',
210                               'build-debug'])
211  parser.add_argument('-d', '--out_dir', action='store',
212                      help='name of the build directory')
213  parser.add_argument('-x', '--x86', action='store_true',
214                      help='build for Intel x86 architecture')
215  parser.add_argument('-r', '--release', action='store_true',
216                      help='use release configuration')
217  parser.add_argument('-a', '--asan', action='store_true',
218                      help='use address sanitizer')
219  if is_ios:
220    parser.add_argument('-i', '--iphoneos', action='store_true',
221                      help='build for physical iphone')
222    parser.add_argument('-b', '--bundle-id-prefix', action='store',
223                      dest='bundle_id_prefix', default='org.chromium',
224                      help='configure bundle id prefix')
225
226  options, extra_options = parser.parse_known_args()
227  print("Options:", options)
228  print("Extra options:", extra_options)
229
230  if is_ios:
231    test_target = 'cronet_test'
232    unit_target = 'cronet_unittests_ios'
233    if options.iphoneos:
234      out_dir_suffix = '-iphoneos'
235      target_cpu = 'arm64'
236    else:
237      out_dir_suffix = '-iphonesimulator'
238      target_cpu = 'x64'
239  else:  # is_android
240    test_target = 'cronet_test_instrumentation_apk'
241    unit_target = 'cronet_unittests_android'
242    if options.x86:
243      target_cpu = 'x86'
244      out_dir_suffix = '-x86'
245    else:
246      target_cpu = 'arm64'
247      out_dir_suffix = '-arm64'
248    if options.asan:
249      # ASAN on Android requires one-time setup described here:
250      # https://www.chromium.org/developers/testing/addresssanitizer
251      out_dir_suffix += '-asan'
252
253  if options.out_dir:
254    out_dir = options.out_dir
255  else:
256    if options.release:
257      out_dir = 'out/Release' + out_dir_suffix
258    else:
259      out_dir = 'out/Debug' + out_dir_suffix
260
261  if (options.command=='gn'):
262    return gn_gen(options.release, target_cpu, out_dir, is_ios)
263  if (options.command=='sync'):
264    return run(['git', 'pull', '--rebase']) or run(['gclient', 'sync'])
265  if (options.command=='build'):
266    return build(out_dir, test_target, extra_options)
267  if (not is_ios):
268    if (options.command=='install'):
269      return install(out_dir)
270    if (options.command=='proguard'):
271      return build(out_dir, 'cronet_sample_proguard_apk')
272    if (options.command=='test'):
273      return install(out_dir) or test(out_dir, extra_options)
274    if (options.command=='build-test'):
275      return build(out_dir, test_target) or install(out_dir) or \
276          test(out_dir, extra_options)
277    if (options.command=='stack'):
278      return stack(out_dir)
279    if (options.command=='debug'):
280      return install(out_dir) or debug(extra_options)
281    if (options.command=='build-debug'):
282      return build(out_dir, test_target) or install(out_dir) or \
283          debug(extra_options)
284    if (options.command=='unit'):
285      return unittest(out_dir, extra_options)
286    if (options.command=='build-unit'):
287      return build(out_dir, unit_target) or unittest(out_dir, extra_options)
288  else:
289    if (options.command=='test'):
290      return test_ios(out_dir, extra_options)
291    if (options.command=='build-test'):
292      return build(out_dir, test_target) or test_ios(out_dir, extra_options)
293    if (options.command=='unit'):
294      return unittest_ios(out_dir, extra_options)
295    if (options.command=='build-unit'):
296      return build(out_dir, unit_target) or unittest_ios(out_dir, extra_options)
297
298  parser.print_help()
299  return 1
300
301
302if __name__ == '__main__':
303  sys.exit(main())
304