buildman: Support #include files in defconfigs

This is used by some boards in U-Boot and is a convenient way to deal
with common settings where using a Kconfig files is not desirable.

Detect #include files and process them as if they were part of the
original file.

Signed-off-by: Simon Glass <sjg@chromium.org>
Fixes: https://source.denx.de/u-boot/custodians/u-boot-dm/-/issues/30
This commit is contained in:
Simon Glass
2024-11-08 08:23:44 -07:00
committed by Tom Rini
parent 6d66ded18e
commit 6bf74a2e0b
3 changed files with 82 additions and 1 deletions

View File

@@ -19,7 +19,10 @@ import time
from buildman import board
from buildman import kconfiglib
from u_boot_pylib import command
from u_boot_pylib.terminal import print_clear, tprint
from u_boot_pylib import tools
from u_boot_pylib import tout
### constant variables ###
OUTPUT_FILE = 'boards.cfg'
@@ -202,6 +205,7 @@ class KconfigScanner:
os.environ['KCONFIG_OBJDIR'] = ''
self._tmpfile = None
self._conf = kconfiglib.Kconfig(warn=False)
self._srctree = srctree
def __del__(self):
"""Delete a leftover temporary file before exit.
@@ -239,7 +243,26 @@ class KconfigScanner:
expect_target, match, rear = leaf.partition('_defconfig')
assert match and not rear, f'{leaf} : invalid defconfig'
self._conf.load_config(defconfig)
temp = None
if b'#include' in tools.read_file(defconfig):
cmd = [
os.getenv('CPP', 'cpp'),
'-nostdinc', '-P',
'-I', self._srctree,
'-undef',
'-x', 'assembler-with-cpp',
defconfig]
result = command.run_pipe([cmd], capture=True, capture_stderr=True)
temp = tempfile.NamedTemporaryFile(prefix='buildman-')
tools.write_file(temp.name, result.stdout, False)
fname = temp.name
tout.info(f'Processing #include to produce {defconfig}')
else:
fname = defconfig
self._conf.load_config(fname)
if temp:
del temp
self._tmpfile = None
params = {}

View File

@@ -1112,6 +1112,30 @@ The -U option uses the u-boot.env files which are produced by a build.
Internally, buildman writes out an out-env file into the build directory for
later comparison.
defconfig fragments
-------------------
Buildman provides some initial support for configuration fragments. It can scan
these when present in defconfig files and handle the resuiting Kconfig
correctly. Thus it is possible to build a board which has a ``#include`` in the
defconfig file.
For now, Buildman simply includes the files to produce a single output file,
using the C preprocessor. It does not call the ``merge_config.sh`` script. The
redefined/redundant logic in that script could fairly easily be repeated in
Buildman, to detect potential problems. For now it is not clear that this is
useful.
To specify the C preprocessor to use, set the ``CPP`` environment variable. The
default is ``cpp``.
Note that Buildman does not support adding fragments to existing boards, e.g.
like::
make qemu_riscv64_defconfig acpi.config
This is partly because there is no way for Buildman to know which fragments are
valid on which boards.
Building with clang
-------------------

View File

@@ -2,8 +2,10 @@
# Copyright (c) 2014 Google, Inc
#
import io
import os
from pathlib import Path
import re
import shutil
import sys
import tempfile
@@ -373,6 +375,22 @@ class TestFunctional(unittest.TestCase):
def _HandleCommandSize(self, args):
return command.CommandResult(return_code=0)
def _HandleCommandCpp(self, args):
# args ['-nostdinc', '-P', '-I', '/tmp/tmp7f17xk_o/src', '-undef',
# '-x', 'assembler-with-cpp', fname]
fname = args[7]
buf = io.StringIO()
for line in tools.read_file(fname, False).splitlines():
if line.startswith('#include'):
# Example: #include <configs/renesas_rcar2.config>
m_incfname = re.match('#include <(.*)>', line)
data = tools.read_file(m_incfname.group(1), False)
for line in data.splitlines():
print(line, file=buf)
else:
print(line, file=buf)
return command.CommandResult(stdout=buf.getvalue(), return_code=0)
def _HandleCommand(self, **kwargs):
"""Handle a command execution.
@@ -406,6 +424,8 @@ class TestFunctional(unittest.TestCase):
return self._HandleCommandObjcopy(args)
elif cmd.endswith( 'size'):
return self._HandleCommandSize(args)
elif cmd.endswith( 'cpp'):
return self._HandleCommandCpp(args)
if not result:
# Not handled, so abort
@@ -1118,3 +1138,17 @@ CONFIG_SOC="fred"
'config': '-',
'target': 'board0'},
['WARNING: board0_defconfig: No TARGET_BOARD0 enabled']), res)
# check handling of #include files; see _HandleCommandCpp()
inc = os.path.join(src, 'common')
tools.write_file(inc, b'CONFIG_TARGET_BOARD0=y\n')
tools.write_file(norm, f'#include <{inc}>', False)
res = scanner.scan(norm, True)
self.assertEqual(({
'arch': 'arm',
'cpu': 'armv7',
'soc': '-',
'vendor': 'Tester',
'board': 'ARM Board 0',
'config': 'config0',
'target': 'board0'}, []), res)