buildman: Allow adjusting board config on the fly

Add a -a option to specify changes to the config before the build
commences. For example

   buildman -a ~CONFIG_CMDLINE

disables CONFIG_CMDLINE before doing the build.

This makes it easier to try things out as well as to write tests without
creating a new board or manually manging the .config file.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2022-01-22 05:07:33 -07:00 committed by Tom Rini
parent 8ca0931a91
commit 2b4806e481
5 changed files with 93 additions and 8 deletions

View file

@ -1095,6 +1095,55 @@ This will write the full build into /tmp/build including object files. You must
specify the output directory with -o when using -w.
Changing the configuration
==========================
Sometimes it is useful to change the CONFIG options for a build on the fly. This
can be used to build a board (or multiple) with a few changes to see the impact.
The -a option supports this:
-a <cfg>
where <cfg> is a CONFIG option (with or without the CONFIG_ prefix) to enable.
For example:
buildman -a CMD_SETEXPR_FMT
will build with CONFIG_CMD_SETEXPR_FMT enabled.
You can disable options by preceding them with tilde (~). You can specify the
-a option multiple times:
buildman -a CMD_SETEXPR_FMT -a ~CMDLINE
Some options have values, in which case you can change them:
buildman -a 'BOOTCOMMAND="echo hello"' CONFIG_SYS_LOAD_ADDR=0x1000
Note that you must put quotes around string options and the whole thing must be
in single quotes, to make sure the shell leave it alone.
If you try to set an option that does not exist, or that cannot be changed for
some other reason (e.g. it is 'selected' by another option), then buildman
shows an error:
buildman --board sandbox -a FRED
Building current source for 1 boards (1 thread, 32 jobs per thread)
0 0 0 /1 -1 (starting)errs
Some CONFIG adjustments did not take effect. This may be because
the request CONFIGs do not exist or conflict with others.
Failed adjustments:
FRED Missing expected line: CONFIG_FRED=y
One major caveat with this feature with branches (-b) is that buildman does not
name the output directories differently when you change the configuration, so
doing the same build again with different configuration will not trigger a
rebuild. You can use -f to work around that.
Other options
=============

View file

@ -250,7 +250,7 @@ class Builder:
mrproper=False, per_board_out_dir=False,
config_only=False, squash_config_y=False,
warnings_as_errors=False, work_in_output=False,
test_thread_exceptions=False):
test_thread_exceptions=False, adjust_cfg=None):
"""Create a new Builder object
Args:
@ -280,6 +280,15 @@ class Builder:
test_thread_exceptions: Uses for tests only, True to make the
threads raise an exception instead of reporting their result.
This simulates a failure in the code somewhere
adjust_cfg_list (list of str): List of changes to make to .config
file before building. Each is one of (where C is the config
option with or without the CONFIG_ prefix)
C to enable C
~C to disable C
C=val to set the value of C (val must have quotes if C is
a string Kconfig
"""
self.toolchains = toolchains
self.base_dir = base_dir
@ -315,6 +324,8 @@ class Builder:
self.squash_config_y = squash_config_y
self.config_filenames = BASE_CONFIG_FILENAMES
self.work_in_output = work_in_output
self.adjust_cfg = adjust_cfg
if not self.squash_config_y:
self.config_filenames += EXTRA_CONFIG_FILENAMES
self._terminated = False
@ -1747,6 +1758,7 @@ class Builder:
job.commits = commits
job.keep_outputs = keep_outputs
job.work_in_output = self.work_in_output
job.adjust_cfg = self.adjust_cfg
job.step = self._step
if self.num_threads:
self.queue.put(job)

View file

@ -9,6 +9,7 @@ import shutil
import sys
import threading
from buildman import cfgutil
from patman import command
from patman import gitutil
@ -130,7 +131,8 @@ class BuilderThread(threading.Thread):
**kwargs)
def RunCommit(self, commit_upto, brd, work_dir, do_config, config_only,
force_build, force_build_failures, work_in_output):
force_build, force_build_failures, work_in_output,
adjust_cfg):
"""Build a particular commit.
If the build is already done, and we are not forcing a build, we skip
@ -147,6 +149,13 @@ class BuilderThread(threading.Thread):
failure
work_in_output: Use the output directory as the work directory and
don't write to a separate output directory.
adjust_cfg (list of str): List of changes to make to .config file
before building. Each is one of (where C is either CONFIG_xxx
or just xxx):
C to enable C
~C to disable C
C=val to set the value of C (val must have quotes if C is
a string Kconfig
Returns:
tuple containing:
@ -261,7 +270,8 @@ class BuilderThread(threading.Thread):
os.remove(fname)
# If we need to reconfigure, do that now
if do_config:
cfg_file = os.path.join(out_dir, '.config')
if do_config or adjust_cfg:
config_out = ''
if self.mrproper:
result = self.Make(commit, brd, 'mrproper', cwd,
@ -271,11 +281,19 @@ class BuilderThread(threading.Thread):
*(args + config_args), env=env)
config_out += result.combined
do_config = False # No need to configure next time
if adjust_cfg:
cfgutil.adjust_cfg_file(cfg_file, adjust_cfg)
if result.return_code == 0:
if config_only:
args.append('cfg')
result = self.Make(commit, brd, 'build', cwd, *args,
env=env)
if adjust_cfg:
errs = cfgutil.check_cfg_file(cfg_file, adjust_cfg)
if errs:
print('errs', errs)
result.stderr += errs
result.return_code = 1
result.stderr = result.stderr.replace(src_dir + '/', '')
if self.builder.verbose_build:
result.stdout = config_out + result.stdout
@ -486,7 +504,7 @@ class BuilderThread(threading.Thread):
work_dir, do_config, self.builder.config_only,
force_build or self.builder.force_build,
self.builder.force_build_failures,
work_in_output=job.work_in_output)
job.work_in_output, job.adjust_cfg)
failed = result.return_code or result.stderr
did_config = do_config
if failed and not do_config:
@ -495,7 +513,7 @@ class BuilderThread(threading.Thread):
if self.builder.force_config_on_failure:
result, request_config = self.RunCommit(commit_upto,
brd, work_dir, True, False, True, False,
work_in_output=job.work_in_output)
job.work_in_output, job.adjust_cfg)
did_config = True
if not self.builder.force_reconfig:
do_config = request_config
@ -540,8 +558,8 @@ class BuilderThread(threading.Thread):
# Just build the currently checked-out build
result, request_config = self.RunCommit(None, brd, work_dir, True,
self.builder.config_only, True,
self.builder.force_build_failures,
work_in_output=job.work_in_output)
self.builder.force_build_failures, job.work_in_output,
job.adjust_cfg)
result.commit_upto = 0
self._WriteResult(result, job.keep_outputs, job.work_in_output)
self._SendResult(result)

View file

@ -13,6 +13,8 @@ def ParseArgs():
args: command lin arguments
"""
parser = OptionParser()
parser.add_option('-a', '--adjust-cfg', type=str, action='append',
help='Adjust the Kconfig settings in .config before building')
parser.add_option('-A', '--print-prefix', action='store_true',
help='Print the tool-chain prefix for a board (CROSS_COMPILE=)')
parser.add_option('-b', '--branch', type='string',

View file

@ -10,6 +10,7 @@ import sys
from buildman import board
from buildman import bsettings
from buildman import cfgutil
from buildman import toolchain
from buildman.builder import Builder
from patman import command
@ -321,6 +322,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
output_dir = os.path.join(options.output_dir, dirname)
if clean_dir and os.path.exists(output_dir):
shutil.rmtree(output_dir)
adjust_cfg = cfgutil.convert_list_to_dict(options.adjust_cfg)
builder = Builder(toolchains, output_dir, options.git_dir,
options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
show_unknown=options.show_unknown, step=options.step,
@ -332,7 +335,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
squash_config_y=not options.preserve_config_y,
warnings_as_errors=options.warnings_as_errors,
work_in_output=options.work_in_output,
test_thread_exceptions=test_thread_exceptions)
test_thread_exceptions=test_thread_exceptions,
adjust_cfg=adjust_cfg)
builder.force_config_on_failure = not options.quick
if make_func:
builder.do_make = make_func