1190064b4SSimon Glass# Copyright (c) 2014 Google, Inc 2190064b4SSimon Glass# 3190064b4SSimon Glass# SPDX-License-Identifier: GPL-2.0+ 4190064b4SSimon Glass# 5190064b4SSimon Glass 6190064b4SSimon Glassimport errno 7190064b4SSimon Glassimport glob 8190064b4SSimon Glassimport os 9190064b4SSimon Glassimport shutil 10190064b4SSimon Glassimport threading 11190064b4SSimon Glass 12190064b4SSimon Glassimport command 13190064b4SSimon Glassimport gitutil 14190064b4SSimon Glass 1588c8dcf9SSimon GlassRETURN_CODE_RETRY = -1 1688c8dcf9SSimon Glass 17f3d015cbSThierry Redingdef Mkdir(dirname, parents = False): 18190064b4SSimon Glass """Make a directory if it doesn't already exist. 19190064b4SSimon Glass 20190064b4SSimon Glass Args: 21190064b4SSimon Glass dirname: Directory to create 22190064b4SSimon Glass """ 23190064b4SSimon Glass try: 24f3d015cbSThierry Reding if parents: 25f3d015cbSThierry Reding os.makedirs(dirname) 26f3d015cbSThierry Reding else: 27190064b4SSimon Glass os.mkdir(dirname) 28190064b4SSimon Glass except OSError as err: 29190064b4SSimon Glass if err.errno == errno.EEXIST: 30190064b4SSimon Glass pass 31190064b4SSimon Glass else: 32190064b4SSimon Glass raise 33190064b4SSimon Glass 34190064b4SSimon Glassclass BuilderJob: 35190064b4SSimon Glass """Holds information about a job to be performed by a thread 36190064b4SSimon Glass 37190064b4SSimon Glass Members: 38190064b4SSimon Glass board: Board object to build 39190064b4SSimon Glass commits: List of commit options to build. 40190064b4SSimon Glass """ 41190064b4SSimon Glass def __init__(self): 42190064b4SSimon Glass self.board = None 43190064b4SSimon Glass self.commits = [] 44190064b4SSimon Glass 45190064b4SSimon Glass 46190064b4SSimon Glassclass ResultThread(threading.Thread): 47190064b4SSimon Glass """This thread processes results from builder threads. 48190064b4SSimon Glass 49190064b4SSimon Glass It simply passes the results on to the builder. There is only one 50190064b4SSimon Glass result thread, and this helps to serialise the build output. 51190064b4SSimon Glass """ 52190064b4SSimon Glass def __init__(self, builder): 53190064b4SSimon Glass """Set up a new result thread 54190064b4SSimon Glass 55190064b4SSimon Glass Args: 56190064b4SSimon Glass builder: Builder which will be sent each result 57190064b4SSimon Glass """ 58190064b4SSimon Glass threading.Thread.__init__(self) 59190064b4SSimon Glass self.builder = builder 60190064b4SSimon Glass 61190064b4SSimon Glass def run(self): 62190064b4SSimon Glass """Called to start up the result thread. 63190064b4SSimon Glass 64190064b4SSimon Glass We collect the next result job and pass it on to the build. 65190064b4SSimon Glass """ 66190064b4SSimon Glass while True: 67190064b4SSimon Glass result = self.builder.out_queue.get() 68190064b4SSimon Glass self.builder.ProcessResult(result) 69190064b4SSimon Glass self.builder.out_queue.task_done() 70190064b4SSimon Glass 71190064b4SSimon Glass 72190064b4SSimon Glassclass BuilderThread(threading.Thread): 73190064b4SSimon Glass """This thread builds U-Boot for a particular board. 74190064b4SSimon Glass 75190064b4SSimon Glass An input queue provides each new job. We run 'make' to build U-Boot 76190064b4SSimon Glass and then pass the results on to the output queue. 77190064b4SSimon Glass 78190064b4SSimon Glass Members: 79190064b4SSimon Glass builder: The builder which contains information we might need 80190064b4SSimon Glass thread_num: Our thread number (0-n-1), used to decide on a 81190064b4SSimon Glass temporary directory 82190064b4SSimon Glass """ 83*f79f1e0cSStephen Warren def __init__(self, builder, thread_num, incremental, per_board_out_dir): 84190064b4SSimon Glass """Set up a new builder thread""" 85190064b4SSimon Glass threading.Thread.__init__(self) 86190064b4SSimon Glass self.builder = builder 87190064b4SSimon Glass self.thread_num = thread_num 88*f79f1e0cSStephen Warren self.incremental = incremental 89*f79f1e0cSStephen Warren self.per_board_out_dir = per_board_out_dir 90190064b4SSimon Glass 91190064b4SSimon Glass def Make(self, commit, brd, stage, cwd, *args, **kwargs): 92190064b4SSimon Glass """Run 'make' on a particular commit and board. 93190064b4SSimon Glass 94190064b4SSimon Glass The source code will already be checked out, so the 'commit' 95190064b4SSimon Glass argument is only for information. 96190064b4SSimon Glass 97190064b4SSimon Glass Args: 98190064b4SSimon Glass commit: Commit object that is being built 99190064b4SSimon Glass brd: Board object that is being built 100190064b4SSimon Glass stage: Stage of the build. Valid stages are: 101fd18a89eSRoger Meier mrproper - can be called to clean source 102190064b4SSimon Glass config - called to configure for a board 103190064b4SSimon Glass build - the main make invocation - it does the build 104190064b4SSimon Glass args: A list of arguments to pass to 'make' 105190064b4SSimon Glass kwargs: A list of keyword arguments to pass to command.RunPipe() 106190064b4SSimon Glass 107190064b4SSimon Glass Returns: 108190064b4SSimon Glass CommandResult object 109190064b4SSimon Glass """ 110190064b4SSimon Glass return self.builder.do_make(commit, brd, stage, cwd, *args, 111190064b4SSimon Glass **kwargs) 112190064b4SSimon Glass 113190064b4SSimon Glass def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build, 114190064b4SSimon Glass force_build_failures): 115190064b4SSimon Glass """Build a particular commit. 116190064b4SSimon Glass 117190064b4SSimon Glass If the build is already done, and we are not forcing a build, we skip 118190064b4SSimon Glass the build and just return the previously-saved results. 119190064b4SSimon Glass 120190064b4SSimon Glass Args: 121190064b4SSimon Glass commit_upto: Commit number to build (0...n-1) 122190064b4SSimon Glass brd: Board object to build 123190064b4SSimon Glass work_dir: Directory to which the source will be checked out 124190064b4SSimon Glass do_config: True to run a make <board>_defconfig on the source 125190064b4SSimon Glass force_build: Force a build even if one was previously done 126190064b4SSimon Glass force_build_failures: Force a bulid if the previous result showed 127190064b4SSimon Glass failure 128190064b4SSimon Glass 129190064b4SSimon Glass Returns: 130190064b4SSimon Glass tuple containing: 131190064b4SSimon Glass - CommandResult object containing the results of the build 132190064b4SSimon Glass - boolean indicating whether 'make config' is still needed 133190064b4SSimon Glass """ 134190064b4SSimon Glass # Create a default result - it will be overwritte by the call to 135190064b4SSimon Glass # self.Make() below, in the event that we do a build. 136190064b4SSimon Glass result = command.CommandResult() 137190064b4SSimon Glass result.return_code = 0 138190064b4SSimon Glass if self.builder.in_tree: 139190064b4SSimon Glass out_dir = work_dir 140190064b4SSimon Glass else: 141*f79f1e0cSStephen Warren if self.per_board_out_dir: 142*f79f1e0cSStephen Warren out_rel_dir = os.path.join('..', brd.target) 143*f79f1e0cSStephen Warren else: 144*f79f1e0cSStephen Warren out_rel_dir = 'build' 145*f79f1e0cSStephen Warren out_dir = os.path.join(work_dir, out_rel_dir) 146190064b4SSimon Glass 147190064b4SSimon Glass # Check if the job was already completed last time 148190064b4SSimon Glass done_file = self.builder.GetDoneFile(commit_upto, brd.target) 149190064b4SSimon Glass result.already_done = os.path.exists(done_file) 150190064b4SSimon Glass will_build = (force_build or force_build_failures or 151190064b4SSimon Glass not result.already_done) 152fb3954f9SSimon Glass if result.already_done: 153190064b4SSimon Glass # Get the return code from that build and use it 154190064b4SSimon Glass with open(done_file, 'r') as fd: 155190064b4SSimon Glass result.return_code = int(fd.readline()) 15688c8dcf9SSimon Glass 15788c8dcf9SSimon Glass # Check the signal that the build needs to be retried 15888c8dcf9SSimon Glass if result.return_code == RETURN_CODE_RETRY: 15988c8dcf9SSimon Glass will_build = True 16088c8dcf9SSimon Glass elif will_build: 161190064b4SSimon Glass err_file = self.builder.GetErrFile(commit_upto, brd.target) 162190064b4SSimon Glass if os.path.exists(err_file) and os.stat(err_file).st_size: 163190064b4SSimon Glass result.stderr = 'bad' 164190064b4SSimon Glass elif not force_build: 165190064b4SSimon Glass # The build passed, so no need to build it again 166190064b4SSimon Glass will_build = False 167190064b4SSimon Glass 168190064b4SSimon Glass if will_build: 169190064b4SSimon Glass # We are going to have to build it. First, get a toolchain 170190064b4SSimon Glass if not self.toolchain: 171190064b4SSimon Glass try: 172190064b4SSimon Glass self.toolchain = self.builder.toolchains.Select(brd.arch) 173190064b4SSimon Glass except ValueError as err: 174190064b4SSimon Glass result.return_code = 10 175190064b4SSimon Glass result.stdout = '' 176190064b4SSimon Glass result.stderr = str(err) 177190064b4SSimon Glass # TODO(sjg@chromium.org): This gets swallowed, but needs 178190064b4SSimon Glass # to be reported. 179190064b4SSimon Glass 180190064b4SSimon Glass if self.toolchain: 181190064b4SSimon Glass # Checkout the right commit 182190064b4SSimon Glass if self.builder.commits: 183190064b4SSimon Glass commit = self.builder.commits[commit_upto] 184190064b4SSimon Glass if self.builder.checkout: 185190064b4SSimon Glass git_dir = os.path.join(work_dir, '.git') 186190064b4SSimon Glass gitutil.Checkout(commit.hash, git_dir, work_dir, 187190064b4SSimon Glass force=True) 188190064b4SSimon Glass else: 189190064b4SSimon Glass commit = 'current' 190190064b4SSimon Glass 191190064b4SSimon Glass # Set up the environment and command line 192bb1501f2SSimon Glass env = self.toolchain.MakeEnvironment(self.builder.full_path) 193190064b4SSimon Glass Mkdir(out_dir) 194190064b4SSimon Glass args = [] 195190064b4SSimon Glass cwd = work_dir 19648c1b6a8SSimon Glass src_dir = os.path.realpath(work_dir) 197190064b4SSimon Glass if not self.builder.in_tree: 198190064b4SSimon Glass if commit_upto is None: 199190064b4SSimon Glass # In this case we are building in the original source 200190064b4SSimon Glass # directory (i.e. the current directory where buildman 201190064b4SSimon Glass # is invoked. The output directory is set to this 202190064b4SSimon Glass # thread's selected work directory. 203190064b4SSimon Glass # 204190064b4SSimon Glass # Symlinks can confuse U-Boot's Makefile since 205190064b4SSimon Glass # we may use '..' in our path, so remove them. 206*f79f1e0cSStephen Warren out_dir = os.path.realpath(out_dir) 207*f79f1e0cSStephen Warren args.append('O=%s' % out_dir) 208190064b4SSimon Glass cwd = None 20948c1b6a8SSimon Glass src_dir = os.getcwd() 210190064b4SSimon Glass else: 211*f79f1e0cSStephen Warren args.append('O=%s' % out_rel_dir) 212f5e5ece0STom Rini if self.builder.verbose_build: 213f5e5ece0STom Rini args.append('V=1') 214f5e5ece0STom Rini else: 215190064b4SSimon Glass args.append('-s') 216190064b4SSimon Glass if self.builder.num_jobs is not None: 217190064b4SSimon Glass args.extend(['-j', str(self.builder.num_jobs)]) 218190064b4SSimon Glass config_args = ['%s_defconfig' % brd.target] 219190064b4SSimon Glass config_out = '' 220190064b4SSimon Glass args.extend(self.builder.toolchains.GetMakeArguments(brd)) 221190064b4SSimon Glass 222190064b4SSimon Glass # If we need to reconfigure, do that now 223190064b4SSimon Glass if do_config: 224*f79f1e0cSStephen Warren config_out = '' 225*f79f1e0cSStephen Warren if not self.incremental: 226fd18a89eSRoger Meier result = self.Make(commit, brd, 'mrproper', cwd, 227fd18a89eSRoger Meier 'mrproper', *args, env=env) 228*f79f1e0cSStephen Warren config_out += result.combined 229190064b4SSimon Glass result = self.Make(commit, brd, 'config', cwd, 230190064b4SSimon Glass *(args + config_args), env=env) 23140f11fceSSimon Glass config_out += result.combined 232190064b4SSimon Glass do_config = False # No need to configure next time 233190064b4SSimon Glass if result.return_code == 0: 234190064b4SSimon Glass result = self.Make(commit, brd, 'build', cwd, *args, 235190064b4SSimon Glass env=env) 23648c1b6a8SSimon Glass result.stderr = result.stderr.replace(src_dir + '/', '') 23740f11fceSSimon Glass if self.builder.verbose_build: 23840f11fceSSimon Glass result.stdout = config_out + result.stdout 239190064b4SSimon Glass else: 240190064b4SSimon Glass result.return_code = 1 241190064b4SSimon Glass result.stderr = 'No tool chain for %s\n' % brd.arch 242190064b4SSimon Glass result.already_done = False 243190064b4SSimon Glass 244190064b4SSimon Glass result.toolchain = self.toolchain 245190064b4SSimon Glass result.brd = brd 246190064b4SSimon Glass result.commit_upto = commit_upto 247190064b4SSimon Glass result.out_dir = out_dir 248190064b4SSimon Glass return result, do_config 249190064b4SSimon Glass 250190064b4SSimon Glass def _WriteResult(self, result, keep_outputs): 251190064b4SSimon Glass """Write a built result to the output directory. 252190064b4SSimon Glass 253190064b4SSimon Glass Args: 254190064b4SSimon Glass result: CommandResult object containing result to write 255190064b4SSimon Glass keep_outputs: True to store the output binaries, False 256190064b4SSimon Glass to delete them 257190064b4SSimon Glass """ 258190064b4SSimon Glass # Fatal error 259190064b4SSimon Glass if result.return_code < 0: 260190064b4SSimon Glass return 261190064b4SSimon Glass 26288c8dcf9SSimon Glass # If we think this might have been aborted with Ctrl-C, record the 26388c8dcf9SSimon Glass # failure but not that we are 'done' with this board. A retry may fix 26488c8dcf9SSimon Glass # it. 26588c8dcf9SSimon Glass maybe_aborted = result.stderr and 'No child processes' in result.stderr 266190064b4SSimon Glass 267190064b4SSimon Glass if result.already_done: 268190064b4SSimon Glass return 269190064b4SSimon Glass 270190064b4SSimon Glass # Write the output and stderr 271190064b4SSimon Glass output_dir = self.builder._GetOutputDir(result.commit_upto) 272190064b4SSimon Glass Mkdir(output_dir) 273190064b4SSimon Glass build_dir = self.builder.GetBuildDir(result.commit_upto, 274190064b4SSimon Glass result.brd.target) 275190064b4SSimon Glass Mkdir(build_dir) 276190064b4SSimon Glass 277190064b4SSimon Glass outfile = os.path.join(build_dir, 'log') 278190064b4SSimon Glass with open(outfile, 'w') as fd: 279190064b4SSimon Glass if result.stdout: 280190064b4SSimon Glass fd.write(result.stdout) 281190064b4SSimon Glass 282190064b4SSimon Glass errfile = self.builder.GetErrFile(result.commit_upto, 283190064b4SSimon Glass result.brd.target) 284190064b4SSimon Glass if result.stderr: 285190064b4SSimon Glass with open(errfile, 'w') as fd: 286190064b4SSimon Glass fd.write(result.stderr) 287190064b4SSimon Glass elif os.path.exists(errfile): 288190064b4SSimon Glass os.remove(errfile) 289190064b4SSimon Glass 290190064b4SSimon Glass if result.toolchain: 291190064b4SSimon Glass # Write the build result and toolchain information. 292190064b4SSimon Glass done_file = self.builder.GetDoneFile(result.commit_upto, 293190064b4SSimon Glass result.brd.target) 294190064b4SSimon Glass with open(done_file, 'w') as fd: 29588c8dcf9SSimon Glass if maybe_aborted: 29688c8dcf9SSimon Glass # Special code to indicate we need to retry 29788c8dcf9SSimon Glass fd.write('%s' % RETURN_CODE_RETRY) 29888c8dcf9SSimon Glass else: 299190064b4SSimon Glass fd.write('%s' % result.return_code) 300190064b4SSimon Glass with open(os.path.join(build_dir, 'toolchain'), 'w') as fd: 301190064b4SSimon Glass print >>fd, 'gcc', result.toolchain.gcc 302190064b4SSimon Glass print >>fd, 'path', result.toolchain.path 303190064b4SSimon Glass print >>fd, 'cross', result.toolchain.cross 304190064b4SSimon Glass print >>fd, 'arch', result.toolchain.arch 305190064b4SSimon Glass fd.write('%s' % result.return_code) 306190064b4SSimon Glass 307190064b4SSimon Glass with open(os.path.join(build_dir, 'toolchain'), 'w') as fd: 308190064b4SSimon Glass print >>fd, 'gcc', result.toolchain.gcc 309190064b4SSimon Glass print >>fd, 'path', result.toolchain.path 310190064b4SSimon Glass 311190064b4SSimon Glass # Write out the image and function size information and an objdump 312bb1501f2SSimon Glass env = result.toolchain.MakeEnvironment(self.builder.full_path) 313190064b4SSimon Glass lines = [] 314190064b4SSimon Glass for fname in ['u-boot', 'spl/u-boot-spl']: 315190064b4SSimon Glass cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname] 316190064b4SSimon Glass nm_result = command.RunPipe([cmd], capture=True, 317190064b4SSimon Glass capture_stderr=True, cwd=result.out_dir, 318190064b4SSimon Glass raise_on_error=False, env=env) 319190064b4SSimon Glass if nm_result.stdout: 320190064b4SSimon Glass nm = self.builder.GetFuncSizesFile(result.commit_upto, 321190064b4SSimon Glass result.brd.target, fname) 322190064b4SSimon Glass with open(nm, 'w') as fd: 323190064b4SSimon Glass print >>fd, nm_result.stdout, 324190064b4SSimon Glass 325190064b4SSimon Glass cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname] 326190064b4SSimon Glass dump_result = command.RunPipe([cmd], capture=True, 327190064b4SSimon Glass capture_stderr=True, cwd=result.out_dir, 328190064b4SSimon Glass raise_on_error=False, env=env) 329190064b4SSimon Glass rodata_size = '' 330190064b4SSimon Glass if dump_result.stdout: 331190064b4SSimon Glass objdump = self.builder.GetObjdumpFile(result.commit_upto, 332190064b4SSimon Glass result.brd.target, fname) 333190064b4SSimon Glass with open(objdump, 'w') as fd: 334190064b4SSimon Glass print >>fd, dump_result.stdout, 335190064b4SSimon Glass for line in dump_result.stdout.splitlines(): 336190064b4SSimon Glass fields = line.split() 337190064b4SSimon Glass if len(fields) > 5 and fields[1] == '.rodata': 338190064b4SSimon Glass rodata_size = fields[2] 339190064b4SSimon Glass 340190064b4SSimon Glass cmd = ['%ssize' % self.toolchain.cross, fname] 341190064b4SSimon Glass size_result = command.RunPipe([cmd], capture=True, 342190064b4SSimon Glass capture_stderr=True, cwd=result.out_dir, 343190064b4SSimon Glass raise_on_error=False, env=env) 344190064b4SSimon Glass if size_result.stdout: 345190064b4SSimon Glass lines.append(size_result.stdout.splitlines()[1] + ' ' + 346190064b4SSimon Glass rodata_size) 347190064b4SSimon Glass 348190064b4SSimon Glass # Write out the image sizes file. This is similar to the output 349190064b4SSimon Glass # of binutil's 'size' utility, but it omits the header line and 350190064b4SSimon Glass # adds an additional hex value at the end of each line for the 351190064b4SSimon Glass # rodata size 352190064b4SSimon Glass if len(lines): 353190064b4SSimon Glass sizes = self.builder.GetSizesFile(result.commit_upto, 354190064b4SSimon Glass result.brd.target) 355190064b4SSimon Glass with open(sizes, 'w') as fd: 356190064b4SSimon Glass print >>fd, '\n'.join(lines) 357190064b4SSimon Glass 358970f932aSSimon Glass # Write out the configuration files, with a special case for SPL 359970f932aSSimon Glass for dirname in ['', 'spl', 'tpl']: 360970f932aSSimon Glass self.CopyFiles(result.out_dir, build_dir, dirname, ['u-boot.cfg', 361970f932aSSimon Glass 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg', '.config', 362970f932aSSimon Glass 'include/autoconf.mk', 'include/generated/autoconf.h']) 363970f932aSSimon Glass 364190064b4SSimon Glass # Now write the actual build output 365190064b4SSimon Glass if keep_outputs: 3660eb4c045STom Rini self.CopyFiles(result.out_dir, build_dir, '', ['u-boot*', '*.bin', 367dd592110STom Rini '*.map', '*.img', 'MLO', 'SPL', 'include/autoconf.mk', 3680eb4c045STom Rini 'spl/u-boot-spl*']) 369190064b4SSimon Glass 370970f932aSSimon Glass def CopyFiles(self, out_dir, build_dir, dirname, patterns): 371970f932aSSimon Glass """Copy files from the build directory to the output. 372970f932aSSimon Glass 373970f932aSSimon Glass Args: 374970f932aSSimon Glass out_dir: Path to output directory containing the files 375970f932aSSimon Glass build_dir: Place to copy the files 376970f932aSSimon Glass dirname: Source directory, '' for normal U-Boot, 'spl' for SPL 377970f932aSSimon Glass patterns: A list of filenames (strings) to copy, each relative 378970f932aSSimon Glass to the build directory 379970f932aSSimon Glass """ 380970f932aSSimon Glass for pattern in patterns: 381970f932aSSimon Glass file_list = glob.glob(os.path.join(out_dir, dirname, pattern)) 382970f932aSSimon Glass for fname in file_list: 383970f932aSSimon Glass target = os.path.basename(fname) 384970f932aSSimon Glass if dirname: 385970f932aSSimon Glass base, ext = os.path.splitext(target) 386970f932aSSimon Glass if ext: 387970f932aSSimon Glass target = '%s-%s%s' % (base, dirname, ext) 388970f932aSSimon Glass shutil.copy(fname, os.path.join(build_dir, target)) 389190064b4SSimon Glass 390190064b4SSimon Glass def RunJob(self, job): 391190064b4SSimon Glass """Run a single job 392190064b4SSimon Glass 393190064b4SSimon Glass A job consists of a building a list of commits for a particular board. 394190064b4SSimon Glass 395190064b4SSimon Glass Args: 396190064b4SSimon Glass job: Job to build 397190064b4SSimon Glass """ 398190064b4SSimon Glass brd = job.board 399190064b4SSimon Glass work_dir = self.builder.GetThreadDir(self.thread_num) 400190064b4SSimon Glass self.toolchain = None 401190064b4SSimon Glass if job.commits: 402190064b4SSimon Glass # Run 'make board_defconfig' on the first commit 403190064b4SSimon Glass do_config = True 404190064b4SSimon Glass commit_upto = 0 405190064b4SSimon Glass force_build = False 406190064b4SSimon Glass for commit_upto in range(0, len(job.commits), job.step): 407190064b4SSimon Glass result, request_config = self.RunCommit(commit_upto, brd, 408190064b4SSimon Glass work_dir, do_config, 409190064b4SSimon Glass force_build or self.builder.force_build, 410190064b4SSimon Glass self.builder.force_build_failures) 411190064b4SSimon Glass failed = result.return_code or result.stderr 412190064b4SSimon Glass did_config = do_config 413190064b4SSimon Glass if failed and not do_config: 414190064b4SSimon Glass # If our incremental build failed, try building again 415190064b4SSimon Glass # with a reconfig. 416190064b4SSimon Glass if self.builder.force_config_on_failure: 417190064b4SSimon Glass result, request_config = self.RunCommit(commit_upto, 418190064b4SSimon Glass brd, work_dir, True, True, False) 419190064b4SSimon Glass did_config = True 420190064b4SSimon Glass if not self.builder.force_reconfig: 421190064b4SSimon Glass do_config = request_config 422190064b4SSimon Glass 423190064b4SSimon Glass # If we built that commit, then config is done. But if we got 424190064b4SSimon Glass # an warning, reconfig next time to force it to build the same 425190064b4SSimon Glass # files that created warnings this time. Otherwise an 426190064b4SSimon Glass # incremental build may not build the same file, and we will 427190064b4SSimon Glass # think that the warning has gone away. 428190064b4SSimon Glass # We could avoid this by using -Werror everywhere... 429190064b4SSimon Glass # For errors, the problem doesn't happen, since presumably 430190064b4SSimon Glass # the build stopped and didn't generate output, so will retry 431190064b4SSimon Glass # that file next time. So we could detect warnings and deal 432190064b4SSimon Glass # with them specially here. For now, we just reconfigure if 433190064b4SSimon Glass # anything goes work. 434190064b4SSimon Glass # Of course this is substantially slower if there are build 435190064b4SSimon Glass # errors/warnings (e.g. 2-3x slower even if only 10% of builds 436190064b4SSimon Glass # have problems). 437190064b4SSimon Glass if (failed and not result.already_done and not did_config and 438190064b4SSimon Glass self.builder.force_config_on_failure): 439190064b4SSimon Glass # If this build failed, try the next one with a 440190064b4SSimon Glass # reconfigure. 441190064b4SSimon Glass # Sometimes if the board_config.h file changes it can mess 442190064b4SSimon Glass # with dependencies, and we get: 443190064b4SSimon Glass # make: *** No rule to make target `include/autoconf.mk', 444190064b4SSimon Glass # needed by `depend'. 445190064b4SSimon Glass do_config = True 446190064b4SSimon Glass force_build = True 447190064b4SSimon Glass else: 448190064b4SSimon Glass force_build = False 449190064b4SSimon Glass if self.builder.force_config_on_failure: 450190064b4SSimon Glass if failed: 451190064b4SSimon Glass do_config = True 452190064b4SSimon Glass result.commit_upto = commit_upto 453190064b4SSimon Glass if result.return_code < 0: 454190064b4SSimon Glass raise ValueError('Interrupt') 455190064b4SSimon Glass 456190064b4SSimon Glass # We have the build results, so output the result 457190064b4SSimon Glass self._WriteResult(result, job.keep_outputs) 458190064b4SSimon Glass self.builder.out_queue.put(result) 459190064b4SSimon Glass else: 460190064b4SSimon Glass # Just build the currently checked-out build 461190064b4SSimon Glass result, request_config = self.RunCommit(None, brd, work_dir, True, 462190064b4SSimon Glass True, self.builder.force_build_failures) 463190064b4SSimon Glass result.commit_upto = 0 464190064b4SSimon Glass self._WriteResult(result, job.keep_outputs) 465190064b4SSimon Glass self.builder.out_queue.put(result) 466190064b4SSimon Glass 467190064b4SSimon Glass def run(self): 468190064b4SSimon Glass """Our thread's run function 469190064b4SSimon Glass 470190064b4SSimon Glass This thread picks a job from the queue, runs it, and then goes to the 471190064b4SSimon Glass next job. 472190064b4SSimon Glass """ 473190064b4SSimon Glass alive = True 474190064b4SSimon Glass while True: 475190064b4SSimon Glass job = self.builder.queue.get() 476190064b4SSimon Glass if self.builder.active and alive: 477190064b4SSimon Glass self.RunJob(job) 478190064b4SSimon Glass ''' 479190064b4SSimon Glass try: 480190064b4SSimon Glass if self.builder.active and alive: 481190064b4SSimon Glass self.RunJob(job) 482190064b4SSimon Glass except Exception as err: 483190064b4SSimon Glass alive = False 484190064b4SSimon Glass print err 485190064b4SSimon Glass ''' 486190064b4SSimon Glass self.builder.queue.task_done() 487