aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorMasahiro Yamada2014-08-21 11:44:34 +0900
committerTom Rini2014-08-22 10:41:50 -0400
commit3ff291f371fa9858426774f3732924bacb61ed1c (patch)
treec260c2b787df3749a8ddcbbd50c15dd84a591dc5 /scripts
parentfd18a89e7f998133000ccb149366ba76f75e7ba5 (diff)
kconfig: convert Kconfig helper script into a shell script
Commit 51148790 added scripts/multiconfig.py written in Python 2 to adjust Kconfig for U-Boot. It has been hard for Python 3 users because Python 2 and Python 3 are not compatible with each other. We are not happy about adding a new host tool dependency (in this case, Python version dependency) for the core build process. After some discussion, we decided to use only basic tools. The script may get a bit more unreadable by shell scripting, but we believe it is worthwhile. In addition, this commit revives "<board>_config" target that is equivalent to "<board>_defconfig" for backwards compatibility. It is annoying to adjust various projects which use U-Boot. Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com> Suggested-by: Igor Grinberg <grinberg@compulab.co.il> Tested-by: Igor Grinberg <grinberg@compulab.co.il> Acked-by: Simon Glass <sjg@chromium.org> Cc: Tom Rini <trini@ti.com> Cc: Jeroen Hofstee <jeroen@myspectrum.nl> Cc: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/multiconfig.py405
-rw-r--r--scripts/multiconfig.sh260
2 files changed, 260 insertions, 405 deletions
diff --git a/scripts/multiconfig.py b/scripts/multiconfig.py
deleted file mode 100755
index 69a470e51fa..00000000000
--- a/scripts/multiconfig.py
+++ /dev/null
@@ -1,405 +0,0 @@
-#!/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 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()
- sys.exit("'%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()
diff --git a/scripts/multiconfig.sh b/scripts/multiconfig.sh
new file mode 100644
index 00000000000..56cf0c2a5d5
--- /dev/null
+++ b/scripts/multiconfig.sh
@@ -0,0 +1,260 @@
+#!/bin/sh
+#
+# A wrapper script to adjust Kconfig for U-Boot
+#
+# 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.
+# See doc/README.kconfig for further information of Kconfig.
+#
+# Copyright (C) 2014, Masahiro Yamada <yamada.m@jp.panasonic.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+set -e
+
+# Set "DEBUG" enavironment variable to show debug messages
+debug () {
+ if [ $DEBUG ]; then
+ echo "$@"
+ fi
+}
+
+# Useful shorthands
+build () {
+ debug $progname: $MAKE -f $srctree/scripts/Makefile.build obj="$@"
+ $MAKE -f $srctree/scripts/Makefile.build obj="$@"
+}
+
+autoconf () {
+ debug $progname: $MAKE -f $srctree/scripts/Makefile.autoconf obj="$@"
+ $MAKE -f $srctree/scripts/Makefile.autoconf obj="$@"
+}
+
+# Make a configuration target
+# Usage:
+# run_make_config <target> <objdir>
+# <target>: Make target such as "config", "menuconfig", "defconfig", etc.
+# <objdir>: Target directory where the make command is run.
+# Typically "", "spl", "tpl" for Normal, SPL, TPL, respectively.
+run_make_config () {
+ target=$1
+ objdir=$2
+
+ # Linux expects defconfig files in arch/$(SRCARCH)/configs/ directory,
+ # but U-Boot has them in configs/ directory.
+ # Give SRCARCH=.. to fake scripts/kconfig/Makefile.
+ options="SRCARCH=.. KCONFIG_OBJDIR=$objdir"
+ if [ "$objdir" ]; then
+ options="$options KCONFIG_CONFIG=$objdir/$KCONFIG_CONFIG"
+ mkdir -p $objdir
+ fi
+
+ build scripts/kconfig $options $target
+}
+
+# Parse .config file to detect if CONFIG_SPL, CONFIG_TPL is enabled
+# and returns:
+# "" 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
+get_enabled_subimages() {
+ if [ ! -r "$KCONFIG_CONFIG" ]; then
+ # This should never happen
+ echo "$progname: $KCONFIG_CONFIG not found" >&2
+ exit 1
+ fi
+
+ # CONFIG_SPL=y -> spl
+ # CONFIG_TPL=y -> tpl
+ sed -n -e 's/^CONFIG_\(SPL\|TPL\)=y$/\1/p' $KCONFIG_CONFIG | \
+ tr '[A-Z]' '[a-z]'
+}
+
+do_silentoldconfig () {
+ run_make_config silentoldconfig
+ subimages=$(get_enabled_subimages)
+
+ for obj in $subimages
+ do
+ mkdir -p $obj/include/config $obj/include/generated
+ run_make_config silentoldconfig $obj
+ done
+
+ # If the following part fails, include/config/auto.conf should be
+ # deleted so "make silentoldconfig" will be re-run on the next build.
+ autoconf include include/autoconf.mk include/autoconf.mk.dep || {
+ rm -f include/config/auto.conf
+ exit 1
+ }
+
+ # 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.
+ touch include/config/auto.conf
+
+ for obj in $subimages
+ do
+ autoconf $obj/include $obj/include/autoconf.mk || {
+ rm -f include/config/auto.conf
+ exit 1
+ }
+ done
+}
+
+cleanup_after_defconfig () {
+ rm -f configs/.tmp_defconfig
+ # ignore 'Directory not empty' error
+ # without using non-POSIX option '--ignore-fail-on-non-empty'
+ rmdir arch configs 2>/dev/null || true
+}
+
+# Usage:
+# do_board_defconfig <board>_defconfig
+do_board_defconfig () {
+ defconfig_path=$srctree/configs/$1
+ tmp_defconfig_path=configs/.tmp_defconfig
+
+ mkdir -p arch configs
+ # defconfig for Normal:
+ # pick lines without prefixes and lines starting '+' prefix
+ # and rip the prefixes off.
+ sed -n -e '/^[+A-Z]*:/!p' -e 's/^+[A-Z]*://p' $defconfig_path \
+ > configs/.tmp_defconfig
+
+ run_make_config .tmp_defconfig || {
+ cleanup_after_defconfig
+ exit 1
+ }
+
+ for img in $(get_enabled_subimages)
+ do
+ symbol=$(echo $img | cut -c 1 | tr '[a-z]' '[A-Z]')
+ # defconfig for SPL, TPL:
+ # pick lines with 'S', 'T' prefix and rip the prefixes off
+ sed -n -e 's/^[+A-Z]*'$symbol'[A-Z]*://p' $defconfig_path \
+ > configs/.tmp_defconfig
+ run_make_config .tmp_defconfig $img || {
+ cleanup_after_defconfig
+ exit 1
+ }
+ done
+
+ cleanup_after_defconfig
+}
+
+do_defconfig () {
+ if [ "$KBUILD_DEFCONFIG" ]; then
+ do_board_defconfig $KBUILD_DEFCONFIG
+ echo "*** Default configuration is based on '$KBUILD_DEFCONFIG'"
+ else
+ run_make_config defconfig
+ fi
+}
+
+do_savedefconfig () {
+ if [ -r "$KCONFIG_CONFIG" ]; then
+ subimages=$(get_enabled_subimages)
+ else
+ subimages=
+ fi
+
+ run_make_config savedefconfig
+
+ output_lines=
+
+ # -r option is necessay because some string-type configs may include
+ # backslashes as an escape character
+ while read -r line
+ do
+ output_lines="$output_lines $line"
+ done < defconfig
+
+ for img in $subimages
+ do
+ run_make_config savedefconfig $img
+
+ symbol=$(echo $img | cut -c 1 | tr '[a-z]' '[A-Z]')
+ unmatched=
+
+ while read -r line
+ do
+ tmp=
+ match=
+
+ # coalesce common lines together
+ for i in $output_lines
+ do
+ case "$i" in
+ "[+A-Z]*:$line")
+ tmp="$tmp $unmatched"
+ i=$(echo "$i" | \
+ sed -e "s/^\([^:]\)*/\1$symbol/")
+ tmp="$tmp $i"
+ match=1
+ ;;
+ "$line")
+ tmp="$tmp $unmatched"
+ tmp="$tmp +$symbol:$i"
+ match=1
+ ;;
+ *)
+ tmp="$tmp $i"
+ ;;
+ esac
+ done
+
+ if [ "$match" ]; then
+ output_lines="$tmp"
+ unmatched=
+ else
+ unmatched="$unmatched $symbol:$line"
+ fi
+ done < defconfig
+ done
+
+ rm -f defconfig
+ for line in $output_lines
+ do
+ echo $line >> defconfig
+ done
+}
+
+# Usage:
+# do_others <objdir>/<target>
+# The field "<objdir>/" is typically empy, "spl/", "tpl/" for Normal, SPL, TPL,
+# respectively.
+# The field "<target>" is a configuration target such as "config",
+# "menuconfig", etc.
+do_others () {
+ target=${1##*/}
+
+ if [ "$target" = "$1" ]; then
+ objdir=
+ else
+ objdir=${1%/*}
+ fi
+
+ run_make_config $target $objdir
+}
+
+progname=$(basename $0)
+target=$1
+
+case $target in
+*_defconfig)
+ do_board_defconfig $target;;
+*_config)
+ do_board_defconfig ${target%_config}_defconfig;;
+silentoldconfig)
+ do_silentoldconfig;;
+defconfig)
+ do_defconfig;;
+savedefconfig)
+ do_savedefconfig;;
+*)
+ do_others $target;;
+esac