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:
197 def run_command(command, callback_on_error=None):
198 """Run the given command in a sub-shell (and exit if it fails).
201 command: A string of the command
202 callback_on_error: Callback handler invoked just before exit
203 when the command fails (Default=None)
205 retcode = subprocess.call(command, shell=True)
207 if callback_on_error:
209 sys.exit("'%s' Failed" % command)
211 def run_make_config(cmd, objdir, callback_on_error=None):
212 """Run the make command in a sub-shell (and exit if it fails).
215 cmd: Make target such as 'config', 'menuconfig', 'defconfig', etc.
216 objdir: Target directory where the make command is run.
217 Typically '', 'spl', 'tpl' for Normal, SPL, TPL image,
219 callback_on_error: Callback handler invoked just before exit
220 when the command fails (Default=None)
222 # Linux expects defconfig files in arch/$(SRCARCH)/configs/ directory,
223 # but U-Boot puts them in configs/ directory.
224 # Give SRCARCH=.. to fake scripts/kconfig/Makefile.
225 options = 'SRCARCH=.. KCONFIG_OBJDIR=%s' % objdir
227 options += ' KCONFIG_CONFIG=%s/%s' % (objdir, KCONFIG_CONFIG)
229 run_command(build % cmd + ' ' + options, callback_on_error)
231 def get_enabled_subimages(ignore_error=False):
232 """Parse .config file to detect if CONFIG_SPL, CONFIG_TPL is enabled
233 and return a tuple of enabled subimages.
236 ignore_error: Specify the behavior when '.config' is not found;
237 Raise an exception if this flag is False.
238 Return a null tuple if this flag is True.
241 A tuple of enabled subimages as follows:
242 () if neither CONFIG_SPL nor CONFIG_TPL is defined
243 ('spl',) if CONFIG_SPL is defined but CONFIG_TPL is not
244 ('spl', 'tpl') if both CONFIG_SPL and CONFIG_TPL are defined
247 match_patterns = [ (img, 'CONFIG_' + img.upper() + '=y\n')
248 for img in SUB_IMAGES ]
250 f = open(KCONFIG_CONFIG)
251 except IOError as exception:
252 if not ignore_error or exception.errno != errno.ENOENT:
257 for img, pattern in match_patterns:
262 def do_silentoldconfig(cmd):
263 """Run 'make silentoldconfig' for all the enabled images.
266 cmd: should always be a string 'silentoldconfig'
268 run_make_config(cmd, '')
269 subimages = get_enabled_subimages()
270 for obj in subimages:
271 mkdirs(os.path.join(obj, 'include', 'config'),
272 os.path.join(obj, 'include', 'generated'))
273 run_make_config(cmd, obj)
274 remove_auto_conf = lambda : rmfiles('include/config/auto.conf')
275 # If the following part failed, include/config/auto.conf should be deleted
276 # so 'make silentoldconfig' will be re-run on the next build.
277 run_command(autoconf %
278 ('include', 'include/autoconf.mk include/autoconf.mk.dep'),
280 # include/config.h has been updated after 'make silentoldconfig'.
281 # We need to touch include/config/auto.conf so it gets newer
282 # than include/config.h.
283 # Otherwise, 'make silentoldconfig' would be invoked twice.
284 os.utime('include/config/auto.conf', None)
285 for obj in subimages:
286 run_command(autoconf % (obj + '/include',
287 obj + '/include/autoconf.mk'),
290 def do_tmp_defconfig(output_lines, img):
291 """Helper function for do_board_defconfig().
293 Write the defconfig contents into a file '.tmp_defconfig' and
294 invoke 'make .tmp_defconfig'.
297 output_lines: A sequence of defconfig lines of each image
298 img: Target image. Typically '', 'spl', 'tpl' for
299 Normal, SPL, TPL images, respectively.
301 TMP_DEFCONFIG = '.tmp_defconfig'
302 TMP_DIRS = ('arch', 'configs')
303 defconfig_path = os.path.join('configs', TMP_DEFCONFIG)
305 with open(defconfig_path, 'w') as f:
306 f.write(''.join(output_lines[img]))
307 cleanup = lambda: (rmfiles(defconfig_path), rmdirs(*TMP_DIRS))
308 run_make_config(TMP_DEFCONFIG, img, cleanup)
311 def do_board_defconfig(cmd):
312 """Run 'make <board>_defconfig'.
315 cmd: should be a string '<board>_defconfig'
317 defconfig_path = os.path.join(srctree, 'configs', cmd)
318 output_lines = dict([ (img, []) for img in IMAGES ])
319 with open(defconfig_path) as f:
321 m = PATTERN_SYMBOL.match(line)
323 for idx, img in enumerate(IMAGES):
325 output_lines[img].append(m.group(4) + '\n')
327 output_lines[''].append(line)
328 do_tmp_defconfig(output_lines, '')
329 for img in get_enabled_subimages():
330 do_tmp_defconfig(output_lines, img)
332 def do_defconfig(cmd):
333 """Run 'make defconfig'.
336 cmd: should always be a string 'defconfig'
338 KBUILD_DEFCONFIG = os.environ['KBUILD_DEFCONFIG']
339 print "*** Default configuration is based on '%s'" % KBUILD_DEFCONFIG
340 do_board_defconfig(KBUILD_DEFCONFIG)
342 def do_savedefconfig(cmd):
343 """Run 'make savedefconfig'.
346 cmd: should always be a string 'savedefconfig'
348 DEFCONFIG = 'defconfig'
349 # Continue even if '.config' does not exist
350 subimages = get_enabled_subimages(True)
351 run_make_config(cmd, '')
354 with open(DEFCONFIG) as f:
356 output_lines.append(line)
358 for img in subimages:
359 run_make_config(cmd, img)
361 with open(DEFCONFIG) as f:
363 if line in output_lines:
364 index = output_lines.index(line)
365 output_lines[index:index] = unmatched_lines
367 prefix[line] += SYMBOL_MAP[img]
369 ummatched_lines.append(line)
370 prefix[line] = SYMBOL_MAP[img]
371 with open(DEFCONFIG, 'w') as f:
372 for line in output_lines:
373 if prefix[line] == '+':
376 f.write(prefix[line] + ':' + line)
379 """Run the make command other than 'silentoldconfig', 'defconfig',
380 '<board>_defconfig' and 'savedefconfig'.
383 cmd: Make target in the form of '<target_image>/<config_command>'
384 The field '<target_image>/' is typically empty, 'spl/', 'tpl/'
385 for Normal, SPL, TPL images, respectively.
386 The field '<config_command>' is make target such as 'config',
389 objdir, _, cmd = cmd.rpartition('/')
390 run_make_config(cmd, objdir)
392 cmd_list = {'silentoldconfig': do_silentoldconfig,
393 'defconfig': do_defconfig,
394 'savedefconfig': do_savedefconfig}
398 if cmd.endswith('_defconfig'):
399 do_board_defconfig(cmd)
401 func = cmd_list.get(cmd, do_others)
404 if __name__ == '__main__':