blob: 6c6dbd78725ec2f043a2c463595fc2a39c95915a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4a1e88b2014-08-09 15:33:00 -06002# Copyright (c) 2014 Google, Inc
3#
Simon Glass4a1e88b2014-08-09 15:33:00 -06004
5import errno
6import glob
7import os
8import shutil
Lothar Waßmannce6df922018-04-08 05:14:11 -06009import sys
Simon Glass4a1e88b2014-08-09 15:33:00 -060010import threading
11
Simon Glassa997ea52020-04-17 18:09:04 -060012from patman import command
13from patman import gitutil
Simon Glass4a1e88b2014-08-09 15:33:00 -060014
Simon Glassfd3eea12015-02-05 22:06:13 -070015RETURN_CODE_RETRY = -1
Simon Glasse0f19712020-12-16 17:24:17 -070016BASE_ELF_FILENAMES = ['u-boot', 'spl/u-boot-spl', 'tpl/u-boot-tpl']
Simon Glassfd3eea12015-02-05 22:06:13 -070017
Thierry Reding336d5bd2014-08-19 10:22:39 +020018def Mkdir(dirname, parents = False):
Simon Glass4a1e88b2014-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 Reding336d5bd2014-08-19 10:22:39 +020025 if parents:
26 os.makedirs(dirname)
27 else:
28 os.mkdir(dirname)
Simon Glass4a1e88b2014-08-09 15:33:00 -060029 except OSError as err:
30 if err.errno == errno.EEXIST:
Lothar Waßmannce6df922018-04-08 05:14:11 -060031 if os.path.realpath('.') == os.path.realpath(dirname):
Simon Glassc78ed662019-10-31 07:42:53 -060032 print("Cannot create the current working directory '%s'!" % dirname)
Lothar Waßmannce6df922018-04-08 05:14:11 -060033 sys.exit(1)
Simon Glass4a1e88b2014-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 Glassdf890152020-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 Glassb6eb8cf2020-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 Glass4a1e88b2014-08-09 15:33:00 -060048 """
49 def __init__(self):
50 self.board = None
51 self.commits = []
Simon Glassdf890152020-03-18 09:42:41 -060052 self.keep_outputs = False
53 self.step = 1
Simon Glassb6eb8cf2020-03-18 09:42:42 -060054 self.work_in_output = False
Simon Glass4a1e88b2014-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 Glassc635d892021-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 Glass4a1e88b2014-08-09 15:33:00 -060094 """
Simon Glass6029af12020-04-09 15:08:51 -060095 def __init__(self, builder, thread_num, mrproper, per_board_out_dir):
Simon Glass4a1e88b2014-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 Glass6029af12020-04-09 15:08:51 -0600100 self.mrproper = mrproper
Stephen Warren97c96902016-04-11 10:48:44 -0600101 self.per_board_out_dir = per_board_out_dir
Simon Glass4a1e88b2014-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 Meiere0a0e552014-08-20 22:10:29 +0200113 mrproper - can be called to clean source
Simon Glass4a1e88b2014-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 Glassb55b57d2016-11-16 14:09:25 -0700125 def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only,
Simon Glassb6eb8cf2020-03-18 09:42:42 -0600126 force_build, force_build_failures, work_in_output):
Simon Glass4a1e88b2014-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 Glassb55b57d2016-11-16 14:09:25 -0700137 config_only: Only configure the source, do not build it
Simon Glass4a1e88b2014-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 Glassb6eb8cf2020-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 Glass4a1e88b2014-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 Glassb6eb8cf2020-03-18 09:42:42 -0600153 if work_in_output or self.builder.in_tree:
Simon Glass4a1e88b2014-08-09 15:33:00 -0600154 out_dir = work_dir
155 else:
Stephen Warren97c96902016-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 Glass4a1e88b2014-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 Glass09f1fe52014-09-05 19:00:17 -0600167 if result.already_done:
Simon Glass4a1e88b2014-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 Glass4345a6d2018-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 Glassfd3eea12015-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 Glass09f1fe52014-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 Glass4a1e88b2014-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 Glassd48a46c2014-12-01 17:34:00 -0700212 env = self.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600213 Mkdir(out_dir)
214 args = []
215 cwd = work_dir
Simon Glasse3096252014-08-28 09:43:42 -0600216 src_dir = os.path.realpath(work_dir)
Simon Glass4a1e88b2014-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 Warren97c96902016-04-11 10:48:44 -0600226 out_dir = os.path.realpath(out_dir)
227 args.append('O=%s' % out_dir)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600228 cwd = None
Simon Glasse3096252014-08-28 09:43:42 -0600229 src_dir = os.getcwd()
Simon Glass4a1e88b2014-08-09 15:33:00 -0600230 else:
Stephen Warren97c96902016-04-11 10:48:44 -0600231 args.append('O=%s' % out_rel_dir)
Tom Rinif06dd812015-04-01 07:47:41 -0400232 if self.builder.verbose_build:
233 args.append('V=1')
234 else:
Simon Glass655b6102014-12-01 17:34:07 -0700235 args.append('-s')
Simon Glass4a1e88b2014-08-09 15:33:00 -0600236 if self.builder.num_jobs is not None:
237 args.extend(['-j', str(self.builder.num_jobs)])
Daniel Schwierzeck20e2ea92018-01-26 16:31:05 +0100238 if self.builder.warnings_as_errors:
239 args.append('KCFLAGS=-Werror')
Simon Glass4a1e88b2014-08-09 15:33:00 -0600240 config_args = ['%s_defconfig' % brd.target]
241 config_out = ''
242 args.extend(self.builder.toolchains.GetMakeArguments(brd))
Simon Glassf77ca5b2019-01-07 16:44:20 -0700243 args.extend(self.toolchain.MakeArgs())
Simon Glass4a1e88b2014-08-09 15:33:00 -0600244
Simon Glasse0f19712020-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 Glass4a1e88b2014-08-09 15:33:00 -0600256 # If we need to reconfigure, do that now
257 if do_config:
Stephen Warren97c96902016-04-11 10:48:44 -0600258 config_out = ''
Simon Glass6029af12020-04-09 15:08:51 -0600259 if self.mrproper:
Stephen Warren97c96902016-04-11 10:48:44 -0600260 result = self.Make(commit, brd, 'mrproper', cwd,
261 'mrproper', *args, env=env)
262 config_out += result.combined
Simon Glass4a1e88b2014-08-09 15:33:00 -0600263 result = self.Make(commit, brd, 'config', cwd,
264 *(args + config_args), env=env)
Simon Glass413f91a2015-02-05 22:06:12 -0700265 config_out += result.combined
Simon Glass4a1e88b2014-08-09 15:33:00 -0600266 do_config = False # No need to configure next time
267 if result.return_code == 0:
Simon Glassb55b57d2016-11-16 14:09:25 -0700268 if config_only:
Simon Glass739e8512016-11-13 14:25:51 -0700269 args.append('cfg')
Simon Glass4a1e88b2014-08-09 15:33:00 -0600270 result = self.Make(commit, brd, 'build', cwd, *args,
271 env=env)
Simon Glasse3096252014-08-28 09:43:42 -0600272 result.stderr = result.stderr.replace(src_dir + '/', '')
Simon Glass413f91a2015-02-05 22:06:12 -0700273 if self.builder.verbose_build:
274 result.stdout = config_out + result.stdout
Simon Glass4a1e88b2014-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 Glassb6eb8cf2020-03-18 09:42:42 -0600286 def _WriteResult(self, result, keep_outputs, work_in_output):
Simon Glass4a1e88b2014-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 Glassb6eb8cf2020-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 Glass4a1e88b2014-08-09 15:33:00 -0600295 """
296 # Fatal error
297 if result.return_code < 0:
298 return
299
Simon Glassfd3eea12015-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 Glass4a1e88b2014-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 Glassc78ed662019-10-31 07:42:53 -0600318 fd.write(result.stdout)
Simon Glass4a1e88b2014-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 Glassc78ed662019-10-31 07:42:53 -0600324 fd.write(result.stderr)
Simon Glass4a1e88b2014-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 Glassfd3eea12015-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 Glass4a1e88b2014-08-09 15:33:00 -0600338 with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
Simon Glassc78ed662019-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 Glass4a1e88b2014-08-09 15:33:00 -0600343 fd.write('%s' % result.return_code)
344
Simon Glass4a1e88b2014-08-09 15:33:00 -0600345 # Write out the image and function size information and an objdump
Simon Glassd48a46c2014-12-01 17:34:00 -0700346 env = result.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glassff48a212020-04-17 17:51:33 -0600347 with open(os.path.join(build_dir, 'out-env'), 'w') as fd:
Simon Glass9e90d312019-01-07 16:44:23 -0700348 for var in sorted(env.keys()):
Simon Glassc78ed662019-10-31 07:42:53 -0600349 print('%s="%s"' % (var, env[var]), file=fd)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600350 lines = []
Simon Glasse0f19712020-12-16 17:24:17 -0700351 for fname in BASE_ELF_FILENAMES:
Simon Glass4a1e88b2014-08-09 15:33:00 -0600352 cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
353 nm_result = command.RunPipe([cmd], capture=True,
354 capture_stderr=True, cwd=result.out_dir,
355 raise_on_error=False, env=env)
356 if nm_result.stdout:
357 nm = self.builder.GetFuncSizesFile(result.commit_upto,
358 result.brd.target, fname)
359 with open(nm, 'w') as fd:
Simon Glassc78ed662019-10-31 07:42:53 -0600360 print(nm_result.stdout, end=' ', file=fd)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600361
362 cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
363 dump_result = command.RunPipe([cmd], capture=True,
364 capture_stderr=True, cwd=result.out_dir,
365 raise_on_error=False, env=env)
366 rodata_size = ''
367 if dump_result.stdout:
368 objdump = self.builder.GetObjdumpFile(result.commit_upto,
369 result.brd.target, fname)
370 with open(objdump, 'w') as fd:
Simon Glassc78ed662019-10-31 07:42:53 -0600371 print(dump_result.stdout, end=' ', file=fd)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600372 for line in dump_result.stdout.splitlines():
373 fields = line.split()
374 if len(fields) > 5 and fields[1] == '.rodata':
375 rodata_size = fields[2]
376
377 cmd = ['%ssize' % self.toolchain.cross, fname]
378 size_result = command.RunPipe([cmd], capture=True,
379 capture_stderr=True, cwd=result.out_dir,
380 raise_on_error=False, env=env)
381 if size_result.stdout:
382 lines.append(size_result.stdout.splitlines()[1] + ' ' +
383 rodata_size)
384
Alex Kiernanf07ed232018-05-31 04:48:33 +0000385 # Extract the environment from U-Boot and dump it out
386 cmd = ['%sobjcopy' % self.toolchain.cross, '-O', 'binary',
387 '-j', '.rodata.default_environment',
388 'env/built-in.o', 'uboot.env']
389 command.RunPipe([cmd], capture=True,
390 capture_stderr=True, cwd=result.out_dir,
391 raise_on_error=False, env=env)
392 ubootenv = os.path.join(result.out_dir, 'uboot.env')
Simon Glasse3c85ab2020-04-17 17:51:34 -0600393 if not work_in_output:
394 self.CopyFiles(result.out_dir, build_dir, '', ['uboot.env'])
Alex Kiernanf07ed232018-05-31 04:48:33 +0000395
Simon Glass4a1e88b2014-08-09 15:33:00 -0600396 # Write out the image sizes file. This is similar to the output
397 # of binutil's 'size' utility, but it omits the header line and
398 # adds an additional hex value at the end of each line for the
399 # rodata size
400 if len(lines):
401 sizes = self.builder.GetSizesFile(result.commit_upto,
402 result.brd.target)
403 with open(sizes, 'w') as fd:
Simon Glassc78ed662019-10-31 07:42:53 -0600404 print('\n'.join(lines), file=fd)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600405
Simon Glasse3c85ab2020-04-17 17:51:34 -0600406 if not work_in_output:
407 # Write out the configuration files, with a special case for SPL
408 for dirname in ['', 'spl', 'tpl']:
409 self.CopyFiles(
410 result.out_dir, build_dir, dirname,
411 ['u-boot.cfg', 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg',
412 '.config', 'include/autoconf.mk',
413 'include/generated/autoconf.h'])
Simon Glass4b14c532015-02-05 22:06:14 -0700414
Simon Glasse3c85ab2020-04-17 17:51:34 -0600415 # Now write the actual build output
416 if keep_outputs:
417 self.CopyFiles(
418 result.out_dir, build_dir, '',
419 ['u-boot*', '*.bin', '*.map', '*.img', 'MLO', 'SPL',
420 'include/autoconf.mk', 'spl/u-boot-spl*'])
Simon Glass4b14c532015-02-05 22:06:14 -0700421
422 def CopyFiles(self, out_dir, build_dir, dirname, patterns):
423 """Copy files from the build directory to the output.
Simon Glass4a1e88b2014-08-09 15:33:00 -0600424
Simon Glass4b14c532015-02-05 22:06:14 -0700425 Args:
426 out_dir: Path to output directory containing the files
427 build_dir: Place to copy the files
428 dirname: Source directory, '' for normal U-Boot, 'spl' for SPL
429 patterns: A list of filenames (strings) to copy, each relative
430 to the build directory
431 """
432 for pattern in patterns:
433 file_list = glob.glob(os.path.join(out_dir, dirname, pattern))
434 for fname in file_list:
435 target = os.path.basename(fname)
436 if dirname:
437 base, ext = os.path.splitext(target)
438 if ext:
439 target = '%s-%s%s' % (base, dirname, ext)
440 shutil.copy(fname, os.path.join(build_dir, target))
Simon Glass4a1e88b2014-08-09 15:33:00 -0600441
442 def RunJob(self, job):
443 """Run a single job
444
445 A job consists of a building a list of commits for a particular board.
446
447 Args:
448 job: Job to build
Simon Glassc635d892021-01-30 22:17:46 -0700449
450 Returns:
451 List of Result objects
Simon Glass4a1e88b2014-08-09 15:33:00 -0600452 """
453 brd = job.board
454 work_dir = self.builder.GetThreadDir(self.thread_num)
455 self.toolchain = None
456 if job.commits:
457 # Run 'make board_defconfig' on the first commit
458 do_config = True
459 commit_upto = 0
460 force_build = False
461 for commit_upto in range(0, len(job.commits), job.step):
462 result, request_config = self.RunCommit(commit_upto, brd,
Simon Glassb55b57d2016-11-16 14:09:25 -0700463 work_dir, do_config, self.builder.config_only,
Simon Glass4a1e88b2014-08-09 15:33:00 -0600464 force_build or self.builder.force_build,
Simon Glassb6eb8cf2020-03-18 09:42:42 -0600465 self.builder.force_build_failures,
466 work_in_output=job.work_in_output)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600467 failed = result.return_code or result.stderr
468 did_config = do_config
469 if failed and not do_config:
470 # If our incremental build failed, try building again
471 # with a reconfig.
472 if self.builder.force_config_on_failure:
473 result, request_config = self.RunCommit(commit_upto,
Simon Glassb6eb8cf2020-03-18 09:42:42 -0600474 brd, work_dir, True, False, True, False,
475 work_in_output=job.work_in_output)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600476 did_config = True
477 if not self.builder.force_reconfig:
478 do_config = request_config
479
480 # If we built that commit, then config is done. But if we got
481 # an warning, reconfig next time to force it to build the same
482 # files that created warnings this time. Otherwise an
483 # incremental build may not build the same file, and we will
484 # think that the warning has gone away.
485 # We could avoid this by using -Werror everywhere...
486 # For errors, the problem doesn't happen, since presumably
487 # the build stopped and didn't generate output, so will retry
488 # that file next time. So we could detect warnings and deal
489 # with them specially here. For now, we just reconfigure if
490 # anything goes work.
491 # Of course this is substantially slower if there are build
492 # errors/warnings (e.g. 2-3x slower even if only 10% of builds
493 # have problems).
494 if (failed and not result.already_done and not did_config and
495 self.builder.force_config_on_failure):
496 # If this build failed, try the next one with a
497 # reconfigure.
498 # Sometimes if the board_config.h file changes it can mess
499 # with dependencies, and we get:
500 # make: *** No rule to make target `include/autoconf.mk',
501 # needed by `depend'.
502 do_config = True
503 force_build = True
504 else:
505 force_build = False
506 if self.builder.force_config_on_failure:
507 if failed:
508 do_config = True
509 result.commit_upto = commit_upto
510 if result.return_code < 0:
511 raise ValueError('Interrupt')
512
513 # We have the build results, so output the result
Simon Glassb6eb8cf2020-03-18 09:42:42 -0600514 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glassc635d892021-01-30 22:17:46 -0700515 if self.thread_num != -1:
516 self.builder.out_queue.put(result)
517 else:
518 self.builder.ProcessResult(result)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600519 else:
520 # Just build the currently checked-out build
521 result, request_config = self.RunCommit(None, brd, work_dir, True,
Simon Glassb55b57d2016-11-16 14:09:25 -0700522 self.builder.config_only, True,
Simon Glassb6eb8cf2020-03-18 09:42:42 -0600523 self.builder.force_build_failures,
524 work_in_output=job.work_in_output)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600525 result.commit_upto = 0
Simon Glassb6eb8cf2020-03-18 09:42:42 -0600526 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glassc635d892021-01-30 22:17:46 -0700527 if self.thread_num != -1:
528 self.builder.out_queue.put(result)
529 else:
530 self.builder.ProcessResult(result)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600531
532 def run(self):
533 """Our thread's run function
534
535 This thread picks a job from the queue, runs it, and then goes to the
536 next job.
537 """
Simon Glass4a1e88b2014-08-09 15:33:00 -0600538 while True:
539 job = self.builder.queue.get()
Simon Glass52a9ce92016-09-18 16:48:38 -0600540 self.RunJob(job)
Simon Glass4a1e88b2014-08-09 15:33:00 -0600541 self.builder.queue.task_done()