diff options
author | Simon Glass <sjg@chromium.org> | 2021-10-20 06:43:24 +0300 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2021-10-20 11:59:55 +0300 |
commit | 7bf83a5d7be036969807c0f44ff75d211e039a02 (patch) | |
tree | a866b3676aa62584cbda8643aee6c7ca85eaff19 /tools/buildman | |
parent | bafdeb45462683692e0ae217d4683b8062c59608 (diff) | |
download | u-boot-7bf83a5d7be036969807c0f44ff75d211e039a02.tar.xz |
buildman: Detect Kconfig loops
Hex and int Kconfig options are supposed to have defaults. This is so we
can configure U-Boot without having to enter particular values for the
items that don't have specific values in the board's defconfig file.
If this rule is not followed, then introducing a new Kconfig can produce
a loop like this:
Break things (BREAK_ME) [] (NEW)
Error in reading or end of file.
Break things (BREAK_ME) [] (NEW)
Error in reading or end of file.
The continues forever since buildman passes /dev/null to 'conf', and
the build system just tries again. Eventually there is so much output that
buildman runs out of memory.
We can detect this situation by looking for a symbol (like 'BREAK_ME')
which has no default (the '[]' above) and is marked as new. If this
appears multiple times in the output, we know something is wrong.
Add a filter function for the output which detects this situation. Allow
it to return True to terminate the process. Implement this termination in
cros_subprocess.
With this we get a nice message:
buildman --board sandbox -T0
Building current source for 1 boards (0 threads, 32 jobs per thread)
sandbox: w+ sandbox
+.config:66:warning: symbol value '' invalid for BREAK_ME
+
+Error in reading or end of file.
+make[3]: *** [scripts/kconfig/Makefile:75: syncconfig] Terminated
+make[2]: *** [Makefile:569: syncconfig] Terminated
+make: *** [Makefile:177: sub-make] Terminated
+(** did you define an int/hex Kconfig with no default? **)
Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'tools/buildman')
-rw-r--r-- | tools/buildman/builder.py | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py index ce852eb03a..122f0d1406 100644 --- a/tools/buildman/builder.py +++ b/tools/buildman/builder.py @@ -24,6 +24,17 @@ from patman import gitutil from patman import terminal from patman.terminal import Print +# This indicates an new int or hex Kconfig property with no default +# It hangs the build since the 'conf' tool cannot proceed without valid input. +# +# We get a repeat sequence of something like this: +# >> +# Break things (BREAK_ME) [] (NEW) +# Error in reading or end of file. +# << +# which indicates that BREAK_ME has an empty default +RE_NO_DEFAULT = re.compile(b'\((\w+)\) \[] \(NEW\)') + """ Theory of Operation @@ -200,6 +211,8 @@ class Builder: _working_dir: Base working directory containing all threads _single_builder: BuilderThread object for the singer builder, if threading is not being used + _terminated: Thread was terminated due to an error + _restarting_config: True if 'Restart config' is detected in output """ class Outcome: """Records a build outcome for a single make invocation @@ -304,6 +317,8 @@ class Builder: self.work_in_output = work_in_output if not self.squash_config_y: self.config_filenames += EXTRA_CONFIG_FILENAMES + self._terminated = False + self._restarting_config = False self.warnings_as_errors = warnings_as_errors self.col = terminal.Color() @@ -429,9 +444,35 @@ class Builder: args: Arguments to pass to make kwargs: Arguments to pass to command.RunPipe() """ + + def check_output(stream, data): + if b'Restart config' in data: + self._restarting_config = True + + # If we see 'Restart config' following by multiple errors + if self._restarting_config: + m = RE_NO_DEFAULT.findall(data) + + # Number of occurences of each Kconfig item + multiple = [m.count(val) for val in set(m)] + + # If any of them occur more than once, we have a loop + if [val for val in multiple if val > 1]: + self._terminated = True + return True + return False + + self._restarting_config = False + self._terminated = False cmd = [self.gnu_make] + list(args) result = command.RunPipe([cmd], capture=True, capture_stderr=True, - cwd=cwd, raise_on_error=False, infile='/dev/null', **kwargs) + cwd=cwd, raise_on_error=False, infile='/dev/null', + output_func=check_output, **kwargs) + + if self._terminated: + # Try to be helpful + result.stderr += '(** did you define an int/hex Kconfig with no default? **)' + if self.verbose_build: result.stdout = '%s\n' % (' '.join(cmd)) + result.stdout result.combined = '%s\n' % (' '.join(cmd)) + result.combined |