qibuild make used with -J does not have correct exit code
Opened this issue · 0 comments
dmerejkowsky commented
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"))