|
@@ -96,6 +96,13 @@ OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = range(4)
|
|
|
# Translate a commit subject into a valid filename
|
|
|
trans_valid_chars = string.maketrans("/: ", "---")
|
|
|
|
|
|
+CONFIG_FILENAMES = [
|
|
|
+ '.config', '.config-spl', '.config-tpl',
|
|
|
+ 'autoconf.mk', 'autoconf-spl.mk', 'autoconf-tpl.mk',
|
|
|
+ 'autoconf.h', 'autoconf-spl.h','autoconf-tpl.h',
|
|
|
+ 'u-boot.cfg', 'u-boot-spl.cfg', 'u-boot-tpl.cfg'
|
|
|
+]
|
|
|
+
|
|
|
|
|
|
class Builder:
|
|
|
"""Class for building U-Boot for a particular commit.
|
|
@@ -166,12 +173,17 @@ class Builder:
|
|
|
value is itself a dictionary:
|
|
|
key: function name
|
|
|
value: Size of function in bytes
|
|
|
+ config: Dictionary keyed by filename - e.g. '.config'. Each
|
|
|
+ value is itself a dictionary:
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
"""
|
|
|
- def __init__(self, rc, err_lines, sizes, func_sizes):
|
|
|
+ def __init__(self, rc, err_lines, sizes, func_sizes, config):
|
|
|
self.rc = rc
|
|
|
self.err_lines = err_lines
|
|
|
self.sizes = sizes
|
|
|
self.func_sizes = func_sizes
|
|
|
+ self.config = config
|
|
|
|
|
|
def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs,
|
|
|
gnu_make='make', checkout=True, show_unknown=True, step=1,
|
|
@@ -254,7 +266,7 @@ class Builder:
|
|
|
|
|
|
def SetDisplayOptions(self, show_errors=False, show_sizes=False,
|
|
|
show_detail=False, show_bloat=False,
|
|
|
- list_error_boards=False):
|
|
|
+ list_error_boards=False, show_config=False):
|
|
|
"""Setup display options for the builder.
|
|
|
|
|
|
show_errors: True to show summarised error/warning info
|
|
@@ -262,12 +274,14 @@ class Builder:
|
|
|
show_detail: Show detail for each board
|
|
|
show_bloat: Show detail for each function
|
|
|
list_error_boards: Show the boards which caused each error/warning
|
|
|
+ show_config: Show config deltas
|
|
|
"""
|
|
|
self._show_errors = show_errors
|
|
|
self._show_sizes = show_sizes
|
|
|
self._show_detail = show_detail
|
|
|
self._show_bloat = show_bloat
|
|
|
self._list_error_boards = list_error_boards
|
|
|
+ self._show_config = show_config
|
|
|
|
|
|
def _AddTimestamp(self):
|
|
|
"""Add a new timestamp to the list and record the build period.
|
|
@@ -335,6 +349,9 @@ class Builder:
|
|
|
cmd = [self.gnu_make] + list(args)
|
|
|
result = command.RunPipe([cmd], capture=True, capture_stderr=True,
|
|
|
cwd=cwd, raise_on_error=False, **kwargs)
|
|
|
+ if self.verbose_build:
|
|
|
+ result.stdout = '%s\n' % (' '.join(cmd)) + result.stdout
|
|
|
+ result.combined = '%s\n' % (' '.join(cmd)) + result.combined
|
|
|
return result
|
|
|
|
|
|
def ProcessResult(self, result):
|
|
@@ -516,13 +533,50 @@ class Builder:
|
|
|
sym[name] = sym.get(name, 0) + int(size, 16)
|
|
|
return sym
|
|
|
|
|
|
- def GetBuildOutcome(self, commit_upto, target, read_func_sizes):
|
|
|
+ def _ProcessConfig(self, fname):
|
|
|
+ """Read in a .config, autoconf.mk or autoconf.h file
|
|
|
+
|
|
|
+ This function handles all config file types. It ignores comments and
|
|
|
+ any #defines which don't start with CONFIG_.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ fname: Filename to read
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ Dictionary:
|
|
|
+ key: Config name (e.g. CONFIG_DM)
|
|
|
+ value: Config value (e.g. 1)
|
|
|
+ """
|
|
|
+ config = {}
|
|
|
+ if os.path.exists(fname):
|
|
|
+ with open(fname) as fd:
|
|
|
+ for line in fd:
|
|
|
+ line = line.strip()
|
|
|
+ if line.startswith('#define'):
|
|
|
+ values = line[8:].split(' ', 1)
|
|
|
+ if len(values) > 1:
|
|
|
+ key, value = values
|
|
|
+ else:
|
|
|
+ key = values[0]
|
|
|
+ value = ''
|
|
|
+ if not key.startswith('CONFIG_'):
|
|
|
+ continue
|
|
|
+ elif not line or line[0] in ['#', '*', '/']:
|
|
|
+ continue
|
|
|
+ else:
|
|
|
+ key, value = line.split('=', 1)
|
|
|
+ config[key] = value
|
|
|
+ return config
|
|
|
+
|
|
|
+ def GetBuildOutcome(self, commit_upto, target, read_func_sizes,
|
|
|
+ read_config):
|
|
|
"""Work out the outcome of a build.
|
|
|
|
|
|
Args:
|
|
|
commit_upto: Commit number to check (0..n-1)
|
|
|
target: Target board to check
|
|
|
read_func_sizes: True to read function size information
|
|
|
+ read_config: True to read .config and autoconf.h files
|
|
|
|
|
|
Returns:
|
|
|
Outcome object
|
|
@@ -531,6 +585,7 @@ class Builder:
|
|
|
sizes_file = self.GetSizesFile(commit_upto, target)
|
|
|
sizes = {}
|
|
|
func_sizes = {}
|
|
|
+ config = {}
|
|
|
if os.path.exists(done_file):
|
|
|
with open(done_file, 'r') as fd:
|
|
|
return_code = int(fd.readline())
|
|
@@ -574,17 +629,25 @@ class Builder:
|
|
|
'')
|
|
|
func_sizes[dict_name] = self.ReadFuncSizes(fname, fd)
|
|
|
|
|
|
- return Builder.Outcome(rc, err_lines, sizes, func_sizes)
|
|
|
+ if read_config:
|
|
|
+ output_dir = self.GetBuildDir(commit_upto, target)
|
|
|
+ for name in CONFIG_FILENAMES:
|
|
|
+ fname = os.path.join(output_dir, name)
|
|
|
+ config[name] = self._ProcessConfig(fname)
|
|
|
+
|
|
|
+ return Builder.Outcome(rc, err_lines, sizes, func_sizes, config)
|
|
|
|
|
|
- return Builder.Outcome(OUTCOME_UNKNOWN, [], {}, {})
|
|
|
+ return Builder.Outcome(OUTCOME_UNKNOWN, [], {}, {}, {})
|
|
|
|
|
|
- def GetResultSummary(self, boards_selected, commit_upto, read_func_sizes):
|
|
|
+ def GetResultSummary(self, boards_selected, commit_upto, read_func_sizes,
|
|
|
+ read_config):
|
|
|
"""Calculate a summary of the results of building a commit.
|
|
|
|
|
|
Args:
|
|
|
board_selected: Dict containing boards to summarise
|
|
|
commit_upto: Commit number to summarize (0..self.count-1)
|
|
|
read_func_sizes: True to read function size information
|
|
|
+ read_config: True to read .config and autoconf.h files
|
|
|
|
|
|
Returns:
|
|
|
Tuple:
|
|
@@ -596,6 +659,10 @@ class Builder:
|
|
|
List containing a summary of warning lines
|
|
|
Dict keyed by error line, containing a list of the Board
|
|
|
objects with that warning
|
|
|
+ Dictionary keyed by filename - e.g. '.config'. Each
|
|
|
+ value is itself a dictionary:
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
"""
|
|
|
def AddLine(lines_summary, lines_boards, line, board):
|
|
|
line = line.rstrip()
|
|
@@ -610,10 +677,13 @@ class Builder:
|
|
|
err_lines_boards = {}
|
|
|
warn_lines_summary = []
|
|
|
warn_lines_boards = {}
|
|
|
+ config = {}
|
|
|
+ for fname in CONFIG_FILENAMES:
|
|
|
+ config[fname] = {}
|
|
|
|
|
|
for board in boards_selected.itervalues():
|
|
|
outcome = self.GetBuildOutcome(commit_upto, board.target,
|
|
|
- read_func_sizes)
|
|
|
+ read_func_sizes, read_config)
|
|
|
board_dict[board.target] = outcome
|
|
|
last_func = None
|
|
|
last_was_warning = False
|
|
@@ -639,8 +709,14 @@ class Builder:
|
|
|
line, board)
|
|
|
last_was_warning = is_warning
|
|
|
last_func = None
|
|
|
+ for fname in CONFIG_FILENAMES:
|
|
|
+ config[fname] = {}
|
|
|
+ if outcome.config:
|
|
|
+ for key, value in outcome.config[fname].iteritems():
|
|
|
+ config[fname][key] = value
|
|
|
+
|
|
|
return (board_dict, err_lines_summary, err_lines_boards,
|
|
|
- warn_lines_summary, warn_lines_boards)
|
|
|
+ warn_lines_summary, warn_lines_boards, config)
|
|
|
|
|
|
def AddOutcome(self, board_dict, arch_list, changes, char, color):
|
|
|
"""Add an output to our list of outcomes for each architecture
|
|
@@ -693,11 +769,14 @@ class Builder:
|
|
|
"""
|
|
|
self._base_board_dict = {}
|
|
|
for board in board_selected:
|
|
|
- self._base_board_dict[board] = Builder.Outcome(0, [], [], {})
|
|
|
+ self._base_board_dict[board] = Builder.Outcome(0, [], [], {}, {})
|
|
|
self._base_err_lines = []
|
|
|
self._base_warn_lines = []
|
|
|
self._base_err_line_boards = {}
|
|
|
self._base_warn_line_boards = {}
|
|
|
+ self._base_config = {}
|
|
|
+ for fname in CONFIG_FILENAMES:
|
|
|
+ self._base_config[fname] = {}
|
|
|
|
|
|
def PrintFuncSizeDetail(self, fname, old, new):
|
|
|
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
|
|
@@ -892,7 +971,8 @@ class Builder:
|
|
|
|
|
|
def PrintResultSummary(self, board_selected, board_dict, err_lines,
|
|
|
err_line_boards, warn_lines, warn_line_boards,
|
|
|
- show_sizes, show_detail, show_bloat):
|
|
|
+ config, show_sizes, show_detail, show_bloat,
|
|
|
+ show_config):
|
|
|
"""Compare results with the base results and display delta.
|
|
|
|
|
|
Only boards mentioned in board_selected will be considered. This
|
|
@@ -913,9 +993,14 @@ class Builder:
|
|
|
none, or we don't want to print errors
|
|
|
warn_line_boards: Dict keyed by warning line, containing a list of
|
|
|
the Board objects with that warning
|
|
|
+ config: Dictionary keyed by filename - e.g. '.config'. Each
|
|
|
+ value is itself a dictionary:
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
show_sizes: Show image size deltas
|
|
|
show_detail: Show detail for each board
|
|
|
show_bloat: Show detail for each function
|
|
|
+ show_config: Show config changes
|
|
|
"""
|
|
|
def _BoardList(line, line_boards):
|
|
|
"""Helper function to get a line of boards containing a line
|
|
@@ -950,6 +1035,48 @@ class Builder:
|
|
|
_BoardList(line, base_line_boards) + line)
|
|
|
return better_lines, worse_lines
|
|
|
|
|
|
+ def _CalcConfig(delta, name, config):
|
|
|
+ """Calculate configuration changes
|
|
|
+
|
|
|
+ Args:
|
|
|
+ delta: Type of the delta, e.g. '+'
|
|
|
+ name: name of the file which changed (e.g. .config)
|
|
|
+ config: configuration change dictionary
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
+ Returns:
|
|
|
+ String containing the configuration changes which can be
|
|
|
+ printed
|
|
|
+ """
|
|
|
+ out = ''
|
|
|
+ for key in sorted(config.keys()):
|
|
|
+ out += '%s=%s ' % (key, config[key])
|
|
|
+ return '%5s %s: %s' % (delta, name, out)
|
|
|
+
|
|
|
+ def _ShowConfig(name, config_plus, config_minus, config_change):
|
|
|
+ """Show changes in configuration
|
|
|
+
|
|
|
+ Args:
|
|
|
+ config_plus: configurations added, dictionary
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
+ config_minus: configurations removed, dictionary
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
+ config_change: configurations changed, dictionary
|
|
|
+ key: config name
|
|
|
+ value: config value
|
|
|
+ """
|
|
|
+ if config_plus:
|
|
|
+ Print(_CalcConfig('+', name, config_plus),
|
|
|
+ colour=self.col.GREEN)
|
|
|
+ if config_minus:
|
|
|
+ Print(_CalcConfig('-', name, config_minus),
|
|
|
+ colour=self.col.RED)
|
|
|
+ if config_change:
|
|
|
+ Print(_CalcConfig('+/-', name, config_change),
|
|
|
+ colour=self.col.YELLOW)
|
|
|
+
|
|
|
better = [] # List of boards fixed since last commit
|
|
|
worse = [] # List of new broken boards since last commit
|
|
|
new = [] # List of boards that didn't exist last time
|
|
@@ -1010,12 +1137,42 @@ class Builder:
|
|
|
self.PrintSizeSummary(board_selected, board_dict, show_detail,
|
|
|
show_bloat)
|
|
|
|
|
|
+ if show_config:
|
|
|
+ all_config_plus = {}
|
|
|
+ all_config_minus = {}
|
|
|
+ all_config_change = {}
|
|
|
+ for name in CONFIG_FILENAMES:
|
|
|
+ if not config[name]:
|
|
|
+ continue
|
|
|
+ config_plus = {}
|
|
|
+ config_minus = {}
|
|
|
+ config_change = {}
|
|
|
+ base = self._base_config[name]
|
|
|
+ for key, value in config[name].iteritems():
|
|
|
+ if key not in base:
|
|
|
+ config_plus[key] = value
|
|
|
+ all_config_plus[key] = value
|
|
|
+ for key, value in base.iteritems():
|
|
|
+ if key not in config[name]:
|
|
|
+ config_minus[key] = value
|
|
|
+ all_config_minus[key] = value
|
|
|
+ for key, value in base.iteritems():
|
|
|
+ new_value = base[key]
|
|
|
+ if key in config[name] and value != new_value:
|
|
|
+ desc = '%s -> %s' % (value, new_value)
|
|
|
+ config_change[key] = desc
|
|
|
+ all_config_change[key] = desc
|
|
|
+ _ShowConfig(name, config_plus, config_minus, config_change)
|
|
|
+ _ShowConfig('all', all_config_plus, all_config_minus,
|
|
|
+ all_config_change)
|
|
|
+
|
|
|
# Save our updated information for the next call to this function
|
|
|
self._base_board_dict = board_dict
|
|
|
self._base_err_lines = err_lines
|
|
|
self._base_warn_lines = warn_lines
|
|
|
self._base_err_line_boards = err_line_boards
|
|
|
self._base_warn_line_boards = warn_line_boards
|
|
|
+ self._base_config = config
|
|
|
|
|
|
# Get a list of boards that did not get built, if needed
|
|
|
not_built = []
|
|
@@ -1028,9 +1185,10 @@ class Builder:
|
|
|
|
|
|
def ProduceResultSummary(self, commit_upto, commits, board_selected):
|
|
|
(board_dict, err_lines, err_line_boards, warn_lines,
|
|
|
- warn_line_boards) = self.GetResultSummary(
|
|
|
+ warn_line_boards, config) = self.GetResultSummary(
|
|
|
board_selected, commit_upto,
|
|
|
- read_func_sizes=self._show_bloat)
|
|
|
+ read_func_sizes=self._show_bloat,
|
|
|
+ read_config=self._show_config)
|
|
|
if commits:
|
|
|
msg = '%02d: %s' % (commit_upto + 1,
|
|
|
commits[commit_upto].subject)
|
|
@@ -1038,7 +1196,8 @@ class Builder:
|
|
|
self.PrintResultSummary(board_selected, board_dict,
|
|
|
err_lines if self._show_errors else [], err_line_boards,
|
|
|
warn_lines if self._show_errors else [], warn_line_boards,
|
|
|
- self._show_sizes, self._show_detail, self._show_bloat)
|
|
|
+ config, self._show_sizes, self._show_detail,
|
|
|
+ self._show_bloat, self._show_config)
|
|
|
|
|
|
def ShowSummary(self, commits, board_selected):
|
|
|
"""Show a build summary for U-Boot for a given board list.
|