blob: 6f08ff2da0c2ab5cc6b0a8a9561362c1b9aabb03 [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 Glass24993312021-04-11 16:27:25 +120092 temporary directory. If this is -1 then there are no threads
93 and we are the (only) main process
94 mrproper: Use 'make mrproper' before each reconfigure
95 per_board_out_dir: True to build in a separate persistent directory per
96 board rather than a thread-specific directory
97 test_exception: Used for testing; True to raise an exception instead of
98 reporting the build result
Simon Glass190064b2014-08-09 15:33:00 -060099 """
Simon Glass190064b2014-08-09 15:33:00 -0600100 """Set up a new builder thread"""
101 threading.Thread.__init__(self)
102 self.builder = builder
103 self.thread_num = thread_num
Simon Glasseb70a2c2020-04-09 15:08:51 -0600104 self.mrproper = mrproper
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600105 self.per_board_out_dir = per_board_out_dir
Simon Glass190064b2014-08-09 15:33:00 -0600106
107 def Make(self, commit, brd, stage, cwd, *args, **kwargs):
108 """Run 'make' on a particular commit and board.
109
110 The source code will already be checked out, so the 'commit'
111 argument is only for information.
112
113 Args:
114 commit: Commit object that is being built
115 brd: Board object that is being built
116 stage: Stage of the build. Valid stages are:
Roger Meierfd18a892014-08-20 22:10:29 +0200117 mrproper - can be called to clean source
Simon Glass190064b2014-08-09 15:33:00 -0600118 config - called to configure for a board
119 build - the main make invocation - it does the build
120 args: A list of arguments to pass to 'make'
121 kwargs: A list of keyword arguments to pass to command.RunPipe()
122
123 Returns:
124 CommandResult object
125 """
126 return self.builder.do_make(commit, brd, stage, cwd, *args,
127 **kwargs)
128
Simon Glassa9401b22016-11-16 14:09:25 -0700129 def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only,
Simon Glassd829f122020-03-18 09:42:42 -0600130 force_build, force_build_failures, work_in_output):
Simon Glass190064b2014-08-09 15:33:00 -0600131 """Build a particular commit.
132
133 If the build is already done, and we are not forcing a build, we skip
134 the build and just return the previously-saved results.
135
136 Args:
137 commit_upto: Commit number to build (0...n-1)
138 brd: Board object to build
139 work_dir: Directory to which the source will be checked out
140 do_config: True to run a make <board>_defconfig on the source
Simon Glassa9401b22016-11-16 14:09:25 -0700141 config_only: Only configure the source, do not build it
Simon Glass190064b2014-08-09 15:33:00 -0600142 force_build: Force a build even if one was previously done
143 force_build_failures: Force a bulid if the previous result showed
144 failure
Simon Glassd829f122020-03-18 09:42:42 -0600145 work_in_output: Use the output directory as the work directory and
146 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -0600147
148 Returns:
149 tuple containing:
150 - CommandResult object containing the results of the build
151 - boolean indicating whether 'make config' is still needed
152 """
153 # Create a default result - it will be overwritte by the call to
154 # self.Make() below, in the event that we do a build.
155 result = command.CommandResult()
156 result.return_code = 0
Simon Glassd829f122020-03-18 09:42:42 -0600157 if work_in_output or self.builder.in_tree:
Simon Glass190064b2014-08-09 15:33:00 -0600158 out_dir = work_dir
159 else:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600160 if self.per_board_out_dir:
161 out_rel_dir = os.path.join('..', brd.target)
162 else:
163 out_rel_dir = 'build'
164 out_dir = os.path.join(work_dir, out_rel_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600165
166 # Check if the job was already completed last time
167 done_file = self.builder.GetDoneFile(commit_upto, brd.target)
168 result.already_done = os.path.exists(done_file)
169 will_build = (force_build or force_build_failures or
170 not result.already_done)
Simon Glassfb3954f2014-09-05 19:00:17 -0600171 if result.already_done:
Simon Glass190064b2014-08-09 15:33:00 -0600172 # Get the return code from that build and use it
173 with open(done_file, 'r') as fd:
Simon Glasse74429b2018-12-10 09:05:23 -0700174 try:
175 result.return_code = int(fd.readline())
176 except ValueError:
177 # The file may be empty due to running out of disk space.
178 # Try a rebuild
179 result.return_code = RETURN_CODE_RETRY
Simon Glass88c8dcf2015-02-05 22:06:13 -0700180
181 # Check the signal that the build needs to be retried
182 if result.return_code == RETURN_CODE_RETRY:
183 will_build = True
184 elif will_build:
Simon Glassfb3954f2014-09-05 19:00:17 -0600185 err_file = self.builder.GetErrFile(commit_upto, brd.target)
186 if os.path.exists(err_file) and os.stat(err_file).st_size:
187 result.stderr = 'bad'
188 elif not force_build:
189 # The build passed, so no need to build it again
190 will_build = False
Simon Glass190064b2014-08-09 15:33:00 -0600191
192 if will_build:
193 # We are going to have to build it. First, get a toolchain
194 if not self.toolchain:
195 try:
196 self.toolchain = self.builder.toolchains.Select(brd.arch)
197 except ValueError as err:
198 result.return_code = 10
199 result.stdout = ''
200 result.stderr = str(err)
201 # TODO(sjg@chromium.org): This gets swallowed, but needs
202 # to be reported.
203
204 if self.toolchain:
205 # Checkout the right commit
206 if self.builder.commits:
207 commit = self.builder.commits[commit_upto]
208 if self.builder.checkout:
209 git_dir = os.path.join(work_dir, '.git')
210 gitutil.Checkout(commit.hash, git_dir, work_dir,
211 force=True)
212 else:
213 commit = 'current'
214
215 # Set up the environment and command line
Simon Glassbb1501f2014-12-01 17:34:00 -0700216 env = self.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass190064b2014-08-09 15:33:00 -0600217 Mkdir(out_dir)
218 args = []
219 cwd = work_dir
Simon Glass48c1b6a2014-08-28 09:43:42 -0600220 src_dir = os.path.realpath(work_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600221 if not self.builder.in_tree:
222 if commit_upto is None:
223 # In this case we are building in the original source
224 # directory (i.e. the current directory where buildman
225 # is invoked. The output directory is set to this
226 # thread's selected work directory.
227 #
228 # Symlinks can confuse U-Boot's Makefile since
229 # we may use '..' in our path, so remove them.
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600230 out_dir = os.path.realpath(out_dir)
231 args.append('O=%s' % out_dir)
Simon Glass190064b2014-08-09 15:33:00 -0600232 cwd = None
Simon Glass48c1b6a2014-08-28 09:43:42 -0600233 src_dir = os.getcwd()
Simon Glass190064b2014-08-09 15:33:00 -0600234 else:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600235 args.append('O=%s' % out_rel_dir)
Tom Rinif5e5ece2015-04-01 07:47:41 -0400236 if self.builder.verbose_build:
237 args.append('V=1')
238 else:
Simon Glassd2ce6582014-12-01 17:34:07 -0700239 args.append('-s')
Simon Glass190064b2014-08-09 15:33:00 -0600240 if self.builder.num_jobs is not None:
241 args.extend(['-j', str(self.builder.num_jobs)])
Daniel Schwierzeck2371d1b2018-01-26 16:31:05 +0100242 if self.builder.warnings_as_errors:
243 args.append('KCFLAGS=-Werror')
Simon Glass190064b2014-08-09 15:33:00 -0600244 config_args = ['%s_defconfig' % brd.target]
245 config_out = ''
246 args.extend(self.builder.toolchains.GetMakeArguments(brd))
Simon Glass00beb242019-01-07 16:44:20 -0700247 args.extend(self.toolchain.MakeArgs())
Simon Glass190064b2014-08-09 15:33:00 -0600248
Simon Glass73da3d22020-12-16 17:24:17 -0700249 # Remove any output targets. Since we use a build directory that
250 # was previously used by another board, it may have produced an
251 # SPL image. If we don't remove it (i.e. see do_config and
252 # self.mrproper below) then it will appear to be the output of
253 # this build, even if it does not produce SPL images.
254 build_dir = self.builder.GetBuildDir(commit_upto, brd.target)
255 for elf in BASE_ELF_FILENAMES:
256 fname = os.path.join(out_dir, elf)
257 if os.path.exists(fname):
258 os.remove(fname)
259
Simon Glass190064b2014-08-09 15:33:00 -0600260 # If we need to reconfigure, do that now
261 if do_config:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600262 config_out = ''
Simon Glasseb70a2c2020-04-09 15:08:51 -0600263 if self.mrproper:
Stephen Warrenf79f1e02016-04-11 10:48:44 -0600264 result = self.Make(commit, brd, 'mrproper', cwd,
265 'mrproper', *args, env=env)
266 config_out += result.combined
Simon Glass190064b2014-08-09 15:33:00 -0600267 result = self.Make(commit, brd, 'config', cwd,
268 *(args + config_args), env=env)
Simon Glass40f11fc2015-02-05 22:06:12 -0700269 config_out += result.combined
Simon Glass190064b2014-08-09 15:33:00 -0600270 do_config = False # No need to configure next time
271 if result.return_code == 0:
Simon Glassa9401b22016-11-16 14:09:25 -0700272 if config_only:
Simon Glassb50113f2016-11-13 14:25:51 -0700273 args.append('cfg')
Simon Glass190064b2014-08-09 15:33:00 -0600274 result = self.Make(commit, brd, 'build', cwd, *args,
275 env=env)
Simon Glass48c1b6a2014-08-28 09:43:42 -0600276 result.stderr = result.stderr.replace(src_dir + '/', '')
Simon Glass40f11fc2015-02-05 22:06:12 -0700277 if self.builder.verbose_build:
278 result.stdout = config_out + result.stdout
Simon Glass190064b2014-08-09 15:33:00 -0600279 else:
280 result.return_code = 1
281 result.stderr = 'No tool chain for %s\n' % brd.arch
282 result.already_done = False
283
284 result.toolchain = self.toolchain
285 result.brd = brd
286 result.commit_upto = commit_upto
287 result.out_dir = out_dir
288 return result, do_config
289
Simon Glassd829f122020-03-18 09:42:42 -0600290 def _WriteResult(self, result, keep_outputs, work_in_output):
Simon Glass190064b2014-08-09 15:33:00 -0600291 """Write a built result to the output directory.
292
293 Args:
294 result: CommandResult object containing result to write
295 keep_outputs: True to store the output binaries, False
296 to delete them
Simon Glassd829f122020-03-18 09:42:42 -0600297 work_in_output: Use the output directory as the work directory and
298 don't write to a separate output directory.
Simon Glass190064b2014-08-09 15:33:00 -0600299 """
300 # Fatal error
301 if result.return_code < 0:
302 return
303
Simon Glass88c8dcf2015-02-05 22:06:13 -0700304 # If we think this might have been aborted with Ctrl-C, record the
305 # failure but not that we are 'done' with this board. A retry may fix
306 # it.
307 maybe_aborted = result.stderr and 'No child processes' in result.stderr
Simon Glass190064b2014-08-09 15:33:00 -0600308
309 if result.already_done:
310 return
311
312 # Write the output and stderr
313 output_dir = self.builder._GetOutputDir(result.commit_upto)
314 Mkdir(output_dir)
315 build_dir = self.builder.GetBuildDir(result.commit_upto,
316 result.brd.target)
317 Mkdir(build_dir)
318
319 outfile = os.path.join(build_dir, 'log')
320 with open(outfile, 'w') as fd:
321 if result.stdout:
Simon Glassc05aa032019-10-31 07:42:53 -0600322 fd.write(result.stdout)
Simon Glass190064b2014-08-09 15:33:00 -0600323
324 errfile = self.builder.GetErrFile(result.commit_upto,
325 result.brd.target)
326 if result.stderr:
327 with open(errfile, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600328 fd.write(result.stderr)
Simon Glass190064b2014-08-09 15:33:00 -0600329 elif os.path.exists(errfile):
330 os.remove(errfile)
331
332 if result.toolchain:
333 # Write the build result and toolchain information.
334 done_file = self.builder.GetDoneFile(result.commit_upto,
335 result.brd.target)
336 with open(done_file, 'w') as fd:
Simon Glass88c8dcf2015-02-05 22:06:13 -0700337 if maybe_aborted:
338 # Special code to indicate we need to retry
339 fd.write('%s' % RETURN_CODE_RETRY)
340 else:
341 fd.write('%s' % result.return_code)
Simon Glass190064b2014-08-09 15:33:00 -0600342 with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600343 print('gcc', result.toolchain.gcc, file=fd)
344 print('path', result.toolchain.path, file=fd)
345 print('cross', result.toolchain.cross, file=fd)
346 print('arch', result.toolchain.arch, file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600347 fd.write('%s' % result.return_code)
348
Simon Glass190064b2014-08-09 15:33:00 -0600349 # Write out the image and function size information and an objdump
Simon Glassbb1501f2014-12-01 17:34:00 -0700350 env = result.toolchain.MakeEnvironment(self.builder.full_path)
Simon Glass5f864542021-03-26 14:39:39 +1300351 with open(os.path.join(build_dir, 'out-env'), 'w',
352 encoding='utf-8') as fd:
Simon Glasse5fc79e2019-01-07 16:44:23 -0700353 for var in sorted(env.keys()):
Simon Glassc05aa032019-10-31 07:42:53 -0600354 print('%s="%s"' % (var, env[var]), file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600355 lines = []
Simon Glass73da3d22020-12-16 17:24:17 -0700356 for fname in BASE_ELF_FILENAMES:
Simon Glass190064b2014-08-09 15:33:00 -0600357 cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
358 nm_result = command.RunPipe([cmd], capture=True,
359 capture_stderr=True, cwd=result.out_dir,
360 raise_on_error=False, env=env)
361 if nm_result.stdout:
362 nm = self.builder.GetFuncSizesFile(result.commit_upto,
363 result.brd.target, fname)
364 with open(nm, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600365 print(nm_result.stdout, end=' ', file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600366
367 cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
368 dump_result = command.RunPipe([cmd], capture=True,
369 capture_stderr=True, cwd=result.out_dir,
370 raise_on_error=False, env=env)
371 rodata_size = ''
372 if dump_result.stdout:
373 objdump = self.builder.GetObjdumpFile(result.commit_upto,
374 result.brd.target, fname)
375 with open(objdump, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600376 print(dump_result.stdout, end=' ', file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600377 for line in dump_result.stdout.splitlines():
378 fields = line.split()
379 if len(fields) > 5 and fields[1] == '.rodata':
380 rodata_size = fields[2]
381
382 cmd = ['%ssize' % self.toolchain.cross, fname]
383 size_result = command.RunPipe([cmd], capture=True,
384 capture_stderr=True, cwd=result.out_dir,
385 raise_on_error=False, env=env)
386 if size_result.stdout:
387 lines.append(size_result.stdout.splitlines()[1] + ' ' +
388 rodata_size)
389
Alex Kiernan0ddc5102018-05-31 04:48:33 +0000390 # Extract the environment from U-Boot and dump it out
391 cmd = ['%sobjcopy' % self.toolchain.cross, '-O', 'binary',
392 '-j', '.rodata.default_environment',
393 'env/built-in.o', 'uboot.env']
394 command.RunPipe([cmd], capture=True,
395 capture_stderr=True, cwd=result.out_dir,
396 raise_on_error=False, env=env)
397 ubootenv = os.path.join(result.out_dir, 'uboot.env')
Simon Glass60b285f2020-04-17 17:51:34 -0600398 if not work_in_output:
399 self.CopyFiles(result.out_dir, build_dir, '', ['uboot.env'])
Alex Kiernan0ddc5102018-05-31 04:48:33 +0000400
Simon Glass190064b2014-08-09 15:33:00 -0600401 # Write out the image sizes file. This is similar to the output
402 # of binutil's 'size' utility, but it omits the header line and
403 # adds an additional hex value at the end of each line for the
404 # rodata size
405 if len(lines):
406 sizes = self.builder.GetSizesFile(result.commit_upto,
407 result.brd.target)
408 with open(sizes, 'w') as fd:
Simon Glassc05aa032019-10-31 07:42:53 -0600409 print('\n'.join(lines), file=fd)
Simon Glass190064b2014-08-09 15:33:00 -0600410
Simon Glass60b285f2020-04-17 17:51:34 -0600411 if not work_in_output:
412 # Write out the configuration files, with a special case for SPL
413 for dirname in ['', 'spl', 'tpl']:
414 self.CopyFiles(
415 result.out_dir, build_dir, dirname,
416 ['u-boot.cfg', 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg',
417 '.config', 'include/autoconf.mk',
418 'include/generated/autoconf.h'])
Simon Glass970f9322015-02-05 22:06:14 -0700419
Simon Glass60b285f2020-04-17 17:51:34 -0600420 # Now write the actual build output
421 if keep_outputs:
422 self.CopyFiles(
423 result.out_dir, build_dir, '',
424 ['u-boot*', '*.bin', '*.map', '*.img', 'MLO', 'SPL',
425 'include/autoconf.mk', 'spl/u-boot-spl*'])
Simon Glass190064b2014-08-09 15:33:00 -0600426
Simon Glass970f9322015-02-05 22:06:14 -0700427 def CopyFiles(self, out_dir, build_dir, dirname, patterns):
428 """Copy files from the build directory to the output.
429
430 Args:
431 out_dir: Path to output directory containing the files
432 build_dir: Place to copy the files
433 dirname: Source directory, '' for normal U-Boot, 'spl' for SPL
434 patterns: A list of filenames (strings) to copy, each relative
435 to the build directory
436 """
437 for pattern in patterns:
438 file_list = glob.glob(os.path.join(out_dir, dirname, pattern))
439 for fname in file_list:
440 target = os.path.basename(fname)
441 if dirname:
442 base, ext = os.path.splitext(target)
443 if ext:
444 target = '%s-%s%s' % (base, dirname, ext)
445 shutil.copy(fname, os.path.join(build_dir, target))
Simon Glass190064b2014-08-09 15:33:00 -0600446
447 def RunJob(self, job):
448 """Run a single job
449
450 A job consists of a building a list of commits for a particular board.
451
452 Args:
453 job: Job to build
Simon Glassb82492b2021-01-30 22:17:46 -0700454
455 Returns:
456 List of Result objects
Simon Glass190064b2014-08-09 15:33:00 -0600457 """
458 brd = job.board
459 work_dir = self.builder.GetThreadDir(self.thread_num)
460 self.toolchain = None
461 if job.commits:
462 # Run 'make board_defconfig' on the first commit
463 do_config = True
464 commit_upto = 0
465 force_build = False
466 for commit_upto in range(0, len(job.commits), job.step):
467 result, request_config = self.RunCommit(commit_upto, brd,
Simon Glassa9401b22016-11-16 14:09:25 -0700468 work_dir, do_config, self.builder.config_only,
Simon Glass190064b2014-08-09 15:33:00 -0600469 force_build or self.builder.force_build,
Simon Glassd829f122020-03-18 09:42:42 -0600470 self.builder.force_build_failures,
471 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600472 failed = result.return_code or result.stderr
473 did_config = do_config
474 if failed and not do_config:
475 # If our incremental build failed, try building again
476 # with a reconfig.
477 if self.builder.force_config_on_failure:
478 result, request_config = self.RunCommit(commit_upto,
Simon Glassd829f122020-03-18 09:42:42 -0600479 brd, work_dir, True, False, True, False,
480 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600481 did_config = True
482 if not self.builder.force_reconfig:
483 do_config = request_config
484
485 # If we built that commit, then config is done. But if we got
486 # an warning, reconfig next time to force it to build the same
487 # files that created warnings this time. Otherwise an
488 # incremental build may not build the same file, and we will
489 # think that the warning has gone away.
490 # We could avoid this by using -Werror everywhere...
491 # For errors, the problem doesn't happen, since presumably
492 # the build stopped and didn't generate output, so will retry
493 # that file next time. So we could detect warnings and deal
494 # with them specially here. For now, we just reconfigure if
495 # anything goes work.
496 # Of course this is substantially slower if there are build
497 # errors/warnings (e.g. 2-3x slower even if only 10% of builds
498 # have problems).
499 if (failed and not result.already_done and not did_config and
500 self.builder.force_config_on_failure):
501 # If this build failed, try the next one with a
502 # reconfigure.
503 # Sometimes if the board_config.h file changes it can mess
504 # with dependencies, and we get:
505 # make: *** No rule to make target `include/autoconf.mk',
506 # needed by `depend'.
507 do_config = True
508 force_build = True
509 else:
510 force_build = False
511 if self.builder.force_config_on_failure:
512 if failed:
513 do_config = True
514 result.commit_upto = commit_upto
515 if result.return_code < 0:
516 raise ValueError('Interrupt')
517
518 # We have the build results, so output the result
Simon Glassd829f122020-03-18 09:42:42 -0600519 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glassb82492b2021-01-30 22:17:46 -0700520 if self.thread_num != -1:
521 self.builder.out_queue.put(result)
522 else:
523 self.builder.ProcessResult(result)
Simon Glass190064b2014-08-09 15:33:00 -0600524 else:
525 # Just build the currently checked-out build
526 result, request_config = self.RunCommit(None, brd, work_dir, True,
Simon Glassa9401b22016-11-16 14:09:25 -0700527 self.builder.config_only, True,
Simon Glassd829f122020-03-18 09:42:42 -0600528 self.builder.force_build_failures,
529 work_in_output=job.work_in_output)
Simon Glass190064b2014-08-09 15:33:00 -0600530 result.commit_upto = 0
Simon Glassd829f122020-03-18 09:42:42 -0600531 self._WriteResult(result, job.keep_outputs, job.work_in_output)
Simon Glassb82492b2021-01-30 22:17:46 -0700532 if self.thread_num != -1:
533 self.builder.out_queue.put(result)
534 else:
535 self.builder.ProcessResult(result)
Simon Glass190064b2014-08-09 15:33:00 -0600536
537 def run(self):
538 """Our thread's run function
539
540 This thread picks a job from the queue, runs it, and then goes to the
541 next job.
542 """
Simon Glass190064b2014-08-09 15:33:00 -0600543 while True:
544 job = self.builder.queue.get()
Simon Glass2880e6b2016-09-18 16:48:38 -0600545 self.RunJob(job)
Simon Glass190064b2014-08-09 15:33:00 -0600546 self.builder.queue.task_done()