buildman: Add a --boards option to specify particular boards to build

At present 'buildman sandbox' will build all 5 boards for the sandbox
architecture rather than the single board 'sandbox'. The only current way
to exclude sandbox_spl, sandbox_noblk, etc. is to use -x which is a bit
clumbsy.

Add a --boards option to allow individual build targets to be specified.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2018-06-11 23:26:46 -06:00
parent bd8b74551b
commit 0689036a35
5 changed files with 72 additions and 23 deletions

View File

@ -114,6 +114,10 @@ a few commits or boards, it will be pretty slow. As a tip, if you don't
plan to use your machine for anything else, you can use -T to increase the
number of threads beyond the default.
Selecting which boards to build
===============================
Buildman lets you build all boards, or a subset. Specify the subset by passing
command-line arguments that list the desired board name, architecture name,
SOC name, or anything else in the boards.cfg file. Multiple arguments are
@ -138,11 +142,17 @@ You can also use -x to specifically exclude some boards. For example:
means to build all arm boards except nvidia, freescale and anything ending
with 'ball'.
For building specific boards you can use the --boards option, which takes a
comma-separated list of board target names and be used multiple times on
the command line:
buidman --boards sandbox,snow --boards
It is convenient to use the -n option to see what will be built based on
the subset given. Use -v as well to get an actual list of boards.
Buildman does not store intermediate object files. It optionally copies
the binary output into a directory when a build is successful. Size
the binary output into a directory when a build is successful (-k). Size
information is always recorded. It needs a fair bit of disk space to work,
typically 250MB per thread.

View File

@ -237,20 +237,30 @@ class Boards:
terms.append(term)
return terms
def SelectBoards(self, args, exclude=[]):
def SelectBoards(self, args, exclude=[], boards=None):
"""Mark boards selected based on args
Normally either boards (an explicit list of boards) or args (a list of
terms to match against) is used. It is possible to specify both, in
which case they are additive.
If boards and args are both empty, all boards are selected.
Args:
args: List of strings specifying boards to include, either named,
or by their target, architecture, cpu, vendor or soc. If
empty, all boards are selected.
exclude: List of boards to exclude, regardless of 'args'
boards: List of boards to build
Returns:
Dictionary which holds the list of boards which were selected
due to each argument, arranged by argument.
Tuple
Dictionary which holds the list of boards which were selected
due to each argument, arranged by argument.
List of errors found
"""
result = {}
warnings = []
terms = self._BuildTerms(args)
result['all'] = []
@ -261,6 +271,7 @@ class Boards:
for expr in exclude:
exclude_list.append(Expr(expr))
found = []
for board in self._boards:
matching_term = None
build_it = False
@ -271,6 +282,10 @@ class Boards:
matching_term = str(term)
build_it = True
break
elif boards:
if board.target in boards:
build_it = True
found.append(board.target)
else:
build_it = True
@ -286,4 +301,9 @@ class Boards:
result[matching_term].append(board.target)
result['all'].append(board.target)
return result
if boards:
remaining = set(boards) - set(found)
if remaining:
warnings.append('Boards not found: %s\n' % ', '.join(remaining))
return result, warnings

View File

@ -18,6 +18,8 @@ def ParseArgs():
parser.add_option('-B', '--bloat', dest='show_bloat',
action='store_true', default=False,
help='Show changes in function code size for each board')
parser.add_option('--boards', type='string', action='append',
help='List of board names to build separated by comma')
parser.add_option('-c', '--count', dest='count', type='int',
default=-1, help='Run build on the top n commits')
parser.add_option('-C', '--force-reconfig', dest='force_reconfig',
@ -102,7 +104,7 @@ def ParseArgs():
type='string', action='append',
help='Specify a list of boards to exclude, separated by comma')
parser.usage += """
parser.usage += """ [list of target/arch/cpu/board/vendor/soc to build]
Build U-Boot for all commits in a branch. Use -n to do a dry run"""

View File

@ -41,7 +41,8 @@ def GetActionSummary(is_summary, commits, selected, options):
GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
return str
def ShowActions(series, why_selected, boards_selected, builder, options):
def ShowActions(series, why_selected, boards_selected, builder, options,
board_warnings):
"""Display a list of actions that we would take, if not a dry run.
Args:
@ -55,6 +56,7 @@ def ShowActions(series, why_selected, boards_selected, builder, options):
value is Board object
builder: The builder that will be used to build the commits
options: Command line options object
board_warnings: List of warnings obtained from board selected
"""
col = terminal.Color()
print 'Dry run, so not doing much. But I would do this:'
@ -79,6 +81,9 @@ def ShowActions(series, why_selected, boards_selected, builder, options):
print ' %s' % ' '.join(why_selected[arg])
print ('Total boards to build for each commit: %d\n' %
len(why_selected['all']))
if board_warnings:
for warning in board_warnings:
print col.Color(col.YELLOW, warning)
def CheckOutputDir(output_dir):
"""Make sure that the output directory is not within the current directory
@ -210,7 +215,15 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
for arg in options.exclude:
exclude += arg.split(',')
why_selected = boards.SelectBoards(args, exclude)
if options.boards:
requested_boards = []
for b in options.boards:
requested_boards += b.split(',')
else:
requested_boards = None
why_selected, board_warnings = boards.SelectBoards(args, exclude,
requested_boards)
selected = boards.GetSelected()
if not len(selected):
sys.exit(col.Color(col.RED, 'No matching boards found'))
@ -292,7 +305,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
# For a dry run, just show our actions as a sanity check
if options.dry_run:
ShowActions(series, why_selected, selected, builder, options)
ShowActions(series, why_selected, selected, builder, options,
board_warnings)
else:
builder.force_build = options.force_build
builder.force_build_failures = options.force_build_failures

View File

@ -313,60 +313,63 @@ class TestBuild(unittest.TestCase):
def testBoardSingle(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['sandbox']),
{'all': ['board4'], 'sandbox': ['board4']})
({'all': ['board4'], 'sandbox': ['board4']}, []))
def testBoardArch(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['arm']),
{'all': ['board0', 'board1'],
'arm': ['board0', 'board1']})
({'all': ['board0', 'board1'],
'arm': ['board0', 'board1']}, []))
def testBoardArchSingle(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['arm sandbox']),
{'sandbox': ['board4'],
({'sandbox': ['board4'],
'all': ['board0', 'board1', 'board4'],
'arm': ['board0', 'board1']})
'arm': ['board0', 'board1']}, []))
def testBoardArchSingleMultiWord(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['arm', 'sandbox']),
{'sandbox': ['board4'], 'all': ['board0', 'board1', 'board4'], 'arm': ['board0', 'board1']})
({'sandbox': ['board4'],
'all': ['board0', 'board1', 'board4'],
'arm': ['board0', 'board1']}, []))
def testBoardSingleAnd(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['Tester & arm']),
{'Tester&arm': ['board0', 'board1'], 'all': ['board0', 'board1']})
({'Tester&arm': ['board0', 'board1'],
'all': ['board0', 'board1']}, []))
def testBoardTwoAnd(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['Tester', '&', 'arm',
'Tester' '&', 'powerpc',
'sandbox']),
{'sandbox': ['board4'],
({'sandbox': ['board4'],
'all': ['board0', 'board1', 'board2', 'board3',
'board4'],
'Tester&powerpc': ['board2', 'board3'],
'Tester&arm': ['board0', 'board1']})
'Tester&arm': ['board0', 'board1']}, []))
def testBoardAll(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards([]),
{'all': ['board0', 'board1', 'board2', 'board3',
'board4']})
({'all': ['board0', 'board1', 'board2', 'board3',
'board4']}, []))
def testBoardRegularExpression(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['T.*r&^Po']),
{'all': ['board2', 'board3'],
'T.*r&^Po': ['board2', 'board3']})
({'all': ['board2', 'board3'],
'T.*r&^Po': ['board2', 'board3']}, []))
def testBoardDuplicate(self):
"""Test single board selection"""
self.assertEqual(self.boards.SelectBoards(['sandbox sandbox',
'sandbox']),
{'all': ['board4'], 'sandbox': ['board4']})
({'all': ['board4'], 'sandbox': ['board4']}, []))
def CheckDirs(self, build, dirname):
self.assertEqual('base%s' % dirname, build._GetOutputDir(1))
self.assertEqual('base%s/fred' % dirname,