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:
parent
e9fbbf633e
commit
d829f1217c
@ -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
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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')
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user