blob: 228d098d8547ccbc343bb647b5c6f6e9acca8b3f [file] [log] [blame]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001#!/usr/bin/env python2
2#
3# Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4#
5# SPDX-License-Identifier: GPL-2.0+
6#
7
8"""
9Move config options from headers to defconfig files.
10
11Since Kconfig was introduced to U-Boot, we have worked on moving
12config options from headers to Kconfig (defconfig).
13
14This tool intends to help this tremendous work.
15
16
17Usage
18-----
19
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090020First, you must edit the Kconfig to add the menu entries for the configs
Joe Hershberger96464ba2015-05-19 13:21:17 -050021you are moving.
22
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090023And then run this tool giving CONFIG names you want to move.
24For example, if you want to move CONFIG_CMD_USB and CONFIG_SYS_TEXT_BASE,
25simply type as follows:
Masahiro Yamada5a27c732015-05-20 11:36:07 +090026
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090027 $ tools/moveconfig.py CONFIG_CMD_USB CONFIG_SYS_TEXT_BASE
Masahiro Yamada5a27c732015-05-20 11:36:07 +090028
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090029The tool walks through all the defconfig files and move the given CONFIGs.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090030
31The log is also displayed on the terminal.
32
Masahiro Yamada1d085562016-05-19 15:52:02 +090033The log is printed for each defconfig as follows:
Masahiro Yamada5a27c732015-05-20 11:36:07 +090034
Masahiro Yamada1d085562016-05-19 15:52:02 +090035<defconfig_name>
36 <action1>
37 <action2>
38 <action3>
39 ...
Masahiro Yamada5a27c732015-05-20 11:36:07 +090040
Masahiro Yamada1d085562016-05-19 15:52:02 +090041<defconfig_name> is the name of the defconfig.
42
43<action*> shows what the tool did for that defconfig.
Masahiro Yamadac21fc7e2016-08-21 16:12:36 +090044It looks like one of the following:
Masahiro Yamada5a27c732015-05-20 11:36:07 +090045
46 - Move 'CONFIG_... '
47 This config option was moved to the defconfig
48
Masahiro Yamadacc008292016-05-19 15:51:56 +090049 - CONFIG_... is not defined in Kconfig. Do nothing.
Masahiro Yamada916224c2016-08-22 22:18:21 +090050 The entry for this CONFIG was not found in Kconfig. The option is not
51 defined in the config header, either. So, this case can be just skipped.
52
53 - CONFIG_... is not defined in Kconfig (suspicious). Do nothing.
54 This option is defined in the config header, but its entry was not found
55 in Kconfig.
Masahiro Yamadacc008292016-05-19 15:51:56 +090056 There are two common cases:
57 - You forgot to create an entry for the CONFIG before running
58 this tool, or made a typo in a CONFIG passed to this tool.
59 - The entry was hidden due to unmet 'depends on'.
Masahiro Yamada916224c2016-08-22 22:18:21 +090060 The tool does not know if the result is reasonable, so please check it
61 manually.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090062
Masahiro Yamadacc008292016-05-19 15:51:56 +090063 - 'CONFIG_...' is the same as the define in Kconfig. Do nothing.
64 The define in the config header matched the one in Kconfig.
65 We do not need to touch it.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090066
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +090067 - Compiler is missing. Do nothing.
68 The compiler specified for this architecture was not found
69 in your PATH environment.
70 (If -e option is passed, the tool exits immediately.)
71
72 - Failed to process.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090073 An error occurred during processing this defconfig. Skipped.
74 (If -e option is passed, the tool exits immediately on error.)
75
76Finally, you will be asked, Clean up headers? [y/n]:
77
78If you say 'y' here, the unnecessary config defines are removed
79from the config headers (include/configs/*.h).
80It just uses the regex method, so you should not rely on it.
81Just in case, please do 'git diff' to see what happened.
82
83
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090084How does it work?
85-----------------
Masahiro Yamada5a27c732015-05-20 11:36:07 +090086
87This tool runs configuration and builds include/autoconf.mk for every
88defconfig. The config options defined in Kconfig appear in the .config
89file (unless they are hidden because of unmet dependency.)
90On the other hand, the config options defined by board headers are seen
91in include/autoconf.mk. The tool looks for the specified options in both
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090092of them to decide the appropriate action for the options. If the given
93config option is found in the .config, but its value does not match the
94one from the board header, the config option in the .config is replaced
95with the define in the board header. Then, the .config is synced by
96"make savedefconfig" and the defconfig is updated with it.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090097
98For faster processing, this tool handles multi-threading. It creates
99separate build directories where the out-of-tree build is run. The
100temporary build directories are automatically created and deleted as
101needed. The number of threads are chosen based on the number of the CPU
102cores of your system although you can change it via -j (--jobs) option.
103
104
105Toolchains
106----------
107
108Appropriate toolchain are necessary to generate include/autoconf.mk
109for all the architectures supported by U-Boot. Most of them are available
110at the kernel.org site, some are not provided by kernel.org.
111
112The default per-arch CROSS_COMPILE used by this tool is specified by
113the list below, CROSS_COMPILE. You may wish to update the list to
114use your own. Instead of modifying the list directly, you can give
115them via environments.
116
117
118Available options
119-----------------
120
121 -c, --color
122 Surround each portion of the log with escape sequences to display it
123 in color on the terminal.
124
Simon Glass9ede2122016-09-12 23:18:21 -0600125 -C, --commit
126 Create a git commit with the changes when the operation is complete. A
127 standard commit message is used which may need to be edited.
128
Joe Hershberger91040e82015-05-19 13:21:19 -0500129 -d, --defconfigs
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900130 Specify a file containing a list of defconfigs to move. The defconfig
131 files can be given with shell-style wildcards.
Joe Hershberger91040e82015-05-19 13:21:19 -0500132
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900133 -n, --dry-run
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900134 Perform a trial run that does not make any changes. It is useful to
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900135 see what is going to happen before one actually runs it.
136
137 -e, --exit-on-error
138 Exit immediately if Make exits with a non-zero status while processing
139 a defconfig file.
140
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900141 -s, --force-sync
142 Do "make savedefconfig" forcibly for all the defconfig files.
143 If not specified, "make savedefconfig" only occurs for cases
144 where at least one CONFIG was moved.
145
Masahiro Yamada07913d12016-08-22 22:18:22 +0900146 -S, --spl
147 Look for moved config options in spl/include/autoconf.mk instead of
148 include/autoconf.mk. This is useful for moving options for SPL build
149 because SPL related options (mostly prefixed with CONFIG_SPL_) are
150 sometimes blocked by CONFIG_SPL_BUILD ifdef conditionals.
151
Joe Hershberger2144f882015-05-19 13:21:20 -0500152 -H, --headers-only
153 Only cleanup the headers; skip the defconfig processing
154
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900155 -j, --jobs
156 Specify the number of threads to run simultaneously. If not specified,
157 the number of threads is the same as the number of CPU cores.
158
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500159 -r, --git-ref
160 Specify the git ref to clone for building the autoconf.mk. If unspecified
161 use the CWD. This is useful for when changes to the Kconfig affect the
162 default values and you want to capture the state of the defconfig from
163 before that change was in effect. If in doubt, specify a ref pre-Kconfig
164 changes (use HEAD if Kconfig changes are not committed). Worst case it will
165 take a bit longer to run, but will always do the right thing.
166
Joe Hershberger95bf9c72015-05-19 13:21:24 -0500167 -v, --verbose
168 Show any build errors as boards are built
169
Simon Glass6b403df2016-09-12 23:18:20 -0600170 -y, --yes
171 Instead of prompting, automatically go ahead with all operations. This
172 includes cleaning up headers and CONFIG_SYS_EXTRA_OPTIONS.
173
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900174To see the complete list of supported options, run
175
176 $ tools/moveconfig.py -h
177
178"""
179
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900180import copy
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900181import difflib
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900182import filecmp
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900183import fnmatch
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900184import glob
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900185import multiprocessing
186import optparse
187import os
188import re
189import shutil
190import subprocess
191import sys
192import tempfile
193import time
194
195SHOW_GNU_MAKE = 'scripts/show-gnu-make'
196SLEEP_TIME=0.03
197
198# Here is the list of cross-tools I use.
199# Most of them are available at kernel.org
Masahiro Yamadac21fc7e2016-08-21 16:12:36 +0900200# (https://www.kernel.org/pub/tools/crosstool/files/bin/), except the following:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900201# arc: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases
202# blackfin: http://sourceforge.net/projects/adi-toolchain/files/
Bin Meng4440ece2015-09-25 01:22:39 -0700203# nds32: http://osdk.andestech.com/packages/nds32le-linux-glibc-v1.tgz
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900204# nios2: https://sourcery.mentor.com/GNUToolchain/subscription42545
205# sh: http://sourcery.mentor.com/public/gnu_toolchain/sh-linux-gnu
Bin Menge8aebc42016-02-21 21:18:02 -0800206#
207# openrisc kernel.org toolchain is out of date, download latest one from
208# http://opencores.org/or1k/OpenRISC_GNU_tool_chain#Prebuilt_versions
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900209CROSS_COMPILE = {
210 'arc': 'arc-linux-',
211 'aarch64': 'aarch64-linux-',
212 'arm': 'arm-unknown-linux-gnueabi-',
213 'avr32': 'avr32-linux-',
214 'blackfin': 'bfin-elf-',
215 'm68k': 'm68k-linux-',
216 'microblaze': 'microblaze-linux-',
217 'mips': 'mips-linux-',
218 'nds32': 'nds32le-linux-',
219 'nios2': 'nios2-linux-gnu-',
Bin Menge8aebc42016-02-21 21:18:02 -0800220 'openrisc': 'or1k-elf-',
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900221 'powerpc': 'powerpc-linux-',
222 'sh': 'sh-linux-gnu-',
223 'sparc': 'sparc-linux-',
Masahiro Yamada88e13462016-08-21 16:03:08 +0900224 'x86': 'i386-linux-',
225 'xtensa': 'xtensa-linux-'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900226}
227
228STATE_IDLE = 0
229STATE_DEFCONFIG = 1
230STATE_AUTOCONF = 2
Joe Hershberger96464ba2015-05-19 13:21:17 -0500231STATE_SAVEDEFCONFIG = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900232
233ACTION_MOVE = 0
Masahiro Yamadacc008292016-05-19 15:51:56 +0900234ACTION_NO_ENTRY = 1
Masahiro Yamada916224c2016-08-22 22:18:21 +0900235ACTION_NO_ENTRY_WARN = 2
236ACTION_NO_CHANGE = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900237
238COLOR_BLACK = '0;30'
239COLOR_RED = '0;31'
240COLOR_GREEN = '0;32'
241COLOR_BROWN = '0;33'
242COLOR_BLUE = '0;34'
243COLOR_PURPLE = '0;35'
244COLOR_CYAN = '0;36'
245COLOR_LIGHT_GRAY = '0;37'
246COLOR_DARK_GRAY = '1;30'
247COLOR_LIGHT_RED = '1;31'
248COLOR_LIGHT_GREEN = '1;32'
249COLOR_YELLOW = '1;33'
250COLOR_LIGHT_BLUE = '1;34'
251COLOR_LIGHT_PURPLE = '1;35'
252COLOR_LIGHT_CYAN = '1;36'
253COLOR_WHITE = '1;37'
254
255### helper functions ###
256def get_devnull():
257 """Get the file object of '/dev/null' device."""
258 try:
259 devnull = subprocess.DEVNULL # py3k
260 except AttributeError:
261 devnull = open(os.devnull, 'wb')
262 return devnull
263
264def check_top_directory():
265 """Exit if we are not at the top of source directory."""
266 for f in ('README', 'Licenses'):
267 if not os.path.exists(f):
268 sys.exit('Please run at the top of source directory.')
269
Masahiro Yamadabd63e5b2016-05-19 15:51:54 +0900270def check_clean_directory():
271 """Exit if the source tree is not clean."""
272 for f in ('.config', 'include/config'):
273 if os.path.exists(f):
274 sys.exit("source tree is not clean, please run 'make mrproper'")
275
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900276def get_make_cmd():
277 """Get the command name of GNU Make.
278
279 U-Boot needs GNU Make for building, but the command name is not
280 necessarily "make". (for example, "gmake" on FreeBSD).
281 Returns the most appropriate command name on your system.
282 """
283 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
284 ret = process.communicate()
285 if process.returncode:
286 sys.exit('GNU Make not found')
287 return ret[0].rstrip()
288
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900289def get_matched_defconfigs(defconfigs_file):
290 """Get all the defconfig files that match the patterns in a file."""
291 defconfigs = []
292 for i, line in enumerate(open(defconfigs_file)):
293 line = line.strip()
294 if not line:
295 continue # skip blank lines silently
296 pattern = os.path.join('configs', line)
297 matched = glob.glob(pattern) + glob.glob(pattern + '_defconfig')
298 if not matched:
299 print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \
300 (defconfigs_file, i + 1, line)
301
302 defconfigs += matched
303
304 # use set() to drop multiple matching
305 return [ defconfig[len('configs') + 1:] for defconfig in set(defconfigs) ]
306
Masahiro Yamada684c3062016-07-25 19:15:28 +0900307def get_all_defconfigs():
308 """Get all the defconfig files under the configs/ directory."""
309 defconfigs = []
310 for (dirpath, dirnames, filenames) in os.walk('configs'):
311 dirpath = dirpath[len('configs') + 1:]
312 for filename in fnmatch.filter(filenames, '*_defconfig'):
313 defconfigs.append(os.path.join(dirpath, filename))
314
315 return defconfigs
316
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900317def color_text(color_enabled, color, string):
318 """Return colored string."""
319 if color_enabled:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900320 # LF should not be surrounded by the escape sequence.
321 # Otherwise, additional whitespace or line-feed might be printed.
322 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
323 for s in string.split('\n') ])
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900324 else:
325 return string
326
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900327def show_diff(a, b, file_path, color_enabled):
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900328 """Show unidified diff.
329
330 Arguments:
331 a: A list of lines (before)
332 b: A list of lines (after)
333 file_path: Path to the file
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900334 color_enabled: Display the diff in color
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900335 """
336
337 diff = difflib.unified_diff(a, b,
338 fromfile=os.path.join('a', file_path),
339 tofile=os.path.join('b', file_path))
340
341 for line in diff:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900342 if line[0] == '-' and line[1] != '-':
343 print color_text(color_enabled, COLOR_RED, line),
344 elif line[0] == '+' and line[1] != '+':
345 print color_text(color_enabled, COLOR_GREEN, line),
346 else:
347 print line,
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900348
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900349def update_cross_compile(color_enabled):
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400350 """Update per-arch CROSS_COMPILE via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900351
352 The default CROSS_COMPILE values are available
353 in the CROSS_COMPILE list above.
354
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400355 You can override them via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900356 CROSS_COMPILE_{ARCH}.
357
358 For example, if you want to override toolchain prefixes
359 for ARM and PowerPC, you can do as follows in your shell:
360
361 export CROSS_COMPILE_ARM=...
362 export CROSS_COMPILE_POWERPC=...
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900363
364 Then, this function checks if specified compilers really exist in your
365 PATH environment.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900366 """
367 archs = []
368
369 for arch in os.listdir('arch'):
370 if os.path.exists(os.path.join('arch', arch, 'Makefile')):
371 archs.append(arch)
372
373 # arm64 is a special case
374 archs.append('aarch64')
375
376 for arch in archs:
377 env = 'CROSS_COMPILE_' + arch.upper()
378 cross_compile = os.environ.get(env)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900379 if not cross_compile:
380 cross_compile = CROSS_COMPILE.get(arch, '')
381
382 for path in os.environ["PATH"].split(os.pathsep):
383 gcc_path = os.path.join(path, cross_compile + 'gcc')
384 if os.path.isfile(gcc_path) and os.access(gcc_path, os.X_OK):
385 break
386 else:
387 print >> sys.stderr, color_text(color_enabled, COLOR_YELLOW,
388 'warning: %sgcc: not found in PATH. %s architecture boards will be skipped'
389 % (cross_compile, arch))
390 cross_compile = None
391
392 CROSS_COMPILE[arch] = cross_compile
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900393
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900394def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
395 extend_post):
396 """Extend matched lines if desired patterns are found before/after already
397 matched lines.
398
399 Arguments:
400 lines: A list of lines handled.
401 matched: A list of line numbers that have been already matched.
402 (will be updated by this function)
403 pre_patterns: A list of regular expression that should be matched as
404 preamble.
405 post_patterns: A list of regular expression that should be matched as
406 postamble.
407 extend_pre: Add the line number of matched preamble to the matched list.
408 extend_post: Add the line number of matched postamble to the matched list.
409 """
410 extended_matched = []
411
412 j = matched[0]
413
414 for i in matched:
415 if i == 0 or i < j:
416 continue
417 j = i
418 while j in matched:
419 j += 1
420 if j >= len(lines):
421 break
422
423 for p in pre_patterns:
424 if p.search(lines[i - 1]):
425 break
426 else:
427 # not matched
428 continue
429
430 for p in post_patterns:
431 if p.search(lines[j]):
432 break
433 else:
434 # not matched
435 continue
436
437 if extend_pre:
438 extended_matched.append(i - 1)
439 if extend_post:
440 extended_matched.append(j)
441
442 matched += extended_matched
443 matched.sort()
444
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900445def cleanup_one_header(header_path, patterns, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900446 """Clean regex-matched lines away from a file.
447
448 Arguments:
449 header_path: path to the cleaned file.
450 patterns: list of regex patterns. Any lines matching to these
451 patterns are deleted.
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900452 options: option flags.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900453 """
454 with open(header_path) as f:
455 lines = f.readlines()
456
457 matched = []
458 for i, line in enumerate(lines):
Masahiro Yamadaa3a779f2016-07-25 19:15:27 +0900459 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
460 matched.append(i)
461 continue
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900462 for pattern in patterns:
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900463 if pattern.search(line):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900464 matched.append(i)
465 break
466
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900467 if not matched:
468 return
469
470 # remove empty #ifdef ... #endif, successive blank lines
471 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
472 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
473 pattern_endif = re.compile(r'#\s*endif\W') # #endif
474 pattern_blank = re.compile(r'^\s*$') # empty line
475
476 while True:
477 old_matched = copy.copy(matched)
478 extend_matched_lines(lines, matched, [pattern_if],
479 [pattern_endif], True, True)
480 extend_matched_lines(lines, matched, [pattern_elif],
481 [pattern_elif, pattern_endif], True, False)
482 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
483 [pattern_blank], False, True)
484 extend_matched_lines(lines, matched, [pattern_blank],
485 [pattern_elif, pattern_endif], True, False)
486 extend_matched_lines(lines, matched, [pattern_blank],
487 [pattern_blank], True, False)
488 if matched == old_matched:
489 break
490
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900491 tolines = copy.copy(lines)
492
493 for i in reversed(matched):
494 tolines.pop(i)
495
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900496 show_diff(lines, tolines, header_path, options.color)
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900497
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900498 if options.dry_run:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900499 return
500
501 with open(header_path, 'w') as f:
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900502 for line in tolines:
503 f.write(line)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900504
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900505def cleanup_headers(configs, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900506 """Delete config defines from board headers.
507
508 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900509 configs: A list of CONFIGs to remove.
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900510 options: option flags.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900511 """
Simon Glass6b403df2016-09-12 23:18:20 -0600512 if not options.yes:
513 while True:
514 choice = raw_input('Clean up headers? [y/n]: ').lower()
515 print choice
516 if choice == 'y' or choice == 'n':
517 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900518
Simon Glass6b403df2016-09-12 23:18:20 -0600519 if choice == 'n':
520 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900521
522 patterns = []
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900523 for config in configs:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900524 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
525 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
526
Joe Hershberger60727f52015-05-19 13:21:21 -0500527 for dir in 'include', 'arch', 'board':
528 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamadadc6de502016-07-25 19:15:22 +0900529 if dirpath == os.path.join('include', 'generated'):
530 continue
Joe Hershberger60727f52015-05-19 13:21:21 -0500531 for filename in filenames:
532 if not fnmatch.fnmatch(filename, '*~'):
533 cleanup_one_header(os.path.join(dirpath, filename),
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900534 patterns, options)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900535
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900536def cleanup_one_extra_option(defconfig_path, configs, options):
537 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
538
539 Arguments:
540 defconfig_path: path to the cleaned defconfig file.
541 configs: A list of CONFIGs to remove.
542 options: option flags.
543 """
544
545 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
546 end = '"\n'
547
548 with open(defconfig_path) as f:
549 lines = f.readlines()
550
551 for i, line in enumerate(lines):
552 if line.startswith(start) and line.endswith(end):
553 break
554 else:
555 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
556 return
557
558 old_tokens = line[len(start):-len(end)].split(',')
559 new_tokens = []
560
561 for token in old_tokens:
562 pos = token.find('=')
563 if not (token[:pos] if pos >= 0 else token) in configs:
564 new_tokens.append(token)
565
566 if new_tokens == old_tokens:
567 return
568
569 tolines = copy.copy(lines)
570
571 if new_tokens:
572 tolines[i] = start + ','.join(new_tokens) + end
573 else:
574 tolines.pop(i)
575
576 show_diff(lines, tolines, defconfig_path, options.color)
577
578 if options.dry_run:
579 return
580
581 with open(defconfig_path, 'w') as f:
582 for line in tolines:
583 f.write(line)
584
585def cleanup_extra_options(configs, options):
586 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
587
588 Arguments:
589 configs: A list of CONFIGs to remove.
590 options: option flags.
591 """
Simon Glass6b403df2016-09-12 23:18:20 -0600592 if not options.yes:
593 while True:
594 choice = (raw_input('Clean up CONFIG_SYS_EXTRA_OPTIONS? [y/n]: ').
595 lower())
596 print choice
597 if choice == 'y' or choice == 'n':
598 break
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900599
Simon Glass6b403df2016-09-12 23:18:20 -0600600 if choice == 'n':
601 return
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900602
603 configs = [ config[len('CONFIG_'):] for config in configs ]
604
605 defconfigs = get_all_defconfigs()
606
607 for defconfig in defconfigs:
608 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
609 options)
610
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900611### classes ###
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900612class Progress:
613
614 """Progress Indicator"""
615
616 def __init__(self, total):
617 """Create a new progress indicator.
618
619 Arguments:
620 total: A number of defconfig files to process.
621 """
622 self.current = 0
623 self.total = total
624
625 def inc(self):
626 """Increment the number of processed defconfig files."""
627
628 self.current += 1
629
630 def show(self):
631 """Display the progress."""
632 print ' %d defconfigs out of %d\r' % (self.current, self.total),
633 sys.stdout.flush()
634
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900635class KconfigParser:
636
637 """A parser of .config and include/autoconf.mk."""
638
639 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
640 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
641
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900642 def __init__(self, configs, options, build_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900643 """Create a new parser.
644
645 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900646 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900647 options: option flags.
648 build_dir: Build directory.
649 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900650 self.configs = configs
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900651 self.options = options
Masahiro Yamada1f169922016-05-19 15:52:00 +0900652 self.dotconfig = os.path.join(build_dir, '.config')
653 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada07913d12016-08-22 22:18:22 +0900654 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
655 'autoconf.mk')
Masahiro Yamada1f169922016-05-19 15:52:00 +0900656 self.config_autoconf = os.path.join(build_dir, 'include', 'config',
657 'auto.conf')
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900658 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900659
660 def get_cross_compile(self):
661 """Parse .config file and return CROSS_COMPILE.
662
663 Returns:
664 A string storing the compiler prefix for the architecture.
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900665 Return a NULL string for architectures that do not require
666 compiler prefix (Sandbox and native build is the case).
667 Return None if the specified compiler is missing in your PATH.
668 Caller should distinguish '' and None.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900669 """
670 arch = ''
671 cpu = ''
Masahiro Yamada1f169922016-05-19 15:52:00 +0900672 for line in open(self.dotconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900673 m = self.re_arch.match(line)
674 if m:
675 arch = m.group(1)
676 continue
677 m = self.re_cpu.match(line)
678 if m:
679 cpu = m.group(1)
680
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900681 if not arch:
682 return None
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900683
684 # fix-up for aarch64
685 if arch == 'arm' and cpu == 'armv8':
686 arch = 'aarch64'
687
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900688 return CROSS_COMPILE.get(arch, None)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900689
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900690 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900691 """Parse .config, defconfig, include/autoconf.mk for one config.
692
693 This function looks for the config options in the lines from
694 defconfig, .config, and include/autoconf.mk in order to decide
695 which action should be taken for this defconfig.
696
697 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900698 config: CONFIG name to parse.
Masahiro Yamadacc008292016-05-19 15:51:56 +0900699 dotconfig_lines: lines from the .config file.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900700 autoconf_lines: lines from the include/autoconf.mk file.
701
702 Returns:
703 A tupple of the action for this defconfig and the line
704 matched for the config.
705 """
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900706 not_set = '# %s is not set' % config
707
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900708 for line in autoconf_lines:
709 line = line.rstrip()
710 if line.startswith(config + '='):
Masahiro Yamadacc008292016-05-19 15:51:56 +0900711 new_val = line
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900712 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900713 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900714 new_val = not_set
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900715
Masahiro Yamada916224c2016-08-22 22:18:21 +0900716 for line in dotconfig_lines:
717 line = line.rstrip()
718 if line.startswith(config + '=') or line == not_set:
719 old_val = line
720 break
721 else:
722 if new_val == not_set:
723 return (ACTION_NO_ENTRY, config)
724 else:
725 return (ACTION_NO_ENTRY_WARN, config)
726
Masahiro Yamadacc008292016-05-19 15:51:56 +0900727 # If this CONFIG is neither bool nor trisate
728 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
729 # tools/scripts/define2mk.sed changes '1' to 'y'.
730 # This is a problem if the CONFIG is int type.
731 # Check the type in Kconfig and handle it correctly.
732 if new_val[-2:] == '=y':
733 new_val = new_val[:-1] + '1'
734
Masahiro Yamada50301592016-06-15 14:33:50 +0900735 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
736 new_val)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900737
Masahiro Yamada1d085562016-05-19 15:52:02 +0900738 def update_dotconfig(self):
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900739 """Parse files for the config options and update the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900740
Masahiro Yamadacc008292016-05-19 15:51:56 +0900741 This function parses the generated .config and include/autoconf.mk
742 searching the target options.
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900743 Move the config option(s) to the .config as needed.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900744
745 Arguments:
746 defconfig: defconfig name.
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900747
748 Returns:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900749 Return a tuple of (updated flag, log string).
750 The "updated flag" is True if the .config was updated, False
751 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900752 """
753
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900754 results = []
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900755 updated = False
Masahiro Yamada916224c2016-08-22 22:18:21 +0900756 suspicious = False
Masahiro Yamada07913d12016-08-22 22:18:22 +0900757 rm_files = [self.config_autoconf, self.autoconf]
758
759 if self.options.spl:
760 if os.path.exists(self.spl_autoconf):
761 autoconf_path = self.spl_autoconf
762 rm_files.append(self.spl_autoconf)
763 else:
764 for f in rm_files:
765 os.remove(f)
766 return (updated, suspicious,
767 color_text(self.options.color, COLOR_BROWN,
768 "SPL is not enabled. Skipped.") + '\n')
769 else:
770 autoconf_path = self.autoconf
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900771
Masahiro Yamada1f169922016-05-19 15:52:00 +0900772 with open(self.dotconfig) as f:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900773 dotconfig_lines = f.readlines()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900774
Masahiro Yamada07913d12016-08-22 22:18:22 +0900775 with open(autoconf_path) as f:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900776 autoconf_lines = f.readlines()
777
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900778 for config in self.configs:
779 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger96464ba2015-05-19 13:21:17 -0500780 autoconf_lines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900781 results.append(result)
782
783 log = ''
784
785 for (action, value) in results:
786 if action == ACTION_MOVE:
787 actlog = "Move '%s'" % value
788 log_color = COLOR_LIGHT_GREEN
Masahiro Yamadacc008292016-05-19 15:51:56 +0900789 elif action == ACTION_NO_ENTRY:
790 actlog = "%s is not defined in Kconfig. Do nothing." % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900791 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada916224c2016-08-22 22:18:21 +0900792 elif action == ACTION_NO_ENTRY_WARN:
793 actlog = "%s is not defined in Kconfig (suspicious). Do nothing." % value
794 log_color = COLOR_YELLOW
795 suspicious = True
Masahiro Yamadacc008292016-05-19 15:51:56 +0900796 elif action == ACTION_NO_CHANGE:
797 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
798 % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900799 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada07913d12016-08-22 22:18:22 +0900800 elif action == ACTION_SPL_NOT_EXIST:
801 actlog = "SPL is not enabled for this defconfig. Skip."
802 log_color = COLOR_PURPLE
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900803 else:
804 sys.exit("Internal Error. This should not happen.")
805
Masahiro Yamada1d085562016-05-19 15:52:02 +0900806 log += color_text(self.options.color, log_color, actlog) + '\n'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900807
Masahiro Yamada1f169922016-05-19 15:52:00 +0900808 with open(self.dotconfig, 'a') as f:
Masahiro Yamadae423d172016-05-19 15:51:49 +0900809 for (action, value) in results:
810 if action == ACTION_MOVE:
811 f.write(value + '\n')
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900812 updated = True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900813
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900814 self.results = results
Masahiro Yamada07913d12016-08-22 22:18:22 +0900815 for f in rm_files:
816 os.remove(f)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900817
Masahiro Yamada916224c2016-08-22 22:18:21 +0900818 return (updated, suspicious, log)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900819
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900820 def check_defconfig(self):
821 """Check the defconfig after savedefconfig
822
823 Returns:
824 Return additional log if moved CONFIGs were removed again by
825 'make savedefconfig'.
826 """
827
828 log = ''
829
830 with open(self.defconfig) as f:
831 defconfig_lines = f.readlines()
832
833 for (action, value) in self.results:
834 if action != ACTION_MOVE:
835 continue
836 if not value + '\n' in defconfig_lines:
837 log += color_text(self.options.color, COLOR_YELLOW,
838 "'%s' was removed by savedefconfig.\n" %
839 value)
840
841 return log
842
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900843class Slot:
844
845 """A slot to store a subprocess.
846
847 Each instance of this class handles one subprocess.
848 This class is useful to control multiple threads
849 for faster processing.
850 """
851
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500852 def __init__(self, configs, options, progress, devnull, make_cmd, reference_src_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900853 """Create a new process slot.
854
855 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900856 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900857 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900858 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900859 devnull: A file object of '/dev/null'.
860 make_cmd: command name of GNU Make.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500861 reference_src_dir: Determine the true starting config state from this
862 source tree.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900863 """
864 self.options = options
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900865 self.progress = progress
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900866 self.build_dir = tempfile.mkdtemp()
867 self.devnull = devnull
868 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500869 self.reference_src_dir = reference_src_dir
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900870 self.parser = KconfigParser(configs, options, self.build_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900871 self.state = STATE_IDLE
Masahiro Yamada09c6c062016-08-22 22:18:20 +0900872 self.failed_boards = set()
873 self.suspicious_boards = set()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900874
875 def __del__(self):
876 """Delete the working directory
877
878 This function makes sure the temporary directory is cleaned away
879 even if Python suddenly dies due to error. It should be done in here
Joe Hershbergerf2dae752016-06-10 14:53:29 -0500880 because it is guaranteed the destructor is always invoked when the
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900881 instance of the class gets unreferenced.
882
883 If the subprocess is still running, wait until it finishes.
884 """
885 if self.state != STATE_IDLE:
886 while self.ps.poll() == None:
887 pass
888 shutil.rmtree(self.build_dir)
889
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900890 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900891 """Assign a new subprocess for defconfig and add it to the slot.
892
893 If the slot is vacant, create a new subprocess for processing the
894 given defconfig and add it to the slot. Just returns False if
895 the slot is occupied (i.e. the current subprocess is still running).
896
897 Arguments:
898 defconfig: defconfig name.
899
900 Returns:
901 Return True on success or False on failure
902 """
903 if self.state != STATE_IDLE:
904 return False
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900905
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900906 self.defconfig = defconfig
Masahiro Yamada1d085562016-05-19 15:52:02 +0900907 self.log = ''
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900908 self.current_src_dir = self.reference_src_dir
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900909 self.do_defconfig()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900910 return True
911
912 def poll(self):
913 """Check the status of the subprocess and handle it as needed.
914
915 Returns True if the slot is vacant (i.e. in idle state).
916 If the configuration is successfully finished, assign a new
917 subprocess to build include/autoconf.mk.
918 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900919 parse the .config and the include/autoconf.mk, moving
920 config options to the .config as needed.
921 If the .config was updated, run "make savedefconfig" to sync
922 it, update the original defconfig, and then set the slot back
923 to the idle state.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900924
925 Returns:
926 Return True if the subprocess is terminated, False otherwise
927 """
928 if self.state == STATE_IDLE:
929 return True
930
931 if self.ps.poll() == None:
932 return False
933
934 if self.ps.poll() != 0:
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900935 self.handle_error()
936 elif self.state == STATE_DEFCONFIG:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900937 if self.reference_src_dir and not self.current_src_dir:
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500938 self.do_savedefconfig()
939 else:
940 self.do_autoconf()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900941 elif self.state == STATE_AUTOCONF:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900942 if self.current_src_dir:
943 self.current_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500944 self.do_defconfig()
945 else:
946 self.do_savedefconfig()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900947 elif self.state == STATE_SAVEDEFCONFIG:
948 self.update_defconfig()
949 else:
950 sys.exit("Internal Error. This should not happen.")
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900951
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900952 return True if self.state == STATE_IDLE else False
Joe Hershberger96464ba2015-05-19 13:21:17 -0500953
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900954 def handle_error(self):
955 """Handle error cases."""
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900956
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900957 self.log += color_text(self.options.color, COLOR_LIGHT_RED,
958 "Failed to process.\n")
959 if self.options.verbose:
960 self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
961 self.ps.stderr.read())
962 self.finish(False)
Joe Hershberger96464ba2015-05-19 13:21:17 -0500963
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900964 def do_defconfig(self):
965 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900966
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900967 cmd = list(self.make_cmd)
968 cmd.append(self.defconfig)
969 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900970 stderr=subprocess.PIPE,
971 cwd=self.current_src_dir)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900972 self.state = STATE_DEFCONFIG
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900973
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900974 def do_autoconf(self):
975 """Run 'make include/config/auto.conf'."""
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900976
Joe Hershberger25400092015-05-19 13:21:23 -0500977 self.cross_compile = self.parser.get_cross_compile()
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900978 if self.cross_compile is None:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900979 self.log += color_text(self.options.color, COLOR_YELLOW,
980 "Compiler is missing. Do nothing.\n")
Masahiro Yamada4efef992016-05-19 15:52:03 +0900981 self.finish(False)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900982 return
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900983
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900984 cmd = list(self.make_cmd)
Joe Hershberger25400092015-05-19 13:21:23 -0500985 if self.cross_compile:
986 cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
Joe Hershberger7740f652015-05-19 13:21:18 -0500987 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900988 cmd.append('include/config/auto.conf')
Joe Hershberger25400092015-05-19 13:21:23 -0500989 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900990 stderr=subprocess.PIPE,
991 cwd=self.current_src_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900992 self.state = STATE_AUTOCONF
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900993
994 def do_savedefconfig(self):
995 """Update the .config and run 'make savedefconfig'."""
996
Masahiro Yamada916224c2016-08-22 22:18:21 +0900997 (updated, suspicious, log) = self.parser.update_dotconfig()
998 if suspicious:
999 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001000 self.log += log
1001
1002 if not self.options.force_sync and not updated:
1003 self.finish(True)
1004 return
1005 if updated:
1006 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
1007 "Syncing by savedefconfig...\n")
1008 else:
1009 self.log += "Syncing by savedefconfig (forced by option)...\n"
1010
1011 cmd = list(self.make_cmd)
1012 cmd.append('savedefconfig')
1013 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1014 stderr=subprocess.PIPE)
1015 self.state = STATE_SAVEDEFCONFIG
1016
1017 def update_defconfig(self):
1018 """Update the input defconfig and go back to the idle state."""
1019
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001020 log = self.parser.check_defconfig()
1021 if log:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001022 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001023 self.log += log
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001024 orig_defconfig = os.path.join('configs', self.defconfig)
1025 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1026 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1027
1028 if updated:
Joe Hershberger06cc1d32016-06-10 14:53:30 -05001029 self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001030 "defconfig was updated.\n")
1031
1032 if not self.options.dry_run and updated:
1033 shutil.move(new_defconfig, orig_defconfig)
1034 self.finish(True)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001035
Masahiro Yamada4efef992016-05-19 15:52:03 +09001036 def finish(self, success):
1037 """Display log along with progress and go to the idle state.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001038
1039 Arguments:
Masahiro Yamada4efef992016-05-19 15:52:03 +09001040 success: Should be True when the defconfig was processed
1041 successfully, or False when it fails.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001042 """
1043 # output at least 30 characters to hide the "* defconfigs out of *".
1044 log = self.defconfig.ljust(30) + '\n'
1045
1046 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1047 # Some threads are running in parallel.
1048 # Print log atomically to not mix up logs from different threads.
Masahiro Yamada4efef992016-05-19 15:52:03 +09001049 print >> (sys.stdout if success else sys.stderr), log
1050
1051 if not success:
1052 if self.options.exit_on_error:
1053 sys.exit("Exit on error.")
1054 # If --exit-on-error flag is not set, skip this board and continue.
1055 # Record the failed board.
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001056 self.failed_boards.add(self.defconfig)
Masahiro Yamada4efef992016-05-19 15:52:03 +09001057
Masahiro Yamada1d085562016-05-19 15:52:02 +09001058 self.progress.inc()
1059 self.progress.show()
Masahiro Yamada4efef992016-05-19 15:52:03 +09001060 self.state = STATE_IDLE
Masahiro Yamada1d085562016-05-19 15:52:02 +09001061
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001062 def get_failed_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001063 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001064 """
1065 return self.failed_boards
1066
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001067 def get_suspicious_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001068 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001069 """
Masahiro Yamada916224c2016-08-22 22:18:21 +09001070 return self.suspicious_boards - self.failed_boards
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001071
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001072class Slots:
1073
1074 """Controller of the array of subprocess slots."""
1075
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001076 def __init__(self, configs, options, progress, reference_src_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001077 """Create a new slots controller.
1078
1079 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001080 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001081 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001082 progress: A progress indicator.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001083 reference_src_dir: Determine the true starting config state from this
1084 source tree.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001085 """
1086 self.options = options
1087 self.slots = []
1088 devnull = get_devnull()
1089 make_cmd = get_make_cmd()
1090 for i in range(options.jobs):
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001091 self.slots.append(Slot(configs, options, progress, devnull,
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001092 make_cmd, reference_src_dir))
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001093
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001094 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001095 """Add a new subprocess if a vacant slot is found.
1096
1097 Arguments:
1098 defconfig: defconfig name to be put into.
1099
1100 Returns:
1101 Return True on success or False on failure
1102 """
1103 for slot in self.slots:
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001104 if slot.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001105 return True
1106 return False
1107
1108 def available(self):
1109 """Check if there is a vacant slot.
1110
1111 Returns:
1112 Return True if at lease one vacant slot is found, False otherwise.
1113 """
1114 for slot in self.slots:
1115 if slot.poll():
1116 return True
1117 return False
1118
1119 def empty(self):
1120 """Check if all slots are vacant.
1121
1122 Returns:
1123 Return True if all the slots are vacant, False otherwise.
1124 """
1125 ret = True
1126 for slot in self.slots:
1127 if not slot.poll():
1128 ret = False
1129 return ret
1130
1131 def show_failed_boards(self):
1132 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001133 boards = set()
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001134 output_file = 'moveconfig.failed'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001135
1136 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001137 boards |= slot.get_failed_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001138
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001139 if boards:
1140 boards = '\n'.join(boards) + '\n'
1141 msg = "The following boards were not processed due to error:\n"
1142 msg += boards
1143 msg += "(the list has been saved in %s)\n" % output_file
1144 print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
1145 msg)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001146
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001147 with open(output_file, 'w') as f:
1148 f.write(boards)
Joe Hershberger2559cd82015-05-19 13:21:22 -05001149
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001150 def show_suspicious_boards(self):
1151 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001152 boards = set()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001153 output_file = 'moveconfig.suspicious'
1154
1155 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001156 boards |= slot.get_suspicious_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001157
1158 if boards:
1159 boards = '\n'.join(boards) + '\n'
1160 msg = "The following boards might have been converted incorrectly.\n"
1161 msg += "It is highly recommended to check them manually:\n"
1162 msg += boards
1163 msg += "(the list has been saved in %s)\n" % output_file
1164 print >> sys.stderr, color_text(self.options.color, COLOR_YELLOW,
1165 msg)
1166
1167 with open(output_file, 'w') as f:
1168 f.write(boards)
1169
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001170class ReferenceSource:
1171
1172 """Reference source against which original configs should be parsed."""
1173
1174 def __init__(self, commit):
1175 """Create a reference source directory based on a specified commit.
1176
1177 Arguments:
1178 commit: commit to git-clone
1179 """
1180 self.src_dir = tempfile.mkdtemp()
1181 print "Cloning git repo to a separate work directory..."
1182 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1183 cwd=self.src_dir)
1184 print "Checkout '%s' to build the original autoconf.mk." % \
1185 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
1186 subprocess.check_output(['git', 'checkout', commit],
1187 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001188
1189 def __del__(self):
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001190 """Delete the reference source directory
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001191
1192 This function makes sure the temporary directory is cleaned away
1193 even if Python suddenly dies due to error. It should be done in here
1194 because it is guaranteed the destructor is always invoked when the
1195 instance of the class gets unreferenced.
1196 """
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001197 shutil.rmtree(self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001198
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001199 def get_dir(self):
1200 """Return the absolute path to the reference source directory."""
1201
1202 return self.src_dir
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001203
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001204def move_config(configs, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001205 """Move config options to defconfig files.
1206
1207 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001208 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001209 options: option flags
1210 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001211 if len(configs) == 0:
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001212 if options.force_sync:
1213 print 'No CONFIG is specified. You are probably syncing defconfigs.',
1214 else:
1215 print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
1216 else:
1217 print 'Move ' + ', '.join(configs),
1218 print '(jobs: %d)\n' % options.jobs
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001219
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001220 if options.git_ref:
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001221 reference_src = ReferenceSource(options.git_ref)
1222 reference_src_dir = reference_src.get_dir()
1223 else:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001224 reference_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001225
Joe Hershberger91040e82015-05-19 13:21:19 -05001226 if options.defconfigs:
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +09001227 defconfigs = get_matched_defconfigs(options.defconfigs)
Joe Hershberger91040e82015-05-19 13:21:19 -05001228 else:
Masahiro Yamada684c3062016-07-25 19:15:28 +09001229 defconfigs = get_all_defconfigs()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001230
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001231 progress = Progress(len(defconfigs))
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001232 slots = Slots(configs, options, progress, reference_src_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001233
1234 # Main loop to process defconfig files:
1235 # Add a new subprocess into a vacant slot.
1236 # Sleep if there is no available slot.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001237 for defconfig in defconfigs:
1238 while not slots.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001239 while not slots.available():
1240 # No available slot: sleep for a while
1241 time.sleep(SLEEP_TIME)
1242
1243 # wait until all the subprocesses finish
1244 while not slots.empty():
1245 time.sleep(SLEEP_TIME)
1246
Joe Hershberger2e2ce6c2015-05-19 13:21:25 -05001247 print ''
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001248 slots.show_failed_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001249 slots.show_suspicious_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001250
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001251def main():
1252 try:
1253 cpu_count = multiprocessing.cpu_count()
1254 except NotImplementedError:
1255 cpu_count = 1
1256
1257 parser = optparse.OptionParser()
1258 # Add options here
1259 parser.add_option('-c', '--color', action='store_true', default=False,
1260 help='display the log in color')
Simon Glass9ede2122016-09-12 23:18:21 -06001261 parser.add_option('-C', '--commit', action='store_true', default=False,
1262 help='Create a git commit for the operation')
Joe Hershberger91040e82015-05-19 13:21:19 -05001263 parser.add_option('-d', '--defconfigs', type='string',
1264 help='a file containing a list of defconfigs to move')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001265 parser.add_option('-n', '--dry-run', action='store_true', default=False,
1266 help='perform a trial run (show log with no changes)')
1267 parser.add_option('-e', '--exit-on-error', action='store_true',
1268 default=False,
1269 help='exit immediately on any error')
Masahiro Yamada8513dc02016-05-19 15:52:08 +09001270 parser.add_option('-s', '--force-sync', action='store_true', default=False,
1271 help='force sync by savedefconfig')
Masahiro Yamada07913d12016-08-22 22:18:22 +09001272 parser.add_option('-S', '--spl', action='store_true', default=False,
1273 help='parse config options defined for SPL build')
Joe Hershberger2144f882015-05-19 13:21:20 -05001274 parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
1275 action='store_true', default=False,
1276 help='only cleanup the headers')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001277 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
1278 help='the number of jobs to run simultaneously')
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001279 parser.add_option('-r', '--git-ref', type='string',
1280 help='the git ref to clone for building the autoconf.mk')
Simon Glass6b403df2016-09-12 23:18:20 -06001281 parser.add_option('-y', '--yes', action='store_true', default=False,
1282 help="respond 'yes' to any prompts")
Joe Hershberger95bf9c72015-05-19 13:21:24 -05001283 parser.add_option('-v', '--verbose', action='store_true', default=False,
1284 help='show any build errors as boards are built')
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001285 parser.usage += ' CONFIG ...'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001286
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001287 (options, configs) = parser.parse_args()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001288
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001289 if len(configs) == 0 and not options.force_sync:
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001290 parser.print_usage()
1291 sys.exit(1)
1292
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001293 # prefix the option name with CONFIG_ if missing
1294 configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
1295 for config in configs ]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001296
Joe Hershberger2144f882015-05-19 13:21:20 -05001297 check_top_directory()
1298
1299 if not options.cleanup_headers_only:
Masahiro Yamadaf7536f72016-07-25 19:15:23 +09001300 check_clean_directory()
1301 update_cross_compile(options.color)
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001302 move_config(configs, options)
Joe Hershberger2144f882015-05-19 13:21:20 -05001303
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001304 if configs:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +09001305 cleanup_headers(configs, options)
Masahiro Yamada9ab02962016-07-25 19:15:29 +09001306 cleanup_extra_options(configs, options)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001307
Simon Glass9ede2122016-09-12 23:18:21 -06001308 if options.commit:
1309 subprocess.call(['git', 'add', '-u'])
1310 if configs:
1311 msg = 'Convert %s %sto Kconfig' % (configs[0],
1312 'et al ' if len(configs) > 1 else '')
1313 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1314 '\n '.join(configs))
1315 else:
1316 msg = 'configs: Resync with savedefconfig'
1317 msg += '\n\nRsync all defconfig files using moveconfig.py'
1318 subprocess.call(['git', 'commit', '-s', '-m', msg])
1319
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001320if __name__ == '__main__':
1321 main()