From patchwork Sun Mar 29 11:10:32 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2070 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774782720; bh=oT5hnmry/3AtNW2DkP4h60Yns7/eTH/AsWw2rBx76V4=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=VpxdUP7/zcvHM/mWy6awvTQ5su8FUmsa5Zc1RR//sdzP00WDp9uTbHXpBQ+TrVGMb 831O4gDw32BGVxRj8RdtZbYJK6K2oLnZvJ8ML80hOvpozz43AKRVfSH0L/Q388z+oS pBK8PZLCNRvID9vYIFem6wMmUNdL1X2MzQqUyGocul+mI0zIlv1Cv1A3RHEnhgkREi CbC7r78yIQIPJzy/vOUXhsxOKvUY0gNbjCP/cOCKv5yDbj5PVGOBkKblVa6FIYYmNg K1qOKF44oRKSBYw0QLgNdGb/BPD2T0zYvKmy3GsRonPpOg2GAZZAaoz9QSBZxmXAfC dTDt+y4xKk3/g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4AEEE6A2BF for ; Sun, 29 Mar 2026 05:12:00 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id e_LiZQkjDpYe for ; Sun, 29 Mar 2026 05:12:00 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774782720; bh=oT5hnmry/3AtNW2DkP4h60Yns7/eTH/AsWw2rBx76V4=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=VpxdUP7/zcvHM/mWy6awvTQ5su8FUmsa5Zc1RR//sdzP00WDp9uTbHXpBQ+TrVGMb 831O4gDw32BGVxRj8RdtZbYJK6K2oLnZvJ8ML80hOvpozz43AKRVfSH0L/Q388z+oS pBK8PZLCNRvID9vYIFem6wMmUNdL1X2MzQqUyGocul+mI0zIlv1Cv1A3RHEnhgkREi CbC7r78yIQIPJzy/vOUXhsxOKvUY0gNbjCP/cOCKv5yDbj5PVGOBkKblVa6FIYYmNg K1qOKF44oRKSBYw0QLgNdGb/BPD2T0zYvKmy3GsRonPpOg2GAZZAaoz9QSBZxmXAfC dTDt+y4xKk3/g== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 317676A2BC for ; Sun, 29 Mar 2026 05:12:00 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774782717; bh=3g7KgEzToW0hDhUZSKEZMfTAdAuwmgB82QxAdZgbDto=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eZ7T7r6RlKYCZbOPyDt2J6Vc6JJ8eksxk4E5f/2Ui9UK+r9rjCyeL9oCbmKE/FMxo 3SlKDJAB8FBVzd1JYBjOSLgp6exWei603OKtfZwndmUTrqKaydXHi731zKPxPKArMT xSgiJNZYa2QqOSmdJ1FxOkvzVbpbJjn4/jzDoK8mc4BlUNcBxnblN38o/XPD5rXWy/ e7qHrVGp9hOnBpRdjJCX02Lp2y2qs1Lueqbwpok9OMqB4aVxUnQ+hbovd+uL7EkPwX AQIX2g5S9Lg2Ys9vIbWbJJVj4jRWKiIyL5saAA30RhVFoejOvhLiQXKoixwAQC+ZPo qqEI/hZO1STOA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B627867C16; Sun, 29 Mar 2026 05:11:57 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id VUm19F10R1P9; Sun, 29 Mar 2026 05:11:57 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774782709; bh=P1osZmFNuC16Q7//FF8BVhX2UqQQdMV/jwyBnWG3ZLs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CThWyU2rSZw6xuQ7yxz/NPB+vSSyoH894zHWPd8d37qEowLh0OKoW0ETeWI+0UXUk 1gJsBFNehLkDrm1GSJ3RmFT5gSJLsseMF712kJ8JEyZhxYLlE/MqaCXkEIc8XL+eY/ ++W4IDykD6sC4FsVNqUgxBqzaTEaeVzWwI0GAfVD9i7Yjwt0wjEcA52tficzkd2Y1a N5s2OEimlM4+qVfZ/DJqi4wtPOhvLeFV2d/hlW5sWWnm1YoGDWDS31VMHLpOoq7Dxr nSpCRUOeu4ahXgDc1BM+JOdz4/WO9qjry7aY5cNv1HYEDMpj/PLbX5gaLqL1jMo0qi caQSB9idIhN7w== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id A48FC6A2BC; Sun, 29 Mar 2026 05:11:49 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 29 Mar 2026 05:10:32 -0600 Message-ID: <20260329111037.1352652-8-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260329111037.1352652-1-sjg@u-boot.org> References: <20260329111037.1352652-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: Y7CXTU5OYIRLJR3CLQ6IXNCF7T2RACOE X-Message-ID-Hash: Y7CXTU5OYIRLJR3CLQ6IXNCF7T2RACOE X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 7/7] qconfig: Use kconfiglib for -r (git-ref) sync path List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The -r option still uses the old make-based move_config() path, which requires cross-compiler toolchains and is much slower. Handle -r in do_sync_defconfigs() instead: clone the reference commit, create a kconfiglib.Kconfig instance from that tree, load each defconfig against it, write a full .config, then load that into the current tree's Kconfig and write_min_config(). This gives the same result without any toolchain requirement. With move_config() now unreachable, remove it along with all the infrastructure it depended on: KconfigParser, Slot, Slots, DatabaseThread, get_make_cmd(), check_clean_directory(), and the STATE_* constants. Signed-off-by: Simon Glass --- doc/develop/qconfig.rst | 24 +- tools/qconfig.py | 526 +++++----------------------------------- 2 files changed, 72 insertions(+), 478 deletions(-) diff --git a/doc/develop/qconfig.rst b/doc/develop/qconfig.rst index 4a85c78cbbb..7fdbad8923d 100644 --- a/doc/develop/qconfig.rst +++ b/doc/develop/qconfig.rst @@ -51,25 +51,21 @@ that use ``#include`` directives are handled by computing the delta between the full expanded config and the base provided by the included files, so the include structure is preserved. -The ``-r`` (git-ref) option still uses the old make-based path, since it -needs to build against a different source tree. +The ``-r`` (git-ref) option also uses kconfiglib: it clones the reference +commit, creates a Kconfig instance from that tree, loads each defconfig +against it, then normalises the result against the current tree's Kconfig. +No toolchains are needed. Toolchains ---------- -Toolchains are **not** needed for ``-b`` or ``-s``, since both use -kconfiglib to evaluate Kconfig files directly in Python. The only +Toolchains are **not** needed for any qconfig operation. The only difference from using a real toolchain is that ``CONFIG_GCC_VERSION`` reflects the host compiler rather than each board's cross-compiler. This does not affect database queries, imply analysis, or defconfig sync, since ``CONFIG_GCC_VERSION`` is a build-time value that never appears in defconfig files or influences Kconfig defaults. -The ``-r`` (git-ref) option still requires toolchains, as it falls back -to the make-based path. Most toolchains are available at the kernel.org -site. This tool uses the same tools as :doc:`../build/buildman`, so you -can use ``buildman --fetch-arch`` to fetch them. - Examples -------- @@ -256,12 +252,12 @@ Available options the number of threads is the same as the number of CPU cores. -r, --git-ref - Specify the git ref to clone for building the autoconf.mk. If unspecified - use the CWD. This is useful for when changes to the Kconfig affect the - default values and you want to capture the state of the defconfig from + Specify the git ref to clone for evaluating the Kconfig tree. If + unspecified, use the CWD. This is useful when changes to Kconfig affect + default values and you want to capture the state of defconfigs from before that change was in effect. If in doubt, specify a ref pre-Kconfig - changes (use HEAD if Kconfig changes are not committed). Worst case it will - take a bit longer to run, but will always do the right thing. + changes (use HEAD if Kconfig changes are not committed). Worst case it + will take a bit longer to run, but will always do the right thing. -v, --verbose Show any build errors as boards are built diff --git a/tools/qconfig.py b/tools/qconfig.py index 443223cf9f4..86b2bed9283 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -26,22 +26,13 @@ import tempfile import time import unittest -from buildman import bsettings from buildman import kconfiglib -from buildman import toolchain from u_boot_pylib import terminal from u_boot_pylib.terminal import tprint from u_boot_pylib import tools -SHOW_GNU_MAKE = 'scripts/show-gnu-make' SLEEP_TIME=0.03 -STATE_IDLE = 0 -STATE_DEFCONFIG = 1 -STATE_AUTOCONF = 2 -STATE_SAVEDEFCONFIG = 3 - -AUTO_CONF_PATH = 'include/config/auto.conf' CONFIG_DATABASE = 'qconfig.db' FAILED_LIST = 'qconfig.failed' @@ -88,25 +79,6 @@ def check_top_directory(): if not os.path.exists(fname): sys.exit('Please run at the top of source directory.') -def check_clean_directory(): - """Exit if the source tree is not clean.""" - for fname in '.config', 'include/config': - if os.path.exists(fname): - sys.exit("source tree is not clean, please run 'make mrproper'") - -def get_make_cmd(): - """Get the command name of GNU Make. - - U-Boot needs GNU Make for building, but the command name is not - necessarily "make". (for example, "gmake" on FreeBSD). - Returns the most appropriate command name on your system. - """ - with subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE) as proc: - ret = proc.communicate() - if proc.returncode: - sys.exit('GNU Make not found') - return ret[0].rstrip() - def get_matched_defconfig(line): """Get the defconfig files that match a pattern @@ -544,12 +516,16 @@ def _sync_include_defconfig(kconf, srcdir, orig, dry_run): def _sync_defconfigs_worker(srcdir, defconfigs, result_queue, error_queue, - dry_run): + dry_run, ref_srcdir=None): """Worker process that syncs defconfigs using kconfiglib For each defconfig, loads it via kconfiglib and writes a minimal config (equivalent to 'make savedefconfig'), then compares with the original. + When ref_srcdir is set (the -r option), loads each defconfig against the + reference Kconfig tree first, writes a full .config, then loads that + .config into the current tree's Kconfig and writes a minimal config. + Args: srcdir (str): Source-tree directory defconfigs (list of str): Defconfig filenames to process @@ -557,24 +533,57 @@ def _sync_defconfigs_worker(srcdir, defconfigs, result_queue, error_queue, (defconfig, updated) tuples error_queue (multiprocessing.Queue): Output queue for failed defconfigs dry_run (bool): If True, do not update defconfig files + ref_srcdir (str or None): Reference source tree for -r option """ - os.environ['srctree'] = srcdir os.environ['UBOOTVERSION'] = 'dummy' os.environ['KCONFIG_OBJDIR'] = '' os.environ['CC'] = 'gcc' + + os.environ['srctree'] = srcdir kconf = kconfiglib.Kconfig(warn=False) + if ref_srcdir: + os.environ['srctree'] = ref_srcdir + ref_kconf = kconfiglib.Kconfig(warn=False) + os.environ['srctree'] = srcdir + for defconfig in defconfigs: orig = os.path.join(srcdir, 'configs', defconfig) try: - raw = tools.read_file(orig) - has_include = b'#include' in raw - - if has_include: - updated = _sync_include_defconfig(kconf, srcdir, orig, - dry_run) + if ref_srcdir: + # Load defconfig against the reference Kconfig tree, write + # a full .config, then load it into the current tree + ref_orig = os.path.join(ref_srcdir, 'configs', defconfig) + if not os.path.exists(ref_orig): + ref_orig = orig + _load_defconfig(ref_kconf, ref_srcdir, ref_orig) + tmp_config = tempfile.NamedTemporaryFile( + prefix='qconfig-cfg-', delete=False) + tmp_config.close() + ref_kconf.write_config(tmp_config.name) + kconf.load_config(tmp_config.name, replace=True) + os.unlink(tmp_config.name) else: - updated = _sync_plain_defconfig(kconf, orig, dry_run) + raw = tools.read_file(orig) + if b'#include' in raw: + updated = _sync_include_defconfig(kconf, srcdir, orig, + dry_run) + result_queue.put((defconfig, updated, None)) + continue + _load_defconfig(kconf, srcdir, orig) + + confdir = os.path.dirname(orig) + tmp = tempfile.NamedTemporaryFile( + mode='w', prefix='qconfig-', suffix='_defconfig', + dir=confdir, delete=False) + tmp.close() + kconf.write_min_config(tmp.name) + + updated = not filecmp.cmp(orig, tmp.name) + if updated and not dry_run: + shutil.move(tmp.name, orig) + else: + os.unlink(tmp.name) result_queue.put((defconfig, updated, None)) except Exception as exc: error_queue.put((defconfig, str(exc))) @@ -586,15 +595,25 @@ def do_sync_defconfigs(args): Evaluates each defconfig through kconfiglib and writes a minimal config (equivalent to 'make savedefconfig'), updating the original if it differs. + When -r (git-ref) is given, loads each defconfig against the Kconfig tree + from the reference commit first, then normalises it against the current + tree, capturing any Kconfig default changes. + Args: args (Namespace): Program arguments (uses jobs, defconfigs, - defconfiglist, nocolour, dry_run, force_sync) + defconfiglist, nocolour, dry_run, force_sync, git_ref) Returns: Progress: progress indicator """ srcdir = os.getcwd() + if args.git_ref: + reference_src = ReferenceSource(args.git_ref) + ref_srcdir = reference_src.get_dir() + else: + ref_srcdir = None + if args.defconfigs: defconfigs = [os.path.basename(d) for d in get_matched_defconfigs(args.defconfigs)] @@ -619,7 +638,8 @@ def do_sync_defconfigs(args): continue proc = multiprocessing.Process( target=_sync_defconfigs_worker, - args=(srcdir, chunk, result_queue, error_queue, args.dry_run)) + args=(srcdir, chunk, result_queue, error_queue, args.dry_run, + ref_srcdir)) proc.start() processes.append(proc) @@ -665,364 +685,6 @@ def do_sync_defconfigs(args): return progress -# pylint: disable=R0903 -class KconfigParser: - """A parser of .config and include/autoconf.mk.""" - - re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"') - re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"') - - def __init__(self, build_dir): - """Create a new parser. - - Args: - build_dir: Build directory. - """ - self.dotconfig = os.path.join(build_dir, '.config') - self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk') - self.spl_autoconf = os.path.join(build_dir, 'spl', 'include', - 'autoconf.mk') - self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH) - self.defconfig = os.path.join(build_dir, 'defconfig') - - def get_arch(self): - """Parse .config file and return the architecture. - - Returns: - Architecture name (e.g. 'arm'). - """ - arch = '' - cpu = '' - for line in read_file(self.dotconfig): - m_arch = self.re_arch.match(line) - if m_arch: - arch = m_arch.group(1) - continue - m_cpu = self.re_cpu.match(line) - if m_cpu: - cpu = m_cpu.group(1) - - if not arch: - return None - - # fix-up for aarch64 - if arch == 'arm' and cpu == 'armv8': - arch = 'aarch64' - - return arch - - - -class Slot: - - """A slot to store a subprocess. - - Each instance of this class handles one subprocess. - This class is useful to control multiple threads - for faster processing. - """ - - def __init__(self, toolchains, args, progress, devnull, make_cmd, - reference_src_dir): - """Create a new process slot. - - Args: - toolchains: Toolchains object containing toolchains. - args: Program arguments; this class uses verbose, - force_sync, dry_run, exit_on_error - progress: A progress indicator. - devnull: A file object of '/dev/null'. - make_cmd: command name of GNU Make. - reference_src_dir: Determine the true starting config state from this - source tree. - col (terminal.Color): Colour object - """ - self.toolchains = toolchains - self.args = args - self.progress = progress - self.build_dir = tempfile.mkdtemp() - self.devnull = devnull - self.make_cmd = (make_cmd, 'O=' + self.build_dir) - self.reference_src_dir = reference_src_dir - self.col = progress.col - self.parser = KconfigParser(self.build_dir) - self.state = STATE_IDLE - self.failed_boards = set() - self.defconfig = None - self.log = [] - self.current_src_dir = None - self.proc = None - - def __del__(self): - """Delete the working directory - - This function makes sure the temporary directory is cleaned away - even if Python suddenly dies due to error. It should be done in here - because it is guaranteed the destructor is always invoked when the - instance of the class gets unreferenced. - - If the subprocess is still running, wait until it finishes. - """ - if self.state != STATE_IDLE: - while self.proc.poll() is None: - pass - shutil.rmtree(self.build_dir) - - def add(self, defconfig): - """Assign a new subprocess for defconfig and add it to the slot. - - If the slot is vacant, create a new subprocess for processing the - given defconfig and add it to the slot. Just returns False if - the slot is occupied (i.e. the current subprocess is still running). - - Args: - defconfig (str): defconfig name. - - Returns: - Return True on success or False on failure - """ - if self.state != STATE_IDLE: - return False - - self.defconfig = defconfig - self.log = [] - self.current_src_dir = self.reference_src_dir - self.do_defconfig() - return True - - def poll(self): - """Check the status of the subprocess and handle it as needed. - - Returns True if the slot is vacant (i.e. in idle state). - If the configuration is successfully finished, assign a new - subprocess to build include/autoconf.mk. - If include/autoconf.mk is generated, invoke the parser to - parse the .config and the include/autoconf.mk, moving - config options to the .config as needed. - If the .config was updated, run "make savedefconfig" to sync - it, update the original defconfig, and then set the slot back - to the idle state. - - Returns: - Return True if the subprocess is terminated, False otherwise - """ - if self.state == STATE_IDLE: - return True - - if self.proc.poll() is None: - return False - - if self.proc.poll() != 0: - self.handle_error() - elif self.state == STATE_DEFCONFIG: - if self.reference_src_dir and not self.current_src_dir: - self.do_savedefconfig() - else: - self.do_autoconf() - elif self.state == STATE_AUTOCONF: - if self.current_src_dir: - self.current_src_dir = None - self.do_defconfig() - else: - self.do_savedefconfig() - elif self.state == STATE_SAVEDEFCONFIG: - self.update_defconfig() - else: - sys.exit('Internal Error. This should not happen.') - - return self.state == STATE_IDLE - - def handle_error(self): - """Handle error cases.""" - - self.log.append(self.col.build(self.col.RED, 'Failed to process', - bright=True)) - if self.args.verbose: - for line in self.proc.stderr.read().decode().splitlines(): - self.log.append(self.col.build(self.col.CYAN, line, True)) - self.finish(False) - - def do_defconfig(self): - """Run 'make _defconfig' to create the .config file.""" - - cmd = list(self.make_cmd) - cmd.append(self.defconfig) - # pylint: disable=R1732 - self.proc = subprocess.Popen(cmd, stdout=self.devnull, - stderr=subprocess.PIPE, - cwd=self.current_src_dir) - self.state = STATE_DEFCONFIG - - def do_autoconf(self): - """Run 'make AUTO_CONF_PATH'.""" - - arch = self.parser.get_arch() - try: - tchain = self.toolchains.select(arch) - except ValueError: - self.log.append(self.col.build( - self.col.YELLOW, - f"Tool chain for '{arch}' is missing: do nothing")) - self.finish(False) - return - env = tchain.make_environment(False) - - cmd = list(self.make_cmd) - cmd.append('KCONFIG_IGNORE_DUPLICATES=1') - cmd.append(AUTO_CONF_PATH) - # pylint: disable=R1732 - self.proc = subprocess.Popen(cmd, stdout=self.devnull, env=env, - stderr=subprocess.PIPE, - cwd=self.current_src_dir) - self.state = STATE_AUTOCONF - - def do_savedefconfig(self): - """Update the .config and run 'make savedefconfig'.""" - if not self.args.force_sync: - self.finish(True) - return - - cmd = list(self.make_cmd) - cmd.append('savedefconfig') - # pylint: disable=R1732 - self.proc = subprocess.Popen(cmd, stdout=self.devnull, - stderr=subprocess.PIPE) - self.state = STATE_SAVEDEFCONFIG - - def update_defconfig(self): - """Update the input defconfig and go back to the idle state.""" - orig_defconfig = os.path.join('configs', self.defconfig) - new_defconfig = os.path.join(self.build_dir, 'defconfig') - updated = not filecmp.cmp(orig_defconfig, new_defconfig) - success = True - - if updated: - # Files with #include get mangled as savedefconfig doesn't know how to - # deal with them. Ignore them - success = b'#include' not in tools.read_file(orig_defconfig) - if success: - self.log.append( - self.col.build(self.col.BLUE, 'defconfig updated', - bright=True)) - else: - self.log.append( - self.col.build(self.col.RED, 'ignored due to #include', - bright=True)) - updated = False - - if not self.args.dry_run and updated: - shutil.move(new_defconfig, orig_defconfig) - self.finish(success) - - def finish(self, success): - """Display log along with progress and go to the idle state. - - Args: - success (bool): Should be True when the defconfig was processed - successfully, or False when it fails. - """ - # output at least 30 characters to hide the "* defconfigs out of *". - name = self.defconfig[:-len('_defconfig')] - if self.log: - - # Put the first log line on the first line - log = name.ljust(20) + ' ' + self.log[0] - - if len(self.log) > 1: - log += '\n' + '\n'.join([' ' + s for s in self.log[1:]]) - # Some threads are running in parallel. - # Print log atomically to not mix up logs from different threads. - print(log, file=(sys.stdout if success else sys.stderr)) - - if not success: - if self.args.exit_on_error: - sys.exit('Exit on error.') - # If --exit-on-error flag is not set, skip this board and continue. - # Record the failed board. - self.failed_boards.add(name) - - self.progress.inc(success) - self.progress.show() - self.state = STATE_IDLE - - def get_failed_boards(self): - """Returns a set of failed boards (defconfigs) in this slot. - """ - return self.failed_boards - -class Slots: - """Controller of the array of subprocess slots.""" - - def __init__(self, toolchains, args, progress, reference_src_dir): - """Create a new slots controller. - - Args: - toolchains (Toolchains): Toolchains object containing toolchains - args (Namespace): Program arguments; this class uses - verbose, force_sync, dry_run, exit_on_error, jobs, - progress (Progress): A progress indicator. - reference_src_dir (str): Determine the true starting config state - from this source tree (None for none) - """ - self.args = args - self.slots = [] - self.progress = progress - self.col = progress.col - devnull = subprocess.DEVNULL - make_cmd = get_make_cmd() - for _ in range(args.jobs): - self.slots.append(Slot(toolchains, args, progress, devnull, - make_cmd, reference_src_dir)) - - def add(self, defconfig): - """Add a new subprocess if a vacant slot is found. - - Args: - defconfig (str): defconfig name to be put into. - - Returns: - Return True on success or False on failure - """ - for slot in self.slots: - if slot.add(defconfig): - return True - return False - - def available(self): - """Check if there is a vacant slot. - - Returns: - Return True if at lease one vacant slot is found, False otherwise. - """ - for slot in self.slots: - if slot.poll(): - return True - return False - - def empty(self): - """Check if all slots are vacant. - - Returns: - Return True if all the slots are vacant, False otherwise. - """ - ret = True - for slot in self.slots: - if not slot.poll(): - ret = False - return ret - - def write_failed_boards(self): - """Show the results of processing""" - boards = set() - - for slot in self.slots: - boards |= slot.get_failed_boards() - - if boards: - boards = '\n'.join(sorted(boards)) + '\n' - write_file(FAILED_LIST, boards) - - class ReferenceSource: """Reference source against which original configs should be parsed.""" @@ -1058,67 +720,6 @@ class ReferenceSource: return self.src_dir -def move_config(args): - """Sync config options to defconfig files using make (legacy path). - - This is only used with -r (git-ref), which needs to build against a - different source tree. The normal -s path uses do_sync_defconfigs(). - - Args: - args (Namespace): Program arguments; this class uses - verbose, force_sync, dry_run, exit_on_error, jobs, git_ref, - defconfigs, defconfiglist, nocolour - - Returns: - tuple: - config_db (dict): Always empty (database build uses do_build_db()) - Progress: Progress indicator - """ - config_db = {} - - check_clean_directory() - bsettings.setup('') - - # Get toolchains to use - toolchains = toolchain.Toolchains() - toolchains.get_settings() - toolchains.scan(verbose=False) - - if args.git_ref: - reference_src = ReferenceSource(args.git_ref) - reference_src_dir = reference_src.get_dir() - else: - reference_src_dir = None - - if args.defconfigs: - defconfigs = get_matched_defconfigs(args.defconfigs) - elif args.defconfiglist: - defconfigs = get_matched_defconfigs(args.defconfiglist) - else: - defconfigs = get_all_defconfigs() - - col = terminal.Color(terminal.COLOR_NEVER if args.nocolour - else terminal.COLOR_IF_TERMINAL) - progress = Progress(col, len(defconfigs)) - slots = Slots(toolchains, args, progress, reference_src_dir) - - # Main loop to process defconfig files: - # Add a new subprocess into a vacant slot. - # Sleep if there is no available slot. - for defconfig in defconfigs: - while not slots.add(defconfig): - while not slots.available(): - # No available slot: sleep for a while - time.sleep(SLEEP_TIME) - - # wait until all the subprocesses finish - while not slots.empty(): - time.sleep(SLEEP_TIME) - - slots.write_failed_boards() - progress.completed() - return config_db, progress - def find_kconfig_rules(kconf, config, imply_config): """Check whether a config has a 'select' or 'imply' keyword @@ -2222,17 +1823,14 @@ def main(): config_db, progress = do_build_db(args) return write_db(config_db, progress) - if args.force_sync and not args.git_ref: + if args.force_sync: progress = do_sync_defconfigs(args) if args.commit: add_commit(args.configs) return move_done(progress) - config_db, progress = move_config(args) - - if args.commit: - add_commit(args.configs) - return move_done(progress) + parser.print_usage() + return 1 if __name__ == '__main__':