aldebaran/qibuild

qibuild make used with -J does not have correct exit code

Opened this issue · 0 comments

Steps to reproduce : build a project with an invalid C++ syntax with qibuild make -J1

$ qibuild make -J1
Worker #1 starts working on  foo
* (1/1) Building foo in Debug
[ 50%] Building CXX object CMakeFiles/foo.dir/main.cpp.o
/mnt/ssd/src/master/foo/main.cpp:1:1: error: ‘coin’ does not name a type
CMakeFiles/foo.dir/build.make:62: recipe for target 'CMakeFiles/foo.dir/main.cpp.o' failed
make[2]: *** [CMakeFiles/foo.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/foo.dir/all' failed
make[1]: *** [CMakeFiles/foo.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
[ERROR]: Python exception during build
BuildFailed Error occurred when building project foo 
  File "/mnt/ssd/src/master/tools/qibuild/python/qibuild/parallel_builder.py", line 189, in run
    job.execute(*self.args, **self.kwargs)
  File "/mnt/ssd/src/master/tools/qibuild/python/qibuild/parallel_builder.py", line 48, in execute
    self.project.build(**kwargs)
  File "/mnt/ssd/src/master/tools/qibuild/python/qibuild/project.py", line 422, in build
    raise qibuild.build.BuildFailed(self)

When build fails, there is a race condition.

The following code:

class BuildWorker(threading.thread):

    def run(self):

         try:
         # .....
         except Exception, e:
                self.result.ok = False

is indeed executed, but the main loop in ParallelBuilder:

class ParallelBuilder():

    def build(self):

        while all_ok and \
              (self.pending_jobs or not self.running_jobs.empty()):
        # ....
        for worker in self._workers:
            if not worker.result.ok:
                all_ok = False

exits before worker.result.ok is read.

Thus the build terminates but BuildFailedException is not raised, and exit code is 0

On a related note, the error message is incorrect. The code should be changed to look like:

try:
    ui.info(ui.green, "Worker #%i starts working on " % (self.index + 1), ui.reset, ui.bold, job.project.name)
    job.execute(*self.args, **self.kwargs)
    self.queue.task_done()
except BuildFailed as failed_build:
     # Not an exceptional condition -> no need to dispay backtrace
     self.result.ok = False
     self.result.failed_project = failed_build.project
except Exception as e:
      # Oh, oh an unexpected exception was raised in a different thread. Log it 
      # so Python does not dead lock 
       ui.error(ui.red,  *ui.message_for_exception(e, "Python exception during build"))