blob: dcca0ecb5eb8de0b63d1ae4531913f5e2c0e16d0 [file] [log] [blame]
Masahiro Yamadab6160812015-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 Yamadab903c4e2016-05-19 15:51:58 +090020First, you must edit the Kconfig to add the menu entries for the configs
Joe Hershberger166edec2015-05-19 13:21:17 -050021you are moving.
22
Masahiro Yamadab903c4e2016-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 Yamadab6160812015-05-20 11:36:07 +090026
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090027 $ tools/moveconfig.py CONFIG_CMD_USB CONFIG_SYS_TEXT_BASE
Masahiro Yamadab6160812015-05-20 11:36:07 +090028
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090029The tool walks through all the defconfig files and move the given CONFIGs.
Masahiro Yamadab6160812015-05-20 11:36:07 +090030
31The log is also displayed on the terminal.
32
Masahiro Yamada465b7c02016-05-19 15:52:02 +090033The log is printed for each defconfig as follows:
Masahiro Yamadab6160812015-05-20 11:36:07 +090034
Masahiro Yamada465b7c02016-05-19 15:52:02 +090035<defconfig_name>
36 <action1>
37 <action2>
38 <action3>
39 ...
Masahiro Yamadab6160812015-05-20 11:36:07 +090040
Masahiro Yamada465b7c02016-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 Yamada7facf882016-08-21 16:12:36 +090044It looks like one of the following:
Masahiro Yamadab6160812015-05-20 11:36:07 +090045
46 - Move 'CONFIG_... '
47 This config option was moved to the defconfig
48
Masahiro Yamada5643d6e2016-05-19 15:51:56 +090049 - CONFIG_... is not defined in Kconfig. Do nothing.
Masahiro Yamada35204d92016-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 Yamada5643d6e2016-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 Yamada35204d92016-08-22 22:18:21 +090060 The tool does not know if the result is reasonable, so please check it
61 manually.
Masahiro Yamadab6160812015-05-20 11:36:07 +090062
Masahiro Yamada5643d6e2016-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 Yamadab6160812015-05-20 11:36:07 +090066
Masahiro Yamadac4d76eb2016-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 Yamadab6160812015-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 Yamadab903c4e2016-05-19 15:51:58 +090084How does it work?
85-----------------
Masahiro Yamadab6160812015-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 Yamadab903c4e2016-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 Yamadab6160812015-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 Glass8bf41c22016-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 Hershbergerc6e043a2015-05-19 13:21:19 -0500129 -d, --defconfigs
Masahiro Yamada3984d6e2016-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 Hershbergerc6e043a2015-05-19 13:21:19 -0500132
Masahiro Yamadab6160812015-05-20 11:36:07 +0900133 -n, --dry-run
Masahiro Yamadab903c4e2016-05-19 15:51:58 +0900134 Perform a trial run that does not make any changes. It is useful to
Masahiro Yamadab6160812015-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 Yamada83c17672016-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 Yamada6d139172016-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 Hershberger23475932015-05-19 13:21:20 -0500152 -H, --headers-only
153 Only cleanup the headers; skip the defconfig processing
154
Masahiro Yamadab6160812015-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 Hershbergerb1a570f2016-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 Hershberger808b63f2015-05-19 13:21:24 -0500167 -v, --verbose
168 Show any build errors as boards are built
169
Simon Glass13e05a02016-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 Yamadab6160812015-05-20 11:36:07 +0900174To see the complete list of supported options, run
175
176 $ tools/moveconfig.py -h
177
178"""
179
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900180import copy
Masahiro Yamada573b3902016-07-25 19:15:25 +0900181import difflib
Masahiro Yamada0f6beda2016-05-19 15:52:07 +0900182import filecmp
Masahiro Yamadab6160812015-05-20 11:36:07 +0900183import fnmatch
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900184import glob
Masahiro Yamadab6160812015-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 Yamada7facf882016-08-21 16:12:36 +0900200# (https://www.kernel.org/pub/tools/crosstool/files/bin/), except the following:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900201# arc: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases
Bin Meng3bb02f62015-09-25 01:22:39 -0700202# nds32: http://osdk.andestech.com/packages/nds32le-linux-glibc-v1.tgz
Masahiro Yamadab6160812015-05-20 11:36:07 +0900203# nios2: https://sourcery.mentor.com/GNUToolchain/subscription42545
204# sh: http://sourcery.mentor.com/public/gnu_toolchain/sh-linux-gnu
205CROSS_COMPILE = {
206 'arc': 'arc-linux-',
207 'aarch64': 'aarch64-linux-',
208 'arm': 'arm-unknown-linux-gnueabi-',
209 'avr32': 'avr32-linux-',
Masahiro Yamadab6160812015-05-20 11:36:07 +0900210 'm68k': 'm68k-linux-',
211 'microblaze': 'microblaze-linux-',
212 'mips': 'mips-linux-',
213 'nds32': 'nds32le-linux-',
214 'nios2': 'nios2-linux-gnu-',
Masahiro Yamadab6160812015-05-20 11:36:07 +0900215 'powerpc': 'powerpc-linux-',
216 'sh': 'sh-linux-gnu-',
Masahiro Yamadad1d9d602016-08-21 16:03:08 +0900217 'x86': 'i386-linux-',
218 'xtensa': 'xtensa-linux-'
Masahiro Yamadab6160812015-05-20 11:36:07 +0900219}
220
221STATE_IDLE = 0
222STATE_DEFCONFIG = 1
223STATE_AUTOCONF = 2
Joe Hershberger166edec2015-05-19 13:21:17 -0500224STATE_SAVEDEFCONFIG = 3
Masahiro Yamadab6160812015-05-20 11:36:07 +0900225
226ACTION_MOVE = 0
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900227ACTION_NO_ENTRY = 1
Masahiro Yamada35204d92016-08-22 22:18:21 +0900228ACTION_NO_ENTRY_WARN = 2
229ACTION_NO_CHANGE = 3
Masahiro Yamadab6160812015-05-20 11:36:07 +0900230
231COLOR_BLACK = '0;30'
232COLOR_RED = '0;31'
233COLOR_GREEN = '0;32'
234COLOR_BROWN = '0;33'
235COLOR_BLUE = '0;34'
236COLOR_PURPLE = '0;35'
237COLOR_CYAN = '0;36'
238COLOR_LIGHT_GRAY = '0;37'
239COLOR_DARK_GRAY = '1;30'
240COLOR_LIGHT_RED = '1;31'
241COLOR_LIGHT_GREEN = '1;32'
242COLOR_YELLOW = '1;33'
243COLOR_LIGHT_BLUE = '1;34'
244COLOR_LIGHT_PURPLE = '1;35'
245COLOR_LIGHT_CYAN = '1;36'
246COLOR_WHITE = '1;37'
247
248### helper functions ###
249def get_devnull():
250 """Get the file object of '/dev/null' device."""
251 try:
252 devnull = subprocess.DEVNULL # py3k
253 except AttributeError:
254 devnull = open(os.devnull, 'wb')
255 return devnull
256
257def check_top_directory():
258 """Exit if we are not at the top of source directory."""
259 for f in ('README', 'Licenses'):
260 if not os.path.exists(f):
261 sys.exit('Please run at the top of source directory.')
262
Masahiro Yamada990e6772016-05-19 15:51:54 +0900263def check_clean_directory():
264 """Exit if the source tree is not clean."""
265 for f in ('.config', 'include/config'):
266 if os.path.exists(f):
267 sys.exit("source tree is not clean, please run 'make mrproper'")
268
Masahiro Yamadab6160812015-05-20 11:36:07 +0900269def get_make_cmd():
270 """Get the command name of GNU Make.
271
272 U-Boot needs GNU Make for building, but the command name is not
273 necessarily "make". (for example, "gmake" on FreeBSD).
274 Returns the most appropriate command name on your system.
275 """
276 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
277 ret = process.communicate()
278 if process.returncode:
279 sys.exit('GNU Make not found')
280 return ret[0].rstrip()
281
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900282def get_matched_defconfigs(defconfigs_file):
283 """Get all the defconfig files that match the patterns in a file."""
284 defconfigs = []
285 for i, line in enumerate(open(defconfigs_file)):
286 line = line.strip()
287 if not line:
288 continue # skip blank lines silently
289 pattern = os.path.join('configs', line)
290 matched = glob.glob(pattern) + glob.glob(pattern + '_defconfig')
291 if not matched:
292 print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \
293 (defconfigs_file, i + 1, line)
294
295 defconfigs += matched
296
297 # use set() to drop multiple matching
298 return [ defconfig[len('configs') + 1:] for defconfig in set(defconfigs) ]
299
Masahiro Yamada58175e32016-07-25 19:15:28 +0900300def get_all_defconfigs():
301 """Get all the defconfig files under the configs/ directory."""
302 defconfigs = []
303 for (dirpath, dirnames, filenames) in os.walk('configs'):
304 dirpath = dirpath[len('configs') + 1:]
305 for filename in fnmatch.filter(filenames, '*_defconfig'):
306 defconfigs.append(os.path.join(dirpath, filename))
307
308 return defconfigs
309
Masahiro Yamadab6160812015-05-20 11:36:07 +0900310def color_text(color_enabled, color, string):
311 """Return colored string."""
312 if color_enabled:
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900313 # LF should not be surrounded by the escape sequence.
314 # Otherwise, additional whitespace or line-feed might be printed.
315 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
316 for s in string.split('\n') ])
Masahiro Yamadab6160812015-05-20 11:36:07 +0900317 else:
318 return string
319
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900320def show_diff(a, b, file_path, color_enabled):
Masahiro Yamada573b3902016-07-25 19:15:25 +0900321 """Show unidified diff.
322
323 Arguments:
324 a: A list of lines (before)
325 b: A list of lines (after)
326 file_path: Path to the file
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900327 color_enabled: Display the diff in color
Masahiro Yamada573b3902016-07-25 19:15:25 +0900328 """
329
330 diff = difflib.unified_diff(a, b,
331 fromfile=os.path.join('a', file_path),
332 tofile=os.path.join('b', file_path))
333
334 for line in diff:
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900335 if line[0] == '-' and line[1] != '-':
336 print color_text(color_enabled, COLOR_RED, line),
337 elif line[0] == '+' and line[1] != '+':
338 print color_text(color_enabled, COLOR_GREEN, line),
339 else:
340 print line,
Masahiro Yamada573b3902016-07-25 19:15:25 +0900341
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900342def update_cross_compile(color_enabled):
Robert P. J. Day8c60f922016-05-04 04:47:31 -0400343 """Update per-arch CROSS_COMPILE via environment variables
Masahiro Yamadab6160812015-05-20 11:36:07 +0900344
345 The default CROSS_COMPILE values are available
346 in the CROSS_COMPILE list above.
347
Robert P. J. Day8c60f922016-05-04 04:47:31 -0400348 You can override them via environment variables
Masahiro Yamadab6160812015-05-20 11:36:07 +0900349 CROSS_COMPILE_{ARCH}.
350
351 For example, if you want to override toolchain prefixes
352 for ARM and PowerPC, you can do as follows in your shell:
353
354 export CROSS_COMPILE_ARM=...
355 export CROSS_COMPILE_POWERPC=...
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900356
357 Then, this function checks if specified compilers really exist in your
358 PATH environment.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900359 """
360 archs = []
361
362 for arch in os.listdir('arch'):
363 if os.path.exists(os.path.join('arch', arch, 'Makefile')):
364 archs.append(arch)
365
366 # arm64 is a special case
367 archs.append('aarch64')
368
369 for arch in archs:
370 env = 'CROSS_COMPILE_' + arch.upper()
371 cross_compile = os.environ.get(env)
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900372 if not cross_compile:
373 cross_compile = CROSS_COMPILE.get(arch, '')
374
375 for path in os.environ["PATH"].split(os.pathsep):
376 gcc_path = os.path.join(path, cross_compile + 'gcc')
377 if os.path.isfile(gcc_path) and os.access(gcc_path, os.X_OK):
378 break
379 else:
380 print >> sys.stderr, color_text(color_enabled, COLOR_YELLOW,
381 'warning: %sgcc: not found in PATH. %s architecture boards will be skipped'
382 % (cross_compile, arch))
383 cross_compile = None
384
385 CROSS_COMPILE[arch] = cross_compile
Masahiro Yamadab6160812015-05-20 11:36:07 +0900386
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900387def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
388 extend_post):
389 """Extend matched lines if desired patterns are found before/after already
390 matched lines.
391
392 Arguments:
393 lines: A list of lines handled.
394 matched: A list of line numbers that have been already matched.
395 (will be updated by this function)
396 pre_patterns: A list of regular expression that should be matched as
397 preamble.
398 post_patterns: A list of regular expression that should be matched as
399 postamble.
400 extend_pre: Add the line number of matched preamble to the matched list.
401 extend_post: Add the line number of matched postamble to the matched list.
402 """
403 extended_matched = []
404
405 j = matched[0]
406
407 for i in matched:
408 if i == 0 or i < j:
409 continue
410 j = i
411 while j in matched:
412 j += 1
413 if j >= len(lines):
414 break
415
416 for p in pre_patterns:
417 if p.search(lines[i - 1]):
418 break
419 else:
420 # not matched
421 continue
422
423 for p in post_patterns:
424 if p.search(lines[j]):
425 break
426 else:
427 # not matched
428 continue
429
430 if extend_pre:
431 extended_matched.append(i - 1)
432 if extend_post:
433 extended_matched.append(j)
434
435 matched += extended_matched
436 matched.sort()
437
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900438def cleanup_one_header(header_path, patterns, options):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900439 """Clean regex-matched lines away from a file.
440
441 Arguments:
442 header_path: path to the cleaned file.
443 patterns: list of regex patterns. Any lines matching to these
444 patterns are deleted.
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900445 options: option flags.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900446 """
447 with open(header_path) as f:
448 lines = f.readlines()
449
450 matched = []
451 for i, line in enumerate(lines):
Masahiro Yamada6d798ba2016-07-25 19:15:27 +0900452 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
453 matched.append(i)
454 continue
Masahiro Yamadab6160812015-05-20 11:36:07 +0900455 for pattern in patterns:
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900456 if pattern.search(line):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900457 matched.append(i)
458 break
459
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900460 if not matched:
461 return
462
463 # remove empty #ifdef ... #endif, successive blank lines
464 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
465 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
466 pattern_endif = re.compile(r'#\s*endif\W') # #endif
467 pattern_blank = re.compile(r'^\s*$') # empty line
468
469 while True:
470 old_matched = copy.copy(matched)
471 extend_matched_lines(lines, matched, [pattern_if],
472 [pattern_endif], True, True)
473 extend_matched_lines(lines, matched, [pattern_elif],
474 [pattern_elif, pattern_endif], True, False)
475 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
476 [pattern_blank], False, True)
477 extend_matched_lines(lines, matched, [pattern_blank],
478 [pattern_elif, pattern_endif], True, False)
479 extend_matched_lines(lines, matched, [pattern_blank],
480 [pattern_blank], True, False)
481 if matched == old_matched:
482 break
483
Masahiro Yamada573b3902016-07-25 19:15:25 +0900484 tolines = copy.copy(lines)
485
486 for i in reversed(matched):
487 tolines.pop(i)
488
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900489 show_diff(lines, tolines, header_path, options.color)
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900490
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900491 if options.dry_run:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900492 return
493
494 with open(header_path, 'w') as f:
Masahiro Yamada573b3902016-07-25 19:15:25 +0900495 for line in tolines:
496 f.write(line)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900497
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900498def cleanup_headers(configs, options):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900499 """Delete config defines from board headers.
500
501 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900502 configs: A list of CONFIGs to remove.
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900503 options: option flags.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900504 """
Simon Glass13e05a02016-09-12 23:18:20 -0600505 if not options.yes:
506 while True:
507 choice = raw_input('Clean up headers? [y/n]: ').lower()
508 print choice
509 if choice == 'y' or choice == 'n':
510 break
Masahiro Yamadab6160812015-05-20 11:36:07 +0900511
Simon Glass13e05a02016-09-12 23:18:20 -0600512 if choice == 'n':
513 return
Masahiro Yamadab6160812015-05-20 11:36:07 +0900514
515 patterns = []
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900516 for config in configs:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900517 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
518 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
519
Joe Hershbergerb78ad422015-05-19 13:21:21 -0500520 for dir in 'include', 'arch', 'board':
521 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamada28a6d352016-07-25 19:15:22 +0900522 if dirpath == os.path.join('include', 'generated'):
523 continue
Joe Hershbergerb78ad422015-05-19 13:21:21 -0500524 for filename in filenames:
525 if not fnmatch.fnmatch(filename, '*~'):
526 cleanup_one_header(os.path.join(dirpath, filename),
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900527 patterns, options)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900528
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900529def cleanup_one_extra_option(defconfig_path, configs, options):
530 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
531
532 Arguments:
533 defconfig_path: path to the cleaned defconfig file.
534 configs: A list of CONFIGs to remove.
535 options: option flags.
536 """
537
538 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
539 end = '"\n'
540
541 with open(defconfig_path) as f:
542 lines = f.readlines()
543
544 for i, line in enumerate(lines):
545 if line.startswith(start) and line.endswith(end):
546 break
547 else:
548 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
549 return
550
551 old_tokens = line[len(start):-len(end)].split(',')
552 new_tokens = []
553
554 for token in old_tokens:
555 pos = token.find('=')
556 if not (token[:pos] if pos >= 0 else token) in configs:
557 new_tokens.append(token)
558
559 if new_tokens == old_tokens:
560 return
561
562 tolines = copy.copy(lines)
563
564 if new_tokens:
565 tolines[i] = start + ','.join(new_tokens) + end
566 else:
567 tolines.pop(i)
568
569 show_diff(lines, tolines, defconfig_path, options.color)
570
571 if options.dry_run:
572 return
573
574 with open(defconfig_path, 'w') as f:
575 for line in tolines:
576 f.write(line)
577
578def cleanup_extra_options(configs, options):
579 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
580
581 Arguments:
582 configs: A list of CONFIGs to remove.
583 options: option flags.
584 """
Simon Glass13e05a02016-09-12 23:18:20 -0600585 if not options.yes:
586 while True:
587 choice = (raw_input('Clean up CONFIG_SYS_EXTRA_OPTIONS? [y/n]: ').
588 lower())
589 print choice
590 if choice == 'y' or choice == 'n':
591 break
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900592
Simon Glass13e05a02016-09-12 23:18:20 -0600593 if choice == 'n':
594 return
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900595
596 configs = [ config[len('CONFIG_'):] for config in configs ]
597
598 defconfigs = get_all_defconfigs()
599
600 for defconfig in defconfigs:
601 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
602 options)
603
Masahiro Yamadab6160812015-05-20 11:36:07 +0900604### classes ###
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900605class Progress:
606
607 """Progress Indicator"""
608
609 def __init__(self, total):
610 """Create a new progress indicator.
611
612 Arguments:
613 total: A number of defconfig files to process.
614 """
615 self.current = 0
616 self.total = total
617
618 def inc(self):
619 """Increment the number of processed defconfig files."""
620
621 self.current += 1
622
623 def show(self):
624 """Display the progress."""
625 print ' %d defconfigs out of %d\r' % (self.current, self.total),
626 sys.stdout.flush()
627
Masahiro Yamadab6160812015-05-20 11:36:07 +0900628class KconfigParser:
629
630 """A parser of .config and include/autoconf.mk."""
631
632 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
633 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
634
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900635 def __init__(self, configs, options, build_dir):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900636 """Create a new parser.
637
638 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900639 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900640 options: option flags.
641 build_dir: Build directory.
642 """
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900643 self.configs = configs
Masahiro Yamadab6160812015-05-20 11:36:07 +0900644 self.options = options
Masahiro Yamada5393b612016-05-19 15:52:00 +0900645 self.dotconfig = os.path.join(build_dir, '.config')
646 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada6d139172016-08-22 22:18:22 +0900647 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
648 'autoconf.mk')
Masahiro Yamada5393b612016-05-19 15:52:00 +0900649 self.config_autoconf = os.path.join(build_dir, 'include', 'config',
650 'auto.conf')
Masahiro Yamada07f98522016-05-19 15:52:06 +0900651 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamadab6160812015-05-20 11:36:07 +0900652
653 def get_cross_compile(self):
654 """Parse .config file and return CROSS_COMPILE.
655
656 Returns:
657 A string storing the compiler prefix for the architecture.
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900658 Return a NULL string for architectures that do not require
659 compiler prefix (Sandbox and native build is the case).
660 Return None if the specified compiler is missing in your PATH.
661 Caller should distinguish '' and None.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900662 """
663 arch = ''
664 cpu = ''
Masahiro Yamada5393b612016-05-19 15:52:00 +0900665 for line in open(self.dotconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900666 m = self.re_arch.match(line)
667 if m:
668 arch = m.group(1)
669 continue
670 m = self.re_cpu.match(line)
671 if m:
672 cpu = m.group(1)
673
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900674 if not arch:
675 return None
Masahiro Yamadab6160812015-05-20 11:36:07 +0900676
677 # fix-up for aarch64
678 if arch == 'arm' and cpu == 'armv8':
679 arch = 'aarch64'
680
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900681 return CROSS_COMPILE.get(arch, None)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900682
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900683 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900684 """Parse .config, defconfig, include/autoconf.mk for one config.
685
686 This function looks for the config options in the lines from
687 defconfig, .config, and include/autoconf.mk in order to decide
688 which action should be taken for this defconfig.
689
690 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900691 config: CONFIG name to parse.
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900692 dotconfig_lines: lines from the .config file.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900693 autoconf_lines: lines from the include/autoconf.mk file.
694
695 Returns:
696 A tupple of the action for this defconfig and the line
697 matched for the config.
698 """
Masahiro Yamadab6160812015-05-20 11:36:07 +0900699 not_set = '# %s is not set' % config
700
Masahiro Yamadab6160812015-05-20 11:36:07 +0900701 for line in autoconf_lines:
702 line = line.rstrip()
703 if line.startswith(config + '='):
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900704 new_val = line
Masahiro Yamadab6160812015-05-20 11:36:07 +0900705 break
Masahiro Yamadab6160812015-05-20 11:36:07 +0900706 else:
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900707 new_val = not_set
708
Masahiro Yamada35204d92016-08-22 22:18:21 +0900709 for line in dotconfig_lines:
710 line = line.rstrip()
711 if line.startswith(config + '=') or line == not_set:
712 old_val = line
713 break
714 else:
715 if new_val == not_set:
716 return (ACTION_NO_ENTRY, config)
717 else:
718 return (ACTION_NO_ENTRY_WARN, config)
719
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900720 # If this CONFIG is neither bool nor trisate
721 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
722 # tools/scripts/define2mk.sed changes '1' to 'y'.
723 # This is a problem if the CONFIG is int type.
724 # Check the type in Kconfig and handle it correctly.
725 if new_val[-2:] == '=y':
726 new_val = new_val[:-1] + '1'
727
Masahiro Yamadab48387f2016-06-15 14:33:50 +0900728 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
729 new_val)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900730
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900731 def update_dotconfig(self):
Masahiro Yamada7c0d9d22016-05-19 15:51:50 +0900732 """Parse files for the config options and update the .config.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900733
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900734 This function parses the generated .config and include/autoconf.mk
735 searching the target options.
Masahiro Yamada7c0d9d22016-05-19 15:51:50 +0900736 Move the config option(s) to the .config as needed.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900737
738 Arguments:
739 defconfig: defconfig name.
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900740
741 Returns:
Masahiro Yamada263d1372016-05-19 15:52:04 +0900742 Return a tuple of (updated flag, log string).
743 The "updated flag" is True if the .config was updated, False
744 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900745 """
746
Masahiro Yamadab6160812015-05-20 11:36:07 +0900747 results = []
Masahiro Yamada263d1372016-05-19 15:52:04 +0900748 updated = False
Masahiro Yamada35204d92016-08-22 22:18:21 +0900749 suspicious = False
Masahiro Yamada6d139172016-08-22 22:18:22 +0900750 rm_files = [self.config_autoconf, self.autoconf]
751
752 if self.options.spl:
753 if os.path.exists(self.spl_autoconf):
754 autoconf_path = self.spl_autoconf
755 rm_files.append(self.spl_autoconf)
756 else:
757 for f in rm_files:
758 os.remove(f)
759 return (updated, suspicious,
760 color_text(self.options.color, COLOR_BROWN,
761 "SPL is not enabled. Skipped.") + '\n')
762 else:
763 autoconf_path = self.autoconf
Masahiro Yamadab6160812015-05-20 11:36:07 +0900764
Masahiro Yamada5393b612016-05-19 15:52:00 +0900765 with open(self.dotconfig) as f:
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900766 dotconfig_lines = f.readlines()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900767
Masahiro Yamada6d139172016-08-22 22:18:22 +0900768 with open(autoconf_path) as f:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900769 autoconf_lines = f.readlines()
770
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900771 for config in self.configs:
772 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger166edec2015-05-19 13:21:17 -0500773 autoconf_lines)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900774 results.append(result)
775
776 log = ''
777
778 for (action, value) in results:
779 if action == ACTION_MOVE:
780 actlog = "Move '%s'" % value
781 log_color = COLOR_LIGHT_GREEN
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900782 elif action == ACTION_NO_ENTRY:
783 actlog = "%s is not defined in Kconfig. Do nothing." % value
Masahiro Yamadab6160812015-05-20 11:36:07 +0900784 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada35204d92016-08-22 22:18:21 +0900785 elif action == ACTION_NO_ENTRY_WARN:
786 actlog = "%s is not defined in Kconfig (suspicious). Do nothing." % value
787 log_color = COLOR_YELLOW
788 suspicious = True
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900789 elif action == ACTION_NO_CHANGE:
790 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
791 % value
Masahiro Yamadab6160812015-05-20 11:36:07 +0900792 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada6d139172016-08-22 22:18:22 +0900793 elif action == ACTION_SPL_NOT_EXIST:
794 actlog = "SPL is not enabled for this defconfig. Skip."
795 log_color = COLOR_PURPLE
Masahiro Yamadab6160812015-05-20 11:36:07 +0900796 else:
797 sys.exit("Internal Error. This should not happen.")
798
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900799 log += color_text(self.options.color, log_color, actlog) + '\n'
Masahiro Yamadab6160812015-05-20 11:36:07 +0900800
Masahiro Yamada5393b612016-05-19 15:52:00 +0900801 with open(self.dotconfig, 'a') as f:
Masahiro Yamada953d93b2016-05-19 15:51:49 +0900802 for (action, value) in results:
803 if action == ACTION_MOVE:
804 f.write(value + '\n')
Masahiro Yamada263d1372016-05-19 15:52:04 +0900805 updated = True
Masahiro Yamadab6160812015-05-20 11:36:07 +0900806
Masahiro Yamada07f98522016-05-19 15:52:06 +0900807 self.results = results
Masahiro Yamada6d139172016-08-22 22:18:22 +0900808 for f in rm_files:
809 os.remove(f)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900810
Masahiro Yamada35204d92016-08-22 22:18:21 +0900811 return (updated, suspicious, log)
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900812
Masahiro Yamada07f98522016-05-19 15:52:06 +0900813 def check_defconfig(self):
814 """Check the defconfig after savedefconfig
815
816 Returns:
817 Return additional log if moved CONFIGs were removed again by
818 'make savedefconfig'.
819 """
820
821 log = ''
822
823 with open(self.defconfig) as f:
824 defconfig_lines = f.readlines()
825
826 for (action, value) in self.results:
827 if action != ACTION_MOVE:
828 continue
829 if not value + '\n' in defconfig_lines:
830 log += color_text(self.options.color, COLOR_YELLOW,
831 "'%s' was removed by savedefconfig.\n" %
832 value)
833
834 return log
835
Masahiro Yamadab6160812015-05-20 11:36:07 +0900836class Slot:
837
838 """A slot to store a subprocess.
839
840 Each instance of this class handles one subprocess.
841 This class is useful to control multiple threads
842 for faster processing.
843 """
844
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500845 def __init__(self, configs, options, progress, devnull, make_cmd, reference_src_dir):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900846 """Create a new process slot.
847
848 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900849 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900850 options: option flags.
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900851 progress: A progress indicator.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900852 devnull: A file object of '/dev/null'.
853 make_cmd: command name of GNU Make.
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500854 reference_src_dir: Determine the true starting config state from this
855 source tree.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900856 """
857 self.options = options
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900858 self.progress = progress
Masahiro Yamadab6160812015-05-20 11:36:07 +0900859 self.build_dir = tempfile.mkdtemp()
860 self.devnull = devnull
861 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500862 self.reference_src_dir = reference_src_dir
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900863 self.parser = KconfigParser(configs, options, self.build_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900864 self.state = STATE_IDLE
Masahiro Yamada1271b672016-08-22 22:18:20 +0900865 self.failed_boards = set()
866 self.suspicious_boards = set()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900867
868 def __del__(self):
869 """Delete the working directory
870
871 This function makes sure the temporary directory is cleaned away
872 even if Python suddenly dies due to error. It should be done in here
Joe Hershberger640de872016-06-10 14:53:29 -0500873 because it is guaranteed the destructor is always invoked when the
Masahiro Yamadab6160812015-05-20 11:36:07 +0900874 instance of the class gets unreferenced.
875
876 If the subprocess is still running, wait until it finishes.
877 """
878 if self.state != STATE_IDLE:
879 while self.ps.poll() == None:
880 pass
881 shutil.rmtree(self.build_dir)
882
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900883 def add(self, defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900884 """Assign a new subprocess for defconfig and add it to the slot.
885
886 If the slot is vacant, create a new subprocess for processing the
887 given defconfig and add it to the slot. Just returns False if
888 the slot is occupied (i.e. the current subprocess is still running).
889
890 Arguments:
891 defconfig: defconfig name.
892
893 Returns:
894 Return True on success or False on failure
895 """
896 if self.state != STATE_IDLE:
897 return False
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900898
Masahiro Yamadab6160812015-05-20 11:36:07 +0900899 self.defconfig = defconfig
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900900 self.log = ''
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900901 self.current_src_dir = self.reference_src_dir
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900902 self.do_defconfig()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900903 return True
904
905 def poll(self):
906 """Check the status of the subprocess and handle it as needed.
907
908 Returns True if the slot is vacant (i.e. in idle state).
909 If the configuration is successfully finished, assign a new
910 subprocess to build include/autoconf.mk.
911 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada263d1372016-05-19 15:52:04 +0900912 parse the .config and the include/autoconf.mk, moving
913 config options to the .config as needed.
914 If the .config was updated, run "make savedefconfig" to sync
915 it, update the original defconfig, and then set the slot back
916 to the idle state.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900917
918 Returns:
919 Return True if the subprocess is terminated, False otherwise
920 """
921 if self.state == STATE_IDLE:
922 return True
923
924 if self.ps.poll() == None:
925 return False
926
927 if self.ps.poll() != 0:
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900928 self.handle_error()
929 elif self.state == STATE_DEFCONFIG:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900930 if self.reference_src_dir and not self.current_src_dir:
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500931 self.do_savedefconfig()
932 else:
933 self.do_autoconf()
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900934 elif self.state == STATE_AUTOCONF:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900935 if self.current_src_dir:
936 self.current_src_dir = None
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500937 self.do_defconfig()
938 else:
939 self.do_savedefconfig()
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900940 elif self.state == STATE_SAVEDEFCONFIG:
941 self.update_defconfig()
942 else:
943 sys.exit("Internal Error. This should not happen.")
Masahiro Yamadab6160812015-05-20 11:36:07 +0900944
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900945 return True if self.state == STATE_IDLE else False
Joe Hershberger166edec2015-05-19 13:21:17 -0500946
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900947 def handle_error(self):
948 """Handle error cases."""
Masahiro Yamada83c17672016-05-19 15:52:08 +0900949
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900950 self.log += color_text(self.options.color, COLOR_LIGHT_RED,
951 "Failed to process.\n")
952 if self.options.verbose:
953 self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
954 self.ps.stderr.read())
955 self.finish(False)
Joe Hershberger166edec2015-05-19 13:21:17 -0500956
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900957 def do_defconfig(self):
958 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamada0f6beda2016-05-19 15:52:07 +0900959
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900960 cmd = list(self.make_cmd)
961 cmd.append(self.defconfig)
962 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900963 stderr=subprocess.PIPE,
964 cwd=self.current_src_dir)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900965 self.state = STATE_DEFCONFIG
Masahiro Yamada0f6beda2016-05-19 15:52:07 +0900966
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900967 def do_autoconf(self):
968 """Run 'make include/config/auto.conf'."""
Masahiro Yamadab6160812015-05-20 11:36:07 +0900969
Joe Hershberger11b02702015-05-19 13:21:23 -0500970 self.cross_compile = self.parser.get_cross_compile()
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900971 if self.cross_compile is None:
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900972 self.log += color_text(self.options.color, COLOR_YELLOW,
973 "Compiler is missing. Do nothing.\n")
Masahiro Yamada274a5ee2016-05-19 15:52:03 +0900974 self.finish(False)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900975 return
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900976
Masahiro Yamadab6160812015-05-20 11:36:07 +0900977 cmd = list(self.make_cmd)
Joe Hershberger11b02702015-05-19 13:21:23 -0500978 if self.cross_compile:
979 cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
Joe Hershberger765442b2015-05-19 13:21:18 -0500980 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Masahiro Yamadab6160812015-05-20 11:36:07 +0900981 cmd.append('include/config/auto.conf')
Joe Hershberger11b02702015-05-19 13:21:23 -0500982 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900983 stderr=subprocess.PIPE,
984 cwd=self.current_src_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900985 self.state = STATE_AUTOCONF
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900986
987 def do_savedefconfig(self):
988 """Update the .config and run 'make savedefconfig'."""
989
Masahiro Yamada35204d92016-08-22 22:18:21 +0900990 (updated, suspicious, log) = self.parser.update_dotconfig()
991 if suspicious:
992 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900993 self.log += log
994
995 if not self.options.force_sync and not updated:
996 self.finish(True)
997 return
998 if updated:
999 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
1000 "Syncing by savedefconfig...\n")
1001 else:
1002 self.log += "Syncing by savedefconfig (forced by option)...\n"
1003
1004 cmd = list(self.make_cmd)
1005 cmd.append('savedefconfig')
1006 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1007 stderr=subprocess.PIPE)
1008 self.state = STATE_SAVEDEFCONFIG
1009
1010 def update_defconfig(self):
1011 """Update the input defconfig and go back to the idle state."""
1012
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001013 log = self.parser.check_defconfig()
1014 if log:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001015 self.suspicious_boards.add(self.defconfig)
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001016 self.log += log
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001017 orig_defconfig = os.path.join('configs', self.defconfig)
1018 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1019 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1020
1021 if updated:
Joe Hershberger93f1c2d2016-06-10 14:53:30 -05001022 self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001023 "defconfig was updated.\n")
1024
1025 if not self.options.dry_run and updated:
1026 shutil.move(new_defconfig, orig_defconfig)
1027 self.finish(True)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001028
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001029 def finish(self, success):
1030 """Display log along with progress and go to the idle state.
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001031
1032 Arguments:
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001033 success: Should be True when the defconfig was processed
1034 successfully, or False when it fails.
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001035 """
1036 # output at least 30 characters to hide the "* defconfigs out of *".
1037 log = self.defconfig.ljust(30) + '\n'
1038
1039 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1040 # Some threads are running in parallel.
1041 # Print log atomically to not mix up logs from different threads.
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001042 print >> (sys.stdout if success else sys.stderr), log
1043
1044 if not success:
1045 if self.options.exit_on_error:
1046 sys.exit("Exit on error.")
1047 # If --exit-on-error flag is not set, skip this board and continue.
1048 # Record the failed board.
Masahiro Yamada1271b672016-08-22 22:18:20 +09001049 self.failed_boards.add(self.defconfig)
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001050
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001051 self.progress.inc()
1052 self.progress.show()
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001053 self.state = STATE_IDLE
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001054
Masahiro Yamadab6160812015-05-20 11:36:07 +09001055 def get_failed_boards(self):
Masahiro Yamada1271b672016-08-22 22:18:20 +09001056 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001057 """
1058 return self.failed_boards
1059
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001060 def get_suspicious_boards(self):
Masahiro Yamada1271b672016-08-22 22:18:20 +09001061 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001062 """
Masahiro Yamada35204d92016-08-22 22:18:21 +09001063 return self.suspicious_boards - self.failed_boards
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001064
Masahiro Yamadab6160812015-05-20 11:36:07 +09001065class Slots:
1066
1067 """Controller of the array of subprocess slots."""
1068
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001069 def __init__(self, configs, options, progress, reference_src_dir):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001070 """Create a new slots controller.
1071
1072 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001073 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001074 options: option flags.
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001075 progress: A progress indicator.
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001076 reference_src_dir: Determine the true starting config state from this
1077 source tree.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001078 """
1079 self.options = options
1080 self.slots = []
1081 devnull = get_devnull()
1082 make_cmd = get_make_cmd()
1083 for i in range(options.jobs):
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001084 self.slots.append(Slot(configs, options, progress, devnull,
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001085 make_cmd, reference_src_dir))
Masahiro Yamadab6160812015-05-20 11:36:07 +09001086
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001087 def add(self, defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001088 """Add a new subprocess if a vacant slot is found.
1089
1090 Arguments:
1091 defconfig: defconfig name to be put into.
1092
1093 Returns:
1094 Return True on success or False on failure
1095 """
1096 for slot in self.slots:
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001097 if slot.add(defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001098 return True
1099 return False
1100
1101 def available(self):
1102 """Check if there is a vacant slot.
1103
1104 Returns:
1105 Return True if at lease one vacant slot is found, False otherwise.
1106 """
1107 for slot in self.slots:
1108 if slot.poll():
1109 return True
1110 return False
1111
1112 def empty(self):
1113 """Check if all slots are vacant.
1114
1115 Returns:
1116 Return True if all the slots are vacant, False otherwise.
1117 """
1118 ret = True
1119 for slot in self.slots:
1120 if not slot.poll():
1121 ret = False
1122 return ret
1123
1124 def show_failed_boards(self):
1125 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada1271b672016-08-22 22:18:20 +09001126 boards = set()
Masahiro Yamada0153f032016-06-15 14:33:53 +09001127 output_file = 'moveconfig.failed'
Masahiro Yamadab6160812015-05-20 11:36:07 +09001128
1129 for slot in self.slots:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001130 boards |= slot.get_failed_boards()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001131
Masahiro Yamada0153f032016-06-15 14:33:53 +09001132 if boards:
1133 boards = '\n'.join(boards) + '\n'
1134 msg = "The following boards were not processed due to error:\n"
1135 msg += boards
1136 msg += "(the list has been saved in %s)\n" % output_file
1137 print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
1138 msg)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001139
Masahiro Yamada0153f032016-06-15 14:33:53 +09001140 with open(output_file, 'w') as f:
1141 f.write(boards)
Joe Hershbergerdade12e2015-05-19 13:21:22 -05001142
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001143 def show_suspicious_boards(self):
1144 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada1271b672016-08-22 22:18:20 +09001145 boards = set()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001146 output_file = 'moveconfig.suspicious'
1147
1148 for slot in self.slots:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001149 boards |= slot.get_suspicious_boards()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001150
1151 if boards:
1152 boards = '\n'.join(boards) + '\n'
1153 msg = "The following boards might have been converted incorrectly.\n"
1154 msg += "It is highly recommended to check them manually:\n"
1155 msg += boards
1156 msg += "(the list has been saved in %s)\n" % output_file
1157 print >> sys.stderr, color_text(self.options.color, COLOR_YELLOW,
1158 msg)
1159
1160 with open(output_file, 'w') as f:
1161 f.write(boards)
1162
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001163class ReferenceSource:
1164
1165 """Reference source against which original configs should be parsed."""
1166
1167 def __init__(self, commit):
1168 """Create a reference source directory based on a specified commit.
1169
1170 Arguments:
1171 commit: commit to git-clone
1172 """
1173 self.src_dir = tempfile.mkdtemp()
1174 print "Cloning git repo to a separate work directory..."
1175 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1176 cwd=self.src_dir)
1177 print "Checkout '%s' to build the original autoconf.mk." % \
1178 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
1179 subprocess.check_output(['git', 'checkout', commit],
1180 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001181
1182 def __del__(self):
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001183 """Delete the reference source directory
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001184
1185 This function makes sure the temporary directory is cleaned away
1186 even if Python suddenly dies due to error. It should be done in here
1187 because it is guaranteed the destructor is always invoked when the
1188 instance of the class gets unreferenced.
1189 """
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001190 shutil.rmtree(self.src_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001191
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001192 def get_dir(self):
1193 """Return the absolute path to the reference source directory."""
1194
1195 return self.src_dir
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001196
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001197def move_config(configs, options):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001198 """Move config options to defconfig files.
1199
1200 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001201 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001202 options: option flags
1203 """
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001204 if len(configs) == 0:
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001205 if options.force_sync:
1206 print 'No CONFIG is specified. You are probably syncing defconfigs.',
1207 else:
1208 print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
1209 else:
1210 print 'Move ' + ', '.join(configs),
1211 print '(jobs: %d)\n' % options.jobs
Masahiro Yamadab6160812015-05-20 11:36:07 +09001212
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001213 if options.git_ref:
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001214 reference_src = ReferenceSource(options.git_ref)
1215 reference_src_dir = reference_src.get_dir()
1216 else:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001217 reference_src_dir = None
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001218
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001219 if options.defconfigs:
Masahiro Yamada3984d6e2016-10-19 14:39:54 +09001220 defconfigs = get_matched_defconfigs(options.defconfigs)
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001221 else:
Masahiro Yamada58175e32016-07-25 19:15:28 +09001222 defconfigs = get_all_defconfigs()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001223
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001224 progress = Progress(len(defconfigs))
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001225 slots = Slots(configs, options, progress, reference_src_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001226
1227 # Main loop to process defconfig files:
1228 # Add a new subprocess into a vacant slot.
1229 # Sleep if there is no available slot.
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001230 for defconfig in defconfigs:
1231 while not slots.add(defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001232 while not slots.available():
1233 # No available slot: sleep for a while
1234 time.sleep(SLEEP_TIME)
1235
1236 # wait until all the subprocesses finish
1237 while not slots.empty():
1238 time.sleep(SLEEP_TIME)
1239
Joe Hershberger3fa1ab72015-05-19 13:21:25 -05001240 print ''
Masahiro Yamadab6160812015-05-20 11:36:07 +09001241 slots.show_failed_boards()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001242 slots.show_suspicious_boards()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001243
Masahiro Yamadab6160812015-05-20 11:36:07 +09001244def main():
1245 try:
1246 cpu_count = multiprocessing.cpu_count()
1247 except NotImplementedError:
1248 cpu_count = 1
1249
1250 parser = optparse.OptionParser()
1251 # Add options here
1252 parser.add_option('-c', '--color', action='store_true', default=False,
1253 help='display the log in color')
Simon Glass8bf41c22016-09-12 23:18:21 -06001254 parser.add_option('-C', '--commit', action='store_true', default=False,
1255 help='Create a git commit for the operation')
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001256 parser.add_option('-d', '--defconfigs', type='string',
1257 help='a file containing a list of defconfigs to move')
Masahiro Yamadab6160812015-05-20 11:36:07 +09001258 parser.add_option('-n', '--dry-run', action='store_true', default=False,
1259 help='perform a trial run (show log with no changes)')
1260 parser.add_option('-e', '--exit-on-error', action='store_true',
1261 default=False,
1262 help='exit immediately on any error')
Masahiro Yamada83c17672016-05-19 15:52:08 +09001263 parser.add_option('-s', '--force-sync', action='store_true', default=False,
1264 help='force sync by savedefconfig')
Masahiro Yamada6d139172016-08-22 22:18:22 +09001265 parser.add_option('-S', '--spl', action='store_true', default=False,
1266 help='parse config options defined for SPL build')
Joe Hershberger23475932015-05-19 13:21:20 -05001267 parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
1268 action='store_true', default=False,
1269 help='only cleanup the headers')
Masahiro Yamadab6160812015-05-20 11:36:07 +09001270 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
1271 help='the number of jobs to run simultaneously')
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001272 parser.add_option('-r', '--git-ref', type='string',
1273 help='the git ref to clone for building the autoconf.mk')
Simon Glass13e05a02016-09-12 23:18:20 -06001274 parser.add_option('-y', '--yes', action='store_true', default=False,
1275 help="respond 'yes' to any prompts")
Joe Hershberger808b63f2015-05-19 13:21:24 -05001276 parser.add_option('-v', '--verbose', action='store_true', default=False,
1277 help='show any build errors as boards are built')
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001278 parser.usage += ' CONFIG ...'
Masahiro Yamadab6160812015-05-20 11:36:07 +09001279
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001280 (options, configs) = parser.parse_args()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001281
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001282 if len(configs) == 0 and not options.force_sync:
Masahiro Yamadab6160812015-05-20 11:36:07 +09001283 parser.print_usage()
1284 sys.exit(1)
1285
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001286 # prefix the option name with CONFIG_ if missing
1287 configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
1288 for config in configs ]
Masahiro Yamadab6160812015-05-20 11:36:07 +09001289
Joe Hershberger23475932015-05-19 13:21:20 -05001290 check_top_directory()
1291
1292 if not options.cleanup_headers_only:
Masahiro Yamadad0a9d2a2016-07-25 19:15:23 +09001293 check_clean_directory()
1294 update_cross_compile(options.color)
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001295 move_config(configs, options)
Joe Hershberger23475932015-05-19 13:21:20 -05001296
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001297 if configs:
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +09001298 cleanup_headers(configs, options)
Masahiro Yamadadce28de2016-07-25 19:15:29 +09001299 cleanup_extra_options(configs, options)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001300
Simon Glass8bf41c22016-09-12 23:18:21 -06001301 if options.commit:
1302 subprocess.call(['git', 'add', '-u'])
1303 if configs:
1304 msg = 'Convert %s %sto Kconfig' % (configs[0],
1305 'et al ' if len(configs) > 1 else '')
1306 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1307 '\n '.join(configs))
1308 else:
1309 msg = 'configs: Resync with savedefconfig'
1310 msg += '\n\nRsync all defconfig files using moveconfig.py'
1311 subprocess.call(['git', 'commit', '-s', '-m', msg])
1312
Masahiro Yamadab6160812015-05-20 11:36:07 +09001313if __name__ == '__main__':
1314 main()