bulidman: Add support for a simple build

It is useful to run a simple build and put all the output in a single
directory. Add a -w option to support this.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2020-03-18 09:42:42 -06:00 committed by Tom Rini
parent e9fbbf633e
commit d829f1217c
6 changed files with 90 additions and 15 deletions

View File

@ -1056,6 +1056,17 @@ toolchain. For example:
buildman -O clang-7 --board sandbox buildman -O clang-7 --board sandbox
Doing a simple build
====================
In some cases you just want to build a single board and get the full output, use
the -w option, for example:
buildman -o /tmp/build --board sandbox -w
This will write the full build into /tmp/build including object files.
Other options Other options
============= =============

View File

@ -174,6 +174,8 @@ class Builder:
in_tree: Build U-Boot in-tree instead of specifying an output in_tree: Build U-Boot in-tree instead of specifying an output
directory separate from the source code. This option is really directory separate from the source code. This option is really
only useful for testing in-tree builds. only useful for testing in-tree builds.
work_in_output: Use the output directory as the work directory and
don't write to a separate output directory.
Private members: Private members:
_base_board_dict: Last-summarised Dict of boards _base_board_dict: Last-summarised Dict of boards
@ -224,7 +226,7 @@ class Builder:
no_subdirs=False, full_path=False, verbose_build=False, no_subdirs=False, full_path=False, verbose_build=False,
incremental=False, per_board_out_dir=False, incremental=False, per_board_out_dir=False,
config_only=False, squash_config_y=False, config_only=False, squash_config_y=False,
warnings_as_errors=False): warnings_as_errors=False, work_in_output=False):
"""Create a new Builder object """Create a new Builder object
Args: Args:
@ -250,10 +252,15 @@ class Builder:
config_only: Only configure each build, don't build it config_only: Only configure each build, don't build it
squash_config_y: Convert CONFIG options with the value 'y' to '1' squash_config_y: Convert CONFIG options with the value 'y' to '1'
warnings_as_errors: Treat all compiler warnings as errors warnings_as_errors: Treat all compiler warnings as errors
work_in_output: Use the output directory as the work directory and
don't write to a separate output directory.
""" """
self.toolchains = toolchains self.toolchains = toolchains
self.base_dir = base_dir self.base_dir = base_dir
self._working_dir = os.path.join(base_dir, '.bm-work') if work_in_output:
self._working_dir = base_dir
else:
self._working_dir = os.path.join(base_dir, '.bm-work')
self.threads = [] self.threads = []
self.do_make = self.Make self.do_make = self.Make
self.gnu_make = gnu_make self.gnu_make = gnu_make
@ -280,6 +287,7 @@ class Builder:
self.config_only = config_only self.config_only = config_only
self.squash_config_y = squash_config_y self.squash_config_y = squash_config_y
self.config_filenames = BASE_CONFIG_FILENAMES self.config_filenames = BASE_CONFIG_FILENAMES
self.work_in_output = work_in_output
if not self.squash_config_y: if not self.squash_config_y:
self.config_filenames += EXTRA_CONFIG_FILENAMES self.config_filenames += EXTRA_CONFIG_FILENAMES
@ -1474,6 +1482,8 @@ class Builder:
Args: Args:
thread_num: Number of thread to check. thread_num: Number of thread to check.
""" """
if self.work_in_output:
return self._working_dir
return os.path.join(self._working_dir, '%02d' % thread_num) return os.path.join(self._working_dir, '%02d' % thread_num)
def _PrepareThread(self, thread_num, setup_git): def _PrepareThread(self, thread_num, setup_git):
@ -1571,6 +1581,7 @@ class Builder:
job.board = brd job.board = brd
job.commits = commits job.commits = commits
job.keep_outputs = keep_outputs job.keep_outputs = keep_outputs
job.work_in_output = self.work_in_output
job.step = self._step job.step = self._step
self.queue.put(job) self.queue.put(job)

View File

@ -42,12 +42,15 @@ class BuilderJob:
commits: List of Commit objects to build commits: List of Commit objects to build
keep_outputs: True to save build output files keep_outputs: True to save build output files
step: 1 to process every commit, n to process every nth commit step: 1 to process every commit, n to process every nth commit
work_in_output: Use the output directory as the work directory and
don't write to a separate output directory.
""" """
def __init__(self): def __init__(self):
self.board = None self.board = None
self.commits = [] self.commits = []
self.keep_outputs = False self.keep_outputs = False
self.step = 1 self.step = 1
self.work_in_output = False
class ResultThread(threading.Thread): class ResultThread(threading.Thread):
@ -118,7 +121,7 @@ class BuilderThread(threading.Thread):
**kwargs) **kwargs)
def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only, def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only,
force_build, force_build_failures): force_build, force_build_failures, work_in_output):
"""Build a particular commit. """Build a particular commit.
If the build is already done, and we are not forcing a build, we skip If the build is already done, and we are not forcing a build, we skip
@ -133,6 +136,8 @@ class BuilderThread(threading.Thread):
force_build: Force a build even if one was previously done force_build: Force a build even if one was previously done
force_build_failures: Force a bulid if the previous result showed force_build_failures: Force a bulid if the previous result showed
failure failure
work_in_output: Use the output directory as the work directory and
don't write to a separate output directory.
Returns: Returns:
tuple containing: tuple containing:
@ -143,7 +148,7 @@ class BuilderThread(threading.Thread):
# self.Make() below, in the event that we do a build. # self.Make() below, in the event that we do a build.
result = command.CommandResult() result = command.CommandResult()
result.return_code = 0 result.return_code = 0
if self.builder.in_tree: if work_in_output or self.builder.in_tree:
out_dir = work_dir out_dir = work_dir
else: else:
if self.per_board_out_dir: if self.per_board_out_dir:
@ -265,14 +270,18 @@ class BuilderThread(threading.Thread):
result.out_dir = out_dir result.out_dir = out_dir
return result, do_config return result, do_config
def _WriteResult(self, result, keep_outputs): def _WriteResult(self, result, keep_outputs, work_in_output):
"""Write a built result to the output directory. """Write a built result to the output directory.
Args: Args:
result: CommandResult object containing result to write result: CommandResult object containing result to write
keep_outputs: True to store the output binaries, False keep_outputs: True to store the output binaries, False
to delete them to delete them
work_in_output: Use the output directory as the work directory and
don't write to a separate output directory.
""" """
if work_in_output:
return
# Fatal error # Fatal error
if result.return_code < 0: if result.return_code < 0:
return return
@ -434,7 +443,8 @@ class BuilderThread(threading.Thread):
result, request_config = self.RunCommit(commit_upto, brd, result, request_config = self.RunCommit(commit_upto, brd,
work_dir, do_config, self.builder.config_only, work_dir, do_config, self.builder.config_only,
force_build or self.builder.force_build, force_build or self.builder.force_build,
self.builder.force_build_failures) self.builder.force_build_failures,
work_in_output=job.work_in_output)
failed = result.return_code or result.stderr failed = result.return_code or result.stderr
did_config = do_config did_config = do_config
if failed and not do_config: if failed and not do_config:
@ -442,7 +452,8 @@ class BuilderThread(threading.Thread):
# with a reconfig. # with a reconfig.
if self.builder.force_config_on_failure: if self.builder.force_config_on_failure:
result, request_config = self.RunCommit(commit_upto, result, request_config = self.RunCommit(commit_upto,
brd, work_dir, True, False, True, False) brd, work_dir, True, False, True, False,
work_in_output=job.work_in_output)
did_config = True did_config = True
if not self.builder.force_reconfig: if not self.builder.force_reconfig:
do_config = request_config do_config = request_config
@ -481,15 +492,16 @@ class BuilderThread(threading.Thread):
raise ValueError('Interrupt') raise ValueError('Interrupt')
# We have the build results, so output the result # We have the build results, so output the result
self._WriteResult(result, job.keep_outputs) self._WriteResult(result, job.keep_outputs, job.work_in_output)
self.builder.out_queue.put(result) self.builder.out_queue.put(result)
else: else:
# Just build the currently checked-out build # Just build the currently checked-out build
result, request_config = self.RunCommit(None, brd, work_dir, True, result, request_config = self.RunCommit(None, brd, work_dir, True,
self.builder.config_only, True, self.builder.config_only, True,
self.builder.force_build_failures) self.builder.force_build_failures,
work_in_output=job.work_in_output)
result.commit_upto = 0 result.commit_upto = 0
self._WriteResult(result, job.keep_outputs) self._WriteResult(result, job.keep_outputs, job.work_in_output)
self.builder.out_queue.put(result) self.builder.out_queue.put(result)
def run(self): def run(self):

View File

@ -106,6 +106,8 @@ def ParseArgs():
default=False, help='Show build results while the build progresses') default=False, help='Show build results while the build progresses')
parser.add_option('-V', '--verbose-build', action='store_true', parser.add_option('-V', '--verbose-build', action='store_true',
default=False, help='Run make with V=1, logging all output') default=False, help='Run make with V=1, logging all output')
parser.add_option('-w', '--work-in-output', action='store_true',
default=False, help='Use the output directory as the work directory')
parser.add_option('-x', '--exclude', dest='exclude', parser.add_option('-x', '--exclude', dest='exclude',
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')

View File

@ -263,6 +263,13 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
str = ("No commits found to process in branch '%s': " str = ("No commits found to process in branch '%s': "
"set branch's upstream or use -c flag" % options.branch) "set branch's upstream or use -c flag" % options.branch)
sys.exit(col.Color(col.RED, str)) sys.exit(col.Color(col.RED, str))
if options.work_in_output:
if len(selected) != 1:
sys.exit(col.Color(col.RED,
'-w can only be used with a single board'))
if count != 1:
sys.exit(col.Color(col.RED,
'-w can only be used with a single commit'))
# Read the metadata from the commits. First look at the upstream commit, # Read the metadata from the commits. First look at the upstream commit,
# then the ones in the branch. We would like to do something like # then the ones in the branch. We would like to do something like
@ -334,7 +341,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
per_board_out_dir=options.per_board_out_dir, per_board_out_dir=options.per_board_out_dir,
config_only=options.config_only, config_only=options.config_only,
squash_config_y=not options.preserve_config_y, squash_config_y=not options.preserve_config_y,
warnings_as_errors=options.warnings_as_errors) warnings_as_errors=options.warnings_as_errors,
work_in_output=options.work_in_output)
builder.force_config_on_failure = not options.quick builder.force_config_on_failure = not options.quick
if make_func: if make_func:
builder.do_make = make_func builder.do_make = make_func

View File

@ -16,6 +16,7 @@ import control
import gitutil import gitutil
import terminal import terminal
import toolchain import toolchain
import tools
settings_data = ''' settings_data = '''
# Buildman settings file # Buildman settings file
@ -208,7 +209,7 @@ class TestFunctional(unittest.TestCase):
def tearDown(self): def tearDown(self):
shutil.rmtree(self._base_dir) shutil.rmtree(self._base_dir)
shutil.rmtree(self._output_dir) #shutil.rmtree(self._output_dir)
def setupToolchains(self): def setupToolchains(self):
self._toolchains = toolchain.Toolchains() self._toolchains = toolchain.Toolchains()
@ -218,12 +219,12 @@ class TestFunctional(unittest.TestCase):
return command.RunPipe([[self._buildman_pathname] + list(args)], return command.RunPipe([[self._buildman_pathname] + list(args)],
capture=True, capture_stderr=True) capture=True, capture_stderr=True)
def _RunControl(self, *args, **kwargs): def _RunControl(self, *args, clean_dir=False, boards=None):
sys.argv = [sys.argv[0]] + list(args) sys.argv = [sys.argv[0]] + list(args)
options, args = cmdline.ParseArgs() options, args = cmdline.ParseArgs()
result = control.DoBuildman(options, args, toolchains=self._toolchains, result = control.DoBuildman(options, args, toolchains=self._toolchains,
make_func=self._HandleMake, boards=self._boards, make_func=self._HandleMake, boards=boards or self._boards,
clean_dir=kwargs.get('clean_dir', True)) clean_dir=clean_dir)
self._builder = control.builder self._builder = control.builder
return result return result
@ -397,6 +398,12 @@ class TestFunctional(unittest.TestCase):
combined='Test configuration complete') combined='Test configuration complete')
elif stage == 'build': elif stage == 'build':
stderr = '' stderr = ''
out_dir = ''
for arg in args:
if arg.startswith('O='):
out_dir = arg[2:]
fname = os.path.join(cwd or '', out_dir, 'u-boot')
tools.WriteFile(fname, b'U-Boot')
if type(commit) is not str: if type(commit) is not str:
stderr = self._error.get((brd.target, commit.sequence)) stderr = self._error.get((brd.target, commit.sequence))
if stderr: if stderr:
@ -535,3 +542,27 @@ class TestFunctional(unittest.TestCase):
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
self._RunControl('-b', self._test_branch, '-o', self._RunControl('-b', self._test_branch, '-o',
os.path.join(os.getcwd(), 'test')) os.path.join(os.getcwd(), 'test'))
def testWorkInOutput(self):
"""Test the -w option which should write directly to the output dir"""
board_list = board.Boards()
board_list.AddBoard(board.Board(*boards[0]))
self._RunControl('-o', self._output_dir, '-w', clean_dir=False,
boards=board_list)
self.assertTrue(
os.path.exists(os.path.join(self._output_dir, 'u-boot')))
def testWorkInOutputFail(self):
"""Test the -w option failures"""
with self.assertRaises(SystemExit) as e:
self._RunControl('-o', self._output_dir, '-w', clean_dir=False)
self.assertIn("single board", str(e.exception))
self.assertFalse(
os.path.exists(os.path.join(self._output_dir, 'u-boot')))
board_list = board.Boards()
board_list.AddBoard(board.Board(*boards[0]))
with self.assertRaises(SystemExit) as e:
self._RunControl('-b', self._test_branch, '-o', self._output_dir,
'-w', clean_dir=False, boards=board_list)
self.assertIn("single commit", str(e.exception))