blob: 8f1edf9dbb959857e84edd2a944ec01673e7b357 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassfc3fe1c2013-04-03 11:07:16 +00002# Copyright (c) 2013 The Chromium OS Authors.
3#
Simon Glassfc3fe1c2013-04-03 11:07:16 +00004
Simon Glass9ef05b92023-07-19 17:48:30 -06005"""Control module for buildman
6
7This holds the main control logic for buildman, when not running tests.
8"""
9
Simon Glassfc3fe1c2013-04-03 11:07:16 +000010import multiprocessing
11import os
Simon Glass883a3212014-09-05 19:00:18 -060012import shutil
Simon Glassfc3fe1c2013-04-03 11:07:16 +000013import sys
14
Simon Glassc52bd222022-07-11 19:04:03 -060015from buildman import boards
Simon Glass0ede00f2020-04-17 18:09:02 -060016from buildman import bsettings
Simon Glass2b4806e2022-01-22 05:07:33 -070017from buildman import cfgutil
Simon Glass0ede00f2020-04-17 18:09:02 -060018from buildman import toolchain
19from buildman.builder import Builder
Simon Glassbf776672020-04-17 18:09:04 -060020from patman import gitutil
21from patman import patchstream
Simon Glass4583c002023-02-23 18:18:04 -070022from u_boot_pylib import command
23from u_boot_pylib import terminal
Simon Glass4583c002023-02-23 18:18:04 -070024from u_boot_pylib.terminal import tprint
Simon Glassfc3fe1c2013-04-03 11:07:16 +000025
Simon Glassb8be2bd2023-07-19 17:48:31 -060026TEST_BUILDER = None
27
Simon Glass9ef05b92023-07-19 17:48:30 -060028def get_plural(count):
Simon Glassfc3fe1c2013-04-03 11:07:16 +000029 """Returns a plural 's' if count is not 1"""
30 return 's' if count != 1 else ''
31
Simon Glass9ef05b92023-07-19 17:48:30 -060032def get_action_summary(is_summary, commits, selected, options):
Simon Glassfc3fe1c2013-04-03 11:07:16 +000033 """Return a string summarising the intended action.
34
35 Returns:
36 Summary string.
37 """
Simon Glassfea58582014-08-09 15:32:59 -060038 if commits:
39 count = len(commits)
Simon Glassc05aa032019-10-31 07:42:53 -060040 count = (count + options.step - 1) // options.step
Simon Glassb8be2bd2023-07-19 17:48:31 -060041 commit_str = f'{count} commit{get_plural(count)}'
Simon Glassfea58582014-08-09 15:32:59 -060042 else:
43 commit_str = 'current source'
Simon Glassb8be2bd2023-07-19 17:48:31 -060044 msg = (f"{'Summary of' if is_summary else 'Building'} "
45 f'{commit_str} for {len(selected)} boards')
46 msg += (f' ({options.threads} thread{get_plural(options.threads)}, '
47 f'{options.jobs} job{get_plural(options.jobs)} per thread)')
48 return msg
Simon Glassfc3fe1c2013-04-03 11:07:16 +000049
Simon Glassb8be2bd2023-07-19 17:48:31 -060050# pylint: disable=R0913
Simon Glassd233dfb2023-07-19 17:48:36 -060051def show_actions(series, why_selected, boards_selected, output_dir, options,
Simon Glass9ef05b92023-07-19 17:48:30 -060052 board_warnings):
Simon Glassfc3fe1c2013-04-03 11:07:16 +000053 """Display a list of actions that we would take, if not a dry run.
54
55 Args:
56 series: Series object
57 why_selected: Dictionary where each key is a buildman argument
Simon Glass8d7523c2017-01-23 05:38:56 -070058 provided by the user, and the value is the list of boards
59 brought in by that argument. For example, 'arm' might bring
60 in 400 boards, so in this case the key would be 'arm' and
Simon Glassfc3fe1c2013-04-03 11:07:16 +000061 the value would be a list of board names.
62 boards_selected: Dict of selected boards, key is target name,
63 value is Board object
Simon Glassd233dfb2023-07-19 17:48:36 -060064 output_dir (str): Output directory for builder
Simon Glassfc3fe1c2013-04-03 11:07:16 +000065 options: Command line options object
Simon Glass06890362018-06-11 23:26:46 -060066 board_warnings: List of warnings obtained from board selected
Simon Glassfc3fe1c2013-04-03 11:07:16 +000067 """
68 col = terminal.Color()
Simon Glassc05aa032019-10-31 07:42:53 -060069 print('Dry run, so not doing much. But I would do this:')
70 print()
Simon Glassfea58582014-08-09 15:32:59 -060071 if series:
72 commits = series.commits
73 else:
74 commits = None
Simon Glass9ef05b92023-07-19 17:48:30 -060075 print(get_action_summary(False, commits, boards_selected,
Simon Glassc05aa032019-10-31 07:42:53 -060076 options))
Simon Glassd233dfb2023-07-19 17:48:36 -060077 print(f'Build directory: {output_dir}')
Simon Glassfea58582014-08-09 15:32:59 -060078 if commits:
79 for upto in range(0, len(series.commits), options.step):
80 commit = series.commits[upto]
Simon Glass252ac582022-01-29 14:14:17 -070081 print(' ', col.build(col.YELLOW, commit.hash[:8], bright=False), end=' ')
Simon Glassc05aa032019-10-31 07:42:53 -060082 print(commit.subject)
83 print()
Simon Glassfc3fe1c2013-04-03 11:07:16 +000084 for arg in why_selected:
85 if arg != 'all':
Simon Glassb8be2bd2023-07-19 17:48:31 -060086 print(arg, f': {len(why_selected[arg])} boards')
Simon Glass8d7523c2017-01-23 05:38:56 -070087 if options.verbose:
Simon Glassb8be2bd2023-07-19 17:48:31 -060088 print(f" {' '.join(why_selected[arg])}")
89 print('Total boards to build for each '
90 f"commit: {len(why_selected['all'])}\n")
Simon Glass06890362018-06-11 23:26:46 -060091 if board_warnings:
92 for warning in board_warnings:
Simon Glass252ac582022-01-29 14:14:17 -070093 print(col.build(col.YELLOW, warning))
Simon Glassfc3fe1c2013-04-03 11:07:16 +000094
Simon Glass9ef05b92023-07-19 17:48:30 -060095def show_toolchain_prefix(brds, toolchains):
Simon Glass57cb9d52019-12-05 15:59:14 -070096 """Show information about a the tool chain used by one or more boards
97
Simon Glass4e9162d2020-03-18 09:42:47 -060098 The function checks that all boards use the same toolchain, then prints
99 the correct value for CROSS_COMPILE.
Simon Glass57cb9d52019-12-05 15:59:14 -0700100
101 Args:
102 boards: Boards object containing selected boards
103 toolchains: Toolchains object containing available toolchains
Simon Glass57cb9d52019-12-05 15:59:14 -0700104
105 Return:
106 None on success, string error message otherwise
107 """
Simon Glass6014db62022-07-11 19:04:02 -0600108 board_selected = brds.get_selected_dict()
Simon Glass57cb9d52019-12-05 15:59:14 -0700109 tc_set = set()
Simon Glasscc2c0d12022-07-11 19:04:00 -0600110 for brd in board_selected.values():
Simon Glass57cb9d52019-12-05 15:59:14 -0700111 tc_set.add(toolchains.Select(brd.arch))
112 if len(tc_set) != 1:
113 return 'Supplied boards must share one toolchain'
Simon Glassb8be2bd2023-07-19 17:48:31 -0600114 tchain = tc_set.pop()
115 print(tchain.GetEnvArgs(toolchain.VAR_CROSS_COMPILE))
Simon Glass57cb9d52019-12-05 15:59:14 -0700116 return None
117
Tom Rinid7713ad2022-11-09 19:14:53 -0700118def get_allow_missing(opt_allow, opt_no_allow, num_selected, has_branch):
Simon Glassb8be2bd2023-07-19 17:48:31 -0600119 """Figure out whether to allow external blobs
120
121 Uses the allow-missing setting and the provided arguments to decide whether
122 missing external blobs should be allowed
123
124 Args:
125 opt_allow (bool): True if --allow-missing flag is set
126 opt_no_allow (bool): True if --no-allow-missing flag is set
127 num_selected (int): Number of selected board
128 has_branch (bool): True if a git branch (to build) has been provided
129
130 Returns:
131 bool: True to allow missing external blobs, False to produce an error if
132 external blobs are used
133 """
Tom Rinid7713ad2022-11-09 19:14:53 -0700134 allow_missing = False
135 am_setting = bsettings.GetGlobalItemValue('allow-missing')
136 if am_setting:
137 if am_setting == 'always':
138 allow_missing = True
139 if 'multiple' in am_setting and num_selected > 1:
140 allow_missing = True
141 if 'branch' in am_setting and has_branch:
142 allow_missing = True
143
144 if opt_allow:
145 allow_missing = True
146 if opt_no_allow:
147 allow_missing = False
148 return allow_missing
149
Simon Glassd230c012023-07-19 17:48:33 -0600150
151def determine_series(count, has_range, branch, git_dir):
152 """Determine the series which is to be built, if any
153
154 Args:
155 count (int): Number of commits in branch
156 has_range (bool): True if a range of commits ('xx..yy') is being built
157 branch (str): Name of branch to build, or None if none
158 git_dir (str): Git directory to use, e.g. './.git'
159
160 Returns:
161 Series: Series to build, or None for none
162
163 Read the metadata from the commits. First look at the upstream commit,
164 then the ones in the branch. We would like to do something like
165 upstream/master~..branch but that isn't possible if upstream/master is
166 a merge commit (it will list all the commits that form part of the
167 merge)
168
169 Conflicting tags are not a problem for buildman, since it does not use
170 them. For example, Series-version is not useful for buildman. On the
171 other hand conflicting tags will cause an error. So allow later tags
172 to overwrite earlier ones by setting allow_overwrite=True
173 """
174 if branch:
175 if count == -1:
176 if has_range:
177 range_expr = branch
178 else:
179 range_expr = gitutil.get_range_in_branch(git_dir, branch)
180 upstream_commit = gitutil.get_upstream(git_dir, branch)
181 series = patchstream.get_metadata_for_list(upstream_commit,
182 git_dir, 1, series=None, allow_overwrite=True)
183
184 series = patchstream.get_metadata_for_list(range_expr,
185 git_dir, None, series, allow_overwrite=True)
186 else:
187 # Honour the count
188 series = patchstream.get_metadata_for_list(branch,
189 git_dir, count, series=None, allow_overwrite=True)
190 else:
191 series = None
192 return series
193
194
Simon Glassf7a36d52023-07-19 17:48:34 -0600195def do_fetch_arch(toolchains, col, fetch_arch):
196 """Handle the --fetch-arch option
197
198 Args:
199 toolchains (Toolchains): Tool chains to use
200 col (terminal.Color): Color object to build
201 fetch_arch (str): Argument passed to the --fetch-arch option
202
203 Returns:
204 int: Return code for buildman
205 """
206 if fetch_arch == 'list':
207 sorted_list = toolchains.ListArchs()
208 print(col.build(
209 col.BLUE,
210 f"Available architectures: {' '.join(sorted_list)}\n"))
211 return 0
212
213 if fetch_arch == 'all':
214 fetch_arch = ','.join(toolchains.ListArchs())
215 print(col.build(col.CYAN,
216 f'\nDownloading toolchains: {fetch_arch}'))
217 for arch in fetch_arch.split(','):
218 print()
219 ret = toolchains.FetchAndInstall(arch)
220 if ret:
221 return ret
222 return 0
223
224
Simon Glass0d4874f2023-07-19 17:48:39 -0600225def determine_boards(brds, args, col, opt_boards, exclude_list):
226 """Determine which boards to build
227
228 Each element of args and exclude can refer to a board name, arch or SoC
229
230 Args:
231 brds (Boards): Boards object
232 args (list of str): Arguments describing boards to build
233 col (Terminal.Color): Color object
234 opt_boards (list of str): Specific boards to build, or None for all
235 exclude_list (list of str): Arguments describing boards to exclude
236
237 Returns:
238 tuple:
239 list of Board: List of Board objects that are marked selected
240 why_selected: Dictionary where each key is a buildman argument
241 provided by the user, and the value is the list of boards
242 brought in by that argument. For example, 'arm' might bring
243 in 400 boards, so in this case the key would be 'arm' and
244 the value would be a list of board names.
245 board_warnings: List of warnings obtained from board selected
246 """
247 exclude = []
248 if exclude_list:
249 for arg in exclude_list:
250 exclude += arg.split(',')
251
252 if opt_boards:
253 requested_boards = []
254 for brd in opt_boards:
255 requested_boards += brd.split(',')
256 else:
257 requested_boards = None
258 why_selected, board_warnings = brds.select_boards(args, exclude,
259 requested_boards)
260 selected = brds.get_selected()
261 if not selected:
262 sys.exit(col.build(col.RED, 'No matching boards found'))
263 return selected, why_selected, board_warnings
264
265
Simon Glass9ef05b92023-07-19 17:48:30 -0600266def do_buildman(options, args, toolchains=None, make_func=None, brds=None,
267 clean_dir=False, test_thread_exceptions=False):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000268 """The main control code for buildman
269
270 Args:
271 options: Command line options object
272 args: Command line arguments (list of strings)
Simon Glassd4144e42014-09-05 19:00:13 -0600273 toolchains: Toolchains to use - this should be a Toolchains()
274 object. If None, then it will be created and scanned
275 make_func: Make function to use for the builder. This is called
276 to execute 'make'. If this is None, the normal function
277 will be used, which calls the 'make' tool with suitable
278 arguments. This setting is useful for tests.
Simon Glasscc2c0d12022-07-11 19:04:00 -0600279 brds: Boards() object to use, containing a list of available
Simon Glass823e60b2014-09-05 19:00:16 -0600280 boards. If this is None it will be created and scanned.
Simon Glass24993312021-04-11 16:27:25 +1200281 clean_dir: Used for tests only, indicates that the existing output_dir
282 should be removed before starting the build
Simon Glass8116c782021-04-11 16:27:27 +1200283 test_thread_exceptions: Uses for tests only, True to make the threads
284 raise an exception instead of reporting their result. This simulates
285 a failure in the code somewhere
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000286 """
Simon Glassb8be2bd2023-07-19 17:48:31 -0600287 # Used so testing can obtain the builder: pylint: disable=W0603
288 global TEST_BUILDER
Simon Glass883a3212014-09-05 19:00:18 -0600289
Simon Glass0157b182022-01-29 14:14:11 -0700290 gitutil.setup()
Simon Glass713bea32016-07-27 20:33:02 -0600291 col = terminal.Color()
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000292
Simon Glassd230c012023-07-19 17:48:33 -0600293 git_dir = os.path.join(options.git, '.git')
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000294
Simon Glass7e92e462016-07-27 20:33:04 -0600295 no_toolchains = toolchains is None
296 if no_toolchains:
Simon Glass00beb242019-01-07 16:44:20 -0700297 toolchains = toolchain.Toolchains(options.override_toolchain)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000298
Simon Glass827e37b2014-12-01 17:34:06 -0700299 if options.fetch_arch:
Simon Glassf7a36d52023-07-19 17:48:34 -0600300 return do_fetch_arch(toolchains, col, options.fetch_arch)
Simon Glass827e37b2014-12-01 17:34:06 -0700301
Simon Glass7e92e462016-07-27 20:33:04 -0600302 if no_toolchains:
303 toolchains.GetSettings()
Simon Glass40232c92018-11-06 16:02:10 -0700304 toolchains.Scan(options.list_tool_chains and options.verbose)
Simon Glass7e92e462016-07-27 20:33:04 -0600305 if options.list_tool_chains:
306 toolchains.List()
Simon Glassc05aa032019-10-31 07:42:53 -0600307 print()
Simon Glass7e92e462016-07-27 20:33:04 -0600308 return 0
309
Simon Glass88daaef2020-04-17 17:51:32 -0600310 if not options.output_dir:
311 if options.work_in_output:
Simon Glass252ac582022-01-29 14:14:17 -0700312 sys.exit(col.build(col.RED, '-w requires that you specify -o'))
Simon Glass88daaef2020-04-17 17:51:32 -0600313 options.output_dir = '..'
Simon Glasseb70a2c2020-04-09 15:08:51 -0600314
Simon Glass1b218422023-07-19 17:48:27 -0600315 nr_cups = options.threads or multiprocessing.cpu_count()
316
Simon Glass7c66ead2019-12-05 15:59:13 -0700317 # Work out what subset of the boards we are building
Simon Glasscc2c0d12022-07-11 19:04:00 -0600318 if not brds:
Simon Glass7c66ead2019-12-05 15:59:13 -0700319 if not os.path.exists(options.output_dir):
320 os.makedirs(options.output_dir)
321 board_file = os.path.join(options.output_dir, 'boards.cfg')
Simon Glassa1431e62023-07-19 17:48:28 -0600322 if options.regen_board_list and options.regen_board_list != '-':
323 board_file = options.regen_board_list
Simon Glass7c66ead2019-12-05 15:59:13 -0700324
Simon Glassc52bd222022-07-11 19:04:03 -0600325 brds = boards.Boards()
Simon Glassb8be2bd2023-07-19 17:48:31 -0600326
Simon Glass1b218422023-07-19 17:48:27 -0600327 if options.maintainer_check:
328 warnings = brds.build_board_list(jobs=nr_cups)[1]
329 if warnings:
330 for warn in warnings:
331 print(warn, file=sys.stderr)
332 return 2
333 return 0
334
Simon Glassb8be2bd2023-07-19 17:48:31 -0600335 okay = brds.ensure_board_list(
336 board_file,
337 options.threads or multiprocessing.cpu_count(),
338 force=options.regen_board_list,
339 quiet=not options.verbose)
Simon Glassa8a01412022-07-11 19:04:04 -0600340 if options.regen_board_list:
Simon Glassb8be2bd2023-07-19 17:48:31 -0600341 return 0 if okay else 2
Simon Glass6014db62022-07-11 19:04:02 -0600342 brds.read_boards(board_file)
Simon Glass7c66ead2019-12-05 15:59:13 -0700343
Simon Glass0d4874f2023-07-19 17:48:39 -0600344 selected, why_selected, board_warnings = determine_boards(
345 brds, args, col, options.boards, options.exclude)
Simon Glass7c66ead2019-12-05 15:59:13 -0700346
Simon Glass4e9162d2020-03-18 09:42:47 -0600347 if options.print_prefix:
Simon Glass9ef05b92023-07-19 17:48:30 -0600348 err = show_toolchain_prefix(brds, toolchains)
Simon Glass57cb9d52019-12-05 15:59:14 -0700349 if err:
Simon Glass252ac582022-01-29 14:14:17 -0700350 sys.exit(col.build(col.RED, err))
Simon Glass57cb9d52019-12-05 15:59:14 -0700351 return 0
352
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000353 # Work out how many commits to build. We want to build everything on the
354 # branch. We also build the upstream commit as a control so we can see
355 # problems introduced by the first commit on the branch.
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000356 count = options.count
Simon Glass5abab202014-12-01 17:33:57 -0700357 has_range = options.branch and '..' in options.branch
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000358 if count == -1:
359 if not options.branch:
Simon Glassfea58582014-08-09 15:32:59 -0600360 count = 1
361 else:
Simon Glass5abab202014-12-01 17:33:57 -0700362 if has_range:
Simon Glassd230c012023-07-19 17:48:33 -0600363 count, msg = gitutil.count_commits_in_range(git_dir,
364 options.branch)
Simon Glass5abab202014-12-01 17:33:57 -0700365 else:
Simon Glassd230c012023-07-19 17:48:33 -0600366 count, msg = gitutil.count_commits_in_branch(git_dir,
367 options.branch)
Simon Glassfea58582014-08-09 15:32:59 -0600368 if count is None:
Simon Glass252ac582022-01-29 14:14:17 -0700369 sys.exit(col.build(col.RED, msg))
Simon Glass5abab202014-12-01 17:33:57 -0700370 elif count == 0:
Simon Glassb8be2bd2023-07-19 17:48:31 -0600371 sys.exit(col.build(col.RED,
372 f"Range '{options.branch}' has no commits"))
Simon Glass2a9e2c62014-12-01 17:33:54 -0700373 if msg:
Simon Glass252ac582022-01-29 14:14:17 -0700374 print(col.build(col.YELLOW, msg))
Simon Glassfea58582014-08-09 15:32:59 -0600375 count += 1 # Build upstream commit also
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000376
377 if not count:
Simon Glassb8be2bd2023-07-19 17:48:31 -0600378 msg = (f"No commits found to process in branch '{options.branch}': "
379 "set branch's upstream or use -c flag")
Simon Glass8dd7be72023-02-23 18:18:11 -0700380 sys.exit(col.build(col.RED, msg))
Simon Glassd829f122020-03-18 09:42:42 -0600381 if options.work_in_output:
382 if len(selected) != 1:
Simon Glass252ac582022-01-29 14:14:17 -0700383 sys.exit(col.build(col.RED,
Simon Glassd829f122020-03-18 09:42:42 -0600384 '-w can only be used with a single board'))
385 if count != 1:
Simon Glass252ac582022-01-29 14:14:17 -0700386 sys.exit(col.build(col.RED,
Simon Glassd829f122020-03-18 09:42:42 -0600387 '-w can only be used with a single commit'))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000388
Simon Glassd230c012023-07-19 17:48:33 -0600389 series = determine_series(count, has_range, options.branch, git_dir)
390 if not series and not options.dry_run:
391 options.verbose = True
392 if not options.summary:
393 options.show_errors = True
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000394
395 # By default we have one thread per CPU. But if there are not enough jobs
396 # we can have fewer threads and use a high '-j' value for make.
Simon Glassb82492b2021-01-30 22:17:46 -0700397 if options.threads is None:
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000398 options.threads = min(multiprocessing.cpu_count(), len(selected))
399 if not options.jobs:
400 options.jobs = max(1, (multiprocessing.cpu_count() +
Simon Glassc05aa032019-10-31 07:42:53 -0600401 len(selected) - 1) // len(selected))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000402
403 if not options.step:
404 options.step = len(series.commits) - 1
405
Simon Glassd9800692022-01-29 14:14:05 -0700406 gnu_make = command.output(os.path.join(options.git,
Simon Glass785f1542016-07-25 18:59:00 -0600407 'scripts/show-gnu-make'), raise_on_error=False).rstrip()
Masahiro Yamada99796922014-07-22 11:19:09 +0900408 if not gnu_make:
Masahiro Yamada31e21412014-08-16 00:59:26 +0900409 sys.exit('GNU Make not found')
Masahiro Yamada99796922014-07-22 11:19:09 +0900410
Tom Rinid7713ad2022-11-09 19:14:53 -0700411 allow_missing = get_allow_missing(options.allow_missing,
412 options.no_allow_missing, len(selected),
413 options.branch)
414
Simon Glass05c96b12014-12-01 17:33:52 -0700415 # Create a new builder with the selected options.
416 output_dir = options.output_dir
Simon Glassfea58582014-08-09 15:32:59 -0600417 if options.branch:
Simon Glassf7582ce2014-09-05 19:00:22 -0600418 dirname = options.branch.replace('/', '_')
Simon Glass5971ab52014-12-01 17:33:55 -0700419 # As a special case allow the board directory to be placed in the
420 # output directory itself rather than any subdirectory.
421 if not options.no_subdirs:
422 output_dir = os.path.join(options.output_dir, dirname)
Lothar Waßmann409fc022018-04-08 05:14:11 -0600423 if clean_dir and os.path.exists(output_dir):
424 shutil.rmtree(output_dir)
Simon Glassf0207d72023-07-19 17:48:37 -0600425
426 # For a dry run, just show our actions as a sanity check
427 if options.dry_run:
428 show_actions(series, why_selected, selected, output_dir, options,
429 board_warnings)
430 return 0
431
Simon Glass2b4806e2022-01-22 05:07:33 -0700432 adjust_cfg = cfgutil.convert_list_to_dict(options.adjust_cfg)
433
Simon Glassbfb708a2023-02-21 12:40:29 -0700434 # Drop LOCALVERSION_AUTO since it changes the version string on every commit
435 if options.reproducible_builds:
436 # If these are mentioned, leave the local version alone
437 if 'LOCALVERSION' in adjust_cfg or 'LOCALVERSION_AUTO' in adjust_cfg:
438 print('Not dropping LOCALVERSION_AUTO for reproducible build')
439 else:
440 adjust_cfg['LOCALVERSION_AUTO'] = '~'
441
Simon Glassd230c012023-07-19 17:48:33 -0600442 builder = Builder(toolchains, output_dir, git_dir,
Masahiro Yamada99796922014-07-22 11:19:09 +0900443 options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
Simon Glass5971ab52014-12-01 17:33:55 -0700444 show_unknown=options.show_unknown, step=options.step,
Simon Glassd2ce6582014-12-01 17:34:07 -0700445 no_subdirs=options.no_subdirs, full_path=options.full_path,
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600446 verbose_build=options.verbose_build,
Simon Glasseb70a2c2020-04-09 15:08:51 -0600447 mrproper=options.mrproper,
Simon Glassb50113f2016-11-13 14:25:51 -0700448 per_board_out_dir=options.per_board_out_dir,
Simon Glassb464f8e2016-11-13 14:25:53 -0700449 config_only=options.config_only,
Daniel Schwierzeck2371d1b2018-01-26 16:31:05 +0100450 squash_config_y=not options.preserve_config_y,
Simon Glassd829f122020-03-18 09:42:42 -0600451 warnings_as_errors=options.warnings_as_errors,
Simon Glass8116c782021-04-11 16:27:27 +1200452 work_in_output=options.work_in_output,
Simon Glass2b4806e2022-01-22 05:07:33 -0700453 test_thread_exceptions=test_thread_exceptions,
Tom Rinid7713ad2022-11-09 19:14:53 -0700454 adjust_cfg=adjust_cfg,
Simon Glassbfb708a2023-02-21 12:40:29 -0700455 allow_missing=allow_missing, no_lto=options.no_lto,
456 reproducible_builds=options.reproducible_builds)
Simon Glassb8be2bd2023-07-19 17:48:31 -0600457 TEST_BUILDER = builder
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000458 builder.force_config_on_failure = not options.quick
Simon Glassd4144e42014-09-05 19:00:13 -0600459 if make_func:
460 builder.do_make = make_func
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000461
Simon Glassf0207d72023-07-19 17:48:37 -0600462 builder.force_build = options.force_build
463 builder.force_build_failures = options.force_build_failures
464 builder.force_reconfig = options.force_reconfig
465 builder.in_tree = options.in_tree
466
467 # Work out which boards to build
468 board_selected = brds.get_selected_dict()
469
470 if series:
471 commits = series.commits
472 # Number the commits for test purposes
473 for i, commit in enumerate(commits):
474 commit.sequence = i
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000475 else:
Simon Glassf0207d72023-07-19 17:48:37 -0600476 commits = None
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000477
Simon Glassf0207d72023-07-19 17:48:37 -0600478 if not options.ide:
479 tprint(get_action_summary(options.summary, commits, board_selected,
480 options))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000481
Simon Glassf0207d72023-07-19 17:48:37 -0600482 # We can't show function sizes without board details at present
483 if options.show_bloat:
484 options.show_detail = True
485 builder.SetDisplayOptions(
486 options.show_errors, options.show_sizes, options.show_detail,
487 options.show_bloat, options.list_error_boards, options.show_config,
488 options.show_environment, options.filter_dtb_warnings,
489 options.filter_migration_warnings, options.ide)
490 if options.summary:
491 builder.ShowSummary(commits, board_selected)
492 else:
493 fail, warned, excs = builder.BuildBoards(
494 commits, board_selected, options.keep_outputs, options.verbose)
495 if excs:
496 return 102
497 if fail:
498 return 100
499 if warned and not options.ignore_warnings:
500 return 101
Simon Glass2c3deb92014-08-28 09:43:39 -0600501 return 0