blob: d6648685823ac2a2d8a6f39b22a75cd6d641a815 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass190064b2014-08-09 15:33:00 -06002# Copyright (c) 2014 Google, Inc
3#
Simon Glass190064b2014-08-09 15:33:00 -06004
5import errno
6import glob
7import os
8import shutil
Lothar Waßmann409fc022018-04-08 05:14:11 -06009import sys
Simon Glass190064b2014-08-09 15:33:00 -060010import threading
11
Simon Glassbf776672020-04-17 18:09:04 -060012from patman import command
13from patman import gitutil
Simon Glass190064b2014-08-09 15:33:00 -060014
Simon Glass88c8dcf2015-02-05 22:06:13 -070015RETURN_CODE_RETRY = -1
Simon Glass73da3d22020-12-16 17:24:17 -070016BASE_ELF_FILENAMES = ['u-boot', 'spl/u-boot-spl', 'tpl/u-boot-tpl']
Simon Glass88c8dcf2015-02-05 22:06:13 -070017
Thierry Redingf3d015c2014-08-19 10:22:39 +020018def Mkdir(dirname, parents = False):
Simon Glass190064b2014-08-09 15:33:00 -060019 """Make a directory if it doesn't already exist.
20
21 Args:
22 dirname: Directory to create
23 """
24 try:
Thierry Redingf3d015c2014-08-19 10:22:39 +020025 if parents:
26 os.makedirs(dirname)
27 else:
28 os.mkdir(dirname)
Simon Glass190064b2014-08-09 15:33:00 -060029 except OSError as err:
30 if err.errno == errno.EEXIST:
Lothar Waßmann409fc022018-04-08 05:14:11 -060031 if os.path.realpath('.') == os.path.realpath(dirname):
Simon Glassc05aa032019-10-31 07:42:53 -060032 print("Cannot create the current working directory '%s'!" % dirname)
Lothar Waßmann409fc022018-04-08 05:14:11 -060033 sys.exit(1)
Simon Glass190064b2014-08-09 15:33:00 -060034 pass
35 else:
36 raise
37
38class BuilderJob:
39 """Holds information about a job to be performed by a thread
40
41 Members:
42 board: Board object to build
Simon Glasse9fbbf62020-03-18 09:42:41 -060043 commits: List of Commit objects to build
44 keep_outputs: True to save build output files
45 step: 1 to process every commit, n to process every nth commit
Simon Glassd829f122020-03-18 09:42:42 -060046 work_in_output: Use the output directory as the work directory and
47 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -060048 """
49 def __init__(self):
50 self.board = None
51 self.commits = []
Simon Glasse9fbbf62020-03-18 09:42:41 -060052 self.keep_outputs = False
53 self.step = 1
Simon Glassd829f122020-03-18 09:42:42 -060054 self.work_in_output = False
Simon Glass190064b2014-08-09 15:33:00 -060055
56
57class ResultThread(threading.Thread):
58 """This thread processes results from builder threads.
59
60 It simply passes the results on to the builder. There is only one
61 result thread, and this helps to serialise the build output.
62 """
63 def __init__(self, builder):
64 """Set up a new result thread
65
66 Args:
67 builder: Builder which will be sent each result
68 """
69 threading.Thread.__init__(self)
70 self.builder = builder
71
72 def run(self):
73 """Called to start up the result thread.
74
75 We collect the next result job and pass it on to the build.
76 """
77 while True:
78 result = self.builder.out_queue.get()
79 self.builder.ProcessResult(result)
80 self.builder.out_queue.task_done()
81
82
83class BuilderThread(threading.Thread):
84 """This thread builds U-Boot for a particular board.
85
86 An input queue provides each new job. We run 'make' to build U-Boot
87 and then pass the results on to the output queue.
88
89 Members:
90 builder: The builder which contains information we might need
91 thread_num: Our thread number (0-n-1), used to decide on a
92 temporary directory
93 """
Simon Glasseb70a2c2020-04-09 15:08:51 -060094 def __init__(self, builder, thread_num, mrproper, per_board_out_dir):
Simon Glass190064b2014-08-09 15:33:00 -060095 """Set up a new builder thread"""
96 threading.Thread.__init__(self)
97 self.builder = builder
98 self.thread_num = thread_num
Simon Glasseb70a2c2020-04-09 15:08:51 -060099 self.mrproper = mrproper
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600100 self.per_board_out_dir = per_board_out_dir
Simon Glass190064b2014-08-09 15:33:00 -0600101
102 def Make(self, commit, brd, stage, cwd, *args, **kwargs):
103 """Run 'make' on a particular commit and board.
104
105 The source code will already be checked out, so the 'commit'
106 argument is only for information.
107
108 Args:
109 commit: Commit object that is being built
110 brd: Board object that is being built
111 stage: Stage of the build. Valid stages are:
Roger Meierfd18a892014-08-20 22:10:29 +0200112 mrproper - can be called to clean source
Simon Glass190064b2014-08-09 15:33:00 -0600113 config - called to configure for a board
114 build - the main make invocation - it does the build
115 args: A list of arguments to pass to 'make'
116 kwargs: A list of keyword arguments to pass to command.RunPipe()
117
118 Returns:
119 CommandResult object
120 """
121 return self.builder.do_make(commit, brd, stage, cwd, *args,
122 **kwargs)
123
Simon Glassa9401b22016-11-16 14:09:25 -0700124 def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only,
Simon Glassd829f122020-03-18 09:42:42 -0600125 force_build, force_build_failures, work_in_output):
Simon Glass190064b2014-08-09 15:33:00 -0600126 """Build a particular commit.
127
128 If the build is already done, and we are not forcing a build, we skip
129 the build and just return the previously-saved results.
130
131 Args:
132 commit_upto: Commit number to build (0...n-1)
133 brd: Board object to build
134 work_dir: Directory to which the source will be checked out
135 do_config: True to run a make <board>_defconfig on the source
Simon Glassa9401b22016-11-16 14:09:25 -0700136 config_only: Only configure the source, do not build it
Simon Glass190064b2014-08-09 15:33:00 -0600137 force_build: Force a build even if one was previously done
138 force_build_failures: Force a bulid if the previous result showed
139 failure
Simon Glassd829f122020-03-18 09:42:42 -0600140 work_in_output: Use the output directory as the work directory and
141 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -0600142
143 Returns:
144 tuple containing:
145 - CommandResult object containing the results of the build
146 - boolean indicating whether 'make config' is still needed
147 """
148 # Create a default result - it will be overwritte by the call to
149 # self.Make() below, in the event that we do a build.
150 result = command.CommandResult()
151 result.return_code = 0
Simon Glassd829f122020-03-18 09:42:42 -0600152 if work_in_output or self.builder.in_tree:
Simon Glass190064b2014-08-09 15:33:00 -0600153 out_dir = work_dir
154 else:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600155 if self.per_board_out_dir:
156 out_rel_dir = os.path.join('..', brd.target)
157 else:
158 out_rel_dir = 'build'
159 out_dir = os.path.join(work_dir, out_rel_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600160
161 # Check if the job was already completed last time
162 done_file = self.builder.GetDoneFile(commit_upto, brd.target)
163 result.already_done = os.path.exists(done_file)
164 will_build = (force_build or force_build_failures or
165 not result.already_done)
Simon Glassfb3954f2014-09-05 19:00:17 -0600166 if result.already_done:
Simon Glass190064b2014-08-09 15:33:00 -0600167 # Get the return code from that build and use it
168 with open(done_file, 'r') as fd:
Simon Glasse74429b2018-12-10 09:05:23 -0700169 try:
170 result.return_code = int(fd.readline())
171 except ValueError:
172 # The file may be empty due to running out of disk space.
173 # Try a rebuild
174 result.return_code = RETURN_CODE_RETRY
Simon Glass88c8dcf2015-02-05 22:06:13 -0700175
176 # Check the signal that the build needs to be retried
177 if result.return_code == RETURN_CODE_RETRY:
178 will_build = True
179 elif will_build:
Simon Glassfb3954f2014-09-05 19:00:17 -0600180 err_file = self.builder.GetErrFile(commit_upto, brd.target)
181 if os.path.exists(err_file) and os.stat(err_file).st_size:
182 result.stderr = 'bad'
183 elif not force_build:
184 # The build passed, so no need to build it again
185 will_build = False
Simon Glass190064b2014-08-09 15:33:00 -0600186
187 if will_build:
188 # We are going to have to build it. First, get a toolchain
189 if not self.toolchain:
190 try:
191 self.toolchain = self.builder.toolchains.Select(brd.arch)
192 except ValueError as err:
193 result.return_code = 10
194 result.stdout = ''
195 result.stderr = str(err)
196 # TODO(sjg@chromium.org): This gets swallowed, but needs
197 # to be reported.
198
199 if self.toolchain:
200 # Checkout the right commit
201 if self.builder.commits:
202 commit = self.builder.commits[commit_upto]
203 if self.builder.checkout:
204 git_dir = os.path.join(work_dir, '.git')
205 gitutil.Checkout(commit.hash, git_dir, work_dir,
206 force=True)
207 else:
208 commit = 'current'
209
210 # Set up the environment and command line
Simon Glassbb1501f2014-12-01 17:34:00 -0700211 env = self.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass190064b2014-08-09 15:33:00 -0600212 Mkdir(out_dir)
213 args = []
214 cwd = work_dir
Simon Glass48c1b6a2014-08-28 09:43:42 -0600215 src_dir = os.path.realpath(work_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600216 if not self.builder.in_tree:
217 if commit_upto is None:
218 # In this case we are building in the original source
219 # directory (i.e. the current directory where buildman
220 # is invoked. The output directory is set to this
221 # thread's selected work directory.
222 #
223 # Symlinks can confuse U-Boot's Makefile since
224 # we may use '..' in our path, so remove them.
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600225 out_dir = os.path.realpath(out_dir)
226 args.append('O=%s' % out_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600227 cwd = None
Simon Glass48c1b6a2014-08-28 09:43:42 -0600228 src_dir = os.getcwd()
Simon Glass190064b2014-08-09 15:33:00 -0600229 else:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600230 args.append('O=%s' % out_rel_dir)
Tom Rinif5e5ece2015-04-01 07:47:41 -0400231 if self.builder.verbose_build:
232 args.append('V=1')
233 else:
Simon Glassd2ce6582014-12-01 17:34:07 -0700234 args.append('-s')
Simon Glass190064b2014-08-09 15:33:00 -0600235 if self.builder.num_jobs is not None:
236 args.extend(['-j', str(self.builder.num_jobs)])
Daniel Schwierzeck2371d1b2018-01-26 16:31:05 +0100237 if self.builder.warnings_as_errors:
238 args.append('KCFLAGS=-Werror')
Simon Glass190064b2014-08-09 15:33:00 -0600239 config_args = ['%s_defconfig' % brd.target]
240 config_out = ''
241 args.extend(self.builder.toolchains.GetMakeArguments(brd))
Simon Glass00beb242019-01-07 16:44:20 -0700242 args.extend(self.toolchain.MakeArgs())
Simon Glass190064b2014-08-09 15:33:00 -0600243
Simon Glass73da3d22020-12-16 17:24:17 -0700244 # Remove any output targets. Since we use a build directory that
245 # was previously used by another board, it may have produced an
246 # SPL image. If we don't remove it (i.e. see do_config and
247 # self.mrproper below) then it will appear to be the output of
248 # this build, even if it does not produce SPL images.
249 build_dir = self.builder.GetBuildDir(commit_upto, brd.target)
250 for elf in BASE_ELF_FILENAMES:
251 fname = os.path.join(out_dir, elf)
252 if os.path.exists(fname):
253 os.remove(fname)
254
Simon Glass190064b2014-08-09 15:33:00 -0600255 # If we need to reconfigure, do that now
256 if do_config:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600257 config_out = ''
Simon Glasseb70a2c2020-04-09 15:08:51 -0600258 if self.mrproper:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600259 result = self.Make(commit, brd, 'mrproper', cwd,
260 'mrproper', *args, env=env)
261 config_out += result.combined
Simon Glass190064b2014-08-09 15:33:00 -0600262 result = self.Make(commit, brd, 'config', cwd,
263 *(args + config_args), env=env)
Simon Glass40f11fc2015-02-05 22:06:12 -0700264 config_out += result.combined
Simon Glass190064b2014-08-09 15:33:00 -0600265 do_config = False # No need to configure next time
266 if result.return_code == 0:
Simon Glassa9401b22016-11-16 14:09:25 -0700267 if config_only:
Simon Glassb50113f2016-11-13 14:25:51 -0700268 args.append('cfg')
Simon Glass190064b2014-08-09 15:33:00 -0600269 result = self.Make(commit, brd, 'build', cwd, *args,
270 env=env)
Simon Glass48c1b6a2014-08-28 09:43:42 -0600271 result.stderr = result.stderr.replace(src_dir + '/', '')
Simon Glass40f11fc2015-02-05 22:06:12 -0700272 if self.builder.verbose_build:
273 result.stdout = config_out + result.stdout
Simon Glass190064b2014-08-09 15:33:00 -0600274 else:
275 result.return_code = 1
276 result.stderr = 'No tool chain for %s\n' % brd.arch
277 result.already_done = False
278
279 result.toolchain = self.toolchain
280 result.brd = brd
281 result.commit_upto = commit_upto
282 result.out_dir = out_dir
283 return result, do_config
284
Simon Glassd829f122020-03-18 09:42:42 -0600285 def _WriteResult(self, result, keep_outputs, work_in_output):
Simon Glass190064b2014-08-09 15:33:00 -0600286 """Write a built result to the output directory.
287
288 Args:
289 result: CommandResult object containing result to write
290 keep_outputs: True to store the output binaries, False
291 to delete them
Simon Glassd829f122020-03-18 09:42:42 -0600292 work_in_output: Use the output directory as the work directory and
293 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -0600294 """
295 # Fatal error
296 if result.return_code < 0:
297 return
298
Simon Glass88c8dcf2015-02-05 22:06:13 -0700299 # If we think this might have been aborted with Ctrl-C, record the
300 # failure but not that we are 'done' with this board. A retry may fix
301 # it.
302 maybe_aborted = result.stderr and 'No child processes' in result.stderr
Simon Glass190064b2014-08-09 15:33:00 -0600303
304 if result.already_done:
305 return
306
307 # Write the output and stderr
308 output_dir = self.builder._GetOutputDir(result.commit_upto)
309 Mkdir(output_dir)
310 build_dir = self.builder.GetBuildDir(result.commit_upto,
311 result.brd.target)
312 Mkdir(build_dir)
313
314 outfile = os.path.join(build_dir, 'log')
315 with open(outfile, 'w') as fd:
316 if result.stdout:
Simon Glassc05aa032019-10-31 07:42:53 -0600317 fd.write(result.stdout)
Simon Glass190064b2014-08-09 15:33:00 -0600318
319 errfile = self.builder.GetErrFile(result.commit_upto,
320 result.brd.target)
321 if result.stderr:
322 with open(errfile, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600323 fd.write(result.stderr)
Simon Glass190064b2014-08-09 15:33:00 -0600324 elif os.path.exists(errfile):
325 os.remove(errfile)
326
327 if result.toolchain:
328 # Write the build result and toolchain information.
329 done_file = self.builder.GetDoneFile(result.commit_upto,
330 result.brd.target)
331 with open(done_file, 'w') as fd:
Simon Glass88c8dcf2015-02-05 22:06:13 -0700332 if maybe_aborted:
333 # Special code to indicate we need to retry
334 fd.write('%s' % RETURN_CODE_RETRY)
335 else:
336 fd.write('%s' % result.return_code)
Simon Glass190064b2014-08-09 15:33:00 -0600337 with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600338 print('gcc', result.toolchain.gcc, file=fd)
339 print('path', result.toolchain.path, file=fd)
340 print('cross', result.toolchain.cross, file=fd)
341 print('arch', result.toolchain.arch, file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600342 fd.write('%s' % result.return_code)
343
Simon Glass190064b2014-08-09 15:33:00 -0600344 # Write out the image and function size information and an objdump
Simon Glassbb1501f2014-12-01 17:34:00 -0700345 env = result.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass166a98a2020-04-17 17:51:33 -0600346 with open(os.path.join(build_dir, 'out-env'), 'w') as fd:
Simon Glasse5fc79e2019-01-07 16:44:23 -0700347 for var in sorted(env.keys()):
Simon Glassc05aa032019-10-31 07:42:53 -0600348 print('%s="%s"' % (var, env[var]), file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600349 lines = []
Simon Glass73da3d22020-12-16 17:24:17 -0700350 for fname in BASE_ELF_FILENAMES:
Simon Glass190064b2014-08-09 15:33:00 -0600351 cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
352 nm_result = command.RunPipe([cmd], capture=True,
353 capture_stderr=True, cwd=result.out_dir,
354 raise_on_error=False, env=env)
355 if nm_result.stdout:
356 nm = self.builder.GetFuncSizesFile(result.commit_upto,
357 result.brd.target, fname)
358 with open(nm, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600359 print(nm_result.stdout, end=' ', file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600360
361 cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
362 dump_result = command.RunPipe([cmd], capture=True,
363 capture_stderr=True, cwd=result.out_dir,
364 raise_on_error=False, env=env)
365 rodata_size = ''
366 if dump_result.stdout:
367 objdump = self.builder.GetObjdumpFile(result.commit_upto,
368 result.brd.target, fname)
369 with open(objdump, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600370 print(dump_result.stdout, end=' ', file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600371 for line in dump_result.stdout.splitlines():
372 fields = line.split()
373 if len(fields) > 5 and fields[1] == '.rodata':
374 rodata_size = fields[2]
375
376 cmd = ['%ssize' % self.toolchain.cross, fname]
377 size_result = command.RunPipe([cmd], capture=True,
378 capture_stderr=True, cwd=result.out_dir,
379 raise_on_error=False, env=env)
380 if size_result.stdout:
381 lines.append(size_result.stdout.splitlines()[1] + ' ' +
382 rodata_size)
383
Alex Kiernan0ddc5102018-05-31 04:48:33 +0000384 # Extract the environment from U-Boot and dump it out
385 cmd = ['%sobjcopy' % self.toolchain.cross, '-O', 'binary',
386 '-j', '.rodata.default_environment',
387 'env/built-in.o', 'uboot.env']
388 command.RunPipe([cmd], capture=True,
389 capture_stderr=True, cwd=result.out_dir,
390 raise_on_error=False, env=env)
391 ubootenv = os.path.join(result.out_dir, 'uboot.env')
Simon Glass60b285f2020-04-17 17:51:34 -0600392 if not work_in_output:
393 self.CopyFiles(result.out_dir, build_dir, '', ['uboot.env'])
Alex Kiernan0ddc5102018-05-31 04:48:33 +0000394
Simon Glass190064b2014-08-09 15:33:00 -0600395 # Write out the image sizes file. This is similar to the output
396 # of binutil's 'size' utility, but it omits the header line and
397 # adds an additional hex value at the end of each line for the
398 # rodata size
399 if len(lines):
400 sizes = self.builder.GetSizesFile(result.commit_upto,
401 result.brd.target)
402 with open(sizes, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600403 print('\n'.join(lines), file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600404
Simon Glass60b285f2020-04-17 17:51:34 -0600405 if not work_in_output:
406 # Write out the configuration files, with a special case for SPL
407 for dirname in ['', 'spl', 'tpl']:
408 self.CopyFiles(
409 result.out_dir, build_dir, dirname,
410 ['u-boot.cfg', 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg',
411 '.config', 'include/autoconf.mk',
412 'include/generated/autoconf.h'])
Simon Glass970f9322015-02-05 22:06:14 -0700413
Simon Glass60b285f2020-04-17 17:51:34 -0600414 # Now write the actual build output
415 if keep_outputs:
416 self.CopyFiles(
417 result.out_dir, build_dir, '',
418 ['u-boot*', '*.bin', '*.map', '*.img', 'MLO', 'SPL',
419 'include/autoconf.mk', 'spl/u-boot-spl*'])
Simon Glass190064b2014-08-09 15:33:00 -0600420
Simon Glass970f9322015-02-05 22:06:14 -0700421 def CopyFiles(self, out_dir, build_dir, dirname, patterns):
422 """Copy files from the build directory to the output.
423
424 Args:
425 out_dir: Path to output directory containing the files
426 build_dir: Place to copy the files
427 dirname: Source directory, '' for normal U-Boot, 'spl' for SPL
428 patterns: A list of filenames (strings) to copy, each relative
429 to the build directory
430 """
431 for pattern in patterns:
432 file_list = glob.glob(os.path.join(out_dir, dirname, pattern))
433 for fname in file_list:
434 target = os.path.basename(fname)
435 if dirname:
436 base, ext = os.path.splitext(target)
437 if ext:
438 target = '%s-%s%s' % (base, dirname, ext)
439 shutil.copy(fname, os.path.join(build_dir, target))
Simon Glass190064b2014-08-09 15:33:00 -0600440
441 def RunJob(self, job):
442 """Run a single job
443
444 A job consists of a building a list of commits for a particular board.
445
446 Args:
447 job: Job to build
448 """
449 brd = job.board
450 work_dir = self.builder.GetThreadDir(self.thread_num)
451 self.toolchain = None
452 if job.commits:
453 # Run 'make board_defconfig' on the first commit
454 do_config = True
455 commit_upto = 0
456 force_build = False
457 for commit_upto in range(0, len(job.commits), job.step):
458 result, request_config = self.RunCommit(commit_upto, brd,
Simon Glassa9401b22016-11-16 14:09:25 -0700459 work_dir, do_config, self.builder.config_only,
Simon Glass190064b2014-08-09 15:33:00 -0600460 force_build or self.builder.force_build,
Simon Glassd829f122020-03-18 09:42:42 -0600461 self.builder.force_build_failures,
462 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600463 failed = result.return_code or result.stderr
464 did_config = do_config
465 if failed and not do_config:
466 # If our incremental build failed, try building again
467 # with a reconfig.
468 if self.builder.force_config_on_failure:
469 result, request_config = self.RunCommit(commit_upto,
Simon Glassd829f122020-03-18 09:42:42 -0600470 brd, work_dir, True, False, True, False,
471 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600472 did_config = True
473 if not self.builder.force_reconfig:
474 do_config = request_config
475
476 # If we built that commit, then config is done. But if we got
477 # an warning, reconfig next time to force it to build the same
478 # files that created warnings this time. Otherwise an
479 # incremental build may not build the same file, and we will
480 # think that the warning has gone away.
481 # We could avoid this by using -Werror everywhere...
482 # For errors, the problem doesn't happen, since presumably
483 # the build stopped and didn't generate output, so will retry
484 # that file next time. So we could detect warnings and deal
485 # with them specially here. For now, we just reconfigure if
486 # anything goes work.
487 # Of course this is substantially slower if there are build
488 # errors/warnings (e.g. 2-3x slower even if only 10% of builds
489 # have problems).
490 if (failed and not result.already_done and not did_config and
491 self.builder.force_config_on_failure):
492 # If this build failed, try the next one with a
493 # reconfigure.
494 # Sometimes if the board_config.h file changes it can mess
495 # with dependencies, and we get:
496 # make: *** No rule to make target `include/autoconf.mk',
497 # needed by `depend'.
498 do_config = True
499 force_build = True
500 else:
501 force_build = False
502 if self.builder.force_config_on_failure:
503 if failed:
504 do_config = True
505 result.commit_upto = commit_upto
506 if result.return_code < 0:
507 raise ValueError('Interrupt')
508
509 # We have the build results, so output the result
Simon Glassd829f122020-03-18 09:42:42 -0600510 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600511 self.builder.out_queue.put(result)
512 else:
513 # Just build the currently checked-out build
514 result, request_config = self.RunCommit(None, brd, work_dir, True,
Simon Glassa9401b22016-11-16 14:09:25 -0700515 self.builder.config_only, True,
Simon Glassd829f122020-03-18 09:42:42 -0600516 self.builder.force_build_failures,
517 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600518 result.commit_upto = 0
Simon Glassd829f122020-03-18 09:42:42 -0600519 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600520 self.builder.out_queue.put(result)
521
522 def run(self):
523 """Our thread's run function
524
525 This thread picks a job from the queue, runs it, and then goes to the
526 next job.
527 """
Simon Glass190064b2014-08-09 15:33:00 -0600528 while True:
529 job = self.builder.queue.get()
Simon Glass2880e6b2016-09-18 16:48:38 -0600530 self.RunJob(job)
Simon Glass190064b2014-08-09 15:33:00 -0600531 self.builder.queue.task_done()