blob: 06ed27203a27f44c3f7e8f2355c99f894ff46b11 [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
Simon Glassb82492b2021-01-30 22:17:46 -070092 temporary directory. If this is -1 then there are no threads
93 and we are the (only) main process
Simon Glass190064b2014-08-09 15:33:00 -060094 """
Simon Glasseb70a2c2020-04-09 15:08:51 -060095 def __init__(self, builder, thread_num, mrproper, per_board_out_dir):
Simon Glass190064b2014-08-09 15:33:00 -060096 """Set up a new builder thread"""
97 threading.Thread.__init__(self)
98 self.builder = builder
99 self.thread_num = thread_num
Simon Glasseb70a2c2020-04-09 15:08:51 -0600100 self.mrproper = mrproper
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600101 self.per_board_out_dir = per_board_out_dir
Simon Glass190064b2014-08-09 15:33:00 -0600102
103 def Make(self, commit, brd, stage, cwd, *args, **kwargs):
104 """Run 'make' on a particular commit and board.
105
106 The source code will already be checked out, so the 'commit'
107 argument is only for information.
108
109 Args:
110 commit: Commit object that is being built
111 brd: Board object that is being built
112 stage: Stage of the build. Valid stages are:
Roger Meierfd18a892014-08-20 22:10:29 +0200113 mrproper - can be called to clean source
Simon Glass190064b2014-08-09 15:33:00 -0600114 config - called to configure for a board
115 build - the main make invocation - it does the build
116 args: A list of arguments to pass to 'make'
117 kwargs: A list of keyword arguments to pass to command.RunPipe()
118
119 Returns:
120 CommandResult object
121 """
122 return self.builder.do_make(commit, brd, stage, cwd, *args,
123 **kwargs)
124
Simon Glassa9401b22016-11-16 14:09:25 -0700125 def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only,
Simon Glassd829f122020-03-18 09:42:42 -0600126 force_build, force_build_failures, work_in_output):
Simon Glass190064b2014-08-09 15:33:00 -0600127 """Build a particular commit.
128
129 If the build is already done, and we are not forcing a build, we skip
130 the build and just return the previously-saved results.
131
132 Args:
133 commit_upto: Commit number to build (0...n-1)
134 brd: Board object to build
135 work_dir: Directory to which the source will be checked out
136 do_config: True to run a make <board>_defconfig on the source
Simon Glassa9401b22016-11-16 14:09:25 -0700137 config_only: Only configure the source, do not build it
Simon Glass190064b2014-08-09 15:33:00 -0600138 force_build: Force a build even if one was previously done
139 force_build_failures: Force a bulid if the previous result showed
140 failure
Simon Glassd829f122020-03-18 09:42:42 -0600141 work_in_output: Use the output directory as the work directory and
142 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -0600143
144 Returns:
145 tuple containing:
146 - CommandResult object containing the results of the build
147 - boolean indicating whether 'make config' is still needed
148 """
149 # Create a default result - it will be overwritte by the call to
150 # self.Make() below, in the event that we do a build.
151 result = command.CommandResult()
152 result.return_code = 0
Simon Glassd829f122020-03-18 09:42:42 -0600153 if work_in_output or self.builder.in_tree:
Simon Glass190064b2014-08-09 15:33:00 -0600154 out_dir = work_dir
155 else:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600156 if self.per_board_out_dir:
157 out_rel_dir = os.path.join('..', brd.target)
158 else:
159 out_rel_dir = 'build'
160 out_dir = os.path.join(work_dir, out_rel_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600161
162 # Check if the job was already completed last time
163 done_file = self.builder.GetDoneFile(commit_upto, brd.target)
164 result.already_done = os.path.exists(done_file)
165 will_build = (force_build or force_build_failures or
166 not result.already_done)
Simon Glassfb3954f2014-09-05 19:00:17 -0600167 if result.already_done:
Simon Glass190064b2014-08-09 15:33:00 -0600168 # Get the return code from that build and use it
169 with open(done_file, 'r') as fd:
Simon Glasse74429b2018-12-10 09:05:23 -0700170 try:
171 result.return_code = int(fd.readline())
172 except ValueError:
173 # The file may be empty due to running out of disk space.
174 # Try a rebuild
175 result.return_code = RETURN_CODE_RETRY
Simon Glass88c8dcf2015-02-05 22:06:13 -0700176
177 # Check the signal that the build needs to be retried
178 if result.return_code == RETURN_CODE_RETRY:
179 will_build = True
180 elif will_build:
Simon Glassfb3954f2014-09-05 19:00:17 -0600181 err_file = self.builder.GetErrFile(commit_upto, brd.target)
182 if os.path.exists(err_file) and os.stat(err_file).st_size:
183 result.stderr = 'bad'
184 elif not force_build:
185 # The build passed, so no need to build it again
186 will_build = False
Simon Glass190064b2014-08-09 15:33:00 -0600187
188 if will_build:
189 # We are going to have to build it. First, get a toolchain
190 if not self.toolchain:
191 try:
192 self.toolchain = self.builder.toolchains.Select(brd.arch)
193 except ValueError as err:
194 result.return_code = 10
195 result.stdout = ''
196 result.stderr = str(err)
197 # TODO(sjg@chromium.org): This gets swallowed, but needs
198 # to be reported.
199
200 if self.toolchain:
201 # Checkout the right commit
202 if self.builder.commits:
203 commit = self.builder.commits[commit_upto]
204 if self.builder.checkout:
205 git_dir = os.path.join(work_dir, '.git')
206 gitutil.Checkout(commit.hash, git_dir, work_dir,
207 force=True)
208 else:
209 commit = 'current'
210
211 # Set up the environment and command line
Simon Glassbb1501f2014-12-01 17:34:00 -0700212 env = self.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass190064b2014-08-09 15:33:00 -0600213 Mkdir(out_dir)
214 args = []
215 cwd = work_dir
Simon Glass48c1b6a2014-08-28 09:43:42 -0600216 src_dir = os.path.realpath(work_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600217 if not self.builder.in_tree:
218 if commit_upto is None:
219 # In this case we are building in the original source
220 # directory (i.e. the current directory where buildman
221 # is invoked. The output directory is set to this
222 # thread's selected work directory.
223 #
224 # Symlinks can confuse U-Boot's Makefile since
225 # we may use '..' in our path, so remove them.
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600226 out_dir = os.path.realpath(out_dir)
227 args.append('O=%s' % out_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600228 cwd = None
Simon Glass48c1b6a2014-08-28 09:43:42 -0600229 src_dir = os.getcwd()
Simon Glass190064b2014-08-09 15:33:00 -0600230 else:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600231 args.append('O=%s' % out_rel_dir)
Tom Rinif5e5ece2015-04-01 07:47:41 -0400232 if self.builder.verbose_build:
233 args.append('V=1')
234 else:
Simon Glassd2ce6582014-12-01 17:34:07 -0700235 args.append('-s')
Simon Glass190064b2014-08-09 15:33:00 -0600236 if self.builder.num_jobs is not None:
237 args.extend(['-j', str(self.builder.num_jobs)])
Daniel Schwierzeck2371d1b2018-01-26 16:31:05 +0100238 if self.builder.warnings_as_errors:
239 args.append('KCFLAGS=-Werror')
Simon Glass190064b2014-08-09 15:33:00 -0600240 config_args = ['%s_defconfig' % brd.target]
241 config_out = ''
242 args.extend(self.builder.toolchains.GetMakeArguments(brd))
Simon Glass00beb242019-01-07 16:44:20 -0700243 args.extend(self.toolchain.MakeArgs())
Simon Glass190064b2014-08-09 15:33:00 -0600244
Simon Glass73da3d22020-12-16 17:24:17 -0700245 # Remove any output targets. Since we use a build directory that
246 # was previously used by another board, it may have produced an
247 # SPL image. If we don't remove it (i.e. see do_config and
248 # self.mrproper below) then it will appear to be the output of
249 # this build, even if it does not produce SPL images.
250 build_dir = self.builder.GetBuildDir(commit_upto, brd.target)
251 for elf in BASE_ELF_FILENAMES:
252 fname = os.path.join(out_dir, elf)
253 if os.path.exists(fname):
254 os.remove(fname)
255
Simon Glass190064b2014-08-09 15:33:00 -0600256 # If we need to reconfigure, do that now
257 if do_config:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600258 config_out = ''
Simon Glasseb70a2c2020-04-09 15:08:51 -0600259 if self.mrproper:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600260 result = self.Make(commit, brd, 'mrproper', cwd,
261 'mrproper', *args, env=env)
262 config_out += result.combined
Simon Glass190064b2014-08-09 15:33:00 -0600263 result = self.Make(commit, brd, 'config', cwd,
264 *(args + config_args), env=env)
Simon Glass40f11fc2015-02-05 22:06:12 -0700265 config_out += result.combined
Simon Glass190064b2014-08-09 15:33:00 -0600266 do_config = False # No need to configure next time
267 if result.return_code == 0:
Simon Glassa9401b22016-11-16 14:09:25 -0700268 if config_only:
Simon Glassb50113f2016-11-13 14:25:51 -0700269 args.append('cfg')
Simon Glass190064b2014-08-09 15:33:00 -0600270 result = self.Make(commit, brd, 'build', cwd, *args,
271 env=env)
Simon Glass48c1b6a2014-08-28 09:43:42 -0600272 result.stderr = result.stderr.replace(src_dir + '/', '')
Simon Glass40f11fc2015-02-05 22:06:12 -0700273 if self.builder.verbose_build:
274 result.stdout = config_out + result.stdout
Simon Glass190064b2014-08-09 15:33:00 -0600275 else:
276 result.return_code = 1
277 result.stderr = 'No tool chain for %s\n' % brd.arch
278 result.already_done = False
279
280 result.toolchain = self.toolchain
281 result.brd = brd
282 result.commit_upto = commit_upto
283 result.out_dir = out_dir
284 return result, do_config
285
Simon Glassd829f122020-03-18 09:42:42 -0600286 def _WriteResult(self, result, keep_outputs, work_in_output):
Simon Glass190064b2014-08-09 15:33:00 -0600287 """Write a built result to the output directory.
288
289 Args:
290 result: CommandResult object containing result to write
291 keep_outputs: True to store the output binaries, False
292 to delete them
Simon Glassd829f122020-03-18 09:42:42 -0600293 work_in_output: Use the output directory as the work directory and
294 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -0600295 """
296 # Fatal error
297 if result.return_code < 0:
298 return
299
Simon Glass88c8dcf2015-02-05 22:06:13 -0700300 # If we think this might have been aborted with Ctrl-C, record the
301 # failure but not that we are 'done' with this board. A retry may fix
302 # it.
303 maybe_aborted = result.stderr and 'No child processes' in result.stderr
Simon Glass190064b2014-08-09 15:33:00 -0600304
305 if result.already_done:
306 return
307
308 # Write the output and stderr
309 output_dir = self.builder._GetOutputDir(result.commit_upto)
310 Mkdir(output_dir)
311 build_dir = self.builder.GetBuildDir(result.commit_upto,
312 result.brd.target)
313 Mkdir(build_dir)
314
315 outfile = os.path.join(build_dir, 'log')
316 with open(outfile, 'w') as fd:
317 if result.stdout:
Simon Glassc05aa032019-10-31 07:42:53 -0600318 fd.write(result.stdout)
Simon Glass190064b2014-08-09 15:33:00 -0600319
320 errfile = self.builder.GetErrFile(result.commit_upto,
321 result.brd.target)
322 if result.stderr:
323 with open(errfile, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600324 fd.write(result.stderr)
Simon Glass190064b2014-08-09 15:33:00 -0600325 elif os.path.exists(errfile):
326 os.remove(errfile)
327
328 if result.toolchain:
329 # Write the build result and toolchain information.
330 done_file = self.builder.GetDoneFile(result.commit_upto,
331 result.brd.target)
332 with open(done_file, 'w') as fd:
Simon Glass88c8dcf2015-02-05 22:06:13 -0700333 if maybe_aborted:
334 # Special code to indicate we need to retry
335 fd.write('%s' % RETURN_CODE_RETRY)
336 else:
337 fd.write('%s' % result.return_code)
Simon Glass190064b2014-08-09 15:33:00 -0600338 with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600339 print('gcc', result.toolchain.gcc, file=fd)
340 print('path', result.toolchain.path, file=fd)
341 print('cross', result.toolchain.cross, file=fd)
342 print('arch', result.toolchain.arch, file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600343 fd.write('%s' % result.return_code)
344
Simon Glass190064b2014-08-09 15:33:00 -0600345 # Write out the image and function size information and an objdump
Simon Glassbb1501f2014-12-01 17:34:00 -0700346 env = result.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass5f864542021-03-26 14:39:39 +1300347 with open(os.path.join(build_dir, 'out-env'), 'w',
348 encoding='utf-8') as fd:
Simon Glasse5fc79e2019-01-07 16:44:23 -0700349 for var in sorted(env.keys()):
Simon Glassc05aa032019-10-31 07:42:53 -0600350 print('%s="%s"' % (var, env[var]), file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600351 lines = []
Simon Glass73da3d22020-12-16 17:24:17 -0700352 for fname in BASE_ELF_FILENAMES:
Simon Glass190064b2014-08-09 15:33:00 -0600353 cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
354 nm_result = command.RunPipe([cmd], capture=True,
355 capture_stderr=True, cwd=result.out_dir,
356 raise_on_error=False, env=env)
357 if nm_result.stdout:
358 nm = self.builder.GetFuncSizesFile(result.commit_upto,
359 result.brd.target, fname)
360 with open(nm, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600361 print(nm_result.stdout, end=' ', file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600362
363 cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
364 dump_result = command.RunPipe([cmd], capture=True,
365 capture_stderr=True, cwd=result.out_dir,
366 raise_on_error=False, env=env)
367 rodata_size = ''
368 if dump_result.stdout:
369 objdump = self.builder.GetObjdumpFile(result.commit_upto,
370 result.brd.target, fname)
371 with open(objdump, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600372 print(dump_result.stdout, end=' ', file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600373 for line in dump_result.stdout.splitlines():
374 fields = line.split()
375 if len(fields) > 5 and fields[1] == '.rodata':
376 rodata_size = fields[2]
377
378 cmd = ['%ssize' % self.toolchain.cross, fname]
379 size_result = command.RunPipe([cmd], capture=True,
380 capture_stderr=True, cwd=result.out_dir,
381 raise_on_error=False, env=env)
382 if size_result.stdout:
383 lines.append(size_result.stdout.splitlines()[1] + ' ' +
384 rodata_size)
385
Alex Kiernan0ddc5102018-05-31 04:48:33 +0000386 # Extract the environment from U-Boot and dump it out
387 cmd = ['%sobjcopy' % self.toolchain.cross, '-O', 'binary',
388 '-j', '.rodata.default_environment',
389 'env/built-in.o', 'uboot.env']
390 command.RunPipe([cmd], capture=True,
391 capture_stderr=True, cwd=result.out_dir,
392 raise_on_error=False, env=env)
393 ubootenv = os.path.join(result.out_dir, 'uboot.env')
Simon Glass60b285f2020-04-17 17:51:34 -0600394 if not work_in_output:
395 self.CopyFiles(result.out_dir, build_dir, '', ['uboot.env'])
Alex Kiernan0ddc5102018-05-31 04:48:33 +0000396
Simon Glass190064b2014-08-09 15:33:00 -0600397 # Write out the image sizes file. This is similar to the output
398 # of binutil's 'size' utility, but it omits the header line and
399 # adds an additional hex value at the end of each line for the
400 # rodata size
401 if len(lines):
402 sizes = self.builder.GetSizesFile(result.commit_upto,
403 result.brd.target)
404 with open(sizes, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600405 print('\n'.join(lines), file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600406
Simon Glass60b285f2020-04-17 17:51:34 -0600407 if not work_in_output:
408 # Write out the configuration files, with a special case for SPL
409 for dirname in ['', 'spl', 'tpl']:
410 self.CopyFiles(
411 result.out_dir, build_dir, dirname,
412 ['u-boot.cfg', 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg',
413 '.config', 'include/autoconf.mk',
414 'include/generated/autoconf.h'])
Simon Glass970f9322015-02-05 22:06:14 -0700415
Simon Glass60b285f2020-04-17 17:51:34 -0600416 # Now write the actual build output
417 if keep_outputs:
418 self.CopyFiles(
419 result.out_dir, build_dir, '',
420 ['u-boot*', '*.bin', '*.map', '*.img', 'MLO', 'SPL',
421 'include/autoconf.mk', 'spl/u-boot-spl*'])
Simon Glass190064b2014-08-09 15:33:00 -0600422
Simon Glass970f9322015-02-05 22:06:14 -0700423 def CopyFiles(self, out_dir, build_dir, dirname, patterns):
424 """Copy files from the build directory to the output.
425
426 Args:
427 out_dir: Path to output directory containing the files
428 build_dir: Place to copy the files
429 dirname: Source directory, '' for normal U-Boot, 'spl' for SPL
430 patterns: A list of filenames (strings) to copy, each relative
431 to the build directory
432 """
433 for pattern in patterns:
434 file_list = glob.glob(os.path.join(out_dir, dirname, pattern))
435 for fname in file_list:
436 target = os.path.basename(fname)
437 if dirname:
438 base, ext = os.path.splitext(target)
439 if ext:
440 target = '%s-%s%s' % (base, dirname, ext)
441 shutil.copy(fname, os.path.join(build_dir, target))
Simon Glass190064b2014-08-09 15:33:00 -0600442
443 def RunJob(self, job):
444 """Run a single job
445
446 A job consists of a building a list of commits for a particular board.
447
448 Args:
449 job: Job to build
Simon Glassb82492b2021-01-30 22:17:46 -0700450
451 Returns:
452 List of Result objects
Simon Glass190064b2014-08-09 15:33:00 -0600453 """
454 brd = job.board
455 work_dir = self.builder.GetThreadDir(self.thread_num)
456 self.toolchain = None
457 if job.commits:
458 # Run 'make board_defconfig' on the first commit
459 do_config = True
460 commit_upto = 0
461 force_build = False
462 for commit_upto in range(0, len(job.commits), job.step):
463 result, request_config = self.RunCommit(commit_upto, brd,
Simon Glassa9401b22016-11-16 14:09:25 -0700464 work_dir, do_config, self.builder.config_only,
Simon Glass190064b2014-08-09 15:33:00 -0600465 force_build or self.builder.force_build,
Simon Glassd829f122020-03-18 09:42:42 -0600466 self.builder.force_build_failures,
467 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600468 failed = result.return_code or result.stderr
469 did_config = do_config
470 if failed and not do_config:
471 # If our incremental build failed, try building again
472 # with a reconfig.
473 if self.builder.force_config_on_failure:
474 result, request_config = self.RunCommit(commit_upto,
Simon Glassd829f122020-03-18 09:42:42 -0600475 brd, work_dir, True, False, True, False,
476 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600477 did_config = True
478 if not self.builder.force_reconfig:
479 do_config = request_config
480
481 # If we built that commit, then config is done. But if we got
482 # an warning, reconfig next time to force it to build the same
483 # files that created warnings this time. Otherwise an
484 # incremental build may not build the same file, and we will
485 # think that the warning has gone away.
486 # We could avoid this by using -Werror everywhere...
487 # For errors, the problem doesn't happen, since presumably
488 # the build stopped and didn't generate output, so will retry
489 # that file next time. So we could detect warnings and deal
490 # with them specially here. For now, we just reconfigure if
491 # anything goes work.
492 # Of course this is substantially slower if there are build
493 # errors/warnings (e.g. 2-3x slower even if only 10% of builds
494 # have problems).
495 if (failed and not result.already_done and not did_config and
496 self.builder.force_config_on_failure):
497 # If this build failed, try the next one with a
498 # reconfigure.
499 # Sometimes if the board_config.h file changes it can mess
500 # with dependencies, and we get:
501 # make: *** No rule to make target `include/autoconf.mk',
502 # needed by `depend'.
503 do_config = True
504 force_build = True
505 else:
506 force_build = False
507 if self.builder.force_config_on_failure:
508 if failed:
509 do_config = True
510 result.commit_upto = commit_upto
511 if result.return_code < 0:
512 raise ValueError('Interrupt')
513
514 # We have the build results, so output the result
Simon Glassd829f122020-03-18 09:42:42 -0600515 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glassb82492b2021-01-30 22:17:46 -0700516 if self.thread_num != -1:
517 self.builder.out_queue.put(result)
518 else:
519 self.builder.ProcessResult(result)
Simon Glass190064b2014-08-09 15:33:00 -0600520 else:
521 # Just build the currently checked-out build
522 result, request_config = self.RunCommit(None, brd, work_dir, True,
Simon Glassa9401b22016-11-16 14:09:25 -0700523 self.builder.config_only, True,
Simon Glassd829f122020-03-18 09:42:42 -0600524 self.builder.force_build_failures,
525 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600526 result.commit_upto = 0
Simon Glassd829f122020-03-18 09:42:42 -0600527 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glassb82492b2021-01-30 22:17:46 -0700528 if self.thread_num != -1:
529 self.builder.out_queue.put(result)
530 else:
531 self.builder.ProcessResult(result)
Simon Glass190064b2014-08-09 15:33:00 -0600532
533 def run(self):
534 """Our thread's run function
535
536 This thread picks a job from the queue, runs it, and then goes to the
537 next job.
538 """
Simon Glass190064b2014-08-09 15:33:00 -0600539 while True:
540 job = self.builder.queue.get()
Simon Glass2880e6b2016-09-18 16:48:38 -0600541 self.RunJob(job)
Simon Glass190064b2014-08-09 15:33:00 -0600542 self.builder.queue.task_done()