blob: 3c80f23bd79cd23adac540ccca7a4006f969b08a [file] [log] [blame]
Leo Li5f369e92017-05-30 12:02:02 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2017 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
Yi Konge973e242018-09-10 13:44:28 -070017# pylint: disable=not-callable, relative-import
Leo Li5f369e92017-05-30 12:02:02 -070018
19import argparse
Leo Li5f369e92017-05-30 12:02:02 -070020import multiprocessing
21import os
Leo Li5ce70ae2017-06-13 12:42:12 -070022import shutil
23import subprocess
Leo Li5f369e92017-05-30 12:02:02 -070024
Yi Konge973e242018-09-10 13:44:28 -070025import build
26import compiler_wrapper
27import utils
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -070028
Leo Li341ed3d2017-06-07 13:27:48 -070029TARGETS = ('aosp_angler-eng', 'aosp_bullhead-eng', 'aosp_marlin-eng')
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -070030DEFAULT_TIDY_CHECKS = ('*', '-readability-*', '-google-readability-*',
31 '-google-runtime-references', '-cppcoreguidelines-*',
32 '-modernize-*', '-clang-analyzer-alpha*')
Leo Li5f369e92017-05-30 12:02:02 -070033
Pirama Arumuga Nainarb84f6552017-10-03 12:56:02 -070034# We may introduce some new warnings after rebasing and we need to disable them
35# before we fix those warnings.
36DISABLED_WARNINGS = [
Yi Kong44eac342018-10-27 12:31:57 -070037 '-Wno-error=defaulted-function-deleted',
Yi Kongcc269212019-03-01 15:09:25 -080038 '-Wno-error=string-plus-int',
39 '-fsplit-lto-unit',
Pirama Arumuga Nainarb84f6552017-10-03 12:56:02 -070040]
41
Leo Li5f369e92017-05-30 12:02:02 -070042
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -070043class ClangProfileHandler(object):
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -070044
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -070045 def __init__(self):
Pirama Arumuga Nainare6cafd82017-09-07 13:30:55 -070046 self.profiles_dir = utils.out_path('clang-profiles')
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -070047 self.profiles_format = os.path.join(self.profiles_dir, '%4m.profraw')
48
49 def getProfileFileEnvVar(self):
50 return ('LLVM_PROFILE_FILE', self.profiles_format)
51
52 def mergeProfiles(self):
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -070053 stage1_install = utils.out_path('stage1-install')
54 profdata = os.path.join(stage1_install, 'bin', 'llvm-profdata')
55
Pirama Arumuga Nainar41981bc2019-01-10 18:31:19 -080056 profdata_file = build.pgo_profdata_filename()
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -070057
Pirama Arumuga Nainare6cafd82017-09-07 13:30:55 -070058 dist_dir = os.environ.get('DIST_DIR', utils.out_path())
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -070059 out_file = os.path.join(dist_dir, profdata_file)
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -070060
61 cmd = [profdata, 'merge', '-o', out_file, self.profiles_dir]
62 subprocess.check_call(cmd)
63
64
Leo Li5f369e92017-05-30 12:02:02 -070065def parse_args():
66 parser = argparse.ArgumentParser()
67 parser.add_argument('android_path', help='Android source directory.')
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -070068 parser.add_argument(
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -070069 '--clang-path',
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -070070 nargs='?',
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -070071 help='Directory with a previously built Clang.')
72 parser.add_argument(
73 '--clang-package-path',
74 nargs='?',
75 help='Directory of a pre-packaged (.tar.bz2) Clang. '
76 'Toolchain extracted from the package will be used.')
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -070077 parser.add_argument(
78 '-k',
79 '--keep-going',
80 action='store_true',
81 default=False,
82 help='Keep going when some targets '
83 'cannot be built.')
84 parser.add_argument(
85 '-j',
86 action='store',
87 dest='jobs',
88 type=int,
89 default=multiprocessing.cpu_count(),
90 help='Number of executed jobs.')
91 parser.add_argument(
92 '--build-only',
93 action='store_true',
94 default=False,
95 help='Build default targets only.')
96 parser.add_argument(
97 '--flashall-path',
98 nargs='?',
99 help='Use internal '
100 'flashall tool if the path is set.')
101 parser.add_argument(
102 '-t',
103 '--target',
104 nargs='?',
105 help='Build for specified '
106 'target. This will work only when --build-only is '
107 'enabled.')
108 parser.add_argument(
109 '--with-tidy',
110 action='store_true',
111 default=False,
112 help='Enable clang tidy for Android build.')
Leo Li5f369e92017-05-30 12:02:02 -0700113 clean_built_target_group = parser.add_mutually_exclusive_group()
114 clean_built_target_group.add_argument(
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700115 '--clean-built-target',
116 action='store_true',
117 default=True,
Leo Li5f369e92017-05-30 12:02:02 -0700118 help='Clean output for each target that is built.')
119 clean_built_target_group.add_argument(
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700120 '--no-clean-built-target',
121 action='store_false',
122 dest='clean_built_target',
123 help='Do not remove target output.')
Leo Li5ce70ae2017-06-13 12:42:12 -0700124 redirect_stderr_group = parser.add_mutually_exclusive_group()
125 redirect_stderr_group.add_argument(
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700126 '--redirect-stderr',
127 action='store_true',
128 default=True,
Leo Li5ce70ae2017-06-13 12:42:12 -0700129 help='Redirect clang stderr to $OUT/clang-error.log.')
Leo Liaed6bea2017-06-23 16:04:00 -0700130 redirect_stderr_group.add_argument(
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700131 '--no-redirect-stderr',
132 action='store_false',
133 dest='redirect_stderr',
134 help='Do not redirect clang stderr.')
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700135
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700136 parser.add_argument(
137 '--generate-clang-profile',
138 action='store_true',
139 default=False,
140 dest='profile',
141 help='Build instrumented compiler and gather profiles')
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700142
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -0700143 parser.add_argument(
144 '--no-pgo',
145 action='store_true',
146 default=False,
147 help='Do not use PGO profile to build stage2 Clang (defaults to False)')
148
Pirama Arumuga Nainar86364b12017-09-13 10:42:21 -0700149 args = parser.parse_args()
150 if args.profile and not args.no_pgo:
151 parser.error(
152 '--no-pgo must be specified along with --generate-clang-profile')
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -0700153 if args.clang_path and args.clang_package_path:
154 parser.error('Only one of --clang-path and --clang-package-path must'
155 'be specified')
Pirama Arumuga Nainar86364b12017-09-13 10:42:21 -0700156
157 return args
Leo Li5f369e92017-05-30 12:02:02 -0700158
159
160def link_clang(android_base, clang_path):
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700161 android_clang_path = os.path.join(android_base, 'prebuilts',
162 'clang', 'host',
163 utils.build_os_type(), 'clang-dev')
Leo Li5f369e92017-05-30 12:02:02 -0700164 utils.remove(android_clang_path)
165 os.symlink(os.path.abspath(clang_path), android_clang_path)
166
167
168def get_connected_device_list():
169 try:
170 # Get current connected device list.
Haibo Huang797fc542019-08-07 18:04:24 -0700171 out = subprocess.check_output(['adb', 'devices', '-l'], universal_newlines=True)
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700172 devices = [x.split() for x in out.strip().split('\n')[1:]]
Leo Li5f369e92017-05-30 12:02:02 -0700173 return devices
174 except subprocess.CalledProcessError:
175 # If adb is not working properly. Return empty list.
176 return []
177
178
179def rm_current_product_out():
180 if 'ANDROID_PRODUCT_OUT' in os.environ:
181 utils.remove(os.environ['ANDROID_PRODUCT_OUT'])
182
183
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700184def build_target(android_base, clang_version, target, max_jobs, redirect_stderr,
Yi Kongcffd4822018-09-10 14:43:32 -0700185 with_tidy, profiler=None):
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700186 jobs = '-j{}'.format(max(1, min(max_jobs, multiprocessing.cpu_count())))
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700187 env_out = subprocess.Popen(
188 [
189 'bash', '-c', '. ./build/envsetup.sh;'
190 'lunch ' + target + ' >/dev/null && env'
191 ],
192 cwd=android_base,
193 stdout=subprocess.PIPE)
Leo Li5ce70ae2017-06-13 12:42:12 -0700194 env = {}
Leo Li5f369e92017-05-30 12:02:02 -0700195 for line in env_out.stdout:
196 (key, _, value) = line.partition('=')
197 value = value.strip()
Leo Li5ce70ae2017-06-13 12:42:12 -0700198 env[key] = value
Leo Li5f369e92017-05-30 12:02:02 -0700199 env_out.communicate()
200
Leo Li5ce70ae2017-06-13 12:42:12 -0700201 if redirect_stderr:
202 redirect_key = compiler_wrapper.STDERR_REDIRECT_KEY
Leo Liaed6bea2017-06-23 16:04:00 -0700203 if 'DIST_DIR' in env:
204 redirect_path = os.path.join(env['DIST_DIR'], 'logs',
205 'clang-error.log')
206 else:
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700207 redirect_path = os.path.abspath(
208 os.path.join(android_base, 'out', 'clang-error.log'))
Leo Liaed6bea2017-06-23 16:04:00 -0700209 utils.remove(redirect_path)
Leo Li5ce70ae2017-06-13 12:42:12 -0700210 env[redirect_key] = redirect_path
Leo Li686fce82017-07-07 11:18:38 -0700211 fallback_path = build.clang_prebuilt_bin_dir()
212 env[compiler_wrapper.PREBUILT_COMPILER_PATH_KEY] = fallback_path
Pirama Arumuga Nainarb84f6552017-10-03 12:56:02 -0700213 env[compiler_wrapper.DISABLED_WARNINGS_KEY] = ' '.join(
214 DISABLED_WARNINGS)
Leo Li5ce70ae2017-06-13 12:42:12 -0700215
Leo Lidd7832a2017-06-23 16:41:56 -0700216 env['LLVM_PREBUILTS_VERSION'] = 'clang-dev'
Pirama Arumuga Nainar08a41042017-09-20 16:09:00 -0700217 env['LLVM_RELEASE_VERSION'] = clang_version.long_version()
Leo Li5ce70ae2017-06-13 12:42:12 -0700218
Leo Lidd7832a2017-06-23 16:41:56 -0700219 if with_tidy:
220 env['WITH_TIDY'] = '1'
221 if 'DEFAULT_GLOBAL_TIDY_CHECKS' not in env:
222 env['DEFAULT_GLOBAL_TIDY_CHECKS'] = ','.join(DEFAULT_TIDY_CHECKS)
223
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700224 modules = ['dist']
225 if profiler is not None:
226 # Build only a subset of targets and collect profiles
Pirama Arumuga Nainardbb93622017-11-09 21:43:51 -0800227 modules = ['libc', 'libLLVM_android-host64']
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700228
229 key, val = profiler.getProfileFileEnvVar()
230 env[key] = val
231
Yi Konge973e242018-09-10 13:44:28 -0700232 modulesList = ' '.join(modules)
233 print 'Start building target %s and modules %s.' % (target, modulesList)
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700234 subprocess.check_call(
Pirama Arumuga Nainar538a1442019-07-30 16:56:06 -0700235 ['/bin/bash', '-c', 'build/soong/soong_ui.bash --make-mode ' + jobs + \
236 ' ' + modulesList],
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700237 cwd=android_base,
238 env=env)
Leo Li5f369e92017-05-30 12:02:02 -0700239
240
241def test_device(android_base, clang_version, device, max_jobs, clean_output,
Leo Lidd7832a2017-06-23 16:41:56 -0700242 flashall_path, redirect_stderr, with_tidy):
Leo Li5f369e92017-05-30 12:02:02 -0700243 [label, target] = device[-1].split(':')
244 # If current device is not connected correctly we will just skip it.
245 if label != 'device':
Yi Konge973e242018-09-10 13:44:28 -0700246 print 'Device %s is not connecting correctly.' % device[0]
Leo Li5f369e92017-05-30 12:02:02 -0700247 return True
248 else:
249 target = 'aosp_' + target + '-eng'
250 try:
Leo Li5ce70ae2017-06-13 12:42:12 -0700251 build_target(android_base, clang_version, target, max_jobs,
Leo Lidd7832a2017-06-23 16:41:56 -0700252 redirect_stderr, with_tidy)
Leo Li5f369e92017-05-30 12:02:02 -0700253 if flashall_path is None:
Leo Li5ce70ae2017-06-13 12:42:12 -0700254 bin_path = os.path.join(android_base, 'out', 'host',
255 utils.build_os_type(), 'bin')
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700256 subprocess.check_call(
257 ['./adb', '-s', device[0], 'reboot', 'bootloader'],
258 cwd=bin_path)
259 subprocess.check_call(
260 ['./fastboot', '-s', device[0], 'flashall'], cwd=bin_path)
Leo Li5f369e92017-05-30 12:02:02 -0700261 else:
262 os.environ['ANDROID_SERIAL'] = device[0]
263 subprocess.check_call(['./flashall'], cwd=flashall_path)
264 result = True
265 except subprocess.CalledProcessError:
Yi Konge973e242018-09-10 13:44:28 -0700266 print 'Flashing/testing android for target %s failed!' % target
Leo Li5f369e92017-05-30 12:02:02 -0700267 result = False
268 if clean_output:
269 rm_current_product_out()
270 return result
271
272
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -0700273def build_clang(instrumented=False, pgo=True):
Pirama Arumuga Nainare6cafd82017-09-07 13:30:55 -0700274 stage1_install = utils.out_path('stage1-install')
275 stage2_install = utils.out_path('stage2-install')
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700276
277 # LLVM tool llvm-profdata from stage1 is needed to merge the collected
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -0700278 # profiles. Build all LLVM tools if building instrumented stage2
Stephen Hines2a9a0402018-01-31 21:03:39 -0800279 build.build_stage1(stage1_install, build_name='dev',
280 build_llvm_tools=instrumented)
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -0700281
282 profdata = None
283 if pgo:
284 long_version = build.extract_clang_long_version(stage1_install)
285 profdata = build.pgo_profdata_file(long_version)
286
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700287 build.build_stage2(
288 stage1_install,
289 stage2_install,
290 build.STAGE2_TARGETS,
Stephen Hines2a9a0402018-01-31 21:03:39 -0800291 build_name='dev',
Pirama Arumuga Nainar641bc4b2017-09-07 16:48:34 -0700292 build_instrumented=instrumented,
293 profdata_file=profdata)
Leo Li5f369e92017-05-30 12:02:02 -0700294 build.build_runtimes(stage2_install)
Pirama Arumuga Nainar62955702019-08-27 15:40:51 -0700295
296 build.package_toolchain(
297 stage2_install,
298 'dev',
299 utils.build_os_type(),
300 dist_dir=None,
301 strip=True,
302 create_tar=False)
303
304 clang_path = build.get_package_install_path(utils.build_os_type(), 'clang-dev')
305 version = build.extract_clang_version(clang_path)
306 return clang_path, version
Leo Li5f369e92017-05-30 12:02:02 -0700307
308
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -0700309def extract_packaged_clang(package_path):
310 # Find package to extract
311 tarballs = [f for f in os.listdir(package_path) if \
Pirama Arumuga Nainarde37f722018-09-17 15:10:35 -0700312 f.endswith('.tar.bz2') and 'linux' in f]
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -0700313 if len(tarballs) != 1:
314 raise RuntimeError(
315 'No clang packages (.tar.bz2) found in ' + package_path)
316
317 tarball = os.path.join(package_path, tarballs[0])
318
319 # Extract package to $OUT_DIR/extracted
320 extract_dir = utils.out_path('extracted')
321 if os.path.exists(extract_dir):
322 utils.rm_tree(extract_dir)
323 build.check_create_path(extract_dir)
324
325 args = ['tar', '-xjC', extract_dir, '-f', tarball]
326 subprocess.check_call(args)
327
328 # Find and return a singleton subdir
329 extracted = os.listdir(extract_dir)
330 if len(extracted) != 1:
331 raise RuntimeError(
332 'Expected one file from package. Found: ' + ' '.join(extracted))
333
334 clang_path = os.path.join(extract_dir, extracted[0])
335 if not os.path.isdir(clang_path):
336 raise RuntimeError('Extracted path is not a dir: ' + clang_path)
337
338 return clang_path
339
340
Leo Li5f369e92017-05-30 12:02:02 -0700341def main():
342 args = parse_args()
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -0700343 if args.clang_path is not None:
Leo Li5f369e92017-05-30 12:02:02 -0700344 clang_path = args.clang_path
345 clang_version = build.extract_clang_version(clang_path)
Pirama Arumuga Nainara4f171d2018-09-10 11:12:37 -0700346 elif args.clang_package_path is not None:
347 clang_path = extract_packaged_clang(args.clang_package_path)
348 clang_version = build.extract_clang_version(clang_path)
349 else:
350 clang_path, clang_version = build_clang(
351 instrumented=args.profile, pgo=(not args.no_pgo))
Leo Li5f369e92017-05-30 12:02:02 -0700352 link_clang(args.android_path, clang_path)
353
Leo Li062ce692017-06-15 10:36:36 -0700354 if args.build_only:
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700355 profiler = ClangProfileHandler() if args.profile else None
356
Leo Li341ed3d2017-06-07 13:27:48 -0700357 targets = [args.target] if args.target else TARGETS
358 for target in targets:
Pirama Arumuga Nainar56cbbec2017-09-06 22:56:12 -0700359 build_target(args.android_path, clang_version, target, args.jobs,
360 args.redirect_stderr, args.with_tidy, profiler)
Pirama Arumuga Nainarab320212017-09-06 12:25:37 -0700361
362 if profiler is not None:
363 profiler.mergeProfiles()
364
Leo Li5f369e92017-05-30 12:02:02 -0700365 else:
Leo Li062ce692017-06-15 10:36:36 -0700366 devices = get_connected_device_list()
367 if len(devices) == 0:
Yi Konge973e242018-09-10 13:44:28 -0700368 print "You don't have any devices connected."
Leo Li5f369e92017-05-30 12:02:02 -0700369 for device in devices:
370 result = test_device(args.android_path, clang_version, device,
371 args.jobs, args.clean_built_target,
Leo Lidd7832a2017-06-23 16:41:56 -0700372 args.flashall_path, args.redirect_stderr,
373 args.with_tidy)
Leo Li5f369e92017-05-30 12:02:02 -0700374 if not result and not args.keep_going:
375 break
376
377
378if __name__ == '__main__':
379 main()