blob: 87e2bb232434c73fcdeaf701814790ebdfbaac4e [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
130 Specify a file containing a list of defconfigs to move
131
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900132 -n, --dry-run
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900133 Perform a trial run that does not make any changes. It is useful to
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900134 see what is going to happen before one actually runs it.
135
136 -e, --exit-on-error
137 Exit immediately if Make exits with a non-zero status while processing
138 a defconfig file.
139
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900140 -s, --force-sync
141 Do "make savedefconfig" forcibly for all the defconfig files.
142 If not specified, "make savedefconfig" only occurs for cases
143 where at least one CONFIG was moved.
144
Masahiro Yamada07913d12016-08-22 22:18:22 +0900145 -S, --spl
146 Look for moved config options in spl/include/autoconf.mk instead of
147 include/autoconf.mk. This is useful for moving options for SPL build
148 because SPL related options (mostly prefixed with CONFIG_SPL_) are
149 sometimes blocked by CONFIG_SPL_BUILD ifdef conditionals.
150
Joe Hershberger2144f882015-05-19 13:21:20 -0500151 -H, --headers-only
152 Only cleanup the headers; skip the defconfig processing
153
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900154 -j, --jobs
155 Specify the number of threads to run simultaneously. If not specified,
156 the number of threads is the same as the number of CPU cores.
157
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500158 -r, --git-ref
159 Specify the git ref to clone for building the autoconf.mk. If unspecified
160 use the CWD. This is useful for when changes to the Kconfig affect the
161 default values and you want to capture the state of the defconfig from
162 before that change was in effect. If in doubt, specify a ref pre-Kconfig
163 changes (use HEAD if Kconfig changes are not committed). Worst case it will
164 take a bit longer to run, but will always do the right thing.
165
Joe Hershberger95bf9c72015-05-19 13:21:24 -0500166 -v, --verbose
167 Show any build errors as boards are built
168
Simon Glass6b403df2016-09-12 23:18:20 -0600169 -y, --yes
170 Instead of prompting, automatically go ahead with all operations. This
171 includes cleaning up headers and CONFIG_SYS_EXTRA_OPTIONS.
172
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900173To see the complete list of supported options, run
174
175 $ tools/moveconfig.py -h
176
177"""
178
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900179import copy
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900180import difflib
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900181import filecmp
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900182import fnmatch
183import multiprocessing
184import optparse
185import os
186import re
187import shutil
188import subprocess
189import sys
190import tempfile
191import time
192
193SHOW_GNU_MAKE = 'scripts/show-gnu-make'
194SLEEP_TIME=0.03
195
196# Here is the list of cross-tools I use.
197# Most of them are available at kernel.org
Masahiro Yamadac21fc7e2016-08-21 16:12:36 +0900198# (https://www.kernel.org/pub/tools/crosstool/files/bin/), except the following:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900199# arc: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases
200# blackfin: http://sourceforge.net/projects/adi-toolchain/files/
Bin Meng4440ece2015-09-25 01:22:39 -0700201# nds32: http://osdk.andestech.com/packages/nds32le-linux-glibc-v1.tgz
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900202# nios2: https://sourcery.mentor.com/GNUToolchain/subscription42545
203# sh: http://sourcery.mentor.com/public/gnu_toolchain/sh-linux-gnu
Bin Menge8aebc42016-02-21 21:18:02 -0800204#
205# openrisc kernel.org toolchain is out of date, download latest one from
206# http://opencores.org/or1k/OpenRISC_GNU_tool_chain#Prebuilt_versions
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900207CROSS_COMPILE = {
208 'arc': 'arc-linux-',
209 'aarch64': 'aarch64-linux-',
210 'arm': 'arm-unknown-linux-gnueabi-',
211 'avr32': 'avr32-linux-',
212 'blackfin': 'bfin-elf-',
213 'm68k': 'm68k-linux-',
214 'microblaze': 'microblaze-linux-',
215 'mips': 'mips-linux-',
216 'nds32': 'nds32le-linux-',
217 'nios2': 'nios2-linux-gnu-',
Bin Menge8aebc42016-02-21 21:18:02 -0800218 'openrisc': 'or1k-elf-',
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900219 'powerpc': 'powerpc-linux-',
220 'sh': 'sh-linux-gnu-',
221 'sparc': 'sparc-linux-',
Masahiro Yamada88e13462016-08-21 16:03:08 +0900222 'x86': 'i386-linux-',
223 'xtensa': 'xtensa-linux-'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900224}
225
226STATE_IDLE = 0
227STATE_DEFCONFIG = 1
228STATE_AUTOCONF = 2
Joe Hershberger96464ba2015-05-19 13:21:17 -0500229STATE_SAVEDEFCONFIG = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900230
231ACTION_MOVE = 0
Masahiro Yamadacc008292016-05-19 15:51:56 +0900232ACTION_NO_ENTRY = 1
Masahiro Yamada916224c2016-08-22 22:18:21 +0900233ACTION_NO_ENTRY_WARN = 2
234ACTION_NO_CHANGE = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900235
236COLOR_BLACK = '0;30'
237COLOR_RED = '0;31'
238COLOR_GREEN = '0;32'
239COLOR_BROWN = '0;33'
240COLOR_BLUE = '0;34'
241COLOR_PURPLE = '0;35'
242COLOR_CYAN = '0;36'
243COLOR_LIGHT_GRAY = '0;37'
244COLOR_DARK_GRAY = '1;30'
245COLOR_LIGHT_RED = '1;31'
246COLOR_LIGHT_GREEN = '1;32'
247COLOR_YELLOW = '1;33'
248COLOR_LIGHT_BLUE = '1;34'
249COLOR_LIGHT_PURPLE = '1;35'
250COLOR_LIGHT_CYAN = '1;36'
251COLOR_WHITE = '1;37'
252
253### helper functions ###
254def get_devnull():
255 """Get the file object of '/dev/null' device."""
256 try:
257 devnull = subprocess.DEVNULL # py3k
258 except AttributeError:
259 devnull = open(os.devnull, 'wb')
260 return devnull
261
262def check_top_directory():
263 """Exit if we are not at the top of source directory."""
264 for f in ('README', 'Licenses'):
265 if not os.path.exists(f):
266 sys.exit('Please run at the top of source directory.')
267
Masahiro Yamadabd63e5b2016-05-19 15:51:54 +0900268def check_clean_directory():
269 """Exit if the source tree is not clean."""
270 for f in ('.config', 'include/config'):
271 if os.path.exists(f):
272 sys.exit("source tree is not clean, please run 'make mrproper'")
273
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900274def get_make_cmd():
275 """Get the command name of GNU Make.
276
277 U-Boot needs GNU Make for building, but the command name is not
278 necessarily "make". (for example, "gmake" on FreeBSD).
279 Returns the most appropriate command name on your system.
280 """
281 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
282 ret = process.communicate()
283 if process.returncode:
284 sys.exit('GNU Make not found')
285 return ret[0].rstrip()
286
Masahiro Yamada684c3062016-07-25 19:15:28 +0900287def get_all_defconfigs():
288 """Get all the defconfig files under the configs/ directory."""
289 defconfigs = []
290 for (dirpath, dirnames, filenames) in os.walk('configs'):
291 dirpath = dirpath[len('configs') + 1:]
292 for filename in fnmatch.filter(filenames, '*_defconfig'):
293 defconfigs.append(os.path.join(dirpath, filename))
294
295 return defconfigs
296
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900297def color_text(color_enabled, color, string):
298 """Return colored string."""
299 if color_enabled:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900300 # LF should not be surrounded by the escape sequence.
301 # Otherwise, additional whitespace or line-feed might be printed.
302 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
303 for s in string.split('\n') ])
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900304 else:
305 return string
306
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900307def show_diff(a, b, file_path, color_enabled):
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900308 """Show unidified diff.
309
310 Arguments:
311 a: A list of lines (before)
312 b: A list of lines (after)
313 file_path: Path to the file
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900314 color_enabled: Display the diff in color
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900315 """
316
317 diff = difflib.unified_diff(a, b,
318 fromfile=os.path.join('a', file_path),
319 tofile=os.path.join('b', file_path))
320
321 for line in diff:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900322 if line[0] == '-' and line[1] != '-':
323 print color_text(color_enabled, COLOR_RED, line),
324 elif line[0] == '+' and line[1] != '+':
325 print color_text(color_enabled, COLOR_GREEN, line),
326 else:
327 print line,
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900328
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900329def update_cross_compile(color_enabled):
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400330 """Update per-arch CROSS_COMPILE via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900331
332 The default CROSS_COMPILE values are available
333 in the CROSS_COMPILE list above.
334
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400335 You can override them via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900336 CROSS_COMPILE_{ARCH}.
337
338 For example, if you want to override toolchain prefixes
339 for ARM and PowerPC, you can do as follows in your shell:
340
341 export CROSS_COMPILE_ARM=...
342 export CROSS_COMPILE_POWERPC=...
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900343
344 Then, this function checks if specified compilers really exist in your
345 PATH environment.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900346 """
347 archs = []
348
349 for arch in os.listdir('arch'):
350 if os.path.exists(os.path.join('arch', arch, 'Makefile')):
351 archs.append(arch)
352
353 # arm64 is a special case
354 archs.append('aarch64')
355
356 for arch in archs:
357 env = 'CROSS_COMPILE_' + arch.upper()
358 cross_compile = os.environ.get(env)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900359 if not cross_compile:
360 cross_compile = CROSS_COMPILE.get(arch, '')
361
362 for path in os.environ["PATH"].split(os.pathsep):
363 gcc_path = os.path.join(path, cross_compile + 'gcc')
364 if os.path.isfile(gcc_path) and os.access(gcc_path, os.X_OK):
365 break
366 else:
367 print >> sys.stderr, color_text(color_enabled, COLOR_YELLOW,
368 'warning: %sgcc: not found in PATH. %s architecture boards will be skipped'
369 % (cross_compile, arch))
370 cross_compile = None
371
372 CROSS_COMPILE[arch] = cross_compile
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900373
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900374def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
375 extend_post):
376 """Extend matched lines if desired patterns are found before/after already
377 matched lines.
378
379 Arguments:
380 lines: A list of lines handled.
381 matched: A list of line numbers that have been already matched.
382 (will be updated by this function)
383 pre_patterns: A list of regular expression that should be matched as
384 preamble.
385 post_patterns: A list of regular expression that should be matched as
386 postamble.
387 extend_pre: Add the line number of matched preamble to the matched list.
388 extend_post: Add the line number of matched postamble to the matched list.
389 """
390 extended_matched = []
391
392 j = matched[0]
393
394 for i in matched:
395 if i == 0 or i < j:
396 continue
397 j = i
398 while j in matched:
399 j += 1
400 if j >= len(lines):
401 break
402
403 for p in pre_patterns:
404 if p.search(lines[i - 1]):
405 break
406 else:
407 # not matched
408 continue
409
410 for p in post_patterns:
411 if p.search(lines[j]):
412 break
413 else:
414 # not matched
415 continue
416
417 if extend_pre:
418 extended_matched.append(i - 1)
419 if extend_post:
420 extended_matched.append(j)
421
422 matched += extended_matched
423 matched.sort()
424
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900425def cleanup_one_header(header_path, patterns, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900426 """Clean regex-matched lines away from a file.
427
428 Arguments:
429 header_path: path to the cleaned file.
430 patterns: list of regex patterns. Any lines matching to these
431 patterns are deleted.
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900432 options: option flags.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900433 """
434 with open(header_path) as f:
435 lines = f.readlines()
436
437 matched = []
438 for i, line in enumerate(lines):
Masahiro Yamadaa3a779f2016-07-25 19:15:27 +0900439 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
440 matched.append(i)
441 continue
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900442 for pattern in patterns:
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900443 if pattern.search(line):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900444 matched.append(i)
445 break
446
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900447 if not matched:
448 return
449
450 # remove empty #ifdef ... #endif, successive blank lines
451 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
452 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
453 pattern_endif = re.compile(r'#\s*endif\W') # #endif
454 pattern_blank = re.compile(r'^\s*$') # empty line
455
456 while True:
457 old_matched = copy.copy(matched)
458 extend_matched_lines(lines, matched, [pattern_if],
459 [pattern_endif], True, True)
460 extend_matched_lines(lines, matched, [pattern_elif],
461 [pattern_elif, pattern_endif], True, False)
462 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
463 [pattern_blank], False, True)
464 extend_matched_lines(lines, matched, [pattern_blank],
465 [pattern_elif, pattern_endif], True, False)
466 extend_matched_lines(lines, matched, [pattern_blank],
467 [pattern_blank], True, False)
468 if matched == old_matched:
469 break
470
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900471 tolines = copy.copy(lines)
472
473 for i in reversed(matched):
474 tolines.pop(i)
475
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900476 show_diff(lines, tolines, header_path, options.color)
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900477
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900478 if options.dry_run:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900479 return
480
481 with open(header_path, 'w') as f:
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900482 for line in tolines:
483 f.write(line)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900484
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900485def cleanup_headers(configs, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900486 """Delete config defines from board headers.
487
488 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900489 configs: A list of CONFIGs to remove.
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900490 options: option flags.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900491 """
Simon Glass6b403df2016-09-12 23:18:20 -0600492 if not options.yes:
493 while True:
494 choice = raw_input('Clean up headers? [y/n]: ').lower()
495 print choice
496 if choice == 'y' or choice == 'n':
497 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900498
Simon Glass6b403df2016-09-12 23:18:20 -0600499 if choice == 'n':
500 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900501
502 patterns = []
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900503 for config in configs:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900504 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
505 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
506
Joe Hershberger60727f52015-05-19 13:21:21 -0500507 for dir in 'include', 'arch', 'board':
508 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamadadc6de502016-07-25 19:15:22 +0900509 if dirpath == os.path.join('include', 'generated'):
510 continue
Joe Hershberger60727f52015-05-19 13:21:21 -0500511 for filename in filenames:
512 if not fnmatch.fnmatch(filename, '*~'):
513 cleanup_one_header(os.path.join(dirpath, filename),
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900514 patterns, options)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900515
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900516def cleanup_one_extra_option(defconfig_path, configs, options):
517 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
518
519 Arguments:
520 defconfig_path: path to the cleaned defconfig file.
521 configs: A list of CONFIGs to remove.
522 options: option flags.
523 """
524
525 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
526 end = '"\n'
527
528 with open(defconfig_path) as f:
529 lines = f.readlines()
530
531 for i, line in enumerate(lines):
532 if line.startswith(start) and line.endswith(end):
533 break
534 else:
535 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
536 return
537
538 old_tokens = line[len(start):-len(end)].split(',')
539 new_tokens = []
540
541 for token in old_tokens:
542 pos = token.find('=')
543 if not (token[:pos] if pos >= 0 else token) in configs:
544 new_tokens.append(token)
545
546 if new_tokens == old_tokens:
547 return
548
549 tolines = copy.copy(lines)
550
551 if new_tokens:
552 tolines[i] = start + ','.join(new_tokens) + end
553 else:
554 tolines.pop(i)
555
556 show_diff(lines, tolines, defconfig_path, options.color)
557
558 if options.dry_run:
559 return
560
561 with open(defconfig_path, 'w') as f:
562 for line in tolines:
563 f.write(line)
564
565def cleanup_extra_options(configs, options):
566 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
567
568 Arguments:
569 configs: A list of CONFIGs to remove.
570 options: option flags.
571 """
Simon Glass6b403df2016-09-12 23:18:20 -0600572 if not options.yes:
573 while True:
574 choice = (raw_input('Clean up CONFIG_SYS_EXTRA_OPTIONS? [y/n]: ').
575 lower())
576 print choice
577 if choice == 'y' or choice == 'n':
578 break
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900579
Simon Glass6b403df2016-09-12 23:18:20 -0600580 if choice == 'n':
581 return
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900582
583 configs = [ config[len('CONFIG_'):] for config in configs ]
584
585 defconfigs = get_all_defconfigs()
586
587 for defconfig in defconfigs:
588 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
589 options)
590
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900591### classes ###
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900592class Progress:
593
594 """Progress Indicator"""
595
596 def __init__(self, total):
597 """Create a new progress indicator.
598
599 Arguments:
600 total: A number of defconfig files to process.
601 """
602 self.current = 0
603 self.total = total
604
605 def inc(self):
606 """Increment the number of processed defconfig files."""
607
608 self.current += 1
609
610 def show(self):
611 """Display the progress."""
612 print ' %d defconfigs out of %d\r' % (self.current, self.total),
613 sys.stdout.flush()
614
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900615class KconfigParser:
616
617 """A parser of .config and include/autoconf.mk."""
618
619 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
620 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
621
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900622 def __init__(self, configs, options, build_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900623 """Create a new parser.
624
625 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900626 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900627 options: option flags.
628 build_dir: Build directory.
629 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900630 self.configs = configs
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900631 self.options = options
Masahiro Yamada1f169922016-05-19 15:52:00 +0900632 self.dotconfig = os.path.join(build_dir, '.config')
633 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada07913d12016-08-22 22:18:22 +0900634 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
635 'autoconf.mk')
Masahiro Yamada1f169922016-05-19 15:52:00 +0900636 self.config_autoconf = os.path.join(build_dir, 'include', 'config',
637 'auto.conf')
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900638 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900639
640 def get_cross_compile(self):
641 """Parse .config file and return CROSS_COMPILE.
642
643 Returns:
644 A string storing the compiler prefix for the architecture.
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900645 Return a NULL string for architectures that do not require
646 compiler prefix (Sandbox and native build is the case).
647 Return None if the specified compiler is missing in your PATH.
648 Caller should distinguish '' and None.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900649 """
650 arch = ''
651 cpu = ''
Masahiro Yamada1f169922016-05-19 15:52:00 +0900652 for line in open(self.dotconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900653 m = self.re_arch.match(line)
654 if m:
655 arch = m.group(1)
656 continue
657 m = self.re_cpu.match(line)
658 if m:
659 cpu = m.group(1)
660
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900661 if not arch:
662 return None
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900663
664 # fix-up for aarch64
665 if arch == 'arm' and cpu == 'armv8':
666 arch = 'aarch64'
667
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900668 return CROSS_COMPILE.get(arch, None)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900669
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900670 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900671 """Parse .config, defconfig, include/autoconf.mk for one config.
672
673 This function looks for the config options in the lines from
674 defconfig, .config, and include/autoconf.mk in order to decide
675 which action should be taken for this defconfig.
676
677 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900678 config: CONFIG name to parse.
Masahiro Yamadacc008292016-05-19 15:51:56 +0900679 dotconfig_lines: lines from the .config file.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900680 autoconf_lines: lines from the include/autoconf.mk file.
681
682 Returns:
683 A tupple of the action for this defconfig and the line
684 matched for the config.
685 """
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900686 not_set = '# %s is not set' % config
687
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900688 for line in autoconf_lines:
689 line = line.rstrip()
690 if line.startswith(config + '='):
Masahiro Yamadacc008292016-05-19 15:51:56 +0900691 new_val = line
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900692 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900693 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900694 new_val = not_set
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900695
Masahiro Yamada916224c2016-08-22 22:18:21 +0900696 for line in dotconfig_lines:
697 line = line.rstrip()
698 if line.startswith(config + '=') or line == not_set:
699 old_val = line
700 break
701 else:
702 if new_val == not_set:
703 return (ACTION_NO_ENTRY, config)
704 else:
705 return (ACTION_NO_ENTRY_WARN, config)
706
Masahiro Yamadacc008292016-05-19 15:51:56 +0900707 # If this CONFIG is neither bool nor trisate
708 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
709 # tools/scripts/define2mk.sed changes '1' to 'y'.
710 # This is a problem if the CONFIG is int type.
711 # Check the type in Kconfig and handle it correctly.
712 if new_val[-2:] == '=y':
713 new_val = new_val[:-1] + '1'
714
Masahiro Yamada50301592016-06-15 14:33:50 +0900715 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
716 new_val)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900717
Masahiro Yamada1d085562016-05-19 15:52:02 +0900718 def update_dotconfig(self):
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900719 """Parse files for the config options and update the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900720
Masahiro Yamadacc008292016-05-19 15:51:56 +0900721 This function parses the generated .config and include/autoconf.mk
722 searching the target options.
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900723 Move the config option(s) to the .config as needed.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900724
725 Arguments:
726 defconfig: defconfig name.
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900727
728 Returns:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900729 Return a tuple of (updated flag, log string).
730 The "updated flag" is True if the .config was updated, False
731 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900732 """
733
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900734 results = []
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900735 updated = False
Masahiro Yamada916224c2016-08-22 22:18:21 +0900736 suspicious = False
Masahiro Yamada07913d12016-08-22 22:18:22 +0900737 rm_files = [self.config_autoconf, self.autoconf]
738
739 if self.options.spl:
740 if os.path.exists(self.spl_autoconf):
741 autoconf_path = self.spl_autoconf
742 rm_files.append(self.spl_autoconf)
743 else:
744 for f in rm_files:
745 os.remove(f)
746 return (updated, suspicious,
747 color_text(self.options.color, COLOR_BROWN,
748 "SPL is not enabled. Skipped.") + '\n')
749 else:
750 autoconf_path = self.autoconf
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900751
Masahiro Yamada1f169922016-05-19 15:52:00 +0900752 with open(self.dotconfig) as f:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900753 dotconfig_lines = f.readlines()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900754
Masahiro Yamada07913d12016-08-22 22:18:22 +0900755 with open(autoconf_path) as f:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900756 autoconf_lines = f.readlines()
757
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900758 for config in self.configs:
759 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger96464ba2015-05-19 13:21:17 -0500760 autoconf_lines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900761 results.append(result)
762
763 log = ''
764
765 for (action, value) in results:
766 if action == ACTION_MOVE:
767 actlog = "Move '%s'" % value
768 log_color = COLOR_LIGHT_GREEN
Masahiro Yamadacc008292016-05-19 15:51:56 +0900769 elif action == ACTION_NO_ENTRY:
770 actlog = "%s is not defined in Kconfig. Do nothing." % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900771 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada916224c2016-08-22 22:18:21 +0900772 elif action == ACTION_NO_ENTRY_WARN:
773 actlog = "%s is not defined in Kconfig (suspicious). Do nothing." % value
774 log_color = COLOR_YELLOW
775 suspicious = True
Masahiro Yamadacc008292016-05-19 15:51:56 +0900776 elif action == ACTION_NO_CHANGE:
777 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
778 % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900779 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada07913d12016-08-22 22:18:22 +0900780 elif action == ACTION_SPL_NOT_EXIST:
781 actlog = "SPL is not enabled for this defconfig. Skip."
782 log_color = COLOR_PURPLE
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900783 else:
784 sys.exit("Internal Error. This should not happen.")
785
Masahiro Yamada1d085562016-05-19 15:52:02 +0900786 log += color_text(self.options.color, log_color, actlog) + '\n'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900787
Masahiro Yamada1f169922016-05-19 15:52:00 +0900788 with open(self.dotconfig, 'a') as f:
Masahiro Yamadae423d172016-05-19 15:51:49 +0900789 for (action, value) in results:
790 if action == ACTION_MOVE:
791 f.write(value + '\n')
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900792 updated = True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900793
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900794 self.results = results
Masahiro Yamada07913d12016-08-22 22:18:22 +0900795 for f in rm_files:
796 os.remove(f)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900797
Masahiro Yamada916224c2016-08-22 22:18:21 +0900798 return (updated, suspicious, log)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900799
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900800 def check_defconfig(self):
801 """Check the defconfig after savedefconfig
802
803 Returns:
804 Return additional log if moved CONFIGs were removed again by
805 'make savedefconfig'.
806 """
807
808 log = ''
809
810 with open(self.defconfig) as f:
811 defconfig_lines = f.readlines()
812
813 for (action, value) in self.results:
814 if action != ACTION_MOVE:
815 continue
816 if not value + '\n' in defconfig_lines:
817 log += color_text(self.options.color, COLOR_YELLOW,
818 "'%s' was removed by savedefconfig.\n" %
819 value)
820
821 return log
822
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900823class Slot:
824
825 """A slot to store a subprocess.
826
827 Each instance of this class handles one subprocess.
828 This class is useful to control multiple threads
829 for faster processing.
830 """
831
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500832 def __init__(self, configs, options, progress, devnull, make_cmd, reference_src_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900833 """Create a new process slot.
834
835 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900836 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900837 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900838 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900839 devnull: A file object of '/dev/null'.
840 make_cmd: command name of GNU Make.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500841 reference_src_dir: Determine the true starting config state from this
842 source tree.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900843 """
844 self.options = options
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900845 self.progress = progress
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900846 self.build_dir = tempfile.mkdtemp()
847 self.devnull = devnull
848 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500849 self.reference_src_dir = reference_src_dir
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900850 self.parser = KconfigParser(configs, options, self.build_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900851 self.state = STATE_IDLE
Masahiro Yamada09c6c062016-08-22 22:18:20 +0900852 self.failed_boards = set()
853 self.suspicious_boards = set()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900854
855 def __del__(self):
856 """Delete the working directory
857
858 This function makes sure the temporary directory is cleaned away
859 even if Python suddenly dies due to error. It should be done in here
Joe Hershbergerf2dae752016-06-10 14:53:29 -0500860 because it is guaranteed the destructor is always invoked when the
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900861 instance of the class gets unreferenced.
862
863 If the subprocess is still running, wait until it finishes.
864 """
865 if self.state != STATE_IDLE:
866 while self.ps.poll() == None:
867 pass
868 shutil.rmtree(self.build_dir)
869
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900870 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900871 """Assign a new subprocess for defconfig and add it to the slot.
872
873 If the slot is vacant, create a new subprocess for processing the
874 given defconfig and add it to the slot. Just returns False if
875 the slot is occupied (i.e. the current subprocess is still running).
876
877 Arguments:
878 defconfig: defconfig name.
879
880 Returns:
881 Return True on success or False on failure
882 """
883 if self.state != STATE_IDLE:
884 return False
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900885
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900886 self.defconfig = defconfig
Masahiro Yamada1d085562016-05-19 15:52:02 +0900887 self.log = ''
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900888 self.current_src_dir = self.reference_src_dir
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900889 self.do_defconfig()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900890 return True
891
892 def poll(self):
893 """Check the status of the subprocess and handle it as needed.
894
895 Returns True if the slot is vacant (i.e. in idle state).
896 If the configuration is successfully finished, assign a new
897 subprocess to build include/autoconf.mk.
898 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900899 parse the .config and the include/autoconf.mk, moving
900 config options to the .config as needed.
901 If the .config was updated, run "make savedefconfig" to sync
902 it, update the original defconfig, and then set the slot back
903 to the idle state.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900904
905 Returns:
906 Return True if the subprocess is terminated, False otherwise
907 """
908 if self.state == STATE_IDLE:
909 return True
910
911 if self.ps.poll() == None:
912 return False
913
914 if self.ps.poll() != 0:
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900915 self.handle_error()
916 elif self.state == STATE_DEFCONFIG:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900917 if self.reference_src_dir and not self.current_src_dir:
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500918 self.do_savedefconfig()
919 else:
920 self.do_autoconf()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900921 elif self.state == STATE_AUTOCONF:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900922 if self.current_src_dir:
923 self.current_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500924 self.do_defconfig()
925 else:
926 self.do_savedefconfig()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900927 elif self.state == STATE_SAVEDEFCONFIG:
928 self.update_defconfig()
929 else:
930 sys.exit("Internal Error. This should not happen.")
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900931
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900932 return True if self.state == STATE_IDLE else False
Joe Hershberger96464ba2015-05-19 13:21:17 -0500933
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900934 def handle_error(self):
935 """Handle error cases."""
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900936
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900937 self.log += color_text(self.options.color, COLOR_LIGHT_RED,
938 "Failed to process.\n")
939 if self.options.verbose:
940 self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
941 self.ps.stderr.read())
942 self.finish(False)
Joe Hershberger96464ba2015-05-19 13:21:17 -0500943
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900944 def do_defconfig(self):
945 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900946
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900947 cmd = list(self.make_cmd)
948 cmd.append(self.defconfig)
949 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900950 stderr=subprocess.PIPE,
951 cwd=self.current_src_dir)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900952 self.state = STATE_DEFCONFIG
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900953
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900954 def do_autoconf(self):
955 """Run 'make include/config/auto.conf'."""
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900956
Joe Hershberger25400092015-05-19 13:21:23 -0500957 self.cross_compile = self.parser.get_cross_compile()
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900958 if self.cross_compile is None:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900959 self.log += color_text(self.options.color, COLOR_YELLOW,
960 "Compiler is missing. Do nothing.\n")
Masahiro Yamada4efef992016-05-19 15:52:03 +0900961 self.finish(False)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900962 return
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900963
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900964 cmd = list(self.make_cmd)
Joe Hershberger25400092015-05-19 13:21:23 -0500965 if self.cross_compile:
966 cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
Joe Hershberger7740f652015-05-19 13:21:18 -0500967 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900968 cmd.append('include/config/auto.conf')
Joe Hershberger25400092015-05-19 13:21:23 -0500969 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 Yamada5a27c732015-05-20 11:36:07 +0900972 self.state = STATE_AUTOCONF
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900973
974 def do_savedefconfig(self):
975 """Update the .config and run 'make savedefconfig'."""
976
Masahiro Yamada916224c2016-08-22 22:18:21 +0900977 (updated, suspicious, log) = self.parser.update_dotconfig()
978 if suspicious:
979 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900980 self.log += log
981
982 if not self.options.force_sync and not updated:
983 self.finish(True)
984 return
985 if updated:
986 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
987 "Syncing by savedefconfig...\n")
988 else:
989 self.log += "Syncing by savedefconfig (forced by option)...\n"
990
991 cmd = list(self.make_cmd)
992 cmd.append('savedefconfig')
993 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
994 stderr=subprocess.PIPE)
995 self.state = STATE_SAVEDEFCONFIG
996
997 def update_defconfig(self):
998 """Update the input defconfig and go back to the idle state."""
999
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001000 log = self.parser.check_defconfig()
1001 if log:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001002 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001003 self.log += log
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001004 orig_defconfig = os.path.join('configs', self.defconfig)
1005 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1006 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1007
1008 if updated:
Joe Hershberger06cc1d32016-06-10 14:53:30 -05001009 self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001010 "defconfig was updated.\n")
1011
1012 if not self.options.dry_run and updated:
1013 shutil.move(new_defconfig, orig_defconfig)
1014 self.finish(True)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001015
Masahiro Yamada4efef992016-05-19 15:52:03 +09001016 def finish(self, success):
1017 """Display log along with progress and go to the idle state.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001018
1019 Arguments:
Masahiro Yamada4efef992016-05-19 15:52:03 +09001020 success: Should be True when the defconfig was processed
1021 successfully, or False when it fails.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001022 """
1023 # output at least 30 characters to hide the "* defconfigs out of *".
1024 log = self.defconfig.ljust(30) + '\n'
1025
1026 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1027 # Some threads are running in parallel.
1028 # Print log atomically to not mix up logs from different threads.
Masahiro Yamada4efef992016-05-19 15:52:03 +09001029 print >> (sys.stdout if success else sys.stderr), log
1030
1031 if not success:
1032 if self.options.exit_on_error:
1033 sys.exit("Exit on error.")
1034 # If --exit-on-error flag is not set, skip this board and continue.
1035 # Record the failed board.
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001036 self.failed_boards.add(self.defconfig)
Masahiro Yamada4efef992016-05-19 15:52:03 +09001037
Masahiro Yamada1d085562016-05-19 15:52:02 +09001038 self.progress.inc()
1039 self.progress.show()
Masahiro Yamada4efef992016-05-19 15:52:03 +09001040 self.state = STATE_IDLE
Masahiro Yamada1d085562016-05-19 15:52:02 +09001041
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001042 def get_failed_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001043 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001044 """
1045 return self.failed_boards
1046
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001047 def get_suspicious_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001048 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001049 """
Masahiro Yamada916224c2016-08-22 22:18:21 +09001050 return self.suspicious_boards - self.failed_boards
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001051
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001052class Slots:
1053
1054 """Controller of the array of subprocess slots."""
1055
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001056 def __init__(self, configs, options, progress, reference_src_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001057 """Create a new slots controller.
1058
1059 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001060 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001061 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001062 progress: A progress indicator.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001063 reference_src_dir: Determine the true starting config state from this
1064 source tree.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001065 """
1066 self.options = options
1067 self.slots = []
1068 devnull = get_devnull()
1069 make_cmd = get_make_cmd()
1070 for i in range(options.jobs):
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001071 self.slots.append(Slot(configs, options, progress, devnull,
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001072 make_cmd, reference_src_dir))
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001073
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001074 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001075 """Add a new subprocess if a vacant slot is found.
1076
1077 Arguments:
1078 defconfig: defconfig name to be put into.
1079
1080 Returns:
1081 Return True on success or False on failure
1082 """
1083 for slot in self.slots:
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001084 if slot.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001085 return True
1086 return False
1087
1088 def available(self):
1089 """Check if there is a vacant slot.
1090
1091 Returns:
1092 Return True if at lease one vacant slot is found, False otherwise.
1093 """
1094 for slot in self.slots:
1095 if slot.poll():
1096 return True
1097 return False
1098
1099 def empty(self):
1100 """Check if all slots are vacant.
1101
1102 Returns:
1103 Return True if all the slots are vacant, False otherwise.
1104 """
1105 ret = True
1106 for slot in self.slots:
1107 if not slot.poll():
1108 ret = False
1109 return ret
1110
1111 def show_failed_boards(self):
1112 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001113 boards = set()
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001114 output_file = 'moveconfig.failed'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001115
1116 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001117 boards |= slot.get_failed_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001118
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001119 if boards:
1120 boards = '\n'.join(boards) + '\n'
1121 msg = "The following boards were not processed due to error:\n"
1122 msg += boards
1123 msg += "(the list has been saved in %s)\n" % output_file
1124 print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
1125 msg)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001126
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001127 with open(output_file, 'w') as f:
1128 f.write(boards)
Joe Hershberger2559cd82015-05-19 13:21:22 -05001129
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001130 def show_suspicious_boards(self):
1131 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001132 boards = set()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001133 output_file = 'moveconfig.suspicious'
1134
1135 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001136 boards |= slot.get_suspicious_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001137
1138 if boards:
1139 boards = '\n'.join(boards) + '\n'
1140 msg = "The following boards might have been converted incorrectly.\n"
1141 msg += "It is highly recommended to check them manually:\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_YELLOW,
1145 msg)
1146
1147 with open(output_file, 'w') as f:
1148 f.write(boards)
1149
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001150class ReferenceSource:
1151
1152 """Reference source against which original configs should be parsed."""
1153
1154 def __init__(self, commit):
1155 """Create a reference source directory based on a specified commit.
1156
1157 Arguments:
1158 commit: commit to git-clone
1159 """
1160 self.src_dir = tempfile.mkdtemp()
1161 print "Cloning git repo to a separate work directory..."
1162 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1163 cwd=self.src_dir)
1164 print "Checkout '%s' to build the original autoconf.mk." % \
1165 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
1166 subprocess.check_output(['git', 'checkout', commit],
1167 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001168
1169 def __del__(self):
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001170 """Delete the reference source directory
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001171
1172 This function makes sure the temporary directory is cleaned away
1173 even if Python suddenly dies due to error. It should be done in here
1174 because it is guaranteed the destructor is always invoked when the
1175 instance of the class gets unreferenced.
1176 """
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001177 shutil.rmtree(self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001178
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001179 def get_dir(self):
1180 """Return the absolute path to the reference source directory."""
1181
1182 return self.src_dir
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001183
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001184def move_config(configs, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001185 """Move config options to defconfig files.
1186
1187 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001188 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001189 options: option flags
1190 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001191 if len(configs) == 0:
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001192 if options.force_sync:
1193 print 'No CONFIG is specified. You are probably syncing defconfigs.',
1194 else:
1195 print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
1196 else:
1197 print 'Move ' + ', '.join(configs),
1198 print '(jobs: %d)\n' % options.jobs
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001199
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001200 if options.git_ref:
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001201 reference_src = ReferenceSource(options.git_ref)
1202 reference_src_dir = reference_src.get_dir()
1203 else:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001204 reference_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001205
Joe Hershberger91040e82015-05-19 13:21:19 -05001206 if options.defconfigs:
1207 defconfigs = [line.strip() for line in open(options.defconfigs)]
1208 for i, defconfig in enumerate(defconfigs):
1209 if not defconfig.endswith('_defconfig'):
1210 defconfigs[i] = defconfig + '_defconfig'
1211 if not os.path.exists(os.path.join('configs', defconfigs[i])):
1212 sys.exit('%s - defconfig does not exist. Stopping.' %
1213 defconfigs[i])
1214 else:
Masahiro Yamada684c3062016-07-25 19:15:28 +09001215 defconfigs = get_all_defconfigs()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001216
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001217 progress = Progress(len(defconfigs))
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001218 slots = Slots(configs, options, progress, reference_src_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001219
1220 # Main loop to process defconfig files:
1221 # Add a new subprocess into a vacant slot.
1222 # Sleep if there is no available slot.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001223 for defconfig in defconfigs:
1224 while not slots.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001225 while not slots.available():
1226 # No available slot: sleep for a while
1227 time.sleep(SLEEP_TIME)
1228
1229 # wait until all the subprocesses finish
1230 while not slots.empty():
1231 time.sleep(SLEEP_TIME)
1232
Joe Hershberger2e2ce6c2015-05-19 13:21:25 -05001233 print ''
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001234 slots.show_failed_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001235 slots.show_suspicious_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001236
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001237def main():
1238 try:
1239 cpu_count = multiprocessing.cpu_count()
1240 except NotImplementedError:
1241 cpu_count = 1
1242
1243 parser = optparse.OptionParser()
1244 # Add options here
1245 parser.add_option('-c', '--color', action='store_true', default=False,
1246 help='display the log in color')
Simon Glass9ede2122016-09-12 23:18:21 -06001247 parser.add_option('-C', '--commit', action='store_true', default=False,
1248 help='Create a git commit for the operation')
Joe Hershberger91040e82015-05-19 13:21:19 -05001249 parser.add_option('-d', '--defconfigs', type='string',
1250 help='a file containing a list of defconfigs to move')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001251 parser.add_option('-n', '--dry-run', action='store_true', default=False,
1252 help='perform a trial run (show log with no changes)')
1253 parser.add_option('-e', '--exit-on-error', action='store_true',
1254 default=False,
1255 help='exit immediately on any error')
Masahiro Yamada8513dc02016-05-19 15:52:08 +09001256 parser.add_option('-s', '--force-sync', action='store_true', default=False,
1257 help='force sync by savedefconfig')
Masahiro Yamada07913d12016-08-22 22:18:22 +09001258 parser.add_option('-S', '--spl', action='store_true', default=False,
1259 help='parse config options defined for SPL build')
Joe Hershberger2144f882015-05-19 13:21:20 -05001260 parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
1261 action='store_true', default=False,
1262 help='only cleanup the headers')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001263 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
1264 help='the number of jobs to run simultaneously')
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001265 parser.add_option('-r', '--git-ref', type='string',
1266 help='the git ref to clone for building the autoconf.mk')
Simon Glass6b403df2016-09-12 23:18:20 -06001267 parser.add_option('-y', '--yes', action='store_true', default=False,
1268 help="respond 'yes' to any prompts")
Joe Hershberger95bf9c72015-05-19 13:21:24 -05001269 parser.add_option('-v', '--verbose', action='store_true', default=False,
1270 help='show any build errors as boards are built')
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001271 parser.usage += ' CONFIG ...'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001272
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001273 (options, configs) = parser.parse_args()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001274
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001275 if len(configs) == 0 and not options.force_sync:
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001276 parser.print_usage()
1277 sys.exit(1)
1278
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001279 # prefix the option name with CONFIG_ if missing
1280 configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
1281 for config in configs ]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001282
Joe Hershberger2144f882015-05-19 13:21:20 -05001283 check_top_directory()
1284
1285 if not options.cleanup_headers_only:
Masahiro Yamadaf7536f72016-07-25 19:15:23 +09001286 check_clean_directory()
1287 update_cross_compile(options.color)
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001288 move_config(configs, options)
Joe Hershberger2144f882015-05-19 13:21:20 -05001289
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001290 if configs:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +09001291 cleanup_headers(configs, options)
Masahiro Yamada9ab02962016-07-25 19:15:29 +09001292 cleanup_extra_options(configs, options)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001293
Simon Glass9ede2122016-09-12 23:18:21 -06001294 if options.commit:
1295 subprocess.call(['git', 'add', '-u'])
1296 if configs:
1297 msg = 'Convert %s %sto Kconfig' % (configs[0],
1298 'et al ' if len(configs) > 1 else '')
1299 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1300 '\n '.join(configs))
1301 else:
1302 msg = 'configs: Resync with savedefconfig'
1303 msg += '\n\nRsync all defconfig files using moveconfig.py'
1304 subprocess.call(['git', 'commit', '-s', '-m', msg])
1305
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001306if __name__ == '__main__':
1307 main()