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 plan to use your machine for anything else, you can use -T to increase the
number of threads beyond the default. 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 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, command-line arguments that list the desired board name, architecture name,
SOC name, or anything else in the boards.cfg file. Multiple arguments are 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 means to build all arm boards except nvidia, freescale and anything ending
with 'ball'. 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 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. the subset given. Use -v as well to get an actual list of boards.
Buildman does not store intermediate object files. It optionally copies 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, information is always recorded. It needs a fair bit of disk space to work,
typically 250MB per thread. typically 250MB per thread.

View File

@ -237,20 +237,30 @@ class Boards:
terms.append(term) terms.append(term)
return terms return terms
def SelectBoards(self, args, exclude=[]): def SelectBoards(self, args, exclude=[], boards=None):
"""Mark boards selected based on args """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:
args: List of strings specifying boards to include, either named, args: List of strings specifying boards to include, either named,
or by their target, architecture, cpu, vendor or soc. If or by their target, architecture, cpu, vendor or soc. If
empty, all boards are selected. empty, all boards are selected.
exclude: List of boards to exclude, regardless of 'args' exclude: List of boards to exclude, regardless of 'args'
boards: List of boards to build
Returns: Returns:
Dictionary which holds the list of boards which were selected Tuple
due to each argument, arranged by argument. Dictionary which holds the list of boards which were selected
due to each argument, arranged by argument.
List of errors found
""" """
result = {} result = {}
warnings = []
terms = self._BuildTerms(args) terms = self._BuildTerms(args)
result['all'] = [] result['all'] = []
@ -261,6 +271,7 @@ class Boards:
for expr in exclude: for expr in exclude:
exclude_list.append(Expr(expr)) exclude_list.append(Expr(expr))
found = []
for board in self._boards: for board in self._boards:
matching_term = None matching_term = None
build_it = False build_it = False
@ -271,6 +282,10 @@ class Boards:
matching_term = str(term) matching_term = str(term)
build_it = True build_it = True
break break
elif boards:
if board.target in boards:
build_it = True
found.append(board.target)
else: else:
build_it = True build_it = True
@ -286,4 +301,9 @@ class Boards:
result[matching_term].append(board.target) result[matching_term].append(board.target)
result['all'].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', parser.add_option('-B', '--bloat', dest='show_bloat',
action='store_true', default=False, action='store_true', default=False,
help='Show changes in function code size for each board') 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', parser.add_option('-c', '--count', dest='count', type='int',
default=-1, help='Run build on the top n commits') default=-1, help='Run build on the top n commits')
parser.add_option('-C', '--force-reconfig', dest='force_reconfig', parser.add_option('-C', '--force-reconfig', dest='force_reconfig',
@ -102,7 +104,7 @@ def ParseArgs():
type='string', action='append', type='string', action='append',
help='Specify a list of boards to exclude, separated by comma') 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""" 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)) GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
return str 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. """Display a list of actions that we would take, if not a dry run.
Args: Args:
@ -55,6 +56,7 @@ def ShowActions(series, why_selected, boards_selected, builder, options):
value is Board object value is Board object
builder: The builder that will be used to build the commits builder: The builder that will be used to build the commits
options: Command line options object options: Command line options object
board_warnings: List of warnings obtained from board selected
""" """
col = terminal.Color() col = terminal.Color()
print 'Dry run, so not doing much. But I would do this:' 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 ' %s' % ' '.join(why_selected[arg])
print ('Total boards to build for each commit: %d\n' % print ('Total boards to build for each commit: %d\n' %
len(why_selected['all'])) len(why_selected['all']))
if board_warnings:
for warning in board_warnings:
print col.Color(col.YELLOW, warning)
def CheckOutputDir(output_dir): def CheckOutputDir(output_dir):
"""Make sure that the output directory is not within the current directory """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: for arg in options.exclude:
exclude += arg.split(',') 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() selected = boards.GetSelected()
if not len(selected): if not len(selected):
sys.exit(col.Color(col.RED, 'No matching boards found')) 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 # For a dry run, just show our actions as a sanity check
if options.dry_run: if options.dry_run:
ShowActions(series, why_selected, selected, builder, options) ShowActions(series, why_selected, selected, builder, options,
board_warnings)
else: else:
builder.force_build = options.force_build builder.force_build = options.force_build
builder.force_build_failures = options.force_build_failures builder.force_build_failures = options.force_build_failures

View File

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