blob: 2bc235e130a27682ed7aa98075ce60e154738397 [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
Simon Glass9df59e42023-07-19 17:48:40 -0600151def determine_series(selected, col, git_dir, count, branch, work_in_output):
Simon Glassd230c012023-07-19 17:48:33 -0600152 """Determine the series which is to be built, if any
153
154 Args:
Simon Glass9df59e42023-07-19 17:48:40 -0600155 selected (list of Board(: List of Board objects that are marked
156 selected
157 col (Terminal.Color): Color object to use
Simon Glassd230c012023-07-19 17:48:33 -0600158 git_dir (str): Git directory to use, e.g. './.git'
Simon Glass9df59e42023-07-19 17:48:40 -0600159 count (int): Number of commits in branch
160 branch (str): Name of branch to build, or None if none
161 work_in_output (bool): True to work in the output directory
Simon Glassd230c012023-07-19 17:48:33 -0600162
163 Returns:
164 Series: Series to build, or None for none
165
166 Read the metadata from the commits. First look at the upstream commit,
167 then the ones in the branch. We would like to do something like
168 upstream/master~..branch but that isn't possible if upstream/master is
169 a merge commit (it will list all the commits that form part of the
170 merge)
171
172 Conflicting tags are not a problem for buildman, since it does not use
173 them. For example, Series-version is not useful for buildman. On the
174 other hand conflicting tags will cause an error. So allow later tags
175 to overwrite earlier ones by setting allow_overwrite=True
176 """
Simon Glass9df59e42023-07-19 17:48:40 -0600177
178 # Work out how many commits to build. We want to build everything on the
179 # branch. We also build the upstream commit as a control so we can see
180 # problems introduced by the first commit on the branch.
181 has_range = branch and '..' in branch
182 if count == -1:
183 if not branch:
184 count = 1
185 else:
186 if has_range:
187 count, msg = gitutil.count_commits_in_range(git_dir, branch)
188 else:
189 count, msg = gitutil.count_commits_in_branch(git_dir, branch)
190 if count is None:
191 sys.exit(col.build(col.RED, msg))
192 elif count == 0:
193 sys.exit(col.build(col.RED,
194 f"Range '{branch}' has no commits"))
195 if msg:
196 print(col.build(col.YELLOW, msg))
197 count += 1 # Build upstream commit also
198
199 if not count:
200 msg = (f"No commits found to process in branch '{branch}': "
201 "set branch's upstream or use -c flag")
202 sys.exit(col.build(col.RED, msg))
203 if work_in_output:
204 if len(selected) != 1:
205 sys.exit(col.build(col.RED,
206 '-w can only be used with a single board'))
207 if count != 1:
208 sys.exit(col.build(col.RED,
209 '-w can only be used with a single commit'))
210
Simon Glassd230c012023-07-19 17:48:33 -0600211 if branch:
212 if count == -1:
213 if has_range:
214 range_expr = branch
215 else:
216 range_expr = gitutil.get_range_in_branch(git_dir, branch)
217 upstream_commit = gitutil.get_upstream(git_dir, branch)
218 series = patchstream.get_metadata_for_list(upstream_commit,
219 git_dir, 1, series=None, allow_overwrite=True)
220
221 series = patchstream.get_metadata_for_list(range_expr,
222 git_dir, None, series, allow_overwrite=True)
223 else:
224 # Honour the count
225 series = patchstream.get_metadata_for_list(branch,
226 git_dir, count, series=None, allow_overwrite=True)
227 else:
228 series = None
229 return series
230
231
Simon Glassf7a36d52023-07-19 17:48:34 -0600232def do_fetch_arch(toolchains, col, fetch_arch):
233 """Handle the --fetch-arch option
234
235 Args:
236 toolchains (Toolchains): Tool chains to use
237 col (terminal.Color): Color object to build
238 fetch_arch (str): Argument passed to the --fetch-arch option
239
240 Returns:
241 int: Return code for buildman
242 """
243 if fetch_arch == 'list':
244 sorted_list = toolchains.ListArchs()
245 print(col.build(
246 col.BLUE,
247 f"Available architectures: {' '.join(sorted_list)}\n"))
248 return 0
249
250 if fetch_arch == 'all':
251 fetch_arch = ','.join(toolchains.ListArchs())
252 print(col.build(col.CYAN,
253 f'\nDownloading toolchains: {fetch_arch}'))
254 for arch in fetch_arch.split(','):
255 print()
256 ret = toolchains.FetchAndInstall(arch)
257 if ret:
258 return ret
259 return 0
260
261
Simon Glassb8680642023-07-19 17:48:42 -0600262def get_toolchains(toolchains, col, override_toolchain, fetch_arch,
263 list_tool_chains, verbose):
264 """Get toolchains object to use
265
266 Args:
267 toolchains (Toolchains or None): Toolchains to use. If None, then a
268 Toolchains object will be created and scanned
269 col (Terminal.Color): Color object
270 override_toolchain (str or None): Override value for toolchain, or None
271 fetch_arch (bool): True to fetch the toolchain for the architectures
272 list_tool_chains (bool): True to list all tool chains
273 verbose (bool): True for verbose output when listing toolchains
274
275 Returns:
276 Either:
277 int: Operation completed and buildman should exit with exit code
278 Toolchains: Toolchains object to use
279 """
280 no_toolchains = toolchains is None
281 if no_toolchains:
282 toolchains = toolchain.Toolchains(override_toolchain)
283
284 if fetch_arch:
285 return do_fetch_arch(toolchains, col, fetch_arch)
286
287 if no_toolchains:
288 toolchains.GetSettings()
289 toolchains.Scan(list_tool_chains and verbose)
290 if list_tool_chains:
291 toolchains.List()
292 print()
293 return 0
294 return toolchains
295
296
Simon Glass180c7182023-07-19 17:48:41 -0600297def get_boards_obj(output_dir, regen_board_list, maintainer_check, threads,
298 verbose):
299 """Object the Boards object to use
300
301 Creates the output directory and ensures there is a boards.cfg file, then
302 read it in.
303
304 Args:
305 output_dir (str): Output directory to use
306 regen_board_list (bool): True to just regenerate the board list
307 maintainer_check (bool): True to just run a maintainer check
308 threads (int or None): Number of threads to use to create boards file
309 verbose (bool): False to suppress output from boards-file generation
310
311 Returns:
312 Either:
313 int: Operation completed and buildman should exit with exit code
314 Boards: Boards object to use
315 """
316 brds = boards.Boards()
317 nr_cpus = threads or multiprocessing.cpu_count()
318 if maintainer_check:
319 warnings = brds.build_board_list(jobs=nr_cpus)[1]
320 if warnings:
321 for warn in warnings:
322 print(warn, file=sys.stderr)
323 return 2
324 return 0
325
326 if not os.path.exists(output_dir):
327 os.makedirs(output_dir)
328 board_file = os.path.join(output_dir, 'boards.cfg')
329 if regen_board_list and regen_board_list != '-':
330 board_file = regen_board_list
331
332 okay = brds.ensure_board_list(board_file, nr_cpus, force=regen_board_list,
333 quiet=not verbose)
334 if regen_board_list:
335 return 0 if okay else 2
336 brds.read_boards(board_file)
337 return brds
338
339
Simon Glass0d4874f2023-07-19 17:48:39 -0600340def determine_boards(brds, args, col, opt_boards, exclude_list):
341 """Determine which boards to build
342
343 Each element of args and exclude can refer to a board name, arch or SoC
344
345 Args:
346 brds (Boards): Boards object
347 args (list of str): Arguments describing boards to build
348 col (Terminal.Color): Color object
349 opt_boards (list of str): Specific boards to build, or None for all
350 exclude_list (list of str): Arguments describing boards to exclude
351
352 Returns:
353 tuple:
354 list of Board: List of Board objects that are marked selected
355 why_selected: Dictionary where each key is a buildman argument
356 provided by the user, and the value is the list of boards
357 brought in by that argument. For example, 'arm' might bring
358 in 400 boards, so in this case the key would be 'arm' and
359 the value would be a list of board names.
360 board_warnings: List of warnings obtained from board selected
361 """
362 exclude = []
363 if exclude_list:
364 for arg in exclude_list:
365 exclude += arg.split(',')
366
367 if opt_boards:
368 requested_boards = []
369 for brd in opt_boards:
370 requested_boards += brd.split(',')
371 else:
372 requested_boards = None
373 why_selected, board_warnings = brds.select_boards(args, exclude,
374 requested_boards)
375 selected = brds.get_selected()
376 if not selected:
377 sys.exit(col.build(col.RED, 'No matching boards found'))
378 return selected, why_selected, board_warnings
379
380
Simon Glass9ef05b92023-07-19 17:48:30 -0600381def do_buildman(options, args, toolchains=None, make_func=None, brds=None,
382 clean_dir=False, test_thread_exceptions=False):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000383 """The main control code for buildman
384
385 Args:
386 options: Command line options object
387 args: Command line arguments (list of strings)
Simon Glassd4144e42014-09-05 19:00:13 -0600388 toolchains: Toolchains to use - this should be a Toolchains()
389 object. If None, then it will be created and scanned
390 make_func: Make function to use for the builder. This is called
391 to execute 'make'. If this is None, the normal function
392 will be used, which calls the 'make' tool with suitable
393 arguments. This setting is useful for tests.
Simon Glasscc2c0d12022-07-11 19:04:00 -0600394 brds: Boards() object to use, containing a list of available
Simon Glass823e60b2014-09-05 19:00:16 -0600395 boards. If this is None it will be created and scanned.
Simon Glass24993312021-04-11 16:27:25 +1200396 clean_dir: Used for tests only, indicates that the existing output_dir
397 should be removed before starting the build
Simon Glass8116c782021-04-11 16:27:27 +1200398 test_thread_exceptions: Uses for tests only, True to make the threads
399 raise an exception instead of reporting their result. This simulates
400 a failure in the code somewhere
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000401 """
Simon Glassb8be2bd2023-07-19 17:48:31 -0600402 # Used so testing can obtain the builder: pylint: disable=W0603
403 global TEST_BUILDER
Simon Glass883a3212014-09-05 19:00:18 -0600404
Simon Glass0157b182022-01-29 14:14:11 -0700405 gitutil.setup()
Simon Glass713bea32016-07-27 20:33:02 -0600406 col = terminal.Color()
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000407
Simon Glassd230c012023-07-19 17:48:33 -0600408 git_dir = os.path.join(options.git, '.git')
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000409
Simon Glassb8680642023-07-19 17:48:42 -0600410 toolchains = get_toolchains(toolchains, col, options.override_toolchain,
411 options.fetch_arch, options.list_tool_chains,
412 options.verbose)
Simon Glass88daaef2020-04-17 17:51:32 -0600413 if not options.output_dir:
414 if options.work_in_output:
Simon Glass252ac582022-01-29 14:14:17 -0700415 sys.exit(col.build(col.RED, '-w requires that you specify -o'))
Simon Glass88daaef2020-04-17 17:51:32 -0600416 options.output_dir = '..'
Simon Glasseb70a2c2020-04-09 15:08:51 -0600417
Simon Glass7c66ead2019-12-05 15:59:13 -0700418 # Work out what subset of the boards we are building
Simon Glasscc2c0d12022-07-11 19:04:00 -0600419 if not brds:
Simon Glass180c7182023-07-19 17:48:41 -0600420 brds = get_boards_obj(options.output_dir, options.regen_board_list,
421 options.maintainer_check, options.threads,
422 options.verbose)
423 if isinstance(brds, int):
424 return brds
Simon Glass7c66ead2019-12-05 15:59:13 -0700425
Simon Glass0d4874f2023-07-19 17:48:39 -0600426 selected, why_selected, board_warnings = determine_boards(
427 brds, args, col, options.boards, options.exclude)
Simon Glass7c66ead2019-12-05 15:59:13 -0700428
Simon Glass4e9162d2020-03-18 09:42:47 -0600429 if options.print_prefix:
Simon Glass9ef05b92023-07-19 17:48:30 -0600430 err = show_toolchain_prefix(brds, toolchains)
Simon Glass57cb9d52019-12-05 15:59:14 -0700431 if err:
Simon Glass252ac582022-01-29 14:14:17 -0700432 sys.exit(col.build(col.RED, err))
Simon Glass57cb9d52019-12-05 15:59:14 -0700433 return 0
434
Simon Glass9df59e42023-07-19 17:48:40 -0600435 series = determine_series(selected, col, git_dir, options.count,
436 options.branch, options.work_in_output)
Simon Glassd230c012023-07-19 17:48:33 -0600437 if not series and not options.dry_run:
438 options.verbose = True
439 if not options.summary:
440 options.show_errors = True
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000441
442 # By default we have one thread per CPU. But if there are not enough jobs
443 # we can have fewer threads and use a high '-j' value for make.
Simon Glassb82492b2021-01-30 22:17:46 -0700444 if options.threads is None:
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000445 options.threads = min(multiprocessing.cpu_count(), len(selected))
446 if not options.jobs:
447 options.jobs = max(1, (multiprocessing.cpu_count() +
Simon Glassc05aa032019-10-31 07:42:53 -0600448 len(selected) - 1) // len(selected))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000449
450 if not options.step:
451 options.step = len(series.commits) - 1
452
Simon Glassd9800692022-01-29 14:14:05 -0700453 gnu_make = command.output(os.path.join(options.git,
Simon Glass785f1542016-07-25 18:59:00 -0600454 'scripts/show-gnu-make'), raise_on_error=False).rstrip()
Masahiro Yamada99796922014-07-22 11:19:09 +0900455 if not gnu_make:
Masahiro Yamada31e21412014-08-16 00:59:26 +0900456 sys.exit('GNU Make not found')
Masahiro Yamada99796922014-07-22 11:19:09 +0900457
Tom Rinid7713ad2022-11-09 19:14:53 -0700458 allow_missing = get_allow_missing(options.allow_missing,
459 options.no_allow_missing, len(selected),
460 options.branch)
461
Simon Glass05c96b12014-12-01 17:33:52 -0700462 # Create a new builder with the selected options.
463 output_dir = options.output_dir
Simon Glassfea58582014-08-09 15:32:59 -0600464 if options.branch:
Simon Glassf7582ce2014-09-05 19:00:22 -0600465 dirname = options.branch.replace('/', '_')
Simon Glass5971ab52014-12-01 17:33:55 -0700466 # As a special case allow the board directory to be placed in the
467 # output directory itself rather than any subdirectory.
468 if not options.no_subdirs:
469 output_dir = os.path.join(options.output_dir, dirname)
Lothar Waßmann409fc022018-04-08 05:14:11 -0600470 if clean_dir and os.path.exists(output_dir):
471 shutil.rmtree(output_dir)
Simon Glassf0207d72023-07-19 17:48:37 -0600472
473 # For a dry run, just show our actions as a sanity check
474 if options.dry_run:
475 show_actions(series, why_selected, selected, output_dir, options,
476 board_warnings)
477 return 0
478
Simon Glass2b4806e2022-01-22 05:07:33 -0700479 adjust_cfg = cfgutil.convert_list_to_dict(options.adjust_cfg)
480
Simon Glassbfb708a2023-02-21 12:40:29 -0700481 # Drop LOCALVERSION_AUTO since it changes the version string on every commit
482 if options.reproducible_builds:
483 # If these are mentioned, leave the local version alone
484 if 'LOCALVERSION' in adjust_cfg or 'LOCALVERSION_AUTO' in adjust_cfg:
485 print('Not dropping LOCALVERSION_AUTO for reproducible build')
486 else:
487 adjust_cfg['LOCALVERSION_AUTO'] = '~'
488
Simon Glassd230c012023-07-19 17:48:33 -0600489 builder = Builder(toolchains, output_dir, git_dir,
Masahiro Yamada99796922014-07-22 11:19:09 +0900490 options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
Simon Glass5971ab52014-12-01 17:33:55 -0700491 show_unknown=options.show_unknown, step=options.step,
Simon Glassd2ce6582014-12-01 17:34:07 -0700492 no_subdirs=options.no_subdirs, full_path=options.full_path,
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600493 verbose_build=options.verbose_build,
Simon Glasseb70a2c2020-04-09 15:08:51 -0600494 mrproper=options.mrproper,
Simon Glassb50113f2016-11-13 14:25:51 -0700495 per_board_out_dir=options.per_board_out_dir,
Simon Glassb464f8e2016-11-13 14:25:53 -0700496 config_only=options.config_only,
Daniel Schwierzeck2371d1b2018-01-26 16:31:05 +0100497 squash_config_y=not options.preserve_config_y,
Simon Glassd829f122020-03-18 09:42:42 -0600498 warnings_as_errors=options.warnings_as_errors,
Simon Glass8116c782021-04-11 16:27:27 +1200499 work_in_output=options.work_in_output,
Simon Glass2b4806e2022-01-22 05:07:33 -0700500 test_thread_exceptions=test_thread_exceptions,
Tom Rinid7713ad2022-11-09 19:14:53 -0700501 adjust_cfg=adjust_cfg,
Simon Glassbfb708a2023-02-21 12:40:29 -0700502 allow_missing=allow_missing, no_lto=options.no_lto,
503 reproducible_builds=options.reproducible_builds)
Simon Glassb8be2bd2023-07-19 17:48:31 -0600504 TEST_BUILDER = builder
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000505 builder.force_config_on_failure = not options.quick
Simon Glassd4144e42014-09-05 19:00:13 -0600506 if make_func:
507 builder.do_make = make_func
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000508
Simon Glassf0207d72023-07-19 17:48:37 -0600509 builder.force_build = options.force_build
510 builder.force_build_failures = options.force_build_failures
511 builder.force_reconfig = options.force_reconfig
512 builder.in_tree = options.in_tree
513
514 # Work out which boards to build
515 board_selected = brds.get_selected_dict()
516
517 if series:
518 commits = series.commits
519 # Number the commits for test purposes
520 for i, commit in enumerate(commits):
521 commit.sequence = i
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000522 else:
Simon Glassf0207d72023-07-19 17:48:37 -0600523 commits = None
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000524
Simon Glassf0207d72023-07-19 17:48:37 -0600525 if not options.ide:
526 tprint(get_action_summary(options.summary, commits, board_selected,
527 options))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000528
Simon Glassf0207d72023-07-19 17:48:37 -0600529 # We can't show function sizes without board details at present
530 if options.show_bloat:
531 options.show_detail = True
532 builder.SetDisplayOptions(
533 options.show_errors, options.show_sizes, options.show_detail,
534 options.show_bloat, options.list_error_boards, options.show_config,
535 options.show_environment, options.filter_dtb_warnings,
536 options.filter_migration_warnings, options.ide)
537 if options.summary:
538 builder.ShowSummary(commits, board_selected)
539 else:
540 fail, warned, excs = builder.BuildBoards(
541 commits, board_selected, options.keep_outputs, options.verbose)
542 if excs:
543 return 102
544 if fail:
545 return 100
546 if warned and not options.ignore_warnings:
547 return 101
Simon Glass2c3deb92014-08-28 09:43:39 -0600548 return 0