blob: e765acc4a46c269945eeae3cc52e3c82775c3fce [file] [log] [blame]
Masahiro Yamadab6160812015-05-20 11:36:07 +09001#!/usr/bin/env python2
2#
3# Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4#
5# SPDX-License-Identifier: GPL-2.0+
6#
7
8"""
9Move config options from headers to defconfig files.
10
11Since Kconfig was introduced to U-Boot, we have worked on moving
12config options from headers to Kconfig (defconfig).
13
14This tool intends to help this tremendous work.
15
16
17Usage
18-----
19
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090020First, you must edit the Kconfig to add the menu entries for the configs
Joe Hershberger166edec2015-05-19 13:21:17 -050021you are moving.
22
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090023And then run this tool giving CONFIG names you want to move.
24For example, if you want to move CONFIG_CMD_USB and CONFIG_SYS_TEXT_BASE,
25simply type as follows:
Masahiro Yamadab6160812015-05-20 11:36:07 +090026
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090027 $ tools/moveconfig.py CONFIG_CMD_USB CONFIG_SYS_TEXT_BASE
Masahiro Yamadab6160812015-05-20 11:36:07 +090028
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090029The tool walks through all the defconfig files and move the given CONFIGs.
Masahiro Yamadab6160812015-05-20 11:36:07 +090030
31The log is also displayed on the terminal.
32
Masahiro Yamada465b7c02016-05-19 15:52:02 +090033The log is printed for each defconfig as follows:
Masahiro Yamadab6160812015-05-20 11:36:07 +090034
Masahiro Yamada465b7c02016-05-19 15:52:02 +090035<defconfig_name>
36 <action1>
37 <action2>
38 <action3>
39 ...
Masahiro Yamadab6160812015-05-20 11:36:07 +090040
Masahiro Yamada465b7c02016-05-19 15:52:02 +090041<defconfig_name> is the name of the defconfig.
42
43<action*> shows what the tool did for that defconfig.
Masahiro Yamada7facf882016-08-21 16:12:36 +090044It looks like one of the following:
Masahiro Yamadab6160812015-05-20 11:36:07 +090045
46 - Move 'CONFIG_... '
47 This config option was moved to the defconfig
48
Masahiro Yamada5643d6e2016-05-19 15:51:56 +090049 - CONFIG_... is not defined in Kconfig. Do nothing.
Masahiro Yamada35204d92016-08-22 22:18:21 +090050 The entry for this CONFIG was not found in Kconfig. The option is not
51 defined in the config header, either. So, this case can be just skipped.
52
53 - CONFIG_... is not defined in Kconfig (suspicious). Do nothing.
54 This option is defined in the config header, but its entry was not found
55 in Kconfig.
Masahiro Yamada5643d6e2016-05-19 15:51:56 +090056 There are two common cases:
57 - You forgot to create an entry for the CONFIG before running
58 this tool, or made a typo in a CONFIG passed to this tool.
59 - The entry was hidden due to unmet 'depends on'.
Masahiro Yamada35204d92016-08-22 22:18:21 +090060 The tool does not know if the result is reasonable, so please check it
61 manually.
Masahiro Yamadab6160812015-05-20 11:36:07 +090062
Masahiro Yamada5643d6e2016-05-19 15:51:56 +090063 - 'CONFIG_...' is the same as the define in Kconfig. Do nothing.
64 The define in the config header matched the one in Kconfig.
65 We do not need to touch it.
Masahiro Yamadab6160812015-05-20 11:36:07 +090066
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +090067 - Compiler is missing. Do nothing.
68 The compiler specified for this architecture was not found
69 in your PATH environment.
70 (If -e option is passed, the tool exits immediately.)
71
72 - Failed to process.
Masahiro Yamadab6160812015-05-20 11:36:07 +090073 An error occurred during processing this defconfig. Skipped.
74 (If -e option is passed, the tool exits immediately on error.)
75
76Finally, you will be asked, Clean up headers? [y/n]:
77
78If you say 'y' here, the unnecessary config defines are removed
79from the config headers (include/configs/*.h).
80It just uses the regex method, so you should not rely on it.
81Just in case, please do 'git diff' to see what happened.
82
83
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090084How does it work?
85-----------------
Masahiro Yamadab6160812015-05-20 11:36:07 +090086
87This tool runs configuration and builds include/autoconf.mk for every
88defconfig. The config options defined in Kconfig appear in the .config
89file (unless they are hidden because of unmet dependency.)
90On the other hand, the config options defined by board headers are seen
91in include/autoconf.mk. The tool looks for the specified options in both
Masahiro Yamadab903c4e2016-05-19 15:51:58 +090092of them to decide the appropriate action for the options. If the given
93config option is found in the .config, but its value does not match the
94one from the board header, the config option in the .config is replaced
95with the define in the board header. Then, the .config is synced by
96"make savedefconfig" and the defconfig is updated with it.
Masahiro Yamadab6160812015-05-20 11:36:07 +090097
98For faster processing, this tool handles multi-threading. It creates
99separate build directories where the out-of-tree build is run. The
100temporary build directories are automatically created and deleted as
101needed. The number of threads are chosen based on the number of the CPU
102cores of your system although you can change it via -j (--jobs) option.
103
104
105Toolchains
106----------
107
108Appropriate toolchain are necessary to generate include/autoconf.mk
109for all the architectures supported by U-Boot. Most of them are available
110at the kernel.org site, some are not provided by kernel.org.
111
112The default per-arch CROSS_COMPILE used by this tool is specified by
113the list below, CROSS_COMPILE. You may wish to update the list to
114use your own. Instead of modifying the list directly, you can give
115them via environments.
116
117
Simon Glass2d79f702017-06-01 19:39:00 -0600118Tips and trips
119--------------
120
121To sync only X86 defconfigs:
122
123 ./tools/moveconfig.py -s -d <(grep -l X86 configs/*)
124
125or:
126
127 grep -l X86 configs/* | ./tools/moveconfig.py -s -d -
128
129To process CONFIG_CMD_FPGAD only for a subset of configs based on path match:
130
131 ls configs/{hrcon*,iocon*,strider*} | \
132 ./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d -
133
134
Simon Glassc6e73cf2017-06-01 19:39:03 -0600135Finding implied CONFIGs
136-----------------------
137
138Some CONFIG options can be implied by others and this can help to reduce
139the size of the defconfig files. For example, CONFIG_X86 implies
140CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
141all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
142each of the x86 defconfig files.
143
144This tool can help find such configs. To use it, first build a database:
145
146 ./tools/moveconfig.py -b
147
148Then try to query it:
149
150 ./tools/moveconfig.py -i CONFIG_CMD_IRQ
151 CONFIG_CMD_IRQ found in 311/2384 defconfigs
152 44 : CONFIG_SYS_FSL_ERRATUM_IFC_A002769
153 41 : CONFIG_SYS_FSL_ERRATUM_A007075
154 31 : CONFIG_SYS_FSL_DDR_VER_44
155 28 : CONFIG_ARCH_P1010
156 28 : CONFIG_SYS_FSL_ERRATUM_P1010_A003549
157 28 : CONFIG_SYS_FSL_ERRATUM_SEC_A003571
158 28 : CONFIG_SYS_FSL_ERRATUM_IFC_A003399
159 25 : CONFIG_SYS_FSL_ERRATUM_A008044
160 22 : CONFIG_ARCH_P1020
161 21 : CONFIG_SYS_FSL_DDR_VER_46
162 20 : CONFIG_MAX_PIRQ_LINKS
163 20 : CONFIG_HPET_ADDRESS
164 20 : CONFIG_X86
165 20 : CONFIG_PCIE_ECAM_SIZE
166 20 : CONFIG_IRQ_SLOT_COUNT
167 20 : CONFIG_I8259_PIC
168 20 : CONFIG_CPU_ADDR_BITS
169 20 : CONFIG_RAMBASE
170 20 : CONFIG_SYS_FSL_ERRATUM_A005871
171 20 : CONFIG_PCIE_ECAM_BASE
172 20 : CONFIG_X86_TSC_TIMER
173 20 : CONFIG_I8254_TIMER
174 20 : CONFIG_CMD_GETTIME
175 19 : CONFIG_SYS_FSL_ERRATUM_A005812
176 18 : CONFIG_X86_RUN_32BIT
177 17 : CONFIG_CMD_CHIP_CONFIG
178 ...
179
180This shows a list of config options which might imply CONFIG_CMD_EEPROM along
181with how many defconfigs they cover. From this you can see that CONFIG_X86
182implies CONFIG_CMD_EEPROM. Therefore, instead of adding CONFIG_CMD_EEPROM to
183the defconfig of every x86 board, you could add a single imply line to the
184Kconfig file:
185
186 config X86
187 bool "x86 architecture"
188 ...
189 imply CMD_EEPROM
190
191That will cover 20 defconfigs. Many of the options listed are not suitable as
192they are not related. E.g. it would be odd for CONFIG_CMD_GETTIME to imply
193CMD_EEPROM.
194
195Using this search you can reduce the size of moveconfig patches.
196
197
Masahiro Yamadab6160812015-05-20 11:36:07 +0900198Available options
199-----------------
200
201 -c, --color
202 Surround each portion of the log with escape sequences to display it
203 in color on the terminal.
204
Simon Glass8bf41c22016-09-12 23:18:21 -0600205 -C, --commit
206 Create a git commit with the changes when the operation is complete. A
207 standard commit message is used which may need to be edited.
208
Joe Hershbergerc6e043a2015-05-19 13:21:19 -0500209 -d, --defconfigs
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900210 Specify a file containing a list of defconfigs to move. The defconfig
Simon Glass2d79f702017-06-01 19:39:00 -0600211 files can be given with shell-style wildcards. Use '-' to read from stdin.
Joe Hershbergerc6e043a2015-05-19 13:21:19 -0500212
Masahiro Yamadab6160812015-05-20 11:36:07 +0900213 -n, --dry-run
Masahiro Yamadab903c4e2016-05-19 15:51:58 +0900214 Perform a trial run that does not make any changes. It is useful to
Masahiro Yamadab6160812015-05-20 11:36:07 +0900215 see what is going to happen before one actually runs it.
216
217 -e, --exit-on-error
218 Exit immediately if Make exits with a non-zero status while processing
219 a defconfig file.
220
Masahiro Yamada83c17672016-05-19 15:52:08 +0900221 -s, --force-sync
222 Do "make savedefconfig" forcibly for all the defconfig files.
223 If not specified, "make savedefconfig" only occurs for cases
224 where at least one CONFIG was moved.
225
Masahiro Yamada6d139172016-08-22 22:18:22 +0900226 -S, --spl
227 Look for moved config options in spl/include/autoconf.mk instead of
228 include/autoconf.mk. This is useful for moving options for SPL build
229 because SPL related options (mostly prefixed with CONFIG_SPL_) are
230 sometimes blocked by CONFIG_SPL_BUILD ifdef conditionals.
231
Joe Hershberger23475932015-05-19 13:21:20 -0500232 -H, --headers-only
233 Only cleanup the headers; skip the defconfig processing
234
Masahiro Yamadab6160812015-05-20 11:36:07 +0900235 -j, --jobs
236 Specify the number of threads to run simultaneously. If not specified,
237 the number of threads is the same as the number of CPU cores.
238
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500239 -r, --git-ref
240 Specify the git ref to clone for building the autoconf.mk. If unspecified
241 use the CWD. This is useful for when changes to the Kconfig affect the
242 default values and you want to capture the state of the defconfig from
243 before that change was in effect. If in doubt, specify a ref pre-Kconfig
244 changes (use HEAD if Kconfig changes are not committed). Worst case it will
245 take a bit longer to run, but will always do the right thing.
246
Joe Hershberger808b63f2015-05-19 13:21:24 -0500247 -v, --verbose
248 Show any build errors as boards are built
249
Simon Glass13e05a02016-09-12 23:18:20 -0600250 -y, --yes
251 Instead of prompting, automatically go ahead with all operations. This
Simon Glass2d79f702017-06-01 19:39:00 -0600252 includes cleaning up headers, CONFIG_SYS_EXTRA_OPTIONS, the config whitelist
253 and the README.
Simon Glass13e05a02016-09-12 23:18:20 -0600254
Masahiro Yamadab6160812015-05-20 11:36:07 +0900255To see the complete list of supported options, run
256
257 $ tools/moveconfig.py -h
258
259"""
260
Simon Glassc6e73cf2017-06-01 19:39:03 -0600261import collections
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900262import copy
Masahiro Yamada573b3902016-07-25 19:15:25 +0900263import difflib
Masahiro Yamada0f6beda2016-05-19 15:52:07 +0900264import filecmp
Masahiro Yamadab6160812015-05-20 11:36:07 +0900265import fnmatch
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900266import glob
Masahiro Yamadab6160812015-05-20 11:36:07 +0900267import multiprocessing
268import optparse
269import os
Simon Glass43cf08f2017-06-01 19:39:02 -0600270import Queue
Masahiro Yamadab6160812015-05-20 11:36:07 +0900271import re
272import shutil
273import subprocess
274import sys
275import tempfile
Simon Glass43cf08f2017-06-01 19:39:02 -0600276import threading
Masahiro Yamadab6160812015-05-20 11:36:07 +0900277import time
278
279SHOW_GNU_MAKE = 'scripts/show-gnu-make'
280SLEEP_TIME=0.03
281
282# Here is the list of cross-tools I use.
283# Most of them are available at kernel.org
Masahiro Yamada7facf882016-08-21 16:12:36 +0900284# (https://www.kernel.org/pub/tools/crosstool/files/bin/), except the following:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900285# arc: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases
Bin Meng3bb02f62015-09-25 01:22:39 -0700286# nds32: http://osdk.andestech.com/packages/nds32le-linux-glibc-v1.tgz
Masahiro Yamadab6160812015-05-20 11:36:07 +0900287# nios2: https://sourcery.mentor.com/GNUToolchain/subscription42545
288# sh: http://sourcery.mentor.com/public/gnu_toolchain/sh-linux-gnu
289CROSS_COMPILE = {
290 'arc': 'arc-linux-',
291 'aarch64': 'aarch64-linux-',
292 'arm': 'arm-unknown-linux-gnueabi-',
Masahiro Yamadab6160812015-05-20 11:36:07 +0900293 'm68k': 'm68k-linux-',
294 'microblaze': 'microblaze-linux-',
295 'mips': 'mips-linux-',
296 'nds32': 'nds32le-linux-',
297 'nios2': 'nios2-linux-gnu-',
Masahiro Yamadab6160812015-05-20 11:36:07 +0900298 'powerpc': 'powerpc-linux-',
299 'sh': 'sh-linux-gnu-',
Masahiro Yamadad1d9d602016-08-21 16:03:08 +0900300 'x86': 'i386-linux-',
301 'xtensa': 'xtensa-linux-'
Masahiro Yamadab6160812015-05-20 11:36:07 +0900302}
303
304STATE_IDLE = 0
305STATE_DEFCONFIG = 1
306STATE_AUTOCONF = 2
Joe Hershberger166edec2015-05-19 13:21:17 -0500307STATE_SAVEDEFCONFIG = 3
Masahiro Yamadab6160812015-05-20 11:36:07 +0900308
309ACTION_MOVE = 0
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900310ACTION_NO_ENTRY = 1
Masahiro Yamada35204d92016-08-22 22:18:21 +0900311ACTION_NO_ENTRY_WARN = 2
312ACTION_NO_CHANGE = 3
Masahiro Yamadab6160812015-05-20 11:36:07 +0900313
314COLOR_BLACK = '0;30'
315COLOR_RED = '0;31'
316COLOR_GREEN = '0;32'
317COLOR_BROWN = '0;33'
318COLOR_BLUE = '0;34'
319COLOR_PURPLE = '0;35'
320COLOR_CYAN = '0;36'
321COLOR_LIGHT_GRAY = '0;37'
322COLOR_DARK_GRAY = '1;30'
323COLOR_LIGHT_RED = '1;31'
324COLOR_LIGHT_GREEN = '1;32'
325COLOR_YELLOW = '1;33'
326COLOR_LIGHT_BLUE = '1;34'
327COLOR_LIGHT_PURPLE = '1;35'
328COLOR_LIGHT_CYAN = '1;36'
329COLOR_WHITE = '1;37'
330
Simon Glass8fb5bd02017-06-01 19:39:01 -0600331AUTO_CONF_PATH = 'include/config/auto.conf'
Simon Glass43cf08f2017-06-01 19:39:02 -0600332CONFIG_DATABASE = 'moveconfig.db'
Simon Glass8fb5bd02017-06-01 19:39:01 -0600333
334
Masahiro Yamadab6160812015-05-20 11:36:07 +0900335### helper functions ###
336def get_devnull():
337 """Get the file object of '/dev/null' device."""
338 try:
339 devnull = subprocess.DEVNULL # py3k
340 except AttributeError:
341 devnull = open(os.devnull, 'wb')
342 return devnull
343
344def check_top_directory():
345 """Exit if we are not at the top of source directory."""
346 for f in ('README', 'Licenses'):
347 if not os.path.exists(f):
348 sys.exit('Please run at the top of source directory.')
349
Masahiro Yamada990e6772016-05-19 15:51:54 +0900350def check_clean_directory():
351 """Exit if the source tree is not clean."""
352 for f in ('.config', 'include/config'):
353 if os.path.exists(f):
354 sys.exit("source tree is not clean, please run 'make mrproper'")
355
Masahiro Yamadab6160812015-05-20 11:36:07 +0900356def get_make_cmd():
357 """Get the command name of GNU Make.
358
359 U-Boot needs GNU Make for building, but the command name is not
360 necessarily "make". (for example, "gmake" on FreeBSD).
361 Returns the most appropriate command name on your system.
362 """
363 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
364 ret = process.communicate()
365 if process.returncode:
366 sys.exit('GNU Make not found')
367 return ret[0].rstrip()
368
Simon Glass18774bc2017-06-01 19:38:58 -0600369def get_matched_defconfig(line):
370 """Get the defconfig files that match a pattern
371
372 Args:
373 line: Path or filename to match, e.g. 'configs/snow_defconfig' or
374 'k2*_defconfig'. If no directory is provided, 'configs/' is
375 prepended
376
377 Returns:
378 a list of matching defconfig files
379 """
380 dirname = os.path.dirname(line)
381 if dirname:
382 pattern = line
383 else:
384 pattern = os.path.join('configs', line)
385 return glob.glob(pattern) + glob.glob(pattern + '_defconfig')
386
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900387def get_matched_defconfigs(defconfigs_file):
Simon Glass8f3cf312017-06-01 19:38:59 -0600388 """Get all the defconfig files that match the patterns in a file.
389
390 Args:
391 defconfigs_file: File containing a list of defconfigs to process, or
392 '-' to read the list from stdin
393
394 Returns:
395 A list of paths to defconfig files, with no duplicates
396 """
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900397 defconfigs = []
Simon Glass8f3cf312017-06-01 19:38:59 -0600398 if defconfigs_file == '-':
399 fd = sys.stdin
400 defconfigs_file = 'stdin'
401 else:
402 fd = open(defconfigs_file)
403 for i, line in enumerate(fd):
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900404 line = line.strip()
405 if not line:
406 continue # skip blank lines silently
Simon Glass452fa8e2017-06-15 21:39:31 -0600407 if ' ' in line:
408 line = line.split(' ')[0] # handle 'git log' input
Simon Glass18774bc2017-06-01 19:38:58 -0600409 matched = get_matched_defconfig(line)
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900410 if not matched:
411 print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \
412 (defconfigs_file, i + 1, line)
413
414 defconfigs += matched
415
416 # use set() to drop multiple matching
417 return [ defconfig[len('configs') + 1:] for defconfig in set(defconfigs) ]
418
Masahiro Yamada58175e32016-07-25 19:15:28 +0900419def get_all_defconfigs():
420 """Get all the defconfig files under the configs/ directory."""
421 defconfigs = []
422 for (dirpath, dirnames, filenames) in os.walk('configs'):
423 dirpath = dirpath[len('configs') + 1:]
424 for filename in fnmatch.filter(filenames, '*_defconfig'):
425 defconfigs.append(os.path.join(dirpath, filename))
426
427 return defconfigs
428
Masahiro Yamadab6160812015-05-20 11:36:07 +0900429def color_text(color_enabled, color, string):
430 """Return colored string."""
431 if color_enabled:
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900432 # LF should not be surrounded by the escape sequence.
433 # Otherwise, additional whitespace or line-feed might be printed.
434 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
435 for s in string.split('\n') ])
Masahiro Yamadab6160812015-05-20 11:36:07 +0900436 else:
437 return string
438
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900439def show_diff(a, b, file_path, color_enabled):
Masahiro Yamada573b3902016-07-25 19:15:25 +0900440 """Show unidified diff.
441
442 Arguments:
443 a: A list of lines (before)
444 b: A list of lines (after)
445 file_path: Path to the file
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900446 color_enabled: Display the diff in color
Masahiro Yamada573b3902016-07-25 19:15:25 +0900447 """
448
449 diff = difflib.unified_diff(a, b,
450 fromfile=os.path.join('a', file_path),
451 tofile=os.path.join('b', file_path))
452
453 for line in diff:
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900454 if line[0] == '-' and line[1] != '-':
455 print color_text(color_enabled, COLOR_RED, line),
456 elif line[0] == '+' and line[1] != '+':
457 print color_text(color_enabled, COLOR_GREEN, line),
458 else:
459 print line,
Masahiro Yamada573b3902016-07-25 19:15:25 +0900460
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900461def update_cross_compile(color_enabled):
Robert P. J. Day8c60f922016-05-04 04:47:31 -0400462 """Update per-arch CROSS_COMPILE via environment variables
Masahiro Yamadab6160812015-05-20 11:36:07 +0900463
464 The default CROSS_COMPILE values are available
465 in the CROSS_COMPILE list above.
466
Robert P. J. Day8c60f922016-05-04 04:47:31 -0400467 You can override them via environment variables
Masahiro Yamadab6160812015-05-20 11:36:07 +0900468 CROSS_COMPILE_{ARCH}.
469
470 For example, if you want to override toolchain prefixes
471 for ARM and PowerPC, you can do as follows in your shell:
472
473 export CROSS_COMPILE_ARM=...
474 export CROSS_COMPILE_POWERPC=...
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900475
476 Then, this function checks if specified compilers really exist in your
477 PATH environment.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900478 """
479 archs = []
480
481 for arch in os.listdir('arch'):
482 if os.path.exists(os.path.join('arch', arch, 'Makefile')):
483 archs.append(arch)
484
485 # arm64 is a special case
486 archs.append('aarch64')
487
488 for arch in archs:
489 env = 'CROSS_COMPILE_' + arch.upper()
490 cross_compile = os.environ.get(env)
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900491 if not cross_compile:
492 cross_compile = CROSS_COMPILE.get(arch, '')
493
494 for path in os.environ["PATH"].split(os.pathsep):
495 gcc_path = os.path.join(path, cross_compile + 'gcc')
496 if os.path.isfile(gcc_path) and os.access(gcc_path, os.X_OK):
497 break
498 else:
499 print >> sys.stderr, color_text(color_enabled, COLOR_YELLOW,
500 'warning: %sgcc: not found in PATH. %s architecture boards will be skipped'
501 % (cross_compile, arch))
502 cross_compile = None
503
504 CROSS_COMPILE[arch] = cross_compile
Masahiro Yamadab6160812015-05-20 11:36:07 +0900505
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900506def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
507 extend_post):
508 """Extend matched lines if desired patterns are found before/after already
509 matched lines.
510
511 Arguments:
512 lines: A list of lines handled.
513 matched: A list of line numbers that have been already matched.
514 (will be updated by this function)
515 pre_patterns: A list of regular expression that should be matched as
516 preamble.
517 post_patterns: A list of regular expression that should be matched as
518 postamble.
519 extend_pre: Add the line number of matched preamble to the matched list.
520 extend_post: Add the line number of matched postamble to the matched list.
521 """
522 extended_matched = []
523
524 j = matched[0]
525
526 for i in matched:
527 if i == 0 or i < j:
528 continue
529 j = i
530 while j in matched:
531 j += 1
532 if j >= len(lines):
533 break
534
535 for p in pre_patterns:
536 if p.search(lines[i - 1]):
537 break
538 else:
539 # not matched
540 continue
541
542 for p in post_patterns:
543 if p.search(lines[j]):
544 break
545 else:
546 # not matched
547 continue
548
549 if extend_pre:
550 extended_matched.append(i - 1)
551 if extend_post:
552 extended_matched.append(j)
553
554 matched += extended_matched
555 matched.sort()
556
Chris Packham85e15c52017-05-02 21:30:46 +1200557def confirm(options, prompt):
558 if not options.yes:
559 while True:
560 choice = raw_input('{} [y/n]: '.format(prompt))
561 choice = choice.lower()
562 print choice
563 if choice == 'y' or choice == 'n':
564 break
565
566 if choice == 'n':
567 return False
568
569 return True
570
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900571def cleanup_one_header(header_path, patterns, options):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900572 """Clean regex-matched lines away from a file.
573
574 Arguments:
575 header_path: path to the cleaned file.
576 patterns: list of regex patterns. Any lines matching to these
577 patterns are deleted.
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900578 options: option flags.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900579 """
580 with open(header_path) as f:
581 lines = f.readlines()
582
583 matched = []
584 for i, line in enumerate(lines):
Masahiro Yamada6d798ba2016-07-25 19:15:27 +0900585 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
586 matched.append(i)
587 continue
Masahiro Yamadab6160812015-05-20 11:36:07 +0900588 for pattern in patterns:
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900589 if pattern.search(line):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900590 matched.append(i)
591 break
592
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900593 if not matched:
594 return
595
596 # remove empty #ifdef ... #endif, successive blank lines
597 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
598 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
599 pattern_endif = re.compile(r'#\s*endif\W') # #endif
600 pattern_blank = re.compile(r'^\s*$') # empty line
601
602 while True:
603 old_matched = copy.copy(matched)
604 extend_matched_lines(lines, matched, [pattern_if],
605 [pattern_endif], True, True)
606 extend_matched_lines(lines, matched, [pattern_elif],
607 [pattern_elif, pattern_endif], True, False)
608 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
609 [pattern_blank], False, True)
610 extend_matched_lines(lines, matched, [pattern_blank],
611 [pattern_elif, pattern_endif], True, False)
612 extend_matched_lines(lines, matched, [pattern_blank],
613 [pattern_blank], True, False)
614 if matched == old_matched:
615 break
616
Masahiro Yamada573b3902016-07-25 19:15:25 +0900617 tolines = copy.copy(lines)
618
619 for i in reversed(matched):
620 tolines.pop(i)
621
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900622 show_diff(lines, tolines, header_path, options.color)
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900623
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900624 if options.dry_run:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900625 return
626
627 with open(header_path, 'w') as f:
Masahiro Yamada573b3902016-07-25 19:15:25 +0900628 for line in tolines:
629 f.write(line)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900630
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900631def cleanup_headers(configs, options):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900632 """Delete config defines from board headers.
633
634 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900635 configs: A list of CONFIGs to remove.
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900636 options: option flags.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900637 """
Chris Packham85e15c52017-05-02 21:30:46 +1200638 if not confirm(options, 'Clean up headers?'):
639 return
Masahiro Yamadab6160812015-05-20 11:36:07 +0900640
641 patterns = []
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900642 for config in configs:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900643 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
644 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
645
Joe Hershbergerb78ad422015-05-19 13:21:21 -0500646 for dir in 'include', 'arch', 'board':
647 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamada28a6d352016-07-25 19:15:22 +0900648 if dirpath == os.path.join('include', 'generated'):
649 continue
Joe Hershbergerb78ad422015-05-19 13:21:21 -0500650 for filename in filenames:
651 if not fnmatch.fnmatch(filename, '*~'):
652 cleanup_one_header(os.path.join(dirpath, filename),
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900653 patterns, options)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900654
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900655def cleanup_one_extra_option(defconfig_path, configs, options):
656 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
657
658 Arguments:
659 defconfig_path: path to the cleaned defconfig file.
660 configs: A list of CONFIGs to remove.
661 options: option flags.
662 """
663
664 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
665 end = '"\n'
666
667 with open(defconfig_path) as f:
668 lines = f.readlines()
669
670 for i, line in enumerate(lines):
671 if line.startswith(start) and line.endswith(end):
672 break
673 else:
674 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
675 return
676
677 old_tokens = line[len(start):-len(end)].split(',')
678 new_tokens = []
679
680 for token in old_tokens:
681 pos = token.find('=')
682 if not (token[:pos] if pos >= 0 else token) in configs:
683 new_tokens.append(token)
684
685 if new_tokens == old_tokens:
686 return
687
688 tolines = copy.copy(lines)
689
690 if new_tokens:
691 tolines[i] = start + ','.join(new_tokens) + end
692 else:
693 tolines.pop(i)
694
695 show_diff(lines, tolines, defconfig_path, options.color)
696
697 if options.dry_run:
698 return
699
700 with open(defconfig_path, 'w') as f:
701 for line in tolines:
702 f.write(line)
703
704def cleanup_extra_options(configs, options):
705 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
706
707 Arguments:
708 configs: A list of CONFIGs to remove.
709 options: option flags.
710 """
Chris Packham85e15c52017-05-02 21:30:46 +1200711 if not confirm(options, 'Clean up CONFIG_SYS_EXTRA_OPTIONS?'):
712 return
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900713
714 configs = [ config[len('CONFIG_'):] for config in configs ]
715
716 defconfigs = get_all_defconfigs()
717
718 for defconfig in defconfigs:
719 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
720 options)
721
Chris Packham9d5274f2017-05-02 21:30:47 +1200722def cleanup_whitelist(configs, options):
723 """Delete config whitelist entries
724
725 Arguments:
726 configs: A list of CONFIGs to remove.
727 options: option flags.
728 """
729 if not confirm(options, 'Clean up whitelist entries?'):
730 return
731
732 with open(os.path.join('scripts', 'config_whitelist.txt')) as f:
733 lines = f.readlines()
734
735 lines = [x for x in lines if x.strip() not in configs]
736
737 with open(os.path.join('scripts', 'config_whitelist.txt'), 'w') as f:
738 f.write(''.join(lines))
739
Chris Packham0e6deff2017-05-02 21:30:48 +1200740def find_matching(patterns, line):
741 for pat in patterns:
742 if pat.search(line):
743 return True
744 return False
745
746def cleanup_readme(configs, options):
747 """Delete config description in README
748
749 Arguments:
750 configs: A list of CONFIGs to remove.
751 options: option flags.
752 """
753 if not confirm(options, 'Clean up README?'):
754 return
755
756 patterns = []
757 for config in configs:
758 patterns.append(re.compile(r'^\s+%s' % config))
759
760 with open('README') as f:
761 lines = f.readlines()
762
763 found = False
764 newlines = []
765 for line in lines:
766 if not found:
767 found = find_matching(patterns, line)
768 if found:
769 continue
770
771 if found and re.search(r'^\s+CONFIG', line):
772 found = False
773
774 if not found:
775 newlines.append(line)
776
777 with open('README', 'w') as f:
778 f.write(''.join(newlines))
779
Chris Packham9d5274f2017-05-02 21:30:47 +1200780
Masahiro Yamadab6160812015-05-20 11:36:07 +0900781### classes ###
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900782class Progress:
783
784 """Progress Indicator"""
785
786 def __init__(self, total):
787 """Create a new progress indicator.
788
789 Arguments:
790 total: A number of defconfig files to process.
791 """
792 self.current = 0
793 self.total = total
794
795 def inc(self):
796 """Increment the number of processed defconfig files."""
797
798 self.current += 1
799
800 def show(self):
801 """Display the progress."""
802 print ' %d defconfigs out of %d\r' % (self.current, self.total),
803 sys.stdout.flush()
804
Masahiro Yamadab6160812015-05-20 11:36:07 +0900805class KconfigParser:
806
807 """A parser of .config and include/autoconf.mk."""
808
809 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
810 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
811
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900812 def __init__(self, configs, options, build_dir):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900813 """Create a new parser.
814
815 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900816 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900817 options: option flags.
818 build_dir: Build directory.
819 """
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900820 self.configs = configs
Masahiro Yamadab6160812015-05-20 11:36:07 +0900821 self.options = options
Masahiro Yamada5393b612016-05-19 15:52:00 +0900822 self.dotconfig = os.path.join(build_dir, '.config')
823 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada6d139172016-08-22 22:18:22 +0900824 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
825 'autoconf.mk')
Simon Glass8fb5bd02017-06-01 19:39:01 -0600826 self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH)
Masahiro Yamada07f98522016-05-19 15:52:06 +0900827 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamadab6160812015-05-20 11:36:07 +0900828
829 def get_cross_compile(self):
830 """Parse .config file and return CROSS_COMPILE.
831
832 Returns:
833 A string storing the compiler prefix for the architecture.
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900834 Return a NULL string for architectures that do not require
835 compiler prefix (Sandbox and native build is the case).
836 Return None if the specified compiler is missing in your PATH.
837 Caller should distinguish '' and None.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900838 """
839 arch = ''
840 cpu = ''
Masahiro Yamada5393b612016-05-19 15:52:00 +0900841 for line in open(self.dotconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900842 m = self.re_arch.match(line)
843 if m:
844 arch = m.group(1)
845 continue
846 m = self.re_cpu.match(line)
847 if m:
848 cpu = m.group(1)
849
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900850 if not arch:
851 return None
Masahiro Yamadab6160812015-05-20 11:36:07 +0900852
853 # fix-up for aarch64
854 if arch == 'arm' and cpu == 'armv8':
855 arch = 'aarch64'
856
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900857 return CROSS_COMPILE.get(arch, None)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900858
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900859 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900860 """Parse .config, defconfig, include/autoconf.mk for one config.
861
862 This function looks for the config options in the lines from
863 defconfig, .config, and include/autoconf.mk in order to decide
864 which action should be taken for this defconfig.
865
866 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900867 config: CONFIG name to parse.
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900868 dotconfig_lines: lines from the .config file.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900869 autoconf_lines: lines from the include/autoconf.mk file.
870
871 Returns:
872 A tupple of the action for this defconfig and the line
873 matched for the config.
874 """
Masahiro Yamadab6160812015-05-20 11:36:07 +0900875 not_set = '# %s is not set' % config
876
Masahiro Yamadab6160812015-05-20 11:36:07 +0900877 for line in autoconf_lines:
878 line = line.rstrip()
879 if line.startswith(config + '='):
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900880 new_val = line
Masahiro Yamadab6160812015-05-20 11:36:07 +0900881 break
Masahiro Yamadab6160812015-05-20 11:36:07 +0900882 else:
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900883 new_val = not_set
884
Masahiro Yamada35204d92016-08-22 22:18:21 +0900885 for line in dotconfig_lines:
886 line = line.rstrip()
887 if line.startswith(config + '=') or line == not_set:
888 old_val = line
889 break
890 else:
891 if new_val == not_set:
892 return (ACTION_NO_ENTRY, config)
893 else:
894 return (ACTION_NO_ENTRY_WARN, config)
895
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900896 # If this CONFIG is neither bool nor trisate
897 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
898 # tools/scripts/define2mk.sed changes '1' to 'y'.
899 # This is a problem if the CONFIG is int type.
900 # Check the type in Kconfig and handle it correctly.
901 if new_val[-2:] == '=y':
902 new_val = new_val[:-1] + '1'
903
Masahiro Yamadab48387f2016-06-15 14:33:50 +0900904 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
905 new_val)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900906
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900907 def update_dotconfig(self):
Masahiro Yamada7c0d9d22016-05-19 15:51:50 +0900908 """Parse files for the config options and update the .config.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900909
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900910 This function parses the generated .config and include/autoconf.mk
911 searching the target options.
Masahiro Yamada7c0d9d22016-05-19 15:51:50 +0900912 Move the config option(s) to the .config as needed.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900913
914 Arguments:
915 defconfig: defconfig name.
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900916
917 Returns:
Masahiro Yamada263d1372016-05-19 15:52:04 +0900918 Return a tuple of (updated flag, log string).
919 The "updated flag" is True if the .config was updated, False
920 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900921 """
922
Masahiro Yamadab6160812015-05-20 11:36:07 +0900923 results = []
Masahiro Yamada263d1372016-05-19 15:52:04 +0900924 updated = False
Masahiro Yamada35204d92016-08-22 22:18:21 +0900925 suspicious = False
Masahiro Yamada6d139172016-08-22 22:18:22 +0900926 rm_files = [self.config_autoconf, self.autoconf]
927
928 if self.options.spl:
929 if os.path.exists(self.spl_autoconf):
930 autoconf_path = self.spl_autoconf
931 rm_files.append(self.spl_autoconf)
932 else:
933 for f in rm_files:
934 os.remove(f)
935 return (updated, suspicious,
936 color_text(self.options.color, COLOR_BROWN,
937 "SPL is not enabled. Skipped.") + '\n')
938 else:
939 autoconf_path = self.autoconf
Masahiro Yamadab6160812015-05-20 11:36:07 +0900940
Masahiro Yamada5393b612016-05-19 15:52:00 +0900941 with open(self.dotconfig) as f:
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900942 dotconfig_lines = f.readlines()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900943
Masahiro Yamada6d139172016-08-22 22:18:22 +0900944 with open(autoconf_path) as f:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900945 autoconf_lines = f.readlines()
946
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900947 for config in self.configs:
948 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger166edec2015-05-19 13:21:17 -0500949 autoconf_lines)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900950 results.append(result)
951
952 log = ''
953
954 for (action, value) in results:
955 if action == ACTION_MOVE:
956 actlog = "Move '%s'" % value
957 log_color = COLOR_LIGHT_GREEN
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900958 elif action == ACTION_NO_ENTRY:
959 actlog = "%s is not defined in Kconfig. Do nothing." % value
Masahiro Yamadab6160812015-05-20 11:36:07 +0900960 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada35204d92016-08-22 22:18:21 +0900961 elif action == ACTION_NO_ENTRY_WARN:
962 actlog = "%s is not defined in Kconfig (suspicious). Do nothing." % value
963 log_color = COLOR_YELLOW
964 suspicious = True
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900965 elif action == ACTION_NO_CHANGE:
966 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
967 % value
Masahiro Yamadab6160812015-05-20 11:36:07 +0900968 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada6d139172016-08-22 22:18:22 +0900969 elif action == ACTION_SPL_NOT_EXIST:
970 actlog = "SPL is not enabled for this defconfig. Skip."
971 log_color = COLOR_PURPLE
Masahiro Yamadab6160812015-05-20 11:36:07 +0900972 else:
973 sys.exit("Internal Error. This should not happen.")
974
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900975 log += color_text(self.options.color, log_color, actlog) + '\n'
Masahiro Yamadab6160812015-05-20 11:36:07 +0900976
Masahiro Yamada5393b612016-05-19 15:52:00 +0900977 with open(self.dotconfig, 'a') as f:
Masahiro Yamada953d93b2016-05-19 15:51:49 +0900978 for (action, value) in results:
979 if action == ACTION_MOVE:
980 f.write(value + '\n')
Masahiro Yamada263d1372016-05-19 15:52:04 +0900981 updated = True
Masahiro Yamadab6160812015-05-20 11:36:07 +0900982
Masahiro Yamada07f98522016-05-19 15:52:06 +0900983 self.results = results
Masahiro Yamada6d139172016-08-22 22:18:22 +0900984 for f in rm_files:
985 os.remove(f)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900986
Masahiro Yamada35204d92016-08-22 22:18:21 +0900987 return (updated, suspicious, log)
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900988
Masahiro Yamada07f98522016-05-19 15:52:06 +0900989 def check_defconfig(self):
990 """Check the defconfig after savedefconfig
991
992 Returns:
993 Return additional log if moved CONFIGs were removed again by
994 'make savedefconfig'.
995 """
996
997 log = ''
998
999 with open(self.defconfig) as f:
1000 defconfig_lines = f.readlines()
1001
1002 for (action, value) in self.results:
1003 if action != ACTION_MOVE:
1004 continue
1005 if not value + '\n' in defconfig_lines:
1006 log += color_text(self.options.color, COLOR_YELLOW,
1007 "'%s' was removed by savedefconfig.\n" %
1008 value)
1009
1010 return log
1011
Simon Glass43cf08f2017-06-01 19:39:02 -06001012
1013class DatabaseThread(threading.Thread):
1014 """This thread processes results from Slot threads.
1015
1016 It collects the data in the master config directary. There is only one
1017 result thread, and this helps to serialise the build output.
1018 """
1019 def __init__(self, config_db, db_queue):
1020 """Set up a new result thread
1021
1022 Args:
1023 builder: Builder which will be sent each result
1024 """
1025 threading.Thread.__init__(self)
1026 self.config_db = config_db
1027 self.db_queue= db_queue
1028
1029 def run(self):
1030 """Called to start up the result thread.
1031
1032 We collect the next result job and pass it on to the build.
1033 """
1034 while True:
1035 defconfig, configs = self.db_queue.get()
1036 self.config_db[defconfig] = configs
1037 self.db_queue.task_done()
1038
1039
Masahiro Yamadab6160812015-05-20 11:36:07 +09001040class Slot:
1041
1042 """A slot to store a subprocess.
1043
1044 Each instance of this class handles one subprocess.
1045 This class is useful to control multiple threads
1046 for faster processing.
1047 """
1048
Simon Glass43cf08f2017-06-01 19:39:02 -06001049 def __init__(self, configs, options, progress, devnull, make_cmd,
1050 reference_src_dir, db_queue):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001051 """Create a new process slot.
1052
1053 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001054 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001055 options: option flags.
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001056 progress: A progress indicator.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001057 devnull: A file object of '/dev/null'.
1058 make_cmd: command name of GNU Make.
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001059 reference_src_dir: Determine the true starting config state from this
1060 source tree.
Simon Glass43cf08f2017-06-01 19:39:02 -06001061 db_queue: output queue to write config info for the database
Masahiro Yamadab6160812015-05-20 11:36:07 +09001062 """
1063 self.options = options
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001064 self.progress = progress
Masahiro Yamadab6160812015-05-20 11:36:07 +09001065 self.build_dir = tempfile.mkdtemp()
1066 self.devnull = devnull
1067 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001068 self.reference_src_dir = reference_src_dir
Simon Glass43cf08f2017-06-01 19:39:02 -06001069 self.db_queue = db_queue
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +09001070 self.parser = KconfigParser(configs, options, self.build_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001071 self.state = STATE_IDLE
Masahiro Yamada1271b672016-08-22 22:18:20 +09001072 self.failed_boards = set()
1073 self.suspicious_boards = set()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001074
1075 def __del__(self):
1076 """Delete the working directory
1077
1078 This function makes sure the temporary directory is cleaned away
1079 even if Python suddenly dies due to error. It should be done in here
Joe Hershberger640de872016-06-10 14:53:29 -05001080 because it is guaranteed the destructor is always invoked when the
Masahiro Yamadab6160812015-05-20 11:36:07 +09001081 instance of the class gets unreferenced.
1082
1083 If the subprocess is still running, wait until it finishes.
1084 """
1085 if self.state != STATE_IDLE:
1086 while self.ps.poll() == None:
1087 pass
1088 shutil.rmtree(self.build_dir)
1089
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001090 def add(self, defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001091 """Assign a new subprocess for defconfig and add it to the slot.
1092
1093 If the slot is vacant, create a new subprocess for processing the
1094 given defconfig and add it to the slot. Just returns False if
1095 the slot is occupied (i.e. the current subprocess is still running).
1096
1097 Arguments:
1098 defconfig: defconfig name.
1099
1100 Returns:
1101 Return True on success or False on failure
1102 """
1103 if self.state != STATE_IDLE:
1104 return False
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001105
Masahiro Yamadab6160812015-05-20 11:36:07 +09001106 self.defconfig = defconfig
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001107 self.log = ''
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001108 self.current_src_dir = self.reference_src_dir
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001109 self.do_defconfig()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001110 return True
1111
1112 def poll(self):
1113 """Check the status of the subprocess and handle it as needed.
1114
1115 Returns True if the slot is vacant (i.e. in idle state).
1116 If the configuration is successfully finished, assign a new
1117 subprocess to build include/autoconf.mk.
1118 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada263d1372016-05-19 15:52:04 +09001119 parse the .config and the include/autoconf.mk, moving
1120 config options to the .config as needed.
1121 If the .config was updated, run "make savedefconfig" to sync
1122 it, update the original defconfig, and then set the slot back
1123 to the idle state.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001124
1125 Returns:
1126 Return True if the subprocess is terminated, False otherwise
1127 """
1128 if self.state == STATE_IDLE:
1129 return True
1130
1131 if self.ps.poll() == None:
1132 return False
1133
1134 if self.ps.poll() != 0:
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001135 self.handle_error()
1136 elif self.state == STATE_DEFCONFIG:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001137 if self.reference_src_dir and not self.current_src_dir:
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001138 self.do_savedefconfig()
1139 else:
1140 self.do_autoconf()
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001141 elif self.state == STATE_AUTOCONF:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001142 if self.current_src_dir:
1143 self.current_src_dir = None
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001144 self.do_defconfig()
Simon Glass43cf08f2017-06-01 19:39:02 -06001145 elif self.options.build_db:
1146 self.do_build_db()
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001147 else:
1148 self.do_savedefconfig()
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001149 elif self.state == STATE_SAVEDEFCONFIG:
1150 self.update_defconfig()
1151 else:
1152 sys.exit("Internal Error. This should not happen.")
Masahiro Yamadab6160812015-05-20 11:36:07 +09001153
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001154 return True if self.state == STATE_IDLE else False
Joe Hershberger166edec2015-05-19 13:21:17 -05001155
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001156 def handle_error(self):
1157 """Handle error cases."""
Masahiro Yamada83c17672016-05-19 15:52:08 +09001158
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001159 self.log += color_text(self.options.color, COLOR_LIGHT_RED,
1160 "Failed to process.\n")
1161 if self.options.verbose:
1162 self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
1163 self.ps.stderr.read())
1164 self.finish(False)
Joe Hershberger166edec2015-05-19 13:21:17 -05001165
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001166 def do_defconfig(self):
1167 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamada0f6beda2016-05-19 15:52:07 +09001168
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001169 cmd = list(self.make_cmd)
1170 cmd.append(self.defconfig)
1171 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001172 stderr=subprocess.PIPE,
1173 cwd=self.current_src_dir)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001174 self.state = STATE_DEFCONFIG
Masahiro Yamada0f6beda2016-05-19 15:52:07 +09001175
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001176 def do_autoconf(self):
Simon Glass8fb5bd02017-06-01 19:39:01 -06001177 """Run 'make AUTO_CONF_PATH'."""
Masahiro Yamadab6160812015-05-20 11:36:07 +09001178
Joe Hershberger11b02702015-05-19 13:21:23 -05001179 self.cross_compile = self.parser.get_cross_compile()
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +09001180 if self.cross_compile is None:
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001181 self.log += color_text(self.options.color, COLOR_YELLOW,
1182 "Compiler is missing. Do nothing.\n")
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001183 self.finish(False)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001184 return
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +09001185
Masahiro Yamadab6160812015-05-20 11:36:07 +09001186 cmd = list(self.make_cmd)
Joe Hershberger11b02702015-05-19 13:21:23 -05001187 if self.cross_compile:
1188 cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
Joe Hershberger765442b2015-05-19 13:21:18 -05001189 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Simon Glass8fb5bd02017-06-01 19:39:01 -06001190 cmd.append(AUTO_CONF_PATH)
Joe Hershberger11b02702015-05-19 13:21:23 -05001191 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001192 stderr=subprocess.PIPE,
1193 cwd=self.current_src_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001194 self.state = STATE_AUTOCONF
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001195
Simon Glass43cf08f2017-06-01 19:39:02 -06001196 def do_build_db(self):
1197 """Add the board to the database"""
1198 configs = {}
1199 with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd:
1200 for line in fd.readlines():
1201 if line.startswith('CONFIG'):
1202 config, value = line.split('=', 1)
1203 configs[config] = value.rstrip()
1204 self.db_queue.put([self.defconfig, configs])
1205 self.finish(True)
1206
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001207 def do_savedefconfig(self):
1208 """Update the .config and run 'make savedefconfig'."""
1209
Masahiro Yamada35204d92016-08-22 22:18:21 +09001210 (updated, suspicious, log) = self.parser.update_dotconfig()
1211 if suspicious:
1212 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001213 self.log += log
1214
1215 if not self.options.force_sync and not updated:
1216 self.finish(True)
1217 return
1218 if updated:
1219 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
1220 "Syncing by savedefconfig...\n")
1221 else:
1222 self.log += "Syncing by savedefconfig (forced by option)...\n"
1223
1224 cmd = list(self.make_cmd)
1225 cmd.append('savedefconfig')
1226 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1227 stderr=subprocess.PIPE)
1228 self.state = STATE_SAVEDEFCONFIG
1229
1230 def update_defconfig(self):
1231 """Update the input defconfig and go back to the idle state."""
1232
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001233 log = self.parser.check_defconfig()
1234 if log:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001235 self.suspicious_boards.add(self.defconfig)
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001236 self.log += log
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001237 orig_defconfig = os.path.join('configs', self.defconfig)
1238 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1239 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1240
1241 if updated:
Joe Hershberger93f1c2d2016-06-10 14:53:30 -05001242 self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001243 "defconfig was updated.\n")
1244
1245 if not self.options.dry_run and updated:
1246 shutil.move(new_defconfig, orig_defconfig)
1247 self.finish(True)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001248
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001249 def finish(self, success):
1250 """Display log along with progress and go to the idle state.
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001251
1252 Arguments:
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001253 success: Should be True when the defconfig was processed
1254 successfully, or False when it fails.
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001255 """
1256 # output at least 30 characters to hide the "* defconfigs out of *".
1257 log = self.defconfig.ljust(30) + '\n'
1258
1259 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1260 # Some threads are running in parallel.
1261 # Print log atomically to not mix up logs from different threads.
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001262 print >> (sys.stdout if success else sys.stderr), log
1263
1264 if not success:
1265 if self.options.exit_on_error:
1266 sys.exit("Exit on error.")
1267 # If --exit-on-error flag is not set, skip this board and continue.
1268 # Record the failed board.
Masahiro Yamada1271b672016-08-22 22:18:20 +09001269 self.failed_boards.add(self.defconfig)
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001270
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001271 self.progress.inc()
1272 self.progress.show()
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001273 self.state = STATE_IDLE
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001274
Masahiro Yamadab6160812015-05-20 11:36:07 +09001275 def get_failed_boards(self):
Masahiro Yamada1271b672016-08-22 22:18:20 +09001276 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001277 """
1278 return self.failed_boards
1279
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001280 def get_suspicious_boards(self):
Masahiro Yamada1271b672016-08-22 22:18:20 +09001281 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001282 """
Masahiro Yamada35204d92016-08-22 22:18:21 +09001283 return self.suspicious_boards - self.failed_boards
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001284
Masahiro Yamadab6160812015-05-20 11:36:07 +09001285class Slots:
1286
1287 """Controller of the array of subprocess slots."""
1288
Simon Glass43cf08f2017-06-01 19:39:02 -06001289 def __init__(self, configs, options, progress, reference_src_dir, db_queue):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001290 """Create a new slots controller.
1291
1292 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001293 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001294 options: option flags.
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001295 progress: A progress indicator.
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001296 reference_src_dir: Determine the true starting config state from this
1297 source tree.
Simon Glass43cf08f2017-06-01 19:39:02 -06001298 db_queue: output queue to write config info for the database
Masahiro Yamadab6160812015-05-20 11:36:07 +09001299 """
1300 self.options = options
1301 self.slots = []
1302 devnull = get_devnull()
1303 make_cmd = get_make_cmd()
1304 for i in range(options.jobs):
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001305 self.slots.append(Slot(configs, options, progress, devnull,
Simon Glass43cf08f2017-06-01 19:39:02 -06001306 make_cmd, reference_src_dir, db_queue))
Masahiro Yamadab6160812015-05-20 11:36:07 +09001307
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001308 def add(self, defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001309 """Add a new subprocess if a vacant slot is found.
1310
1311 Arguments:
1312 defconfig: defconfig name to be put into.
1313
1314 Returns:
1315 Return True on success or False on failure
1316 """
1317 for slot in self.slots:
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001318 if slot.add(defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001319 return True
1320 return False
1321
1322 def available(self):
1323 """Check if there is a vacant slot.
1324
1325 Returns:
1326 Return True if at lease one vacant slot is found, False otherwise.
1327 """
1328 for slot in self.slots:
1329 if slot.poll():
1330 return True
1331 return False
1332
1333 def empty(self):
1334 """Check if all slots are vacant.
1335
1336 Returns:
1337 Return True if all the slots are vacant, False otherwise.
1338 """
1339 ret = True
1340 for slot in self.slots:
1341 if not slot.poll():
1342 ret = False
1343 return ret
1344
1345 def show_failed_boards(self):
1346 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada1271b672016-08-22 22:18:20 +09001347 boards = set()
Masahiro Yamada0153f032016-06-15 14:33:53 +09001348 output_file = 'moveconfig.failed'
Masahiro Yamadab6160812015-05-20 11:36:07 +09001349
1350 for slot in self.slots:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001351 boards |= slot.get_failed_boards()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001352
Masahiro Yamada0153f032016-06-15 14:33:53 +09001353 if boards:
1354 boards = '\n'.join(boards) + '\n'
1355 msg = "The following boards were not processed due to error:\n"
1356 msg += boards
1357 msg += "(the list has been saved in %s)\n" % output_file
1358 print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
1359 msg)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001360
Masahiro Yamada0153f032016-06-15 14:33:53 +09001361 with open(output_file, 'w') as f:
1362 f.write(boards)
Joe Hershbergerdade12e2015-05-19 13:21:22 -05001363
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001364 def show_suspicious_boards(self):
1365 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada1271b672016-08-22 22:18:20 +09001366 boards = set()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001367 output_file = 'moveconfig.suspicious'
1368
1369 for slot in self.slots:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001370 boards |= slot.get_suspicious_boards()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001371
1372 if boards:
1373 boards = '\n'.join(boards) + '\n'
1374 msg = "The following boards might have been converted incorrectly.\n"
1375 msg += "It is highly recommended to check them manually:\n"
1376 msg += boards
1377 msg += "(the list has been saved in %s)\n" % output_file
1378 print >> sys.stderr, color_text(self.options.color, COLOR_YELLOW,
1379 msg)
1380
1381 with open(output_file, 'w') as f:
1382 f.write(boards)
1383
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001384class ReferenceSource:
1385
1386 """Reference source against which original configs should be parsed."""
1387
1388 def __init__(self, commit):
1389 """Create a reference source directory based on a specified commit.
1390
1391 Arguments:
1392 commit: commit to git-clone
1393 """
1394 self.src_dir = tempfile.mkdtemp()
1395 print "Cloning git repo to a separate work directory..."
1396 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1397 cwd=self.src_dir)
1398 print "Checkout '%s' to build the original autoconf.mk." % \
1399 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
1400 subprocess.check_output(['git', 'checkout', commit],
1401 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001402
1403 def __del__(self):
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001404 """Delete the reference source directory
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001405
1406 This function makes sure the temporary directory is cleaned away
1407 even if Python suddenly dies due to error. It should be done in here
1408 because it is guaranteed the destructor is always invoked when the
1409 instance of the class gets unreferenced.
1410 """
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001411 shutil.rmtree(self.src_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001412
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001413 def get_dir(self):
1414 """Return the absolute path to the reference source directory."""
1415
1416 return self.src_dir
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001417
Simon Glass43cf08f2017-06-01 19:39:02 -06001418def move_config(configs, options, db_queue):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001419 """Move config options to defconfig files.
1420
1421 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001422 configs: A list of CONFIGs to move.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001423 options: option flags
1424 """
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001425 if len(configs) == 0:
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001426 if options.force_sync:
1427 print 'No CONFIG is specified. You are probably syncing defconfigs.',
Simon Glass43cf08f2017-06-01 19:39:02 -06001428 elif options.build_db:
1429 print 'Building %s database' % CONFIG_DATABASE
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001430 else:
1431 print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
1432 else:
1433 print 'Move ' + ', '.join(configs),
1434 print '(jobs: %d)\n' % options.jobs
Masahiro Yamadab6160812015-05-20 11:36:07 +09001435
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001436 if options.git_ref:
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001437 reference_src = ReferenceSource(options.git_ref)
1438 reference_src_dir = reference_src.get_dir()
1439 else:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001440 reference_src_dir = None
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001441
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001442 if options.defconfigs:
Masahiro Yamada3984d6e2016-10-19 14:39:54 +09001443 defconfigs = get_matched_defconfigs(options.defconfigs)
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001444 else:
Masahiro Yamada58175e32016-07-25 19:15:28 +09001445 defconfigs = get_all_defconfigs()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001446
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001447 progress = Progress(len(defconfigs))
Simon Glass43cf08f2017-06-01 19:39:02 -06001448 slots = Slots(configs, options, progress, reference_src_dir, db_queue)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001449
1450 # Main loop to process defconfig files:
1451 # Add a new subprocess into a vacant slot.
1452 # Sleep if there is no available slot.
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001453 for defconfig in defconfigs:
1454 while not slots.add(defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001455 while not slots.available():
1456 # No available slot: sleep for a while
1457 time.sleep(SLEEP_TIME)
1458
1459 # wait until all the subprocesses finish
1460 while not slots.empty():
1461 time.sleep(SLEEP_TIME)
1462
Joe Hershberger3fa1ab72015-05-19 13:21:25 -05001463 print ''
Masahiro Yamadab6160812015-05-20 11:36:07 +09001464 slots.show_failed_boards()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001465 slots.show_suspicious_boards()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001466
Simon Glass92e55582017-06-15 21:39:32 -06001467(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD) = (1, 2, 4)
1468
1469IMPLY_FLAGS = {
1470 'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'],
1471 'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'],
1472 'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'],
1473};
1474
1475def do_imply_config(config_list, imply_flags, find_superset=False):
Simon Glassc6e73cf2017-06-01 19:39:03 -06001476 """Find CONFIG options which imply those in the list
1477
1478 Some CONFIG options can be implied by others and this can help to reduce
1479 the size of the defconfig files. For example, CONFIG_X86 implies
1480 CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
1481 all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
1482 each of the x86 defconfig files.
1483
1484 This function uses the moveconfig database to find such options. It
1485 displays a list of things that could possibly imply those in the list.
1486 The algorithm ignores any that start with CONFIG_TARGET since these
1487 typically refer to only a few defconfigs (often one). It also does not
1488 display a config with less than 5 defconfigs.
1489
1490 The algorithm works using sets. For each target config in config_list:
1491 - Get the set 'defconfigs' which use that target config
1492 - For each config (from a list of all configs):
1493 - Get the set 'imply_defconfig' of defconfigs which use that config
1494 -
1495 - If imply_defconfigs contains anything not in defconfigs then
1496 this config does not imply the target config
1497
1498 Params:
1499 config_list: List of CONFIG options to check (each a string)
Simon Glass92e55582017-06-15 21:39:32 -06001500 imply_flags: Flags which control which implying configs are allowed
1501 (IMPLY_...)
Simon Glassc6e73cf2017-06-01 19:39:03 -06001502 find_superset: True to look for configs which are a superset of those
1503 already found. So for example if CONFIG_EXYNOS5 implies an option,
1504 but CONFIG_EXYNOS covers a larger set of defconfigs and also
1505 implies that option, this will drop the former in favour of the
1506 latter. In practice this option has not proved very used.
1507
1508 Note the terminoloy:
1509 config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM')
1510 defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig')
1511 """
1512 # key is defconfig name, value is dict of (CONFIG_xxx, value)
1513 config_db = {}
1514
1515 # Holds a dict containing the set of defconfigs that contain each config
1516 # key is config, value is set of defconfigs using that config
1517 defconfig_db = collections.defaultdict(set)
1518
1519 # Set of all config options we have seen
1520 all_configs = set()
1521
1522 # Set of all defconfigs we have seen
1523 all_defconfigs = set()
1524
1525 # Read in the database
1526 configs = {}
1527 with open(CONFIG_DATABASE) as fd:
1528 for line in fd.readlines():
1529 line = line.rstrip()
1530 if not line: # Separator between defconfigs
1531 config_db[defconfig] = configs
1532 all_defconfigs.add(defconfig)
1533 configs = {}
1534 elif line[0] == ' ': # CONFIG line
1535 config, value = line.strip().split('=', 1)
1536 configs[config] = value
1537 defconfig_db[config].add(defconfig)
1538 all_configs.add(config)
1539 else: # New defconfig
1540 defconfig = line
1541
1542 # Work through each target config option in tern, independently
1543 for config in config_list:
1544 defconfigs = defconfig_db.get(config)
1545 if not defconfigs:
1546 print '%s not found in any defconfig' % config
1547 continue
1548
1549 # Get the set of defconfigs without this one (since a config cannot
1550 # imply itself)
1551 non_defconfigs = all_defconfigs - defconfigs
1552 num_defconfigs = len(defconfigs)
1553 print '%s found in %d/%d defconfigs' % (config, num_defconfigs,
1554 len(all_configs))
1555
1556 # This will hold the results: key=config, value=defconfigs containing it
1557 imply_configs = {}
1558 rest_configs = all_configs - set([config])
1559
1560 # Look at every possible config, except the target one
1561 for imply_config in rest_configs:
Simon Glass92e55582017-06-15 21:39:32 -06001562 if 'ERRATUM' in imply_config:
Simon Glassc6e73cf2017-06-01 19:39:03 -06001563 continue
Simon Glass92e55582017-06-15 21:39:32 -06001564 if not (imply_flags & IMPLY_CMD):
1565 if 'CONFIG_CMD' in imply_config:
1566 continue
1567 if not (imply_flags & IMPLY_TARGET):
1568 if 'CONFIG_TARGET' in imply_config:
1569 continue
Simon Glassc6e73cf2017-06-01 19:39:03 -06001570
1571 # Find set of defconfigs that have this config
1572 imply_defconfig = defconfig_db[imply_config]
1573
1574 # Get the intersection of this with defconfigs containing the
1575 # target config
1576 common_defconfigs = imply_defconfig & defconfigs
1577
1578 # Get the set of defconfigs containing this config which DO NOT
1579 # also contain the taret config. If this set is non-empty it means
1580 # that this config affects other defconfigs as well as (possibly)
1581 # the ones affected by the target config. This means it implies
1582 # things we don't want to imply.
1583 not_common_defconfigs = imply_defconfig & non_defconfigs
1584 if not_common_defconfigs:
1585 continue
1586
1587 # If there are common defconfigs, imply_config may be useful
1588 if common_defconfigs:
1589 skip = False
1590 if find_superset:
1591 for prev in imply_configs.keys():
1592 prev_count = len(imply_configs[prev])
1593 count = len(common_defconfigs)
1594 if (prev_count > count and
1595 (imply_configs[prev] & common_defconfigs ==
1596 common_defconfigs)):
1597 # skip imply_config because prev is a superset
1598 skip = True
1599 break
1600 elif count > prev_count:
1601 # delete prev because imply_config is a superset
1602 del imply_configs[prev]
1603 if not skip:
1604 imply_configs[imply_config] = common_defconfigs
1605
1606 # Now we have a dict imply_configs of configs which imply each config
1607 # The value of each dict item is the set of defconfigs containing that
1608 # config. Rank them so that we print the configs that imply the largest
1609 # number of defconfigs first.
1610 ranked_configs = sorted(imply_configs,
1611 key=lambda k: len(imply_configs[k]), reverse=True)
1612 for config in ranked_configs:
1613 num_common = len(imply_configs[config])
1614
1615 # Don't bother if there are less than 5 defconfigs affected.
Simon Glass92e55582017-06-15 21:39:32 -06001616 if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5):
Simon Glassc6e73cf2017-06-01 19:39:03 -06001617 continue
1618 missing = defconfigs - imply_configs[config]
1619 missing_str = ', '.join(missing) if missing else 'all'
1620 missing_str = ''
1621 print ' %d : %-30s%s' % (num_common, config.ljust(30),
1622 missing_str)
1623
1624
Masahiro Yamadab6160812015-05-20 11:36:07 +09001625def main():
1626 try:
1627 cpu_count = multiprocessing.cpu_count()
1628 except NotImplementedError:
1629 cpu_count = 1
1630
1631 parser = optparse.OptionParser()
1632 # Add options here
Simon Glass43cf08f2017-06-01 19:39:02 -06001633 parser.add_option('-b', '--build-db', action='store_true', default=False,
1634 help='build a CONFIG database')
Masahiro Yamadab6160812015-05-20 11:36:07 +09001635 parser.add_option('-c', '--color', action='store_true', default=False,
1636 help='display the log in color')
Simon Glass8bf41c22016-09-12 23:18:21 -06001637 parser.add_option('-C', '--commit', action='store_true', default=False,
1638 help='Create a git commit for the operation')
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001639 parser.add_option('-d', '--defconfigs', type='string',
Simon Glass8f3cf312017-06-01 19:38:59 -06001640 help='a file containing a list of defconfigs to move, '
1641 "one per line (for example 'snow_defconfig') "
1642 "or '-' to read from stdin")
Simon Glassc6e73cf2017-06-01 19:39:03 -06001643 parser.add_option('-i', '--imply', action='store_true', default=False,
1644 help='find options which imply others')
Simon Glass92e55582017-06-15 21:39:32 -06001645 parser.add_option('-I', '--imply-flags', type='string', default='',
1646 help="control the -i option ('help' for help")
Masahiro Yamadab6160812015-05-20 11:36:07 +09001647 parser.add_option('-n', '--dry-run', action='store_true', default=False,
1648 help='perform a trial run (show log with no changes)')
1649 parser.add_option('-e', '--exit-on-error', action='store_true',
1650 default=False,
1651 help='exit immediately on any error')
Masahiro Yamada83c17672016-05-19 15:52:08 +09001652 parser.add_option('-s', '--force-sync', action='store_true', default=False,
1653 help='force sync by savedefconfig')
Masahiro Yamada6d139172016-08-22 22:18:22 +09001654 parser.add_option('-S', '--spl', action='store_true', default=False,
1655 help='parse config options defined for SPL build')
Joe Hershberger23475932015-05-19 13:21:20 -05001656 parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
1657 action='store_true', default=False,
1658 help='only cleanup the headers')
Masahiro Yamadab6160812015-05-20 11:36:07 +09001659 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
1660 help='the number of jobs to run simultaneously')
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001661 parser.add_option('-r', '--git-ref', type='string',
1662 help='the git ref to clone for building the autoconf.mk')
Simon Glass13e05a02016-09-12 23:18:20 -06001663 parser.add_option('-y', '--yes', action='store_true', default=False,
1664 help="respond 'yes' to any prompts")
Joe Hershberger808b63f2015-05-19 13:21:24 -05001665 parser.add_option('-v', '--verbose', action='store_true', default=False,
1666 help='show any build errors as boards are built')
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001667 parser.usage += ' CONFIG ...'
Masahiro Yamadab6160812015-05-20 11:36:07 +09001668
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001669 (options, configs) = parser.parse_args()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001670
Simon Glassc6e73cf2017-06-01 19:39:03 -06001671 if len(configs) == 0 and not any((options.force_sync, options.build_db,
1672 options.imply)):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001673 parser.print_usage()
1674 sys.exit(1)
1675
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001676 # prefix the option name with CONFIG_ if missing
1677 configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
1678 for config in configs ]
Masahiro Yamadab6160812015-05-20 11:36:07 +09001679
Joe Hershberger23475932015-05-19 13:21:20 -05001680 check_top_directory()
1681
Simon Glassc6e73cf2017-06-01 19:39:03 -06001682 if options.imply:
Simon Glass92e55582017-06-15 21:39:32 -06001683 imply_flags = 0
1684 for flag in options.imply_flags.split():
1685 if flag == 'help' or flag not in IMPLY_FLAGS:
1686 print "Imply flags: (separate with ',')"
1687 for name, info in IMPLY_FLAGS.iteritems():
1688 print ' %-15s: %s' % (name, info[1])
1689 parser.print_usage()
1690 sys.exit(1)
1691 imply_flags |= IMPLY_FLAGS[flag][0]
1692
1693 do_imply_config(configs, imply_flags)
Simon Glassc6e73cf2017-06-01 19:39:03 -06001694 return
1695
Simon Glass43cf08f2017-06-01 19:39:02 -06001696 config_db = {}
1697 db_queue = Queue.Queue()
1698 t = DatabaseThread(config_db, db_queue)
1699 t.setDaemon(True)
1700 t.start()
1701
Joe Hershberger23475932015-05-19 13:21:20 -05001702 if not options.cleanup_headers_only:
Masahiro Yamadad0a9d2a2016-07-25 19:15:23 +09001703 check_clean_directory()
1704 update_cross_compile(options.color)
Simon Glass43cf08f2017-06-01 19:39:02 -06001705 move_config(configs, options, db_queue)
1706 db_queue.join()
Joe Hershberger23475932015-05-19 13:21:20 -05001707
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001708 if configs:
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +09001709 cleanup_headers(configs, options)
Masahiro Yamadadce28de2016-07-25 19:15:29 +09001710 cleanup_extra_options(configs, options)
Chris Packham9d5274f2017-05-02 21:30:47 +12001711 cleanup_whitelist(configs, options)
Chris Packham0e6deff2017-05-02 21:30:48 +12001712 cleanup_readme(configs, options)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001713
Simon Glass8bf41c22016-09-12 23:18:21 -06001714 if options.commit:
1715 subprocess.call(['git', 'add', '-u'])
1716 if configs:
1717 msg = 'Convert %s %sto Kconfig' % (configs[0],
1718 'et al ' if len(configs) > 1 else '')
1719 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1720 '\n '.join(configs))
1721 else:
1722 msg = 'configs: Resync with savedefconfig'
1723 msg += '\n\nRsync all defconfig files using moveconfig.py'
1724 subprocess.call(['git', 'commit', '-s', '-m', msg])
1725
Simon Glass43cf08f2017-06-01 19:39:02 -06001726 if options.build_db:
1727 with open(CONFIG_DATABASE, 'w') as fd:
1728 for defconfig, configs in config_db.iteritems():
1729 print >>fd, '%s' % defconfig
1730 for config in sorted(configs.keys()):
1731 print >>fd, ' %s=%s' % (config, configs[config])
1732 print >>fd
1733
Masahiro Yamadab6160812015-05-20 11:36:07 +09001734if __name__ == '__main__':
1735 main()