blob: a8531f1e510638eeb2ee4d4d48f3ee030fdb90d4 [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 Yamada5a27c732015-05-20 11:36:07 +090044It looks like one of the followings:
45
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.
50 The entry for this CONFIG was not found in Kconfig.
51 There are two common cases:
52 - You forgot to create an entry for the CONFIG before running
53 this tool, or made a typo in a CONFIG passed to this tool.
54 - The entry was hidden due to unmet 'depends on'.
55 This is correct behavior.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090056
Masahiro Yamadacc008292016-05-19 15:51:56 +090057 - 'CONFIG_...' is the same as the define in Kconfig. Do nothing.
58 The define in the config header matched the one in Kconfig.
59 We do not need to touch it.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090060
61 - Undefined. Do nothing.
62 This config option was not found in the config header.
63 Nothing to do.
64
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +090065 - Compiler is missing. Do nothing.
66 The compiler specified for this architecture was not found
67 in your PATH environment.
68 (If -e option is passed, the tool exits immediately.)
69
70 - Failed to process.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090071 An error occurred during processing this defconfig. Skipped.
72 (If -e option is passed, the tool exits immediately on error.)
73
74Finally, you will be asked, Clean up headers? [y/n]:
75
76If you say 'y' here, the unnecessary config defines are removed
77from the config headers (include/configs/*.h).
78It just uses the regex method, so you should not rely on it.
79Just in case, please do 'git diff' to see what happened.
80
81
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090082How does it work?
83-----------------
Masahiro Yamada5a27c732015-05-20 11:36:07 +090084
85This tool runs configuration and builds include/autoconf.mk for every
86defconfig. The config options defined in Kconfig appear in the .config
87file (unless they are hidden because of unmet dependency.)
88On the other hand, the config options defined by board headers are seen
89in include/autoconf.mk. The tool looks for the specified options in both
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090090of them to decide the appropriate action for the options. If the given
91config option is found in the .config, but its value does not match the
92one from the board header, the config option in the .config is replaced
93with the define in the board header. Then, the .config is synced by
94"make savedefconfig" and the defconfig is updated with it.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090095
96For faster processing, this tool handles multi-threading. It creates
97separate build directories where the out-of-tree build is run. The
98temporary build directories are automatically created and deleted as
99needed. The number of threads are chosen based on the number of the CPU
100cores of your system although you can change it via -j (--jobs) option.
101
102
103Toolchains
104----------
105
106Appropriate toolchain are necessary to generate include/autoconf.mk
107for all the architectures supported by U-Boot. Most of them are available
108at the kernel.org site, some are not provided by kernel.org.
109
110The default per-arch CROSS_COMPILE used by this tool is specified by
111the list below, CROSS_COMPILE. You may wish to update the list to
112use your own. Instead of modifying the list directly, you can give
113them via environments.
114
115
116Available options
117-----------------
118
119 -c, --color
120 Surround each portion of the log with escape sequences to display it
121 in color on the terminal.
122
Joe Hershberger91040e82015-05-19 13:21:19 -0500123 -d, --defconfigs
124 Specify a file containing a list of defconfigs to move
125
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900126 -n, --dry-run
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900127 Perform a trial run that does not make any changes. It is useful to
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900128 see what is going to happen before one actually runs it.
129
130 -e, --exit-on-error
131 Exit immediately if Make exits with a non-zero status while processing
132 a defconfig file.
133
Joe Hershberger2144f882015-05-19 13:21:20 -0500134 -H, --headers-only
135 Only cleanup the headers; skip the defconfig processing
136
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900137 -j, --jobs
138 Specify the number of threads to run simultaneously. If not specified,
139 the number of threads is the same as the number of CPU cores.
140
Joe Hershberger95bf9c72015-05-19 13:21:24 -0500141 -v, --verbose
142 Show any build errors as boards are built
143
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900144To see the complete list of supported options, run
145
146 $ tools/moveconfig.py -h
147
148"""
149
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900150import filecmp
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900151import fnmatch
152import multiprocessing
153import optparse
154import os
155import re
156import shutil
157import subprocess
158import sys
159import tempfile
160import time
161
162SHOW_GNU_MAKE = 'scripts/show-gnu-make'
163SLEEP_TIME=0.03
164
165# Here is the list of cross-tools I use.
166# Most of them are available at kernel.org
167# (https://www.kernel.org/pub/tools/crosstool/files/bin/), except the followings:
168# arc: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases
169# blackfin: http://sourceforge.net/projects/adi-toolchain/files/
Bin Meng4440ece2015-09-25 01:22:39 -0700170# nds32: http://osdk.andestech.com/packages/nds32le-linux-glibc-v1.tgz
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900171# nios2: https://sourcery.mentor.com/GNUToolchain/subscription42545
172# sh: http://sourcery.mentor.com/public/gnu_toolchain/sh-linux-gnu
Bin Menge8aebc42016-02-21 21:18:02 -0800173#
174# openrisc kernel.org toolchain is out of date, download latest one from
175# http://opencores.org/or1k/OpenRISC_GNU_tool_chain#Prebuilt_versions
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900176CROSS_COMPILE = {
177 'arc': 'arc-linux-',
178 'aarch64': 'aarch64-linux-',
179 'arm': 'arm-unknown-linux-gnueabi-',
180 'avr32': 'avr32-linux-',
181 'blackfin': 'bfin-elf-',
182 'm68k': 'm68k-linux-',
183 'microblaze': 'microblaze-linux-',
184 'mips': 'mips-linux-',
185 'nds32': 'nds32le-linux-',
186 'nios2': 'nios2-linux-gnu-',
Bin Menge8aebc42016-02-21 21:18:02 -0800187 'openrisc': 'or1k-elf-',
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900188 'powerpc': 'powerpc-linux-',
189 'sh': 'sh-linux-gnu-',
190 'sparc': 'sparc-linux-',
191 'x86': 'i386-linux-'
192}
193
194STATE_IDLE = 0
195STATE_DEFCONFIG = 1
196STATE_AUTOCONF = 2
Joe Hershberger96464ba2015-05-19 13:21:17 -0500197STATE_SAVEDEFCONFIG = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900198
199ACTION_MOVE = 0
Masahiro Yamadacc008292016-05-19 15:51:56 +0900200ACTION_NO_ENTRY = 1
201ACTION_NO_CHANGE = 2
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900202
203COLOR_BLACK = '0;30'
204COLOR_RED = '0;31'
205COLOR_GREEN = '0;32'
206COLOR_BROWN = '0;33'
207COLOR_BLUE = '0;34'
208COLOR_PURPLE = '0;35'
209COLOR_CYAN = '0;36'
210COLOR_LIGHT_GRAY = '0;37'
211COLOR_DARK_GRAY = '1;30'
212COLOR_LIGHT_RED = '1;31'
213COLOR_LIGHT_GREEN = '1;32'
214COLOR_YELLOW = '1;33'
215COLOR_LIGHT_BLUE = '1;34'
216COLOR_LIGHT_PURPLE = '1;35'
217COLOR_LIGHT_CYAN = '1;36'
218COLOR_WHITE = '1;37'
219
220### helper functions ###
221def get_devnull():
222 """Get the file object of '/dev/null' device."""
223 try:
224 devnull = subprocess.DEVNULL # py3k
225 except AttributeError:
226 devnull = open(os.devnull, 'wb')
227 return devnull
228
229def check_top_directory():
230 """Exit if we are not at the top of source directory."""
231 for f in ('README', 'Licenses'):
232 if not os.path.exists(f):
233 sys.exit('Please run at the top of source directory.')
234
Masahiro Yamadabd63e5b2016-05-19 15:51:54 +0900235def check_clean_directory():
236 """Exit if the source tree is not clean."""
237 for f in ('.config', 'include/config'):
238 if os.path.exists(f):
239 sys.exit("source tree is not clean, please run 'make mrproper'")
240
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900241def get_make_cmd():
242 """Get the command name of GNU Make.
243
244 U-Boot needs GNU Make for building, but the command name is not
245 necessarily "make". (for example, "gmake" on FreeBSD).
246 Returns the most appropriate command name on your system.
247 """
248 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
249 ret = process.communicate()
250 if process.returncode:
251 sys.exit('GNU Make not found')
252 return ret[0].rstrip()
253
254def color_text(color_enabled, color, string):
255 """Return colored string."""
256 if color_enabled:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900257 # LF should not be surrounded by the escape sequence.
258 # Otherwise, additional whitespace or line-feed might be printed.
259 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
260 for s in string.split('\n') ])
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900261 else:
262 return string
263
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900264def update_cross_compile(color_enabled):
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400265 """Update per-arch CROSS_COMPILE via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900266
267 The default CROSS_COMPILE values are available
268 in the CROSS_COMPILE list above.
269
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400270 You can override them via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900271 CROSS_COMPILE_{ARCH}.
272
273 For example, if you want to override toolchain prefixes
274 for ARM and PowerPC, you can do as follows in your shell:
275
276 export CROSS_COMPILE_ARM=...
277 export CROSS_COMPILE_POWERPC=...
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900278
279 Then, this function checks if specified compilers really exist in your
280 PATH environment.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900281 """
282 archs = []
283
284 for arch in os.listdir('arch'):
285 if os.path.exists(os.path.join('arch', arch, 'Makefile')):
286 archs.append(arch)
287
288 # arm64 is a special case
289 archs.append('aarch64')
290
291 for arch in archs:
292 env = 'CROSS_COMPILE_' + arch.upper()
293 cross_compile = os.environ.get(env)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900294 if not cross_compile:
295 cross_compile = CROSS_COMPILE.get(arch, '')
296
297 for path in os.environ["PATH"].split(os.pathsep):
298 gcc_path = os.path.join(path, cross_compile + 'gcc')
299 if os.path.isfile(gcc_path) and os.access(gcc_path, os.X_OK):
300 break
301 else:
302 print >> sys.stderr, color_text(color_enabled, COLOR_YELLOW,
303 'warning: %sgcc: not found in PATH. %s architecture boards will be skipped'
304 % (cross_compile, arch))
305 cross_compile = None
306
307 CROSS_COMPILE[arch] = cross_compile
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900308
309def cleanup_one_header(header_path, patterns, dry_run):
310 """Clean regex-matched lines away from a file.
311
312 Arguments:
313 header_path: path to the cleaned file.
314 patterns: list of regex patterns. Any lines matching to these
315 patterns are deleted.
316 dry_run: make no changes, but still display log.
317 """
318 with open(header_path) as f:
319 lines = f.readlines()
320
321 matched = []
322 for i, line in enumerate(lines):
323 for pattern in patterns:
324 m = pattern.search(line)
325 if m:
326 print '%s: %s: %s' % (header_path, i + 1, line),
327 matched.append(i)
328 break
329
330 if dry_run or not matched:
331 return
332
333 with open(header_path, 'w') as f:
334 for i, line in enumerate(lines):
335 if not i in matched:
336 f.write(line)
337
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900338def cleanup_headers(configs, dry_run):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900339 """Delete config defines from board headers.
340
341 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900342 configs: A list of CONFIGs to remove.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900343 dry_run: make no changes, but still display log.
344 """
345 while True:
346 choice = raw_input('Clean up headers? [y/n]: ').lower()
347 print choice
348 if choice == 'y' or choice == 'n':
349 break
350
351 if choice == 'n':
352 return
353
354 patterns = []
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900355 for config in configs:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900356 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
357 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
358
Joe Hershberger60727f52015-05-19 13:21:21 -0500359 for dir in 'include', 'arch', 'board':
360 for (dirpath, dirnames, filenames) in os.walk(dir):
361 for filename in filenames:
362 if not fnmatch.fnmatch(filename, '*~'):
363 cleanup_one_header(os.path.join(dirpath, filename),
364 patterns, dry_run)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900365
366### classes ###
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900367class Progress:
368
369 """Progress Indicator"""
370
371 def __init__(self, total):
372 """Create a new progress indicator.
373
374 Arguments:
375 total: A number of defconfig files to process.
376 """
377 self.current = 0
378 self.total = total
379
380 def inc(self):
381 """Increment the number of processed defconfig files."""
382
383 self.current += 1
384
385 def show(self):
386 """Display the progress."""
387 print ' %d defconfigs out of %d\r' % (self.current, self.total),
388 sys.stdout.flush()
389
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900390class KconfigParser:
391
392 """A parser of .config and include/autoconf.mk."""
393
394 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
395 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
396
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900397 def __init__(self, configs, options, build_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900398 """Create a new parser.
399
400 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900401 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900402 options: option flags.
403 build_dir: Build directory.
404 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900405 self.configs = configs
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900406 self.options = options
Masahiro Yamada1f169922016-05-19 15:52:00 +0900407 self.dotconfig = os.path.join(build_dir, '.config')
408 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
409 self.config_autoconf = os.path.join(build_dir, 'include', 'config',
410 'auto.conf')
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900411 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900412
413 def get_cross_compile(self):
414 """Parse .config file and return CROSS_COMPILE.
415
416 Returns:
417 A string storing the compiler prefix for the architecture.
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900418 Return a NULL string for architectures that do not require
419 compiler prefix (Sandbox and native build is the case).
420 Return None if the specified compiler is missing in your PATH.
421 Caller should distinguish '' and None.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900422 """
423 arch = ''
424 cpu = ''
Masahiro Yamada1f169922016-05-19 15:52:00 +0900425 for line in open(self.dotconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900426 m = self.re_arch.match(line)
427 if m:
428 arch = m.group(1)
429 continue
430 m = self.re_cpu.match(line)
431 if m:
432 cpu = m.group(1)
433
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900434 if not arch:
435 return None
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900436
437 # fix-up for aarch64
438 if arch == 'arm' and cpu == 'armv8':
439 arch = 'aarch64'
440
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900441 return CROSS_COMPILE.get(arch, None)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900442
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900443 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900444 """Parse .config, defconfig, include/autoconf.mk for one config.
445
446 This function looks for the config options in the lines from
447 defconfig, .config, and include/autoconf.mk in order to decide
448 which action should be taken for this defconfig.
449
450 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900451 config: CONFIG name to parse.
Masahiro Yamadacc008292016-05-19 15:51:56 +0900452 dotconfig_lines: lines from the .config file.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900453 autoconf_lines: lines from the include/autoconf.mk file.
454
455 Returns:
456 A tupple of the action for this defconfig and the line
457 matched for the config.
458 """
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900459 not_set = '# %s is not set' % config
460
Masahiro Yamadacc008292016-05-19 15:51:56 +0900461 for line in dotconfig_lines:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900462 line = line.rstrip()
463 if line.startswith(config + '=') or line == not_set:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900464 old_val = line
465 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900466 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900467 return (ACTION_NO_ENTRY, config)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900468
469 for line in autoconf_lines:
470 line = line.rstrip()
471 if line.startswith(config + '='):
Masahiro Yamadacc008292016-05-19 15:51:56 +0900472 new_val = line
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900473 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900474 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900475 new_val = not_set
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900476
Masahiro Yamadacc008292016-05-19 15:51:56 +0900477 if old_val == new_val:
478 return (ACTION_NO_CHANGE, new_val)
479
480 # If this CONFIG is neither bool nor trisate
481 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
482 # tools/scripts/define2mk.sed changes '1' to 'y'.
483 # This is a problem if the CONFIG is int type.
484 # Check the type in Kconfig and handle it correctly.
485 if new_val[-2:] == '=y':
486 new_val = new_val[:-1] + '1'
487
488 return (ACTION_MOVE, new_val)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900489
Masahiro Yamada1d085562016-05-19 15:52:02 +0900490 def update_dotconfig(self):
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900491 """Parse files for the config options and update the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900492
Masahiro Yamadacc008292016-05-19 15:51:56 +0900493 This function parses the generated .config and include/autoconf.mk
494 searching the target options.
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900495 Move the config option(s) to the .config as needed.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900496
497 Arguments:
498 defconfig: defconfig name.
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900499
500 Returns:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900501 Return a tuple of (updated flag, log string).
502 The "updated flag" is True if the .config was updated, False
503 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900504 """
505
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900506 results = []
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900507 updated = False
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900508
Masahiro Yamada1f169922016-05-19 15:52:00 +0900509 with open(self.dotconfig) as f:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900510 dotconfig_lines = f.readlines()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900511
Masahiro Yamada1f169922016-05-19 15:52:00 +0900512 with open(self.autoconf) as f:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900513 autoconf_lines = f.readlines()
514
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900515 for config in self.configs:
516 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger96464ba2015-05-19 13:21:17 -0500517 autoconf_lines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900518 results.append(result)
519
520 log = ''
521
522 for (action, value) in results:
523 if action == ACTION_MOVE:
524 actlog = "Move '%s'" % value
525 log_color = COLOR_LIGHT_GREEN
Masahiro Yamadacc008292016-05-19 15:51:56 +0900526 elif action == ACTION_NO_ENTRY:
527 actlog = "%s is not defined in Kconfig. Do nothing." % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900528 log_color = COLOR_LIGHT_BLUE
Masahiro Yamadacc008292016-05-19 15:51:56 +0900529 elif action == ACTION_NO_CHANGE:
530 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
531 % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900532 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900533 else:
534 sys.exit("Internal Error. This should not happen.")
535
Masahiro Yamada1d085562016-05-19 15:52:02 +0900536 log += color_text(self.options.color, log_color, actlog) + '\n'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900537
Masahiro Yamada1f169922016-05-19 15:52:00 +0900538 with open(self.dotconfig, 'a') as f:
Masahiro Yamadae423d172016-05-19 15:51:49 +0900539 for (action, value) in results:
540 if action == ACTION_MOVE:
541 f.write(value + '\n')
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900542 updated = True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900543
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900544 self.results = results
Masahiro Yamada1f169922016-05-19 15:52:00 +0900545 os.remove(self.config_autoconf)
546 os.remove(self.autoconf)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900547
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900548 return (updated, log)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900549
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900550 def check_defconfig(self):
551 """Check the defconfig after savedefconfig
552
553 Returns:
554 Return additional log if moved CONFIGs were removed again by
555 'make savedefconfig'.
556 """
557
558 log = ''
559
560 with open(self.defconfig) as f:
561 defconfig_lines = f.readlines()
562
563 for (action, value) in self.results:
564 if action != ACTION_MOVE:
565 continue
566 if not value + '\n' in defconfig_lines:
567 log += color_text(self.options.color, COLOR_YELLOW,
568 "'%s' was removed by savedefconfig.\n" %
569 value)
570
571 return log
572
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900573class Slot:
574
575 """A slot to store a subprocess.
576
577 Each instance of this class handles one subprocess.
578 This class is useful to control multiple threads
579 for faster processing.
580 """
581
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900582 def __init__(self, configs, options, progress, devnull, make_cmd):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900583 """Create a new process slot.
584
585 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900586 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900587 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900588 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900589 devnull: A file object of '/dev/null'.
590 make_cmd: command name of GNU Make.
591 """
592 self.options = options
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900593 self.progress = progress
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900594 self.build_dir = tempfile.mkdtemp()
595 self.devnull = devnull
596 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900597 self.parser = KconfigParser(configs, options, self.build_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900598 self.state = STATE_IDLE
599 self.failed_boards = []
600
601 def __del__(self):
602 """Delete the working directory
603
604 This function makes sure the temporary directory is cleaned away
605 even if Python suddenly dies due to error. It should be done in here
606 because it is guranteed the destructor is always invoked when the
607 instance of the class gets unreferenced.
608
609 If the subprocess is still running, wait until it finishes.
610 """
611 if self.state != STATE_IDLE:
612 while self.ps.poll() == None:
613 pass
614 shutil.rmtree(self.build_dir)
615
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900616 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900617 """Assign a new subprocess for defconfig and add it to the slot.
618
619 If the slot is vacant, create a new subprocess for processing the
620 given defconfig and add it to the slot. Just returns False if
621 the slot is occupied (i.e. the current subprocess is still running).
622
623 Arguments:
624 defconfig: defconfig name.
625
626 Returns:
627 Return True on success or False on failure
628 """
629 if self.state != STATE_IDLE:
630 return False
631 cmd = list(self.make_cmd)
632 cmd.append(defconfig)
Joe Hershberger25400092015-05-19 13:21:23 -0500633 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
634 stderr=subprocess.PIPE)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900635 self.defconfig = defconfig
636 self.state = STATE_DEFCONFIG
Masahiro Yamada1d085562016-05-19 15:52:02 +0900637 self.log = ''
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900638 return True
639
640 def poll(self):
641 """Check the status of the subprocess and handle it as needed.
642
643 Returns True if the slot is vacant (i.e. in idle state).
644 If the configuration is successfully finished, assign a new
645 subprocess to build include/autoconf.mk.
646 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900647 parse the .config and the include/autoconf.mk, moving
648 config options to the .config as needed.
649 If the .config was updated, run "make savedefconfig" to sync
650 it, update the original defconfig, and then set the slot back
651 to the idle state.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900652
653 Returns:
654 Return True if the subprocess is terminated, False otherwise
655 """
656 if self.state == STATE_IDLE:
657 return True
658
659 if self.ps.poll() == None:
660 return False
661
662 if self.ps.poll() != 0:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900663 self.log += color_text(self.options.color, COLOR_LIGHT_RED,
664 "Failed to process.\n")
Joe Hershberger95bf9c72015-05-19 13:21:24 -0500665 if self.options.verbose:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900666 self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
667 self.ps.stderr.read())
Masahiro Yamada4efef992016-05-19 15:52:03 +0900668 self.finish(False)
Masahiro Yamadaff8725b2016-05-19 15:51:51 +0900669 return True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900670
671 if self.state == STATE_AUTOCONF:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900672 (updated, log) = self.parser.update_dotconfig()
673 self.log += log
Joe Hershberger96464ba2015-05-19 13:21:17 -0500674
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900675 if not updated:
676 self.finish(True)
677 return True
Masahiro Yamadac1c4d0f2016-05-19 15:52:05 +0900678 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
679 "Syncing by savedefconfig...\n")
Joe Hershberger96464ba2015-05-19 13:21:17 -0500680 cmd = list(self.make_cmd)
681 cmd.append('savedefconfig')
682 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Joe Hershberger25400092015-05-19 13:21:23 -0500683 stderr=subprocess.PIPE)
Joe Hershberger96464ba2015-05-19 13:21:17 -0500684 self.state = STATE_SAVEDEFCONFIG
685 return False
686
687 if self.state == STATE_SAVEDEFCONFIG:
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900688 self.log += self.parser.check_defconfig()
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900689 orig_defconfig = os.path.join('configs', self.defconfig)
690 new_defconfig = os.path.join(self.build_dir, 'defconfig')
691 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
692
693 if updated:
694 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
695 "defconfig was updated.\n")
696
697 if not self.options.dry_run and updated:
698 shutil.move(new_defconfig, orig_defconfig)
Masahiro Yamada4efef992016-05-19 15:52:03 +0900699 self.finish(True)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900700 return True
701
Joe Hershberger25400092015-05-19 13:21:23 -0500702 self.cross_compile = self.parser.get_cross_compile()
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900703 if self.cross_compile is None:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900704 self.log += color_text(self.options.color, COLOR_YELLOW,
705 "Compiler is missing. Do nothing.\n")
Masahiro Yamada4efef992016-05-19 15:52:03 +0900706 self.finish(False)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900707 return True
708
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900709 cmd = list(self.make_cmd)
Joe Hershberger25400092015-05-19 13:21:23 -0500710 if self.cross_compile:
711 cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
Joe Hershberger7740f652015-05-19 13:21:18 -0500712 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900713 cmd.append('include/config/auto.conf')
Joe Hershberger25400092015-05-19 13:21:23 -0500714 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Joe Hershberger25400092015-05-19 13:21:23 -0500715 stderr=subprocess.PIPE)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900716 self.state = STATE_AUTOCONF
717 return False
718
Masahiro Yamada4efef992016-05-19 15:52:03 +0900719 def finish(self, success):
720 """Display log along with progress and go to the idle state.
Masahiro Yamada1d085562016-05-19 15:52:02 +0900721
722 Arguments:
Masahiro Yamada4efef992016-05-19 15:52:03 +0900723 success: Should be True when the defconfig was processed
724 successfully, or False when it fails.
Masahiro Yamada1d085562016-05-19 15:52:02 +0900725 """
726 # output at least 30 characters to hide the "* defconfigs out of *".
727 log = self.defconfig.ljust(30) + '\n'
728
729 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
730 # Some threads are running in parallel.
731 # Print log atomically to not mix up logs from different threads.
Masahiro Yamada4efef992016-05-19 15:52:03 +0900732 print >> (sys.stdout if success else sys.stderr), log
733
734 if not success:
735 if self.options.exit_on_error:
736 sys.exit("Exit on error.")
737 # If --exit-on-error flag is not set, skip this board and continue.
738 # Record the failed board.
739 self.failed_boards.append(self.defconfig)
740
Masahiro Yamada1d085562016-05-19 15:52:02 +0900741 self.progress.inc()
742 self.progress.show()
Masahiro Yamada4efef992016-05-19 15:52:03 +0900743 self.state = STATE_IDLE
Masahiro Yamada1d085562016-05-19 15:52:02 +0900744
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900745 def get_failed_boards(self):
746 """Returns a list of failed boards (defconfigs) in this slot.
747 """
748 return self.failed_boards
749
750class Slots:
751
752 """Controller of the array of subprocess slots."""
753
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900754 def __init__(self, configs, options, progress):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900755 """Create a new slots controller.
756
757 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900758 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900759 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900760 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900761 """
762 self.options = options
763 self.slots = []
764 devnull = get_devnull()
765 make_cmd = get_make_cmd()
766 for i in range(options.jobs):
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900767 self.slots.append(Slot(configs, options, progress, devnull,
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900768 make_cmd))
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900769
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900770 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900771 """Add a new subprocess if a vacant slot is found.
772
773 Arguments:
774 defconfig: defconfig name to be put into.
775
776 Returns:
777 Return True on success or False on failure
778 """
779 for slot in self.slots:
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900780 if slot.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900781 return True
782 return False
783
784 def available(self):
785 """Check if there is a vacant slot.
786
787 Returns:
788 Return True if at lease one vacant slot is found, False otherwise.
789 """
790 for slot in self.slots:
791 if slot.poll():
792 return True
793 return False
794
795 def empty(self):
796 """Check if all slots are vacant.
797
798 Returns:
799 Return True if all the slots are vacant, False otherwise.
800 """
801 ret = True
802 for slot in self.slots:
803 if not slot.poll():
804 ret = False
805 return ret
806
807 def show_failed_boards(self):
808 """Display all of the failed boards (defconfigs)."""
809 failed_boards = []
810
811 for slot in self.slots:
812 failed_boards += slot.get_failed_boards()
813
814 if len(failed_boards) > 0:
815 msg = [ "The following boards were not processed due to error:" ]
816 msg += failed_boards
817 for line in msg:
818 print >> sys.stderr, color_text(self.options.color,
819 COLOR_LIGHT_RED, line)
820
Joe Hershberger2559cd82015-05-19 13:21:22 -0500821 with open('moveconfig.failed', 'w') as f:
822 for board in failed_boards:
823 f.write(board + '\n')
824
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900825def move_config(configs, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900826 """Move config options to defconfig files.
827
828 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900829 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900830 options: option flags
831 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900832 if len(configs) == 0:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900833 print 'Nothing to do. exit.'
834 sys.exit(0)
835
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900836 print 'Move %s (jobs: %d)' % (', '.join(configs), options.jobs)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900837
Joe Hershberger91040e82015-05-19 13:21:19 -0500838 if options.defconfigs:
839 defconfigs = [line.strip() for line in open(options.defconfigs)]
840 for i, defconfig in enumerate(defconfigs):
841 if not defconfig.endswith('_defconfig'):
842 defconfigs[i] = defconfig + '_defconfig'
843 if not os.path.exists(os.path.join('configs', defconfigs[i])):
844 sys.exit('%s - defconfig does not exist. Stopping.' %
845 defconfigs[i])
846 else:
847 # All the defconfig files to be processed
848 defconfigs = []
849 for (dirpath, dirnames, filenames) in os.walk('configs'):
850 dirpath = dirpath[len('configs') + 1:]
851 for filename in fnmatch.filter(filenames, '*_defconfig'):
852 defconfigs.append(os.path.join(dirpath, filename))
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900853
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900854 progress = Progress(len(defconfigs))
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900855 slots = Slots(configs, options, progress)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900856
857 # Main loop to process defconfig files:
858 # Add a new subprocess into a vacant slot.
859 # Sleep if there is no available slot.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900860 for defconfig in defconfigs:
861 while not slots.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900862 while not slots.available():
863 # No available slot: sleep for a while
864 time.sleep(SLEEP_TIME)
865
866 # wait until all the subprocesses finish
867 while not slots.empty():
868 time.sleep(SLEEP_TIME)
869
Joe Hershberger2e2ce6c2015-05-19 13:21:25 -0500870 print ''
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900871 slots.show_failed_boards()
872
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900873def main():
874 try:
875 cpu_count = multiprocessing.cpu_count()
876 except NotImplementedError:
877 cpu_count = 1
878
879 parser = optparse.OptionParser()
880 # Add options here
881 parser.add_option('-c', '--color', action='store_true', default=False,
882 help='display the log in color')
Joe Hershberger91040e82015-05-19 13:21:19 -0500883 parser.add_option('-d', '--defconfigs', type='string',
884 help='a file containing a list of defconfigs to move')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900885 parser.add_option('-n', '--dry-run', action='store_true', default=False,
886 help='perform a trial run (show log with no changes)')
887 parser.add_option('-e', '--exit-on-error', action='store_true',
888 default=False,
889 help='exit immediately on any error')
Joe Hershberger2144f882015-05-19 13:21:20 -0500890 parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
891 action='store_true', default=False,
892 help='only cleanup the headers')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900893 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
894 help='the number of jobs to run simultaneously')
Joe Hershberger95bf9c72015-05-19 13:21:24 -0500895 parser.add_option('-v', '--verbose', action='store_true', default=False,
896 help='show any build errors as boards are built')
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900897 parser.usage += ' CONFIG ...'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900898
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900899 (options, configs) = parser.parse_args()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900900
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900901 if len(configs) == 0:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900902 parser.print_usage()
903 sys.exit(1)
904
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900905 # prefix the option name with CONFIG_ if missing
906 configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
907 for config in configs ]
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900908
Joe Hershberger2144f882015-05-19 13:21:20 -0500909 check_top_directory()
910
Masahiro Yamadabd63e5b2016-05-19 15:51:54 +0900911 check_clean_directory()
912
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900913 update_cross_compile(options.color)
Masahiro Yamada4b430c92016-05-19 15:51:52 +0900914
Joe Hershberger2144f882015-05-19 13:21:20 -0500915 if not options.cleanup_headers_only:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900916 move_config(configs, options)
Joe Hershberger2144f882015-05-19 13:21:20 -0500917
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900918 cleanup_headers(configs, options.dry_run)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900919
920if __name__ == '__main__':
921 main()