blob: 749abcb7a51e7dab35114fa784aefe5b81bfe4ed [file] [log] [blame]
Masahiro Yamada51148792014-07-30 14:08:17 +09001#!/usr/bin/env python
2#
3# Copyright (C) 2014, Masahiro Yamada <yamada.m@jp.panasonic.com>
4#
5# SPDX-License-Identifier: GPL-2.0+
6#
7
8"""
9A wrapper script to adjust Kconfig for U-Boot
10
11The biggest difference between Linux Kernel and U-Boot in terms of the
12board configuration is that U-Boot has to configure multiple boot images
13per board: Normal, SPL, TPL.
14We need to expand the functions of Kconfig to handle multiple boot
15images.
16
17Instead of touching various parts under the scripts/kconfig/ directory,
18pushing necessary adjustments into this single script would be better
19for code maintainance. All the make targets related to the configuration
20(make %config) should be invoked via this script.
21
22Let's see what is different from the original Kconfig.
23
24- config, menuconfig, etc.
25
26The commands 'make config', 'make menuconfig', etc. are used to create
27or modify the .config file, which stores configs for Normal boot image.
28
29The location of the one for SPL, TPL image is spl/.config, tpl/.config,
30respectively. Use 'make spl/config', 'make spl/menuconfig', etc.
31to create or modify the spl/.config file, which contains configs
32for SPL image.
33Do likewise for the tpl/.config file.
34The generic syntax for SPL, TPL configuration is
35'make <target_image>/<config_command>'.
36
37- silentoldconfig
38
39The command 'make silentoldconfig' updates .config, if necessary, and
40additionally updates include/generated/autoconf.h and files under
41include/configs/ directory. In U-Boot, it should do the same things for
42SPL, TPL images for boards supporting them.
43Depending on whether CONFIG_SPL, CONFIG_TPL is defined or not,
44'make silentoldconfig' iterates three times at most changing the target
45directory.
46
47To 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)
53
54- defconfig, <board>_defconfig
55
56The command 'make <board>_defconfig' creates a new .config based on the
57file configs/<board>_defconfig. The command 'make defconfig' is the same
58but the difference is it uses the file specified with KBUILD_DEFCONFIG
59environment.
60
61We need to create .config, spl/.config, tpl/.config for boards where SPL
62and TPL images are supported. One possible solution for that is to have
63multiple defconfig files per board, but it would produce duplication
64among the defconfigs.
65The approach chosen here is to expand the feature and support
66conditional definition in defconfig, that is, each line in defconfig
67files has the form of:
68<condition>:<macro definition>
69
70The '<condition>:' prefix specifies which image the line is valid for.
71The '<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
79
80So, if neither CONFIG_SPL nor CONFIG_TPL is defined, the defconfig file
81has no '<condition>:' part and therefore has the same form of that of
82Linux Kernel.
83
84In U-Boot, for example, a defconfig file can be written like this:
85
86 CONFIG_FOO=100
87 S:CONFIG_FOO=200
88 T:CONFIG_FOO=300
89 ST:CONFIG_BAR=y
90 +S:CONFIG_BAZ=y
91 +T:CONFIG_QUX=y
92 +ST:CONFIG_QUUX=y
93
94The defconfig above is parsed by this script and internally divided into
95three temporary defconfig files.
96
97 - Temporary defconfig for Normal image
98 CONFIG_FOO=100
99 CONFIG_BAZ=y
100 CONFIG_QUX=y
101 CONFIG_QUUX=y
102
103 - Temporary defconfig for SPL image
104 CONFIG_FOO=200
105 CONFIG_BAR=y
106 CONFIG_BAZ=y
107 CONFIG_QUUX=y
108
109 - Temporary defconfig for TPL image
110 CONFIG_FOO=300
111 CONFIG_BAR=y
112 CONFIG_QUX=y
113 CONFIG_QUUX=y
114
115They are passed to scripts/kconfig/conf, each is used for generating
116.config, spl/.config, tpl/.config, respectively.
117
118- savedefconfig
119
120This is the reverse operation of 'make defconfig'.
121If neither CONFIG_SPL nor CONFIG_TPL is defined in the .config file,
122it works as 'make savedefconfig' in Linux Kernel: create the minimal set
123of config based on the .config and save it into 'defconfig' file.
124
125If CONFIG_SPL or CONFIG_TPL is defined, the common lines among .config,
126spl/.config, tpl/.config are coalesced together and output to the file
127'defconfig' in the form like:
128
129 CONFIG_FOO=100
130 S:CONFIG_FOO=200
131 T:CONFIG_FOO=300
132 ST:CONFIG_BAR=y
133 +S:CONFIG_BAZ=y
134 +T:CONFIG_QUX=y
135 +ST:CONFIG_QUUX=y
136
137This can be used as an input of 'make <board>_defconfig' command.
138"""
139
140import errno
141import os
142import re
143import subprocess
144import sys
145
146# Constant variables
147SUB_IMAGES = ('spl', 'tpl')
148IMAGES = ('',) + SUB_IMAGES
149SYMBOL_MAP = {'': '+', 'spl': 'S', 'tpl': 'T'}
150PATTERN_SYMBOL = re.compile(r'(\+?)(S?)(T?):(.*)')
151
152# Environment variables (should be defined in the top Makefile)
153# .get('key', 'default_value') method is useful for standalone testing.
154MAKE = os.environ.get('MAKE', 'make')
155srctree = os.environ.get('srctree', '.')
156KCONFIG_CONFIG = os.environ.get('KCONFIG_CONFIG', '.config')
157
158# Useful shorthand
159build = '%s -f %s/scripts/Makefile.build obj=scripts/kconfig %%s' % (MAKE, srctree)
160autoconf = '%s -f %s/scripts/Makefile.autoconf obj=%%s %%s' % (MAKE, srctree)
161
162### helper functions ###
163def mkdirs(*dirs):
164 """Make directories ignoring 'File exists' error."""
165 for d in dirs:
166 try:
167 os.makedirs(d)
168 except OSError as exception:
169 # Ignore 'File exists' error
170 if exception.errno != errno.EEXIST:
171 raise
172
173def rmfiles(*files):
174 """Remove files ignoring 'No such file or directory' error."""
175 for f in files:
176 try:
177 os.remove(f)
178 except OSError as exception:
179 # Ignore 'No such file or directory' error
180 if exception.errno != errno.ENOENT:
181 raise
182
183def rmdirs(*dirs):
184 """Remove directories ignoring 'No such file or directory'
185 and 'Directory not empty' error.
186 """
187 for d in dirs:
188 try:
189 os.rmdir(d)
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:
195 raise
196
197def error(msg):
198 """Output the given argument to stderr and exit with return code 1."""
199 print >> sys.stderr, msg
200 sys.exit(1)
201
202def run_command(command, callback_on_error=None):
203 """Run the given command in a sub-shell (and exit if it fails).
204
205 Arguments:
206 command: A string of the command
207 callback_on_error: Callback handler invoked just before exit
208 when the command fails (Default=None)
209 """
210 retcode = subprocess.call(command, shell=True)
211 if retcode:
212 if callback_on_error:
213 callback_on_error()
214 error("'%s' Failed" % command)
215
216def run_make_config(cmd, objdir, callback_on_error=None):
217 """Run the make command in a sub-shell (and exit if it fails).
218
219 Arguments:
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,
223 respectively.
224 callback_on_error: Callback handler invoked just before exit
225 when the command fails (Default=None)
226 """
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
231 if objdir:
232 options += ' KCONFIG_CONFIG=%s/%s' % (objdir, KCONFIG_CONFIG)
233 mkdirs(objdir)
234 run_command(build % cmd + ' ' + options, callback_on_error)
235
236def 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.
239
240 Arguments:
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.
244
245 Returns:
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
250 """
251 enabled = ()
252 match_patterns = [ (img, 'CONFIG_' + img.upper() + '=y\n')
253 for img in SUB_IMAGES ]
254 try:
255 f = open(KCONFIG_CONFIG)
256 except IOError as exception:
257 if not ignore_error or exception.errno != errno.ENOENT:
258 raise
259 return enabled
260 with f:
261 for line in f:
262 for img, pattern in match_patterns:
263 if line == pattern:
264 enabled += (img,)
265 return enabled
266
267def do_silentoldconfig(cmd):
268 """Run 'make silentoldconfig' for all the enabled images.
269
270 Arguments:
271 cmd: should always be a string 'silentoldconfig'
272 """
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'),
284 remove_auto_conf)
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'),
293 remove_auto_conf)
294
295def do_tmp_defconfig(output_lines, img):
296 """Helper function for do_board_defconfig().
297
298 Write the defconfig contents into a file '.tmp_defconfig' and
299 invoke 'make .tmp_defconfig'.
300
301 Arguments:
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.
305 """
306 TMP_DEFCONFIG = '.tmp_defconfig'
307 TMP_DIRS = ('arch', 'configs')
308 defconfig_path = os.path.join('configs', TMP_DEFCONFIG)
309 mkdirs(*TMP_DIRS)
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)
314 cleanup()
315
316def do_board_defconfig(cmd):
317 """Run 'make <board>_defconfig'.
318
319 Arguments:
320 cmd: should be a string '<board>_defconfig'
321 """
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:
325 for line in f:
326 m = PATTERN_SYMBOL.match(line)
327 if m:
328 for idx, img in enumerate(IMAGES):
329 if m.group(idx + 1):
330 output_lines[img].append(m.group(4) + '\n')
331 continue
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)
336
337def do_defconfig(cmd):
338 """Run 'make defconfig'.
339
340 Arguments:
341 cmd: should always be a string 'defconfig'
342 """
343 KBUILD_DEFCONFIG = os.environ['KBUILD_DEFCONFIG']
344 print "*** Default configuration is based on '%s'" % KBUILD_DEFCONFIG
345 do_board_defconfig(KBUILD_DEFCONFIG)
346
347def do_savedefconfig(cmd):
348 """Run 'make savedefconfig'.
349
350 Arguments:
351 cmd: should always be a string 'savedefconfig'
352 """
353 DEFCONFIG = 'defconfig'
354 # Continue even if '.config' does not exist
355 subimages = get_enabled_subimages(True)
356 run_make_config(cmd, '')
357 output_lines = []
358 prefix = {}
359 with open(DEFCONFIG) as f:
360 for line in f:
361 output_lines.append(line)
362 prefix[line] = '+'
363 for img in subimages:
364 run_make_config(cmd, img)
365 unmatched_lines = []
366 with open(DEFCONFIG) as f:
367 for line in f:
368 if line in output_lines:
369 index = output_lines.index(line)
370 output_lines[index:index] = unmatched_lines
371 unmatched_lines = []
372 prefix[line] += SYMBOL_MAP[img]
373 else:
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] == '+':
379 f.write(line)
380 else:
381 f.write(prefix[line] + ':' + line)
382
383def do_others(cmd):
384 """Run the make command other than 'silentoldconfig', 'defconfig',
385 '<board>_defconfig' and 'savedefconfig'.
386
387 Arguments:
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',
392 'menuconfig', etc.
393 """
394 objdir, _, cmd = cmd.rpartition('/')
395 run_make_config(cmd, objdir)
396
397cmd_list = {'silentoldconfig': do_silentoldconfig,
398 'defconfig': do_defconfig,
399 'savedefconfig': do_savedefconfig}
400
401def main():
402 cmd = sys.argv[1]
403 if cmd.endswith('_defconfig'):
404 do_board_defconfig(cmd)
405 else:
406 func = cmd_list.get(cmd, do_others)
407 func(cmd)
408
409if __name__ == '__main__':
410 main()