xref: /rk3399_rockchip-uboot/tools/buildman/builderthread.py (revision 190064b4daa30ce8efa7bcbee12ac05b780fb9c8)
1*190064b4SSimon Glass# Copyright (c) 2014 Google, Inc
2*190064b4SSimon Glass#
3*190064b4SSimon Glass# SPDX-License-Identifier:      GPL-2.0+
4*190064b4SSimon Glass#
5*190064b4SSimon Glass
6*190064b4SSimon Glassimport errno
7*190064b4SSimon Glassimport glob
8*190064b4SSimon Glassimport os
9*190064b4SSimon Glassimport shutil
10*190064b4SSimon Glassimport threading
11*190064b4SSimon Glass
12*190064b4SSimon Glassimport command
13*190064b4SSimon Glassimport gitutil
14*190064b4SSimon Glass
15*190064b4SSimon Glassdef Mkdir(dirname):
16*190064b4SSimon Glass    """Make a directory if it doesn't already exist.
17*190064b4SSimon Glass
18*190064b4SSimon Glass    Args:
19*190064b4SSimon Glass        dirname: Directory to create
20*190064b4SSimon Glass    """
21*190064b4SSimon Glass    try:
22*190064b4SSimon Glass        os.mkdir(dirname)
23*190064b4SSimon Glass    except OSError as err:
24*190064b4SSimon Glass        if err.errno == errno.EEXIST:
25*190064b4SSimon Glass            pass
26*190064b4SSimon Glass        else:
27*190064b4SSimon Glass            raise
28*190064b4SSimon Glass
29*190064b4SSimon Glassclass BuilderJob:
30*190064b4SSimon Glass    """Holds information about a job to be performed by a thread
31*190064b4SSimon Glass
32*190064b4SSimon Glass    Members:
33*190064b4SSimon Glass        board: Board object to build
34*190064b4SSimon Glass        commits: List of commit options to build.
35*190064b4SSimon Glass    """
36*190064b4SSimon Glass    def __init__(self):
37*190064b4SSimon Glass        self.board = None
38*190064b4SSimon Glass        self.commits = []
39*190064b4SSimon Glass
40*190064b4SSimon Glass
41*190064b4SSimon Glassclass ResultThread(threading.Thread):
42*190064b4SSimon Glass    """This thread processes results from builder threads.
43*190064b4SSimon Glass
44*190064b4SSimon Glass    It simply passes the results on to the builder. There is only one
45*190064b4SSimon Glass    result thread, and this helps to serialise the build output.
46*190064b4SSimon Glass    """
47*190064b4SSimon Glass    def __init__(self, builder):
48*190064b4SSimon Glass        """Set up a new result thread
49*190064b4SSimon Glass
50*190064b4SSimon Glass        Args:
51*190064b4SSimon Glass            builder: Builder which will be sent each result
52*190064b4SSimon Glass        """
53*190064b4SSimon Glass        threading.Thread.__init__(self)
54*190064b4SSimon Glass        self.builder = builder
55*190064b4SSimon Glass
56*190064b4SSimon Glass    def run(self):
57*190064b4SSimon Glass        """Called to start up the result thread.
58*190064b4SSimon Glass
59*190064b4SSimon Glass        We collect the next result job and pass it on to the build.
60*190064b4SSimon Glass        """
61*190064b4SSimon Glass        while True:
62*190064b4SSimon Glass            result = self.builder.out_queue.get()
63*190064b4SSimon Glass            self.builder.ProcessResult(result)
64*190064b4SSimon Glass            self.builder.out_queue.task_done()
65*190064b4SSimon Glass
66*190064b4SSimon Glass
67*190064b4SSimon Glassclass BuilderThread(threading.Thread):
68*190064b4SSimon Glass    """This thread builds U-Boot for a particular board.
69*190064b4SSimon Glass
70*190064b4SSimon Glass    An input queue provides each new job. We run 'make' to build U-Boot
71*190064b4SSimon Glass    and then pass the results on to the output queue.
72*190064b4SSimon Glass
73*190064b4SSimon Glass    Members:
74*190064b4SSimon Glass        builder: The builder which contains information we might need
75*190064b4SSimon Glass        thread_num: Our thread number (0-n-1), used to decide on a
76*190064b4SSimon Glass                temporary directory
77*190064b4SSimon Glass    """
78*190064b4SSimon Glass    def __init__(self, builder, thread_num):
79*190064b4SSimon Glass        """Set up a new builder thread"""
80*190064b4SSimon Glass        threading.Thread.__init__(self)
81*190064b4SSimon Glass        self.builder = builder
82*190064b4SSimon Glass        self.thread_num = thread_num
83*190064b4SSimon Glass
84*190064b4SSimon Glass    def Make(self, commit, brd, stage, cwd, *args, **kwargs):
85*190064b4SSimon Glass        """Run 'make' on a particular commit and board.
86*190064b4SSimon Glass
87*190064b4SSimon Glass        The source code will already be checked out, so the 'commit'
88*190064b4SSimon Glass        argument is only for information.
89*190064b4SSimon Glass
90*190064b4SSimon Glass        Args:
91*190064b4SSimon Glass            commit: Commit object that is being built
92*190064b4SSimon Glass            brd: Board object that is being built
93*190064b4SSimon Glass            stage: Stage of the build. Valid stages are:
94*190064b4SSimon Glass                        distclean - can be called to clean source
95*190064b4SSimon Glass                        config - called to configure for a board
96*190064b4SSimon Glass                        build - the main make invocation - it does the build
97*190064b4SSimon Glass            args: A list of arguments to pass to 'make'
98*190064b4SSimon Glass            kwargs: A list of keyword arguments to pass to command.RunPipe()
99*190064b4SSimon Glass
100*190064b4SSimon Glass        Returns:
101*190064b4SSimon Glass            CommandResult object
102*190064b4SSimon Glass        """
103*190064b4SSimon Glass        return self.builder.do_make(commit, brd, stage, cwd, *args,
104*190064b4SSimon Glass                **kwargs)
105*190064b4SSimon Glass
106*190064b4SSimon Glass    def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build,
107*190064b4SSimon Glass                  force_build_failures):
108*190064b4SSimon Glass        """Build a particular commit.
109*190064b4SSimon Glass
110*190064b4SSimon Glass        If the build is already done, and we are not forcing a build, we skip
111*190064b4SSimon Glass        the build and just return the previously-saved results.
112*190064b4SSimon Glass
113*190064b4SSimon Glass        Args:
114*190064b4SSimon Glass            commit_upto: Commit number to build (0...n-1)
115*190064b4SSimon Glass            brd: Board object to build
116*190064b4SSimon Glass            work_dir: Directory to which the source will be checked out
117*190064b4SSimon Glass            do_config: True to run a make <board>_defconfig on the source
118*190064b4SSimon Glass            force_build: Force a build even if one was previously done
119*190064b4SSimon Glass            force_build_failures: Force a bulid if the previous result showed
120*190064b4SSimon Glass                failure
121*190064b4SSimon Glass
122*190064b4SSimon Glass        Returns:
123*190064b4SSimon Glass            tuple containing:
124*190064b4SSimon Glass                - CommandResult object containing the results of the build
125*190064b4SSimon Glass                - boolean indicating whether 'make config' is still needed
126*190064b4SSimon Glass        """
127*190064b4SSimon Glass        # Create a default result - it will be overwritte by the call to
128*190064b4SSimon Glass        # self.Make() below, in the event that we do a build.
129*190064b4SSimon Glass        result = command.CommandResult()
130*190064b4SSimon Glass        result.return_code = 0
131*190064b4SSimon Glass        if self.builder.in_tree:
132*190064b4SSimon Glass            out_dir = work_dir
133*190064b4SSimon Glass        else:
134*190064b4SSimon Glass            out_dir = os.path.join(work_dir, 'build')
135*190064b4SSimon Glass
136*190064b4SSimon Glass        # Check if the job was already completed last time
137*190064b4SSimon Glass        done_file = self.builder.GetDoneFile(commit_upto, brd.target)
138*190064b4SSimon Glass        result.already_done = os.path.exists(done_file)
139*190064b4SSimon Glass        will_build = (force_build or force_build_failures or
140*190064b4SSimon Glass            not result.already_done)
141*190064b4SSimon Glass        if result.already_done and will_build:
142*190064b4SSimon Glass            # Get the return code from that build and use it
143*190064b4SSimon Glass            with open(done_file, 'r') as fd:
144*190064b4SSimon Glass                result.return_code = int(fd.readline())
145*190064b4SSimon Glass            err_file = self.builder.GetErrFile(commit_upto, brd.target)
146*190064b4SSimon Glass            if os.path.exists(err_file) and os.stat(err_file).st_size:
147*190064b4SSimon Glass                result.stderr = 'bad'
148*190064b4SSimon Glass            elif not force_build:
149*190064b4SSimon Glass                # The build passed, so no need to build it again
150*190064b4SSimon Glass                will_build = False
151*190064b4SSimon Glass
152*190064b4SSimon Glass        if will_build:
153*190064b4SSimon Glass            # We are going to have to build it. First, get a toolchain
154*190064b4SSimon Glass            if not self.toolchain:
155*190064b4SSimon Glass                try:
156*190064b4SSimon Glass                    self.toolchain = self.builder.toolchains.Select(brd.arch)
157*190064b4SSimon Glass                except ValueError as err:
158*190064b4SSimon Glass                    result.return_code = 10
159*190064b4SSimon Glass                    result.stdout = ''
160*190064b4SSimon Glass                    result.stderr = str(err)
161*190064b4SSimon Glass                    # TODO(sjg@chromium.org): This gets swallowed, but needs
162*190064b4SSimon Glass                    # to be reported.
163*190064b4SSimon Glass
164*190064b4SSimon Glass            if self.toolchain:
165*190064b4SSimon Glass                # Checkout the right commit
166*190064b4SSimon Glass                if self.builder.commits:
167*190064b4SSimon Glass                    commit = self.builder.commits[commit_upto]
168*190064b4SSimon Glass                    if self.builder.checkout:
169*190064b4SSimon Glass                        git_dir = os.path.join(work_dir, '.git')
170*190064b4SSimon Glass                        gitutil.Checkout(commit.hash, git_dir, work_dir,
171*190064b4SSimon Glass                                         force=True)
172*190064b4SSimon Glass                else:
173*190064b4SSimon Glass                    commit = 'current'
174*190064b4SSimon Glass
175*190064b4SSimon Glass                # Set up the environment and command line
176*190064b4SSimon Glass                env = self.toolchain.MakeEnvironment()
177*190064b4SSimon Glass                Mkdir(out_dir)
178*190064b4SSimon Glass                args = []
179*190064b4SSimon Glass                cwd = work_dir
180*190064b4SSimon Glass                if not self.builder.in_tree:
181*190064b4SSimon Glass                    if commit_upto is None:
182*190064b4SSimon Glass                        # In this case we are building in the original source
183*190064b4SSimon Glass                        # directory (i.e. the current directory where buildman
184*190064b4SSimon Glass                        # is invoked. The output directory is set to this
185*190064b4SSimon Glass                        # thread's selected work directory.
186*190064b4SSimon Glass                        #
187*190064b4SSimon Glass                        # Symlinks can confuse U-Boot's Makefile since
188*190064b4SSimon Glass                        # we may use '..' in our path, so remove them.
189*190064b4SSimon Glass                        work_dir = os.path.realpath(work_dir)
190*190064b4SSimon Glass                        args.append('O=%s/build' % work_dir)
191*190064b4SSimon Glass                        cwd = None
192*190064b4SSimon Glass                    else:
193*190064b4SSimon Glass                        args.append('O=build')
194*190064b4SSimon Glass                args.append('-s')
195*190064b4SSimon Glass                if self.builder.num_jobs is not None:
196*190064b4SSimon Glass                    args.extend(['-j', str(self.builder.num_jobs)])
197*190064b4SSimon Glass                config_args = ['%s_defconfig' % brd.target]
198*190064b4SSimon Glass                config_out = ''
199*190064b4SSimon Glass                args.extend(self.builder.toolchains.GetMakeArguments(brd))
200*190064b4SSimon Glass
201*190064b4SSimon Glass                # If we need to reconfigure, do that now
202*190064b4SSimon Glass                if do_config:
203*190064b4SSimon Glass                    result = self.Make(commit, brd, 'distclean', cwd,
204*190064b4SSimon Glass                            'distclean', *args, env=env)
205*190064b4SSimon Glass                    result = self.Make(commit, brd, 'config', cwd,
206*190064b4SSimon Glass                            *(args + config_args), env=env)
207*190064b4SSimon Glass                    config_out = result.combined
208*190064b4SSimon Glass                    do_config = False   # No need to configure next time
209*190064b4SSimon Glass                if result.return_code == 0:
210*190064b4SSimon Glass                    result = self.Make(commit, brd, 'build', cwd, *args,
211*190064b4SSimon Glass                            env=env)
212*190064b4SSimon Glass                    result.stdout = config_out + result.stdout
213*190064b4SSimon Glass            else:
214*190064b4SSimon Glass                result.return_code = 1
215*190064b4SSimon Glass                result.stderr = 'No tool chain for %s\n' % brd.arch
216*190064b4SSimon Glass            result.already_done = False
217*190064b4SSimon Glass
218*190064b4SSimon Glass        result.toolchain = self.toolchain
219*190064b4SSimon Glass        result.brd = brd
220*190064b4SSimon Glass        result.commit_upto = commit_upto
221*190064b4SSimon Glass        result.out_dir = out_dir
222*190064b4SSimon Glass        return result, do_config
223*190064b4SSimon Glass
224*190064b4SSimon Glass    def _WriteResult(self, result, keep_outputs):
225*190064b4SSimon Glass        """Write a built result to the output directory.
226*190064b4SSimon Glass
227*190064b4SSimon Glass        Args:
228*190064b4SSimon Glass            result: CommandResult object containing result to write
229*190064b4SSimon Glass            keep_outputs: True to store the output binaries, False
230*190064b4SSimon Glass                to delete them
231*190064b4SSimon Glass        """
232*190064b4SSimon Glass        # Fatal error
233*190064b4SSimon Glass        if result.return_code < 0:
234*190064b4SSimon Glass            return
235*190064b4SSimon Glass
236*190064b4SSimon Glass        # Aborted?
237*190064b4SSimon Glass        if result.stderr and 'No child processes' in result.stderr:
238*190064b4SSimon Glass            return
239*190064b4SSimon Glass
240*190064b4SSimon Glass        if result.already_done:
241*190064b4SSimon Glass            return
242*190064b4SSimon Glass
243*190064b4SSimon Glass        # Write the output and stderr
244*190064b4SSimon Glass        output_dir = self.builder._GetOutputDir(result.commit_upto)
245*190064b4SSimon Glass        Mkdir(output_dir)
246*190064b4SSimon Glass        build_dir = self.builder.GetBuildDir(result.commit_upto,
247*190064b4SSimon Glass                result.brd.target)
248*190064b4SSimon Glass        Mkdir(build_dir)
249*190064b4SSimon Glass
250*190064b4SSimon Glass        outfile = os.path.join(build_dir, 'log')
251*190064b4SSimon Glass        with open(outfile, 'w') as fd:
252*190064b4SSimon Glass            if result.stdout:
253*190064b4SSimon Glass                fd.write(result.stdout)
254*190064b4SSimon Glass
255*190064b4SSimon Glass        errfile = self.builder.GetErrFile(result.commit_upto,
256*190064b4SSimon Glass                result.brd.target)
257*190064b4SSimon Glass        if result.stderr:
258*190064b4SSimon Glass            with open(errfile, 'w') as fd:
259*190064b4SSimon Glass                fd.write(result.stderr)
260*190064b4SSimon Glass        elif os.path.exists(errfile):
261*190064b4SSimon Glass            os.remove(errfile)
262*190064b4SSimon Glass
263*190064b4SSimon Glass        if result.toolchain:
264*190064b4SSimon Glass            # Write the build result and toolchain information.
265*190064b4SSimon Glass            done_file = self.builder.GetDoneFile(result.commit_upto,
266*190064b4SSimon Glass                    result.brd.target)
267*190064b4SSimon Glass            with open(done_file, 'w') as fd:
268*190064b4SSimon Glass                fd.write('%s' % result.return_code)
269*190064b4SSimon Glass            with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
270*190064b4SSimon Glass                print >>fd, 'gcc', result.toolchain.gcc
271*190064b4SSimon Glass                print >>fd, 'path', result.toolchain.path
272*190064b4SSimon Glass                print >>fd, 'cross', result.toolchain.cross
273*190064b4SSimon Glass                print >>fd, 'arch', result.toolchain.arch
274*190064b4SSimon Glass                fd.write('%s' % result.return_code)
275*190064b4SSimon Glass
276*190064b4SSimon Glass            with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
277*190064b4SSimon Glass                print >>fd, 'gcc', result.toolchain.gcc
278*190064b4SSimon Glass                print >>fd, 'path', result.toolchain.path
279*190064b4SSimon Glass
280*190064b4SSimon Glass            # Write out the image and function size information and an objdump
281*190064b4SSimon Glass            env = result.toolchain.MakeEnvironment()
282*190064b4SSimon Glass            lines = []
283*190064b4SSimon Glass            for fname in ['u-boot', 'spl/u-boot-spl']:
284*190064b4SSimon Glass                cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
285*190064b4SSimon Glass                nm_result = command.RunPipe([cmd], capture=True,
286*190064b4SSimon Glass                        capture_stderr=True, cwd=result.out_dir,
287*190064b4SSimon Glass                        raise_on_error=False, env=env)
288*190064b4SSimon Glass                if nm_result.stdout:
289*190064b4SSimon Glass                    nm = self.builder.GetFuncSizesFile(result.commit_upto,
290*190064b4SSimon Glass                                    result.brd.target, fname)
291*190064b4SSimon Glass                    with open(nm, 'w') as fd:
292*190064b4SSimon Glass                        print >>fd, nm_result.stdout,
293*190064b4SSimon Glass
294*190064b4SSimon Glass                cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
295*190064b4SSimon Glass                dump_result = command.RunPipe([cmd], capture=True,
296*190064b4SSimon Glass                        capture_stderr=True, cwd=result.out_dir,
297*190064b4SSimon Glass                        raise_on_error=False, env=env)
298*190064b4SSimon Glass                rodata_size = ''
299*190064b4SSimon Glass                if dump_result.stdout:
300*190064b4SSimon Glass                    objdump = self.builder.GetObjdumpFile(result.commit_upto,
301*190064b4SSimon Glass                                    result.brd.target, fname)
302*190064b4SSimon Glass                    with open(objdump, 'w') as fd:
303*190064b4SSimon Glass                        print >>fd, dump_result.stdout,
304*190064b4SSimon Glass                    for line in dump_result.stdout.splitlines():
305*190064b4SSimon Glass                        fields = line.split()
306*190064b4SSimon Glass                        if len(fields) > 5 and fields[1] == '.rodata':
307*190064b4SSimon Glass                            rodata_size = fields[2]
308*190064b4SSimon Glass
309*190064b4SSimon Glass                cmd = ['%ssize' % self.toolchain.cross, fname]
310*190064b4SSimon Glass                size_result = command.RunPipe([cmd], capture=True,
311*190064b4SSimon Glass                        capture_stderr=True, cwd=result.out_dir,
312*190064b4SSimon Glass                        raise_on_error=False, env=env)
313*190064b4SSimon Glass                if size_result.stdout:
314*190064b4SSimon Glass                    lines.append(size_result.stdout.splitlines()[1] + ' ' +
315*190064b4SSimon Glass                                 rodata_size)
316*190064b4SSimon Glass
317*190064b4SSimon Glass            # Write out the image sizes file. This is similar to the output
318*190064b4SSimon Glass            # of binutil's 'size' utility, but it omits the header line and
319*190064b4SSimon Glass            # adds an additional hex value at the end of each line for the
320*190064b4SSimon Glass            # rodata size
321*190064b4SSimon Glass            if len(lines):
322*190064b4SSimon Glass                sizes = self.builder.GetSizesFile(result.commit_upto,
323*190064b4SSimon Glass                                result.brd.target)
324*190064b4SSimon Glass                with open(sizes, 'w') as fd:
325*190064b4SSimon Glass                    print >>fd, '\n'.join(lines)
326*190064b4SSimon Glass
327*190064b4SSimon Glass        # Now write the actual build output
328*190064b4SSimon Glass        if keep_outputs:
329*190064b4SSimon Glass            patterns = ['u-boot', '*.bin', 'u-boot.dtb', '*.map',
330*190064b4SSimon Glass                        'include/autoconf.mk', 'spl/u-boot-spl',
331*190064b4SSimon Glass                        'spl/u-boot-spl.bin']
332*190064b4SSimon Glass            for pattern in patterns:
333*190064b4SSimon Glass                file_list = glob.glob(os.path.join(result.out_dir, pattern))
334*190064b4SSimon Glass                for fname in file_list:
335*190064b4SSimon Glass                    shutil.copy(fname, build_dir)
336*190064b4SSimon Glass
337*190064b4SSimon Glass
338*190064b4SSimon Glass    def RunJob(self, job):
339*190064b4SSimon Glass        """Run a single job
340*190064b4SSimon Glass
341*190064b4SSimon Glass        A job consists of a building a list of commits for a particular board.
342*190064b4SSimon Glass
343*190064b4SSimon Glass        Args:
344*190064b4SSimon Glass            job: Job to build
345*190064b4SSimon Glass        """
346*190064b4SSimon Glass        brd = job.board
347*190064b4SSimon Glass        work_dir = self.builder.GetThreadDir(self.thread_num)
348*190064b4SSimon Glass        self.toolchain = None
349*190064b4SSimon Glass        if job.commits:
350*190064b4SSimon Glass            # Run 'make board_defconfig' on the first commit
351*190064b4SSimon Glass            do_config = True
352*190064b4SSimon Glass            commit_upto  = 0
353*190064b4SSimon Glass            force_build = False
354*190064b4SSimon Glass            for commit_upto in range(0, len(job.commits), job.step):
355*190064b4SSimon Glass                result, request_config = self.RunCommit(commit_upto, brd,
356*190064b4SSimon Glass                        work_dir, do_config,
357*190064b4SSimon Glass                        force_build or self.builder.force_build,
358*190064b4SSimon Glass                        self.builder.force_build_failures)
359*190064b4SSimon Glass                failed = result.return_code or result.stderr
360*190064b4SSimon Glass                did_config = do_config
361*190064b4SSimon Glass                if failed and not do_config:
362*190064b4SSimon Glass                    # If our incremental build failed, try building again
363*190064b4SSimon Glass                    # with a reconfig.
364*190064b4SSimon Glass                    if self.builder.force_config_on_failure:
365*190064b4SSimon Glass                        result, request_config = self.RunCommit(commit_upto,
366*190064b4SSimon Glass                            brd, work_dir, True, True, False)
367*190064b4SSimon Glass                        did_config = True
368*190064b4SSimon Glass                if not self.builder.force_reconfig:
369*190064b4SSimon Glass                    do_config = request_config
370*190064b4SSimon Glass
371*190064b4SSimon Glass                # If we built that commit, then config is done. But if we got
372*190064b4SSimon Glass                # an warning, reconfig next time to force it to build the same
373*190064b4SSimon Glass                # files that created warnings this time. Otherwise an
374*190064b4SSimon Glass                # incremental build may not build the same file, and we will
375*190064b4SSimon Glass                # think that the warning has gone away.
376*190064b4SSimon Glass                # We could avoid this by using -Werror everywhere...
377*190064b4SSimon Glass                # For errors, the problem doesn't happen, since presumably
378*190064b4SSimon Glass                # the build stopped and didn't generate output, so will retry
379*190064b4SSimon Glass                # that file next time. So we could detect warnings and deal
380*190064b4SSimon Glass                # with them specially here. For now, we just reconfigure if
381*190064b4SSimon Glass                # anything goes work.
382*190064b4SSimon Glass                # Of course this is substantially slower if there are build
383*190064b4SSimon Glass                # errors/warnings (e.g. 2-3x slower even if only 10% of builds
384*190064b4SSimon Glass                # have problems).
385*190064b4SSimon Glass                if (failed and not result.already_done and not did_config and
386*190064b4SSimon Glass                        self.builder.force_config_on_failure):
387*190064b4SSimon Glass                    # If this build failed, try the next one with a
388*190064b4SSimon Glass                    # reconfigure.
389*190064b4SSimon Glass                    # Sometimes if the board_config.h file changes it can mess
390*190064b4SSimon Glass                    # with dependencies, and we get:
391*190064b4SSimon Glass                    # make: *** No rule to make target `include/autoconf.mk',
392*190064b4SSimon Glass                    #     needed by `depend'.
393*190064b4SSimon Glass                    do_config = True
394*190064b4SSimon Glass                    force_build = True
395*190064b4SSimon Glass                else:
396*190064b4SSimon Glass                    force_build = False
397*190064b4SSimon Glass                    if self.builder.force_config_on_failure:
398*190064b4SSimon Glass                        if failed:
399*190064b4SSimon Glass                            do_config = True
400*190064b4SSimon Glass                    result.commit_upto = commit_upto
401*190064b4SSimon Glass                    if result.return_code < 0:
402*190064b4SSimon Glass                        raise ValueError('Interrupt')
403*190064b4SSimon Glass
404*190064b4SSimon Glass                # We have the build results, so output the result
405*190064b4SSimon Glass                self._WriteResult(result, job.keep_outputs)
406*190064b4SSimon Glass                self.builder.out_queue.put(result)
407*190064b4SSimon Glass        else:
408*190064b4SSimon Glass            # Just build the currently checked-out build
409*190064b4SSimon Glass            result, request_config = self.RunCommit(None, brd, work_dir, True,
410*190064b4SSimon Glass                        True, self.builder.force_build_failures)
411*190064b4SSimon Glass            result.commit_upto = 0
412*190064b4SSimon Glass            self._WriteResult(result, job.keep_outputs)
413*190064b4SSimon Glass            self.builder.out_queue.put(result)
414*190064b4SSimon Glass
415*190064b4SSimon Glass    def run(self):
416*190064b4SSimon Glass        """Our thread's run function
417*190064b4SSimon Glass
418*190064b4SSimon Glass        This thread picks a job from the queue, runs it, and then goes to the
419*190064b4SSimon Glass        next job.
420*190064b4SSimon Glass        """
421*190064b4SSimon Glass        alive = True
422*190064b4SSimon Glass        while True:
423*190064b4SSimon Glass            job = self.builder.queue.get()
424*190064b4SSimon Glass            if self.builder.active and alive:
425*190064b4SSimon Glass                self.RunJob(job)
426*190064b4SSimon Glass            '''
427*190064b4SSimon Glass            try:
428*190064b4SSimon Glass                if self.builder.active and alive:
429*190064b4SSimon Glass                    self.RunJob(job)
430*190064b4SSimon Glass            except Exception as err:
431*190064b4SSimon Glass                alive = False
432*190064b4SSimon Glass                print err
433*190064b4SSimon Glass            '''
434*190064b4SSimon Glass            self.builder.queue.task_done()
435