3 # Copyright (C) 2014, Masahiro Yamada <yamada.m@jp.panasonic.com>
5 # SPDX-License-Identifier: GPL-2.0+
9 A wrapper script to adjust Kconfig for U-Boot
11 The biggest difference between Linux Kernel and U-Boot in terms of the
12 board configuration is that U-Boot has to configure multiple boot images
13 per board: Normal, SPL, TPL.
14 We need to expand the functions of Kconfig to handle multiple boot
17 Instead of touching various parts under the scripts/kconfig/ directory,
18 pushing necessary adjustments into this single script would be better
19 for code maintainance. All the make targets related to the configuration
20 (make %config) should be invoked via this script.
22 Let's see what is different from the original Kconfig.
24 - config, menuconfig, etc.
26 The commands 'make config', 'make menuconfig', etc. are used to create
27 or modify the .config file, which stores configs for Normal boot image.
29 The location of the one for SPL, TPL image is spl/.config, tpl/.config,
30 respectively. Use 'make spl/config', 'make spl/menuconfig', etc.
31 to create or modify the spl/.config file, which contains configs
33 Do likewise for the tpl/.config file.
34 The generic syntax for SPL, TPL configuration is
35 'make <target_image>/<config_command>'.
39 The command 'make silentoldconfig' updates .config, if necessary, and
40 additionally updates include/generated/autoconf.h and files under
41 include/configs/ directory. In U-Boot, it should do the same things for
42 SPL, TPL images for boards supporting them.
43 Depending on whether CONFIG_SPL, CONFIG_TPL is defined or not,
44 'make silentoldconfig' iterates three times at most changing the target
47 To sum up, 'make silentoldconfig' possibly updates
48 - .config, include/generated/autoconf.h, include/config/*
49 - spl/.config, spl/include/generated/autoconf.h, spl/include/config/*
50 (in case CONFIG_SPL=y)
51 - tpl/.config, tpl/include/generated/autoconf.h, tpl/include/config/*
52 (in case CONFIG_TPL=y)
54 - defconfig, <board>_defconfig
56 The command 'make <board>_defconfig' creates a new .config based on the
57 file configs/<board>_defconfig. The command 'make defconfig' is the same
58 but the difference is it uses the file specified with KBUILD_DEFCONFIG
61 We need to create .config, spl/.config, tpl/.config for boards where SPL
62 and TPL images are supported. One possible solution for that is to have
63 multiple defconfig files per board, but it would produce duplication
65 The approach chosen here is to expand the feature and support
66 conditional definition in defconfig, that is, each line in defconfig
67 files has the form of:
68 <condition>:<macro definition>
70 The '<condition>:' prefix specifies which image the line is valid for.
71 The '<condition>:' is one of:
72 None - the line is valid only for Normal image
73 S: - the line is valid only for SPL image
74 T: - the line is valid only for TPL image
75 ST: - the line is valid for SPL and TPL images
76 +S: - the line is valid for Normal and SPL images
77 +T: - the line is valid for Normal and TPL images
78 +ST: - the line is valid for Normal, SPL and SPL images
80 So, if neither CONFIG_SPL nor CONFIG_TPL is defined, the defconfig file
81 has no '<condition>:' part and therefore has the same form of that of
84 In U-Boot, for example, a defconfig file can be written like this:
94 The defconfig above is parsed by this script and internally divided into
95 three temporary defconfig files.
97 - Temporary defconfig for Normal image
103 - Temporary defconfig for SPL image
109 - Temporary defconfig for TPL image
115 They are passed to scripts/kconfig/conf, each is used for generating
116 .config, spl/.config, tpl/.config, respectively.
120 This is the reverse operation of 'make defconfig'.
121 If neither CONFIG_SPL nor CONFIG_TPL is defined in the .config file,
122 it works as 'make savedefconfig' in Linux Kernel: create the minimal set
123 of config based on the .config and save it into 'defconfig' file.
125 If CONFIG_SPL or CONFIG_TPL is defined, the common lines among .config,
126 spl/.config, tpl/.config are coalesced together and output to the file
127 'defconfig' in the form like:
137 This can be used as an input of 'make <board>_defconfig' command.
147 SUB_IMAGES = ('spl', 'tpl')
148 IMAGES = ('',) + SUB_IMAGES
149 SYMBOL_MAP = {'': '+', 'spl': 'S', 'tpl': 'T'}
150 PATTERN_SYMBOL = re.compile(r'(\+?)(S?)(T?):(.*)')
152 # Environment variables (should be defined in the top Makefile)
153 # .get('key', 'default_value') method is useful for standalone testing.
154 MAKE = os.environ.get('MAKE', 'make')
155 srctree = os.environ.get('srctree', '.')
156 KCONFIG_CONFIG = os.environ.get('KCONFIG_CONFIG', '.config')
159 build = '%s -f %s/scripts/Makefile.build obj=scripts/kconfig %%s' % (MAKE, srctree)
160 autoconf = '%s -f %s/scripts/Makefile.autoconf obj=%%s %%s' % (MAKE, srctree)
162 ### helper functions ###
164 """Make directories ignoring 'File exists' error."""
168 except OSError as exception:
169 # Ignore 'File exists' error
170 if exception.errno != errno.EEXIST:
174 """Remove files ignoring 'No such file or directory' error."""
178 except OSError as exception:
179 # Ignore 'No such file or directory' error
180 if exception.errno != errno.ENOENT:
184 """Remove directories ignoring 'No such file or directory'
185 and 'Directory not empty' error.
190 except OSError as exception:
191 # Ignore 'No such file or directory'
192 # and 'Directory not empty' error
193 if exception.errno != errno.ENOENT and \
194 exception.errno != errno.ENOTEMPTY:
198 """Output the given argument to stderr and exit with return code 1."""
199 print >> sys.stderr, msg
202 def run_command(command, callback_on_error=None):
203 """Run the given command in a sub-shell (and exit if it fails).
206 command: A string of the command
207 callback_on_error: Callback handler invoked just before exit
208 when the command fails (Default=None)
210 retcode = subprocess.call(command, shell=True)
212 if callback_on_error:
214 error("'%s' Failed" % command)
216 def run_make_config(cmd, objdir, callback_on_error=None):
217 """Run the make command in a sub-shell (and exit if it fails).
220 cmd: Make target such as 'config', 'menuconfig', 'defconfig', etc.
221 objdir: Target directory where the make command is run.
222 Typically '', 'spl', 'tpl' for Normal, SPL, TPL image,
224 callback_on_error: Callback handler invoked just before exit
225 when the command fails (Default=None)
227 # Linux expects defconfig files in arch/$(SRCARCH)/configs/ directory,
228 # but U-Boot puts them in configs/ directory.
229 # Give SRCARCH=.. to fake scripts/kconfig/Makefile.
230 options = 'SRCARCH=.. KCONFIG_OBJDIR=%s' % objdir
232 options += ' KCONFIG_CONFIG=%s/%s' % (objdir, KCONFIG_CONFIG)
234 run_command(build % cmd + ' ' + options, callback_on_error)
236 def get_enabled_subimages(ignore_error=False):
237 """Parse .config file to detect if CONFIG_SPL, CONFIG_TPL is enabled
238 and return a tuple of enabled subimages.
241 ignore_error: Specify the behavior when '.config' is not found;
242 Raise an exception if this flag is False.
243 Return a null tuple if this flag is True.
246 A tuple of enabled subimages as follows:
247 () if neither CONFIG_SPL nor CONFIG_TPL is defined
248 ('spl',) if CONFIG_SPL is defined but CONFIG_TPL is not
249 ('spl', 'tpl') if both CONFIG_SPL and CONFIG_TPL are defined
252 match_patterns = [ (img, 'CONFIG_' + img.upper() + '=y\n')
253 for img in SUB_IMAGES ]
255 f = open(KCONFIG_CONFIG)
256 except IOError as exception:
257 if not ignore_error or exception.errno != errno.ENOENT:
262 for img, pattern in match_patterns:
267 def do_silentoldconfig(cmd):
268 """Run 'make silentoldconfig' for all the enabled images.
271 cmd: should always be a string 'silentoldconfig'
273 run_make_config(cmd, '')
274 subimages = get_enabled_subimages()
275 for obj in subimages:
276 mkdirs(os.path.join(obj, 'include', 'config'),
277 os.path.join(obj, 'include', 'generated'))
278 run_make_config(cmd, obj)
279 remove_auto_conf = lambda : rmfiles('include/config/auto.conf')
280 # If the following part failed, include/config/auto.conf should be deleted
281 # so 'make silentoldconfig' will be re-run on the next build.
282 run_command(autoconf %
283 ('include', 'include/autoconf.mk include/autoconf.mk.dep'),
285 # include/config.h has been updated after 'make silentoldconfig'.
286 # We need to touch include/config/auto.conf so it gets newer
287 # than include/config.h.
288 # Otherwise, 'make silentoldconfig' would be invoked twice.
289 os.utime('include/config/auto.conf', None)
290 for obj in subimages:
291 run_command(autoconf % (obj + '/include',
292 obj + '/include/autoconf.mk'),
295 def do_tmp_defconfig(output_lines, img):
296 """Helper function for do_board_defconfig().
298 Write the defconfig contents into a file '.tmp_defconfig' and
299 invoke 'make .tmp_defconfig'.
302 output_lines: A sequence of defconfig lines of each image
303 img: Target image. Typically '', 'spl', 'tpl' for
304 Normal, SPL, TPL images, respectively.
306 TMP_DEFCONFIG = '.tmp_defconfig'
307 TMP_DIRS = ('arch', 'configs')
308 defconfig_path = os.path.join('configs', TMP_DEFCONFIG)
310 with open(defconfig_path, 'w') as f:
311 f.write(''.join(output_lines[img]))
312 cleanup = lambda: (rmfiles(defconfig_path), rmdirs(*TMP_DIRS))
313 run_make_config(TMP_DEFCONFIG, img, cleanup)
316 def do_board_defconfig(cmd):
317 """Run 'make <board>_defconfig'.
320 cmd: should be a string '<board>_defconfig'
322 defconfig_path = os.path.join(srctree, 'configs', cmd)
323 output_lines = dict([ (img, []) for img in IMAGES ])
324 with open(defconfig_path) as f:
326 m = PATTERN_SYMBOL.match(line)
328 for idx, img in enumerate(IMAGES):
330 output_lines[img].append(m.group(4) + '\n')
332 output_lines[''].append(line)
333 do_tmp_defconfig(output_lines, '')
334 for img in get_enabled_subimages():
335 do_tmp_defconfig(output_lines, img)
337 def do_defconfig(cmd):
338 """Run 'make defconfig'.
341 cmd: should always be a string 'defconfig'
343 KBUILD_DEFCONFIG = os.environ['KBUILD_DEFCONFIG']
344 print "*** Default configuration is based on '%s'" % KBUILD_DEFCONFIG
345 do_board_defconfig(KBUILD_DEFCONFIG)
347 def do_savedefconfig(cmd):
348 """Run 'make savedefconfig'.
351 cmd: should always be a string 'savedefconfig'
353 DEFCONFIG = 'defconfig'
354 # Continue even if '.config' does not exist
355 subimages = get_enabled_subimages(True)
356 run_make_config(cmd, '')
359 with open(DEFCONFIG) as f:
361 output_lines.append(line)
363 for img in subimages:
364 run_make_config(cmd, img)
366 with open(DEFCONFIG) as f:
368 if line in output_lines:
369 index = output_lines.index(line)
370 output_lines[index:index] = unmatched_lines
372 prefix[line] += SYMBOL_MAP[img]
374 ummatched_lines.append(line)
375 prefix[line] = SYMBOL_MAP[img]
376 with open(DEFCONFIG, 'w') as f:
377 for line in output_lines:
378 if prefix[line] == '+':
381 f.write(prefix[line] + ':' + line)
384 """Run the make command other than 'silentoldconfig', 'defconfig',
385 '<board>_defconfig' and 'savedefconfig'.
388 cmd: Make target in the form of '<target_image>/<config_command>'
389 The field '<target_image>/' is typically empty, 'spl/', 'tpl/'
390 for Normal, SPL, TPL images, respectively.
391 The field '<config_command>' is make target such as 'config',
394 objdir, _, cmd = cmd.rpartition('/')
395 run_make_config(cmd, objdir)
397 cmd_list = {'silentoldconfig': do_silentoldconfig,
398 'defconfig': do_defconfig,
399 'savedefconfig': do_savedefconfig}
403 if cmd.endswith('_defconfig'):
404 do_board_defconfig(cmd)
406 func = cmd_list.get(cmd, do_others)
409 if __name__ == '__main__':