mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	This commit enables Kconfig.
Going forward, we use Kconfig for the board configuration.
mkconfig will never be used. Nor will include/config.mk be generated.
Kconfig must be adjusted for U-Boot because our situation is
a little more complicated than Linux Kernel.
We have to generate multiple boot images (Normal, SPL, TPL)
from one source tree.
Each image needs its own configuration input.
Usage:
Run "make <board>_defconfig" to do the board configuration.
It will create the .config file and additionally spl/.config, tpl/.config
if SPL, TPL is enabled, respectively.
You can use "make config", "make menuconfig" etc. to create
a new .config or modify the existing one.
Use "make spl/config", "make spl/menuconfig" etc. for spl/.config
and do likewise for tpl/.config file.
The generic syntax of configuration targets for SPL, TPL is:
  <target_image>/<config_command>
Here, <target_image> is either 'spl' or 'tpl'
      <config_command> is 'config', 'menuconfig', 'xconfig', etc.
When the configuration is done, run "make".
(Or "make <board>_defconfig all" will do the configuration and build
in one time.)
For futher information of how Kconfig works in U-Boot,
please read the comment block of scripts/multiconfig.py.
By the way, there is another item worth remarking here:
coexistence of Kconfig and board herder files.
Prior to Kconfig, we used C headers to define a set of configs.
We expect a very long term to migrate from C headers to Kconfig.
Two different infractructure must coexist in the interim.
In our former configuration scheme, include/autoconf.mk was generated
for use in makefiles.
It is still generated under include/, spl/include/, tpl/include/ directory
for the Normal, SPL, TPL image, respectively.
Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
Acked-by: Simon Glass <sjg@chromium.org>
		
	
			
		
			
				
	
	
		
			411 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			411 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
#
 | 
						|
# Copyright (C) 2014, Masahiro Yamada <yamada.m@jp.panasonic.com>
 | 
						|
#
 | 
						|
# SPDX-License-Identifier:	GPL-2.0+
 | 
						|
#
 | 
						|
 | 
						|
"""
 | 
						|
A wrapper script to adjust Kconfig for U-Boot
 | 
						|
 | 
						|
The biggest difference between Linux Kernel and U-Boot in terms of the
 | 
						|
board configuration is that U-Boot has to configure multiple boot images
 | 
						|
per board: Normal, SPL, TPL.
 | 
						|
We need to expand the functions of Kconfig to handle multiple boot
 | 
						|
images.
 | 
						|
 | 
						|
Instead of touching various parts under the scripts/kconfig/ directory,
 | 
						|
pushing necessary adjustments into this single script would be better
 | 
						|
for code maintainance. All the make targets related to the configuration
 | 
						|
(make %config) should be invoked via this script.
 | 
						|
 | 
						|
Let's see what is different from the original Kconfig.
 | 
						|
 | 
						|
- config, menuconfig, etc.
 | 
						|
 | 
						|
The commands 'make config', 'make menuconfig', etc. are used to create
 | 
						|
or modify the .config file, which stores configs for Normal boot image.
 | 
						|
 | 
						|
The location of the one for SPL, TPL image is spl/.config, tpl/.config,
 | 
						|
respectively. Use 'make spl/config', 'make spl/menuconfig', etc.
 | 
						|
to create or modify the spl/.config file, which contains configs
 | 
						|
for SPL image.
 | 
						|
Do likewise for the tpl/.config file.
 | 
						|
The generic syntax for SPL, TPL configuration is
 | 
						|
'make <target_image>/<config_command>'.
 | 
						|
 | 
						|
- silentoldconfig
 | 
						|
 | 
						|
The command 'make silentoldconfig' updates .config, if necessary, and
 | 
						|
additionally updates include/generated/autoconf.h and files under
 | 
						|
include/configs/ directory. In U-Boot, it should do the same things for
 | 
						|
SPL, TPL images for boards supporting them.
 | 
						|
Depending on whether CONFIG_SPL, CONFIG_TPL is defined or not,
 | 
						|
'make silentoldconfig' iterates three times at most changing the target
 | 
						|
directory.
 | 
						|
 | 
						|
To sum up, 'make silentoldconfig' possibly updates
 | 
						|
  - .config, include/generated/autoconf.h, include/config/*
 | 
						|
  - spl/.config, spl/include/generated/autoconf.h, spl/include/config/*
 | 
						|
    (in case CONFIG_SPL=y)
 | 
						|
  - tpl/.config, tpl/include/generated/autoconf.h, tpl/include/config/*
 | 
						|
    (in case CONFIG_TPL=y)
 | 
						|
 | 
						|
- defconfig, <board>_defconfig
 | 
						|
 | 
						|
The command 'make <board>_defconfig' creates a new .config based on the
 | 
						|
file configs/<board>_defconfig. The command 'make defconfig' is the same
 | 
						|
but the difference is it uses the file specified with KBUILD_DEFCONFIG
 | 
						|
environment.
 | 
						|
 | 
						|
We need to create .config, spl/.config, tpl/.config for boards where SPL
 | 
						|
and TPL images are supported. One possible solution for that is to have
 | 
						|
multiple defconfig files per board, but it would produce duplication
 | 
						|
among the defconfigs.
 | 
						|
The approach chosen here is to expand the feature and support
 | 
						|
conditional definition in defconfig, that is, each line in defconfig
 | 
						|
files has the form of:
 | 
						|
<condition>:<macro definition>
 | 
						|
 | 
						|
The '<condition>:' prefix specifies which image the line is valid for.
 | 
						|
The '<condition>:' is one of:
 | 
						|
  None  - the line is valid only for Normal image
 | 
						|
  S:    - the line is valid only for SPL image
 | 
						|
  T:    - the line is valid only for TPL image
 | 
						|
  ST:   - the line is valid for SPL and TPL images
 | 
						|
  +S:   - the line is valid for Normal and SPL images
 | 
						|
  +T:   - the line is valid for Normal and TPL images
 | 
						|
  +ST:  - the line is valid for Normal, SPL and SPL images
 | 
						|
 | 
						|
So, if neither CONFIG_SPL nor CONFIG_TPL is defined, the defconfig file
 | 
						|
has no '<condition>:' part and therefore has the same form of that of
 | 
						|
Linux Kernel.
 | 
						|
 | 
						|
In U-Boot, for example, a defconfig file can be written like this:
 | 
						|
 | 
						|
  CONFIG_FOO=100
 | 
						|
  S:CONFIG_FOO=200
 | 
						|
  T:CONFIG_FOO=300
 | 
						|
  ST:CONFIG_BAR=y
 | 
						|
  +S:CONFIG_BAZ=y
 | 
						|
  +T:CONFIG_QUX=y
 | 
						|
  +ST:CONFIG_QUUX=y
 | 
						|
 | 
						|
The defconfig above is parsed by this script and internally divided into
 | 
						|
three temporary defconfig files.
 | 
						|
 | 
						|
  - Temporary defconfig for Normal image
 | 
						|
     CONFIG_FOO=100
 | 
						|
     CONFIG_BAZ=y
 | 
						|
     CONFIG_QUX=y
 | 
						|
     CONFIG_QUUX=y
 | 
						|
 | 
						|
  - Temporary defconfig for SPL image
 | 
						|
     CONFIG_FOO=200
 | 
						|
     CONFIG_BAR=y
 | 
						|
     CONFIG_BAZ=y
 | 
						|
     CONFIG_QUUX=y
 | 
						|
 | 
						|
  - Temporary defconfig for TPL image
 | 
						|
     CONFIG_FOO=300
 | 
						|
     CONFIG_BAR=y
 | 
						|
     CONFIG_QUX=y
 | 
						|
     CONFIG_QUUX=y
 | 
						|
 | 
						|
They are passed to scripts/kconfig/conf, each is used for generating
 | 
						|
.config, spl/.config, tpl/.config, respectively.
 | 
						|
 | 
						|
- savedefconfig
 | 
						|
 | 
						|
This is the reverse operation of 'make defconfig'.
 | 
						|
If neither CONFIG_SPL nor CONFIG_TPL is defined in the .config file,
 | 
						|
it works as 'make savedefconfig' in Linux Kernel: create the minimal set
 | 
						|
of config based on the .config and save it into 'defconfig' file.
 | 
						|
 | 
						|
If CONFIG_SPL or CONFIG_TPL is defined, the common lines among .config,
 | 
						|
spl/.config, tpl/.config are coalesced together and output to the file
 | 
						|
'defconfig' in the form like:
 | 
						|
 | 
						|
  CONFIG_FOO=100
 | 
						|
  S:CONFIG_FOO=200
 | 
						|
  T:CONFIG_FOO=300
 | 
						|
  ST:CONFIG_BAR=y
 | 
						|
  +S:CONFIG_BAZ=y
 | 
						|
  +T:CONFIG_QUX=y
 | 
						|
  +ST:CONFIG_QUUX=y
 | 
						|
 | 
						|
This can be used as an input of 'make <board>_defconfig' command.
 | 
						|
"""
 | 
						|
 | 
						|
import errno
 | 
						|
import os
 | 
						|
import re
 | 
						|
import subprocess
 | 
						|
import sys
 | 
						|
 | 
						|
# Constant variables
 | 
						|
SUB_IMAGES = ('spl', 'tpl')
 | 
						|
IMAGES = ('',) + SUB_IMAGES
 | 
						|
SYMBOL_MAP = {'': '+', 'spl': 'S', 'tpl': 'T'}
 | 
						|
PATTERN_SYMBOL = re.compile(r'(\+?)(S?)(T?):(.*)')
 | 
						|
 | 
						|
# Environment variables (should be defined in the top Makefile)
 | 
						|
# .get('key', 'default_value') method is useful for standalone testing.
 | 
						|
MAKE = os.environ.get('MAKE', 'make')
 | 
						|
srctree = os.environ.get('srctree', '.')
 | 
						|
KCONFIG_CONFIG = os.environ.get('KCONFIG_CONFIG', '.config')
 | 
						|
 | 
						|
# Useful shorthand
 | 
						|
build = '%s -f %s/scripts/Makefile.build obj=scripts/kconfig %%s' % (MAKE, srctree)
 | 
						|
autoconf = '%s -f %s/scripts/Makefile.autoconf obj=%%s %%s' % (MAKE, srctree)
 | 
						|
 | 
						|
### helper functions ###
 | 
						|
def mkdirs(*dirs):
 | 
						|
    """Make directories ignoring 'File exists' error."""
 | 
						|
    for d in dirs:
 | 
						|
        try:
 | 
						|
            os.makedirs(d)
 | 
						|
        except OSError as exception:
 | 
						|
            # Ignore 'File exists' error
 | 
						|
            if exception.errno != errno.EEXIST:
 | 
						|
                raise
 | 
						|
 | 
						|
def rmfiles(*files):
 | 
						|
    """Remove files ignoring 'No such file or directory' error."""
 | 
						|
    for f in files:
 | 
						|
        try:
 | 
						|
            os.remove(f)
 | 
						|
        except OSError as exception:
 | 
						|
            # Ignore 'No such file or directory' error
 | 
						|
            if exception.errno != errno.ENOENT:
 | 
						|
                raise
 | 
						|
 | 
						|
def rmdirs(*dirs):
 | 
						|
    """Remove directories ignoring 'No such file or directory'
 | 
						|
    and 'Directory not empty' error.
 | 
						|
    """
 | 
						|
    for d in dirs:
 | 
						|
        try:
 | 
						|
            os.rmdir(d)
 | 
						|
        except OSError as exception:
 | 
						|
            # Ignore 'No such file or directory'
 | 
						|
            # and 'Directory not empty' error
 | 
						|
            if exception.errno != errno.ENOENT and \
 | 
						|
               exception.errno != errno.ENOTEMPTY:
 | 
						|
                raise
 | 
						|
 | 
						|
def error(msg):
 | 
						|
    """Output the given argument to stderr and exit with return code 1."""
 | 
						|
    print >> sys.stderr, msg
 | 
						|
    sys.exit(1)
 | 
						|
 | 
						|
def run_command(command, callback_on_error=None):
 | 
						|
    """Run the given command in a sub-shell (and exit if it fails).
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      command: A string of the command
 | 
						|
      callback_on_error: Callback handler invoked just before exit
 | 
						|
                         when the command fails (Default=None)
 | 
						|
    """
 | 
						|
    retcode = subprocess.call(command, shell=True)
 | 
						|
    if retcode:
 | 
						|
        if callback_on_error:
 | 
						|
            callback_on_error()
 | 
						|
        error("'%s' Failed" % command)
 | 
						|
 | 
						|
def run_make_config(cmd, objdir, callback_on_error=None):
 | 
						|
    """Run the make command in a sub-shell (and exit if it fails).
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      cmd: Make target such as 'config', 'menuconfig', 'defconfig', etc.
 | 
						|
      objdir: Target directory where the make command is run.
 | 
						|
              Typically '', 'spl', 'tpl' for Normal, SPL, TPL image,
 | 
						|
              respectively.
 | 
						|
      callback_on_error: Callback handler invoked just before exit
 | 
						|
                         when the command fails (Default=None)
 | 
						|
    """
 | 
						|
    # Linux expects defconfig files in arch/$(SRCARCH)/configs/ directory,
 | 
						|
    # but U-Boot puts them in configs/ directory.
 | 
						|
    # Give SRCARCH=.. to fake scripts/kconfig/Makefile.
 | 
						|
    options = 'SRCARCH=.. KCONFIG_OBJDIR=%s' % objdir
 | 
						|
    if objdir:
 | 
						|
        options += ' KCONFIG_CONFIG=%s/%s' % (objdir, KCONFIG_CONFIG)
 | 
						|
        mkdirs(objdir)
 | 
						|
    run_command(build % cmd + ' ' + options, callback_on_error)
 | 
						|
 | 
						|
def get_enabled_subimages(ignore_error=False):
 | 
						|
    """Parse .config file to detect if CONFIG_SPL, CONFIG_TPL is enabled
 | 
						|
    and return a tuple of enabled subimages.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      ignore_error: Specify the behavior when '.config' is not found;
 | 
						|
                    Raise an exception if this flag is False.
 | 
						|
                    Return a null tuple if this flag is True.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      A tuple of enabled subimages as follows:
 | 
						|
        ()             if neither CONFIG_SPL nor CONFIG_TPL is defined
 | 
						|
        ('spl',)       if CONFIG_SPL is defined but CONFIG_TPL is not
 | 
						|
        ('spl', 'tpl') if both CONFIG_SPL and CONFIG_TPL are defined
 | 
						|
    """
 | 
						|
    enabled = ()
 | 
						|
    match_patterns = [ (img, 'CONFIG_' + img.upper() + '=y\n')
 | 
						|
                                                        for img in SUB_IMAGES ]
 | 
						|
    try:
 | 
						|
        f = open(KCONFIG_CONFIG)
 | 
						|
    except IOError as exception:
 | 
						|
        if not ignore_error or exception.errno != errno.ENOENT:
 | 
						|
            raise
 | 
						|
        return enabled
 | 
						|
    with f:
 | 
						|
        for line in f:
 | 
						|
            for img, pattern in match_patterns:
 | 
						|
                if line == pattern:
 | 
						|
                    enabled += (img,)
 | 
						|
    return enabled
 | 
						|
 | 
						|
def do_silentoldconfig(cmd):
 | 
						|
    """Run 'make silentoldconfig' for all the enabled images.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      cmd: should always be a string 'silentoldconfig'
 | 
						|
    """
 | 
						|
    run_make_config(cmd, '')
 | 
						|
    subimages = get_enabled_subimages()
 | 
						|
    for obj in subimages:
 | 
						|
        mkdirs(os.path.join(obj, 'include', 'config'),
 | 
						|
               os.path.join(obj, 'include', 'generated'))
 | 
						|
        run_make_config(cmd, obj)
 | 
						|
    remove_auto_conf = lambda : rmfiles('include/config/auto.conf')
 | 
						|
    # If the following part failed, include/config/auto.conf should be deleted
 | 
						|
    # so 'make silentoldconfig' will be re-run on the next build.
 | 
						|
    run_command(autoconf %
 | 
						|
                ('include', 'include/autoconf.mk include/autoconf.mk.dep'),
 | 
						|
                remove_auto_conf)
 | 
						|
    # include/config.h has been updated after 'make silentoldconfig'.
 | 
						|
    # We need to touch include/config/auto.conf so it gets newer
 | 
						|
    # than include/config.h.
 | 
						|
    # Otherwise, 'make silentoldconfig' would be invoked twice.
 | 
						|
    os.utime('include/config/auto.conf', None)
 | 
						|
    for obj in subimages:
 | 
						|
        run_command(autoconf % (obj + '/include',
 | 
						|
                                obj + '/include/autoconf.mk'),
 | 
						|
                    remove_auto_conf)
 | 
						|
 | 
						|
def do_tmp_defconfig(output_lines, img):
 | 
						|
    """Helper function for do_board_defconfig().
 | 
						|
 | 
						|
    Write the defconfig contents into a file '.tmp_defconfig' and
 | 
						|
    invoke 'make .tmp_defconfig'.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      output_lines: A sequence of defconfig lines of each image
 | 
						|
      img: Target image. Typically '', 'spl', 'tpl' for
 | 
						|
           Normal, SPL, TPL images, respectively.
 | 
						|
    """
 | 
						|
    TMP_DEFCONFIG = '.tmp_defconfig'
 | 
						|
    TMP_DIRS = ('arch', 'configs')
 | 
						|
    defconfig_path = os.path.join('configs', TMP_DEFCONFIG)
 | 
						|
    mkdirs(*TMP_DIRS)
 | 
						|
    with open(defconfig_path, 'w') as f:
 | 
						|
        f.write(''.join(output_lines[img]))
 | 
						|
    cleanup = lambda: (rmfiles(defconfig_path), rmdirs(*TMP_DIRS))
 | 
						|
    run_make_config(TMP_DEFCONFIG, img, cleanup)
 | 
						|
    cleanup()
 | 
						|
 | 
						|
def do_board_defconfig(cmd):
 | 
						|
    """Run 'make <board>_defconfig'.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      cmd: should be a string '<board>_defconfig'
 | 
						|
    """
 | 
						|
    defconfig_path = os.path.join(srctree, 'configs', cmd)
 | 
						|
    output_lines = dict([ (img, []) for img in IMAGES ])
 | 
						|
    with open(defconfig_path) as f:
 | 
						|
        for line in f:
 | 
						|
            m = PATTERN_SYMBOL.match(line)
 | 
						|
            if m:
 | 
						|
                for idx, img in enumerate(IMAGES):
 | 
						|
                    if m.group(idx + 1):
 | 
						|
                        output_lines[img].append(m.group(4) + '\n')
 | 
						|
                continue
 | 
						|
            output_lines[''].append(line)
 | 
						|
    do_tmp_defconfig(output_lines, '')
 | 
						|
    for img in get_enabled_subimages():
 | 
						|
        do_tmp_defconfig(output_lines, img)
 | 
						|
 | 
						|
def do_defconfig(cmd):
 | 
						|
    """Run 'make defconfig'.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      cmd: should always be a string 'defconfig'
 | 
						|
    """
 | 
						|
    KBUILD_DEFCONFIG = os.environ['KBUILD_DEFCONFIG']
 | 
						|
    print "*** Default configuration is based on '%s'" % KBUILD_DEFCONFIG
 | 
						|
    do_board_defconfig(KBUILD_DEFCONFIG)
 | 
						|
 | 
						|
def do_savedefconfig(cmd):
 | 
						|
    """Run 'make savedefconfig'.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      cmd: should always be a string 'savedefconfig'
 | 
						|
    """
 | 
						|
    DEFCONFIG = 'defconfig'
 | 
						|
    # Continue even if '.config' does not exist
 | 
						|
    subimages = get_enabled_subimages(True)
 | 
						|
    run_make_config(cmd, '')
 | 
						|
    output_lines = []
 | 
						|
    prefix = {}
 | 
						|
    with open(DEFCONFIG) as f:
 | 
						|
        for line in f:
 | 
						|
            output_lines.append(line)
 | 
						|
            prefix[line] = '+'
 | 
						|
    for img in subimages:
 | 
						|
        run_make_config(cmd, img)
 | 
						|
        unmatched_lines = []
 | 
						|
        with open(DEFCONFIG) as f:
 | 
						|
            for line in f:
 | 
						|
                if line in output_lines:
 | 
						|
                    index = output_lines.index(line)
 | 
						|
                    output_lines[index:index] = unmatched_lines
 | 
						|
                    unmatched_lines = []
 | 
						|
                    prefix[line] += SYMBOL_MAP[img]
 | 
						|
                else:
 | 
						|
                    ummatched_lines.append(line)
 | 
						|
                    prefix[line] = SYMBOL_MAP[img]
 | 
						|
    with open(DEFCONFIG, 'w') as f:
 | 
						|
        for line in output_lines:
 | 
						|
            if prefix[line] == '+':
 | 
						|
                f.write(line)
 | 
						|
            else:
 | 
						|
                f.write(prefix[line] + ':' + line)
 | 
						|
 | 
						|
def do_others(cmd):
 | 
						|
    """Run the make command other than 'silentoldconfig', 'defconfig',
 | 
						|
    '<board>_defconfig' and 'savedefconfig'.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
      cmd: Make target in the form of '<target_image>/<config_command>'
 | 
						|
           The field '<target_image>/' is typically empty, 'spl/', 'tpl/'
 | 
						|
           for Normal, SPL, TPL images, respectively.
 | 
						|
           The field '<config_command>' is make target such as 'config',
 | 
						|
           'menuconfig', etc.
 | 
						|
    """
 | 
						|
    objdir, _, cmd = cmd.rpartition('/')
 | 
						|
    run_make_config(cmd, objdir)
 | 
						|
 | 
						|
cmd_list = {'silentoldconfig': do_silentoldconfig,
 | 
						|
            'defconfig': do_defconfig,
 | 
						|
            'savedefconfig': do_savedefconfig}
 | 
						|
 | 
						|
def main():
 | 
						|
    cmd = sys.argv[1]
 | 
						|
    if cmd.endswith('_defconfig'):
 | 
						|
        do_board_defconfig(cmd)
 | 
						|
    else:
 | 
						|
        func = cmd_list.get(cmd, do_others)
 | 
						|
        func(cmd)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main()
 |